diff options
694 files changed, 16673 insertions, 11267 deletions
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt index 56d6d8b796db..701d39d3171a 100644 --- a/Documentation/arm64/booting.txt +++ b/Documentation/arm64/booting.txt @@ -109,13 +109,7 @@ Header notes: 1 - 4K 2 - 16K 3 - 64K - Bit 3: Kernel physical placement - 0 - 2MB aligned base should be as close as possible - to the base of DRAM, since memory below it is not - accessible via the linear mapping - 1 - 2MB aligned base may be anywhere in physical - memory - Bits 4-63: Reserved. + Bits 3-63: Reserved. - When image_size is zero, a bootloader should attempt to keep as much memory as possible free for use by the kernel immediately after the @@ -123,14 +117,14 @@ Header notes: depending on selected features, and is effectively unbound. The Image must be placed text_offset bytes from a 2MB aligned base -address anywhere in usable system RAM and called there. The region -between the 2 MB aligned base address and the start of the image has no -special significance to the kernel, and may be used for other purposes. +address near the start of usable system RAM and called there. Memory +below that base address is currently unusable by Linux, and therefore it +is strongly recommended that this location is the start of system RAM. +The region between the 2 MB aligned base address and the start of the +image has no special significance to the kernel, and may be used for +other purposes. At least image_size bytes from the start of the image must be free for use by the kernel. -NOTE: versions prior to v4.6 cannot make use of memory below the -physical offset of the Image so it is recommended that the Image be -placed as close as possible to the start of system RAM. Any memory described to the kernel (even that below the start of the image) which is not marked as reserved from the kernel (e.g., with a diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt deleted file mode 100644 index 58b71ddf9b60..000000000000 --- a/Documentation/arm64/silicon-errata.txt +++ /dev/null @@ -1,58 +0,0 @@ - Silicon Errata and Software Workarounds - ======================================= - -Author: Will Deacon <will.deacon@arm.com> -Date : 27 November 2015 - -It is an unfortunate fact of life that hardware is often produced with -so-called "errata", which can cause it to deviate from the architecture -under specific circumstances. For hardware produced by ARM, these -errata are broadly classified into the following categories: - - Category A: A critical error without a viable workaround. - Category B: A significant or critical error with an acceptable - workaround. - Category C: A minor error that is not expected to occur under normal - operation. - -For more information, consult one of the "Software Developers Errata -Notice" documents available on infocenter.arm.com (registration -required). - -As far as Linux is concerned, Category B errata may require some special -treatment in the operating system. For example, avoiding a particular -sequence of code, or configuring the processor in a particular way. A -less common situation may require similar actions in order to declassify -a Category A erratum into a Category C erratum. These are collectively -known as "software workarounds" and are only required in the minority of -cases (e.g. those cases that both require a non-secure workaround *and* -can be triggered by Linux). - -For software workarounds that may adversely impact systems unaffected by -the erratum in question, a Kconfig entry is added under "Kernel -Features" -> "ARM errata workarounds via the alternatives framework". -These are enabled by default and patched in at runtime when an affected -CPU is detected. For less-intrusive workarounds, a Kconfig option is not -available and the code is structured (preferably with a comment) in such -a way that the erratum will not be hit. - -This approach can make it slightly onerous to determine exactly which -errata are worked around in an arbitrary kernel source tree, so this -file acts as a registry of software workarounds in the Linux Kernel and -will be updated when new workarounds are committed and backported to -stable kernels. - -| Implementor | Component | Erratum ID | Kconfig | -+----------------+-----------------+-----------------+-------------------------+ -| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | -| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 | -| ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 | -| ARM | Cortex-A53 | #819472 | ARM64_ERRATUM_819472 | -| ARM | Cortex-A53 | #845719 | ARM64_ERRATUM_845719 | -| ARM | Cortex-A53 | #843419 | ARM64_ERRATUM_843419 | -| ARM | Cortex-A57 | #832075 | ARM64_ERRATUM_832075 | -| ARM | Cortex-A57 | #852523 | N/A | -| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 | -| | | | | -| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 | -| Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 | diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller-dummy.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller-dummy.txt index fff8c9e20a1b..c6db837fa137 100644 --- a/Documentation/devicetree/bindings/arm/msm/clock-controller-dummy.txt +++ b/Documentation/devicetree/bindings/arm/msm/clock-controller-dummy.txt @@ -9,9 +9,14 @@ Required properties: - #clock_cells: Must be <1>. This will allow the common clock device tree framework to recognize _this_ device node as a clock provider. +Optional properties: +- #reset-cells: Must be <1>. This will allow the common reset device + tree framework to recognize _this_ device node as a + reset controller provider. Example: clock_rpm: qcom,rpmcc { compatible = "qcom,dummycc"; #clock-cells = <1>; + #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index cee9b942a9e3..bcdef5564066 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -16,12 +16,14 @@ Properties: Value type: <prop-encoded-array> Definition: Addresses and sizes for the memory of the OSM controller, cluster PLL management, and APCS common register regions. - + Optionally, the address of the efuse registers used to + determine the pwrcl or perfcl speed-bins. - reg-names Usage: required Value type: <stringlist> Definition: Address names. Must be "osm", "pwrcl_pll", "perfcl_pll", - and "apcs_common". + and "apcs_common". Optionally, "pwrcl_efuse" or + "perfcl_efuse". Must be specified in the same order as the corresponding addresses are specified in the reg property. diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index c000832a7fb9..c2340eeeb97f 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -30,10 +30,6 @@ Optional properties: - target-supply : regulator for SATA target power - phys : reference to the SATA PHY node - phy-names : must be "sata-phy" -- ports-implemented : Mask that indicates which ports that the HBA supports - are available for software to use. Useful if PORTS_IMPL - is not programmed by the BIOS, which is true with - some embedded SOC's. Required properties when using sub-nodes: - #address-cells : number of cells to encode an address diff --git a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt index 72bbb6180258..187c5604b521 100644 --- a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt +++ b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt @@ -29,7 +29,8 @@ Optional properties: - qcom,msm-bus,num-cases: number of cases for bus scaling. - qcom,msm-bus,num-paths: number of paths for bus scale vector. - qcom,msm-bus,vectors-KBps: bus scale vector table. - + - qcom,skip-wlan-en-toggle: Boolean property to be enabled for platforms where + wlan_en toggling is not supported. Example: qcom,cnss-sdio { compatible = "qcom,cnss_sdio"; diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt index da4cdf253b2c..628b4df9fd7d 100644 --- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt +++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt @@ -53,23 +53,29 @@ Optional properties: - "secondary" - "tertiary" -[Optional child nodes]: These nodes are for devices which are -dependent on HDMI Tx controller. If HDMI Tx controller is disabled then -these devices will be disabled as well. Ex. HDMI Audio Codec device. - -- qcom,msm-hdmi-audio-rx: Node for HDMI audio codec. -Required properties: -- compatible : "msm-hdmi-audio-codec-rx"; - msm_ext_disp is a device which manages the interaction between external displays (HDMI and Display Port) and the audio and display frameworks. Required properties: - compatible: Must be "qcom,msm-ext-disp" +[Required child nodes]: These nodes are for devices which are +dependent on msm_ext_disp. If msm_ext_disp is disabled then +these devices will be disabled as well. Ex. Audio Codec device. + +- ext_disp_audio_codec: Node for Audio Codec. + +Required properties: +- compatible : "qcom,msm-ext-disp-audio-codec-rx"; + Example: msm_ext_disp: qcom,msm_ext_disp { compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + qcom,msm_ext_disp = <&msm_ext_disp>; + }; }; mdss_hdmi_tx: qcom,hdmi_tx@fd922100 { @@ -109,9 +115,6 @@ Example: qcom,pluggable; qcom,display-id = "secondary"; - qcom,msm-hdmi-audio-rx { - compatible = "qcom,msm-hdmi-audio-codec-rx"; - }; pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", "hdmi_active", "hdmi_sleep"; diff --git a/Documentation/devicetree/bindings/iio/adc/qcom-tadc.txt b/Documentation/devicetree/bindings/iio/adc/qcom-tadc.txt new file mode 100644 index 000000000000..6880d304367d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/qcom-tadc.txt @@ -0,0 +1,141 @@ +Qualcomm Technologies, Inc. TADC Specific Bindings + +TADC (Telemetry ADC) is a 10 bit resolution ADC which has 8 channels: battery +temperature, skin temperature, die temperature, battery current, battery +voltage, input current, input voltage, and OTG current. + +======================= +Required Node Structure +======================= + +A TADC must be described in two levels of devices nodes. + +======================= +First Level Node - TADC +======================= + +- reg + Usage: required + Value type: <prop-encoded-array> + Definition: Address and size of the TADC register block. + +TADC specific properties: +- compatible + Usage: required + Value type: <string> + Definition: Must be "qcom,tadc". + +- interrupts + Usage: required + Value type: <prop-encoded-array> + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: <stringlist> + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +============================================= +Second Level Nodes - TADC Thermistor Channels +============================================= + +- reg + Usage: required + Value type: <u32> + Definition: The 0 based channel number. + +TADC thermistor channel specific properties: +- qcom,rbias + Usage: required + Value type: <u32> + Definition: The bias resistor value. + +- qcom,therm-at-25degc + Usage: required + Value type: <u32> + Definition: The thermistor resistance at 25 DegC. + +- qcom,beta-coefficient + Usage: required + Value type: <u32> + Definition: The beta coefficeent or B-parameter of the thermistor. + +=============================================== +Second Level Nodes - TADC Scale/Offset Channels +=============================================== + +- reg + Usage: required + Value type: <u32> + Definition: The 0 based channel number. + +TADC scale/offset channel specific properties: +- qcom,scale + Usage: required + Value type: <s32> + Definition: The RAW scaling factor. + +- qcom,offset + Usage: optional + Value type: <s32> + Definition: The offset after scaling. + +======= +Example +======= + +smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_temp@0 { + reg = <0>; + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp@1 { + reg = <1>; + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp@2 { + reg = <2>; + qcom,scale = <(-1032)>; + qcom,offset = <344125>; + }; + + batt_i@3 { + reg = <3>; + qcom,channel = <3>; + qcom,scale = <20000000>; + }; + + batt_v@4 { + reg = <4>; + qcom,scale = <5000000>; + }; + + input_i@5 { + reg = <5>; + qcom,scale = <14285714>; + }; + + input_v@6 { + reg = <6>; + qcom,scale = <25000000>; + }; + + otg_i@7 { + reg = <7>; + qcom,scale = <5714286>; + }; +}; diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt index c852394254ff..ec8b08ad60e4 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt @@ -70,6 +70,8 @@ Optional properties: min y, max x and max y values - focaltech,fw-name : specify the firmware file name - focaltech,psensor-support : specify whether support the proximity sensor + - focaltech,gesture-support : specify whether support gesture feature + - focaltech,resume-in-workqueue : specifiy whether to defer the resume to workqueue Example: i2c@f9923000{ @@ -106,5 +108,6 @@ Example: focaltech,fw-delay-era-flsh-ms = <2000>; focaltech,fw-auto-cal; focaltech,psensor-support; + focaltech,gesture-support; }; }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt index 086af9b337f4..fb1ca0261f9c 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt @@ -106,6 +106,8 @@ Optional properties: - qcom,mount-angle : should contain the physical mount angle of the sensor on the target - 0, 90, 180, 360 +- qcom,secure : should be enabled to operate the camera in secure mode + - 0, 1 - qcom,mclk-23880000 : should be enabled if the supported mclk is 23.88Mhz and not 24 Mhz. - qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is @@ -273,6 +275,7 @@ Example: qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; qcom,mount-angle = <90>; + qcom,secure = <1>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,eeprom-src = <&eeprom0>; diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt index 5a415d04fbcf..510a824fda79 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt @@ -65,6 +65,37 @@ Charger specific properties: maximum charge current in mA for each thermal level. +- qcom,step-soc-thresholds + Usage: optional + Value type: Array of <u32> + Definition: Array of SOC threshold values, size of 4. This should be a + flat array that denotes the percentage ranging from 0 to 100. + If the array is not present, step charging is disabled. + +- qcom,step-current-deltas + Usage: optional + Value type: Array of <s32> + Definition: Array of delta values for charging current, size of 5, with + FCC as base. This should be a flat array that denotes the + offset of charging current in uA, from -3100000 to 3200000. + If the array is not present, step charging is disabled. + +- io-channels + Usage: optional + Value type: List of <phandle u32> + Definition: List of phandle and IIO specifier pairs, one pair + for each IIO input to the device. Note: if the + IIO provider specifies '0' for #io-channel-cells, + then only the phandle portion of the pair will appear. + +- io-channel-names + Usage: optional + Value type: List of <string> + Definition: List of IIO input name strings sorted in the same + order as the io-channels property. Consumer drivers + will use io-channel-names to match IIO input names + with IIO specifiers. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= @@ -95,9 +126,15 @@ pmicobalt_charger: qcom,qpnp-smb2 { #address-cells = <1>; #size-cells = <1>; + io-channels = <&pmic_rradc 0>; + io-channel-names = "rradc_batt_id"; + qcom,suspend-input; dpdm-supply = <&qusb_phy0>; + qcom,step-soc-thresholds = <60 70 80 90>; + qcom,step-current-deltas = <500000 250000 150000 0 (-150000)>; + qcom,chgr@1000 { reg = <0x1000 0x100>; interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt index 7d88e9fbd9c6..af53e59cd87f 100644 --- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt @@ -35,13 +35,15 @@ Platform independent properties: - reg Usage: required Value type: <prop-encoded-array> - Definition: Addresses and sizes for the memory of the CPR3 controller - and the first fuse row + Definition: Addresses and sizes for the memory of the CPR3 controller, + the first fuse row, and optionally a register used to check + if aging measurements are possible. - reg-names Usage: required Value type: <stringlist> - Definition: Address names. Must be "cpr_ctrl" and "fuse_base". Must be + Definition: Address names. Must include "cpr_ctrl" and "fuse_base". + "aging_allowed" may also be specified. The strings must be specified in the same order as the corresponding addresses are specified in the reg property. @@ -183,6 +185,17 @@ Platform independent properties: This is the voltage that vdd-supply must be set to when performing an aging measurement. +- qcom,cpr-aging-allowed-reg-mask + Usage: required if "aging_allowed" register is specified + Value type: <u32> + Definition: Bitmask used to mask off the "aging_allowed" register. + +- qcom,cpr-aging-allowed-reg-value + Usage: required if "aging_allowed" register is specified + Value type: <u32> + Definition: Value required in the masked off "aging_allowed" register + bits in order for a CPR aging measurement to be possible. + - qcom,cpr-panic-reg-addr-list Usage: optional Value type: <prop-encoded-array> diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index f6dadb738175..a01bd451c577 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -470,6 +470,11 @@ Example: qcom,msm-dai-q6-dev-id = <8>; }; + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <24608>; + }; + qcom,msm-dai-q6 { compatible = "qcom,msm-dai-q6"; qcom,msm-dai-q6-sb-0-rx { @@ -784,7 +789,7 @@ Example: "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa"; - asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, + asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, @@ -793,6 +798,7 @@ Example: <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music_2_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", + "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", @@ -1157,7 +1163,7 @@ Example: <&bt_sco_tx>,<&int_fm_rx>,<&int_fm_tx>,<&afe_pcm_rx>, <&afe_pcm_tx>,<&afe_proxy_rx>,<&afe_proxy_tx>, <&incall_record_rx>,<&incall_record_tx>,<&incall_music_rx>, - <&incall_music2_rx>; + <&incall_music2_rx>,<&dai_dp>; asoc-cpu-names = "msm-dai-q6-auxpcm.1","msm-dai-q6-auxpcm.2", "msm-dai-q6-hdmi.8","msm-dai-q6-mi2s.0", "msm-dai-q6-dev.16384","msm-dai-q6-dev.16385", @@ -1171,7 +1177,7 @@ Example: "msm-dai-q6-dev.225","msm-dai-q6-dev.241", "msm-dai-q6-dev.240","msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772","msm-dai-q6-dev.32773", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770","msm-dai-q6-dp.24608"; asoc-codec = <&stub>; asoc-codec-names = "msm-stub-codec.1"; }; diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index dd9c13b4b5ff..0af26ca1f380 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -181,10 +181,12 @@ Required properties: Optional properties: - reg-names: Additional registers corresponding with the following: - "tune2_efuse_addr": EFUSE based register address to read TUNE2 parameter. - via the QSCRATCH interface. + "efuse_addr": EFUSE address to read and update analog tune parameter. "emu_phy_base" : phy base address used for programming emulation target phy. "ref_clk_addr" : ref_clk bcr address used for on/off ref_clk before reset. + "tcsr_clamp_dig_n" : To enable/disable digital clamp to the phy. When + de-asserted, it will prevent random leakage from qusb2 phy resulting from + out of sequence turn on/off of 1p8, 3p3 and DVDD regulators. - clocks: a list of phandles to the PHY clocks. Use as per Documentation/devicetree/bindings/clock/clock-bindings.txt - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" @@ -195,8 +197,8 @@ Optional properties: - qcom,emu-init-seq : emulation initialization sequence with value,reg pair. - qcom,phy-pll-reset-seq : emulation PLL reset sequence with value,reg pair. - qcom,emu-dcm-reset-seq : emulation DCM reset sequence with value,reg pair. - - qcom,tune2-efuse-bit-pos: TUNE2 parameter related start bit position with EFUSE register - - qcom,tune2-efuse-num-bits: Number of bits based value to use for TUNE2 high nibble + - qcom,efuse-bit-pos: start bit position within EFUSE register + - qcom,efuse-num-bits: Number of bits to read from EFUSE register - qcom,emulation: Indicates that we are running on emulation platform. - qcom,hold-reset: Indicates that hold QUSB PHY into reset state. - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided. @@ -211,8 +213,8 @@ Example: vdda18-supply = <&pm8994_l6>; vdda33-supply = <&pm8994_l24>; qcom,vdd-voltage-level = <1 5 7>; - qcom,tune2-efuse-bit-pos = <21>; - qcom,tune2-efuse-num-bits = <3>; + qcom,efuse-bit-pos = <21>; + qcom,efuse-num-bits = <3>; clocks = <&clock_rpm clk_ln_bb_clk>, <&clock_gcc clk_gcc_rx2_usb1_clkref_clk>, diff --git a/Documentation/features/time/irq-time-acct/arch-support.txt b/Documentation/features/time/irq-time-acct/arch-support.txt index 4199ffecc0ff..e63316239938 100644 --- a/Documentation/features/time/irq-time-acct/arch-support.txt +++ b/Documentation/features/time/irq-time-acct/arch-support.txt @@ -9,7 +9,7 @@ | alpha: | .. | | arc: | TODO | | arm: | ok | - | arm64: | ok | + | arm64: | .. | | avr32: | TODO | | blackfin: | TODO | | c6x: | TODO | diff --git a/Documentation/features/vm/huge-vmap/arch-support.txt b/Documentation/features/vm/huge-vmap/arch-support.txt index df1d1f3c9af2..af6816bccb43 100644 --- a/Documentation/features/vm/huge-vmap/arch-support.txt +++ b/Documentation/features/vm/huge-vmap/arch-support.txt @@ -9,7 +9,7 @@ | alpha: | TODO | | arc: | TODO | | arm: | TODO | - | arm64: | ok | + | arm64: | TODO | | avr32: | TODO | | blackfin: | TODO | | c6x: | TODO | diff --git a/MAINTAINERS b/MAINTAINERS index ab65bbecb159..4c3e1d2ac31b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4097,8 +4097,8 @@ F: Documentation/efi-stub.txt F: arch/ia64/kernel/efi.c F: arch/x86/boot/compressed/eboot.[ch] F: arch/x86/include/asm/efi.h -F: arch/x86/platform/efi/ -F: drivers/firmware/efi/ +F: arch/x86/platform/efi/* +F: drivers/firmware/efi/* F: include/linux/efi*.h EFI VARIABLE FILESYSTEM @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 11 +SUBLEVEL = 8 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h index cb69299a492e..27b17adea50d 100644 --- a/arch/arc/include/asm/io.h +++ b/arch/arc/include/asm/io.h @@ -13,15 +13,6 @@ #include <asm/byteorder.h> #include <asm/page.h> -#ifdef CONFIG_ISA_ARCV2 -#include <asm/barrier.h> -#define __iormb() rmb() -#define __iowmb() wmb() -#else -#define __iormb() do { } while (0) -#define __iowmb() do { } while (0) -#endif - extern void __iomem *ioremap(unsigned long physaddr, unsigned long size); extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size, unsigned long flags); @@ -31,15 +22,6 @@ extern void iounmap(const void __iomem *addr); #define ioremap_wc(phy, sz) ioremap(phy, sz) #define ioremap_wt(phy, sz) ioremap(phy, sz) -/* - * io{read,write}{16,32}be() macros - */ -#define ioread16be(p) ({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; }) -#define ioread32be(p) ({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; }) - -#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); }) -#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); }) - /* Change struct page to physical address */ #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) @@ -117,6 +99,15 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr) } +#ifdef CONFIG_ISA_ARCV2 +#include <asm/barrier.h> +#define __iormb() rmb() +#define __iowmb() wmb() +#else +#define __iormb() do { } while (0) +#define __iowmb() do { } while (0) +#endif + /* * MMIO can also get buffered/optimized in micro-arch, so barriers needed * Based on ARM model for the typical use case diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index 00707aac72fc..47954ed990f8 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -792,8 +792,3 @@ tx-num-evt = <32>; rx-num-evt = <32>; }; - -&synctimer_32kclk { - assigned-clocks = <&mux_synctimer32k_ck>; - assigned-clock-parents = <&clkdiv32k_ick>; -}; diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi index cc952cf8ec30..7ccce7529b0c 100644 --- a/arch/arm/boot/dts/armada-375.dtsi +++ b/arch/arm/boot/dts/armada-375.dtsi @@ -529,7 +529,7 @@ }; sata@a0000 { - compatible = "marvell,armada-370-sata"; + compatible = "marvell,orion-sata"; reg = <0xa0000 0x5000>; interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; clocks = <&gateclk 14>, <&gateclk 20>; diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi index 85d2c377c332..3710755c6d76 100644 --- a/arch/arm/boot/dts/armada-385-linksys.dtsi +++ b/arch/arm/boot/dts/armada-385-linksys.dtsi @@ -117,7 +117,7 @@ }; /* USB part of the eSATA/USB 2.0 port */ - usb@58000 { + usb@50000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index cd0cd5fd09a3..0827d594b1f0 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -106,7 +106,7 @@ pmc: pmc@fffffc00 { compatible = "atmel,at91sam9x5-pmc", "syscon"; - reg = <0xfffffc00 0x200>; + reg = <0xfffffc00 0x100>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; interrupt-controller; #address-cells = <1>; diff --git a/arch/arm/boot/dts/pxa3xx.dtsi b/arch/arm/boot/dts/pxa3xx.dtsi index 564341af7e97..cf6998a0804d 100644 --- a/arch/arm/boot/dts/pxa3xx.dtsi +++ b/arch/arm/boot/dts/pxa3xx.dtsi @@ -30,7 +30,7 @@ reg = <0x43100000 90>; interrupts = <45>; clocks = <&clks CLK_NAND>; - dmas = <&pdma 97 3>; + dmas = <&pdma 97>; dma-names = "data"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 6b94608ee2c7..521e9a4a2079 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -113,6 +113,7 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ msmcobalt-v2-cdp.dtb \ msmcobalt-v2-qrd.dtb \ msmcobalt-qrd-skuk.dtb \ + msmcobalt-qrd-vr1.dtb \ apqcobalt-mtp.dtb \ apqcobalt-cdp.dtb \ apqcobalt-v2-mtp.dtb \ @@ -120,7 +121,10 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ apqcobalt-v2-qrd.dtb \ msmcobalt-v2.1-mtp.dtb \ msmcobalt-v2.1-cdp.dtb \ - msmcobalt-v2.1-qrd.dtb + msmcobalt-v2.1-qrd.dtb \ + apqcobalt-v2.1-mtp.dtb \ + apqcobalt-v2.1-cdp.dtb \ + apqcobalt-v2.1-qrd.dtb dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1-cdp.dts b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-cdp.dts new file mode 100644 index 000000000000..f0ab8e0afc78 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-cdp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apqcobalt-v2.1.dtsi" +#include "msmcobalt-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1 CDP"; + compatible = "qcom,apqcobalt-cdp", "qcom,apqcobalt", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1-mtp.dts b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-mtp.dts new file mode 100644 index 000000000000..e23134f8897b --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-mtp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apqcobalt-v2.1.dtsi" +#include "msmcobalt-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1 MTP"; + compatible = "qcom,apqcobalt-mtp", "qcom,apqcobalt", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1-qrd.dts b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-qrd.dts new file mode 100644 index 000000000000..8da6f90958d2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1-qrd.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apqcobalt-v2.1.dtsi" +#include "msmcobalt-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1 QRD"; + compatible = "qcom,apqcobalt-qrd", "qcom,apqcobalt", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm/boot/dts/qcom/apqcobalt-v2.1.dtsi b/arch/arm/boot/dts/qcom/apqcobalt-v2.1.dtsi new file mode 100644 index 000000000000..5a49afecd60b --- /dev/null +++ b/arch/arm/boot/dts/qcom/apqcobalt-v2.1.dtsi @@ -0,0 +1,18 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msmcobalt-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ COBALT V2.1"; + qcom,msm-id = <319 0x20001>; +}; diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi index f3233948d457..41b6f50c520b 100644 --- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -76,6 +76,11 @@ qcom,msm-dai-q6-dev-id = <8>; }; + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <24608>; + }; + loopback: qcom,msm-pcm-loopback { compatible = "qcom,msm-pcm-loopback"; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index d99749a01f6c..7a1c075cdd76 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -145,6 +145,15 @@ qcom,pmic-revid = <&pmicobalt_revid>; + io-channels = <&pmicobalt_rradc 8>, + <&pmicobalt_rradc 10>, + <&pmicobalt_rradc 3>, + <&pmicobalt_rradc 4>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v"; + dpdm-supply = <&qusb_phy0>; qcom,thermal-mitigation diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi index 05328a0f29dc..ec69d7ac895d 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi @@ -34,7 +34,7 @@ sound-9335 { compatible = "qcom,msmcobalt-asoc-snd-tasha"; qcom,model = "msmcobalt-tasha-snd-card"; - qcom,hdmi-audio-rx; + qcom,ext-disp-audio-rx; qcom,audio-routing = "AIF4 VI", "MCLK", @@ -80,7 +80,7 @@ "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", "msm-compr-dsp", "msm-pcm-dsp-noirq"; - asoc-cpu = <&dai_hdmi>, + asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, @@ -90,7 +90,7 @@ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&usb_audio_rx>, <&usb_audio_tx>; - asoc-cpu-names = "msm-dai-q6-hdmi.8", + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", @@ -104,9 +104,9 @@ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673"; - asoc-codec = <&stub_codec>, <&hdmi_audio>; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; asoc-codec-names = "msm-stub-codec.1", - "msm-hdmi-audio-codec-rx"; + "msm-ext-disp-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, <&wsa881x_213>, <&wsa881x_214>; @@ -117,6 +117,7 @@ sound-tavil { compatible = "qcom,msmcobalt-asoc-snd-tavil"; qcom,model = "msmcobalt-tavil-snd-card"; + qcom,ext-disp-audio-rx; qcom,audio-routing = "RX_BIAS", "MCLK", @@ -160,7 +161,7 @@ "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", "msm-compr-dsp", "msm-pcm-dsp-noirq"; - asoc-cpu = <&dai_hdmi>, + asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, @@ -169,7 +170,7 @@ <&incall_record_tx>, <&incall_music_rx>, <&incall_music_2_rx>, <&sb_5_rx>, <&usb_audio_rx>, <&usb_audio_tx>, <&sb_6_rx>; - asoc-cpu-names = "msm-dai-q6-hdmi.8", + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", @@ -182,8 +183,9 @@ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", "msm-dai-q6-dev.16396"; - asoc-codec = <&stub_codec>; - asoc-codec-names = "msm-stub-codec.1"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, <&wsa881x_0213>, <&wsa881x_0214>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi index def8ed6e07a7..b4516f381c0c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi @@ -752,7 +752,7 @@ <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_jpeg0_clk>, + <&clock_mmss clk_mmss_camss_jpeg0_vote_clk>, <&clock_mmss clk_mmss_camss_jpeg_ahb_clk>, <&clock_mmss clk_mmss_camss_jpeg_axi_clk>; qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0>; @@ -766,7 +766,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 666675 666675>; + <62 512 1920000 2880000>; status = "ok"; }; @@ -796,7 +796,7 @@ <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_mmss_camss_jpeg0_clk>, + <&clock_mmss clk_mmss_camss_jpeg0_dma_vote_clk>, <&clock_mmss clk_mmss_camss_jpeg_ahb_clk>, <&clock_mmss clk_mmss_camss_jpeg_axi_clk>; qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0>; @@ -808,7 +808,7 @@ qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <62 512 0 0>, - <62 512 666675 666675>; + <62 512 1920000 2880000>; qcom,max-ds-factor = <128>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi index d1a8ae03cde2..d44002efea11 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi @@ -205,6 +205,68 @@ }; }; +&i2c_7 { + status = "okay"; + qcom,smb138x@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb138x"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + + smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + reg = <0x3600 0x100>; + + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_therm { + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp { + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp { + qcom,scale = <(-1032)>; + qcom,offset = <344125>; + }; + + batt_i { + qcom,channel = <3>; + qcom,scale = <20000000>; + }; + + batt_v { + qcom,scale = <5000000>; + }; + + input_i { + qcom,scale = <14285714>; + }; + + input_v { + qcom,scale = <25000000>; + }; + + otg_i { + qcom,scale = <5714286>; + }; + }; + }; +}; + &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi index b0e3751792dd..fd930d3d1644 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi @@ -448,6 +448,15 @@ qcom,mdss-fb-map = <&mdss_fb1>; }; + msm_ext_disp: qcom,msm_ext_disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + qcom,msm_ext_disp = <&msm_ext_disp>; + }; + }; + mdss_dp_ctrl: qcom,dp_ctrl@c990000 { cell-index = <0>; compatible = "qcom,mdss-dp"; @@ -483,6 +492,8 @@ qcom,dp-usbpd-detection = <&pmicobalt_pdphy>; + qcom,msm_ext_disp = <&msm_ext_disp>; + qcom,core-supply-entries { #address-cells = <1>; #size-cells = <0>; @@ -595,10 +606,6 @@ }; }; - msm_ext_disp: qcom,msm_ext_disp { - compatible = "qcom,msm-ext-disp"; - }; - mdss_hdmi_tx: qcom,hdmi_tx@c9a0000 { cell-index = <0>; compatible = "qcom,hdmi-tx"; @@ -631,10 +638,6 @@ qcom,mdss-fb-map = <&mdss_fb2>; qcom,pluggable; - - hdmi_audio: qcom,msm-hdmi-audio-rx { - compatible = "qcom,msm-hdmi-audio-codec-rx"; - }; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index b84f63ecbd1e..1d64cefaeb4a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -206,6 +206,89 @@ }; }; +&i2c_7 { + status = "okay"; + qcom,smb138x@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb138x"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + + smb138x_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + reg = <0x3600 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_temp@0 { + reg = <0>; + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp@1 { + reg = <1>; + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp@2 { + reg = <2>; + qcom,scale = <(-1032)>; + qcom,offset = <344125>; + }; + + batt_i@3 { + reg = <3>; + qcom,channel = <3>; + qcom,scale = <20000000>; + }; + + batt_v@4 { + reg = <4>; + qcom,scale = <5000000>; + }; + + input_i@5 { + reg = <5>; + qcom,scale = <14285714>; + }; + + input_v@6 { + reg = <6>; + qcom,scale = <25000000>; + }; + + otg_i@7 { + reg = <7>; + qcom,scale = <5714286>; + }; + }; + + smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { + compatible = "qcom,smb138x-parallel-slave"; + qcom,pmic-revid = <&smb138x_revid>; + reg = <0x1000 0x700>; + }; + }; +}; + &mdss_hdmi_tx { pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", "hdmi_active", "hdmi_sleep"; @@ -356,33 +439,6 @@ qcom,5v-boost-gpio = <&tlmm 51 0>; }; -&i2c_7 { - status = "okay"; - qcom,smb138x@8 { - compatible = "qcom,i2c-pmic"; - reg = <0x8>; - #address-cells = <2>; - #size-cells = <0>; - interrupt-parent = <&spmi_bus>; - interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; - interrupt_names = "smb138x"; - interrupt-controller; - #interrupt-cells = <3>; - qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; - - smb138x_revid: qcom,revid@100 { - compatible = "qcom,qpnp-revid"; - reg = <0x100 0x100>; - }; - - smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { - compatible = "qcom,smb138x-parallel-slave"; - qcom,pmic-revid = <&smb138x_revid>; - reg = <0x1000 0x700>; - }; - }; -}; - &pmicobalt_haptics { status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts new file mode 100644 index 000000000000..e53912071502 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "msmcobalt.dtsi" +#include "msmcobalt-qrd-vr1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM COBALT VR1 Board"; + compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd"; + qcom,board-id = <0x02000b 0x80>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi new file mode 100644 index 000000000000..c028ea0eeab3 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi @@ -0,0 +1,102 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include "msmcobalt-pinctrl.dtsi" + +&blsp1_uart3_hs { + status = "ok"; +}; + +&ufsphy1 { + vdda-phy-supply = <&pmcobalt_l1>; + vdda-pll-supply = <&pmcobalt_l2>; + vddp-ref-clk-supply = <&pmcobalt_l26>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14600>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pmcobalt_l20>; + vccq-supply = <&pmcobalt_l26>; + vccq2-supply = <&pmcobalt_s4>; + vcc-max-microamp = <750000>; + vccq-max-microamp = <560000>; + vccq2-max-microamp = <750000>; + status = "ok"; +}; + +&ufs_ice { + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pmcobalt_l21>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pmcobalt_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + cd-gpios = <&tlmm 95 0x1>; + + status = "ok"; +}; + +&uartblsp2dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&pmcobalt_gpios { + /* GPIO 6 for Vol+ Key */ + gpio@c500 { + status = "okay"; + qcom,mode = <0>; + qcom,pull = <0>; + qcom,vin-sel = <0>; + qcom,src-sel = <0>; + qcom,out-strength = <1>; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + status = "okay"; + + vol_up { + label = "volume_up"; + gpios = <&pmcobalt_gpios 6 0x1>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 256c404bb972..86bc048adeb5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -900,8 +900,10 @@ gfx_cpr: cpr4-ctrl@5061000 { compatible = "qcom,cpr4-msmcobalt-v1-mmss-regulator"; - reg = <0x05061000 0x4000>, <0x00784000 0x1000>; - reg-names = "cpr_ctrl", "fuse_base"; + reg = <0x05061000 0x4000>, + <0x00784000 0x1000>, + <0x05065204 0x4>; + reg-names = "cpr_ctrl", "fuse_base", "aging_allowed"; clocks = <&clock_gpu clk_gpucc_rbcpr_clk>, <&clock_gcc clk_cnoc_clk>; clock-names = "core_clk", "bus_clk"; @@ -912,14 +914,16 @@ qcom,cpr-sensor-time = <1000>; qcom,cpr-loop-time = <5000000>; qcom,cpr-idle-cycles = <15>; - qcom,cpr-step-quot-init-min = <10>; - qcom,cpr-step-quot-init-max = <13>; + qcom,cpr-step-quot-init-min = <8>; + qcom,cpr-step-quot-init-max = <12>; qcom,cpr-count-mode = <0>; /* All-at-once min */ vdd-supply = <&pm8005_s1>; qcom,voltage-step = <4000>; mem-acc-supply = <&gfx_mem_acc_vreg>; qcom,cpr-aging-ref-voltage = <1032000>; + qcom,cpr-aging-allowed-reg-mask = <0x00000003>; + qcom,cpr-aging-allowed-reg-value = <0x00000003>; qcom,cpr-enable; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi index f4d5e106e403..7e1b47ddf17a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi @@ -79,6 +79,34 @@ < 2342400000 0x0404007a 0x0a620062 0x3 >, < 2419200000 0x0404007e 0x0a650065 0x3 >, < 2496000000 0x04040082 0x0a680068 0x3 >; + + qcom,perfcl-speedbin1-v0 = + < 300000000 0x0004000f 0x01200020 0x1 >, + < 345600000 0x05040012 0x01200020 0x1 >, + < 422400000 0x05040016 0x02200020 0x1 >, + < 499200000 0x0504001a 0x02200020 0x1 >, + < 576000000 0x0504001e 0x02200020 0x1 >, + < 652800000 0x05040022 0x03200020 0x1 >, + < 729600000 0x05040026 0x03200020 0x1 >, + < 806400000 0x0504002a 0x03220022 0x1 >, + < 902400000 0x0404002f 0x04260026 0x1 >, + < 979200000 0x04040033 0x04290029 0x1 >, + < 1056000000 0x04040037 0x052c002c 0x1 >, + < 1132800000 0x0404003b 0x052f002f 0x1 >, + < 1190400000 0x0404003e 0x05320032 0x2 >, + < 1267200000 0x04040042 0x06350035 0x2 >, + < 1344000000 0x04040046 0x06380038 0x2 >, + < 1420800000 0x0404004a 0x063b003b 0x2 >, + < 1497600000 0x0404004e 0x073e003e 0x2 >, + < 1574400000 0x04040052 0x07420042 0x2 >, + < 1651200000 0x04040056 0x07450045 0x2 >, + < 1728000000 0x0404005a 0x08480048 0x2 >, + < 1804800000 0x0404005e 0x084b004b 0x2 >, + < 1881600000 0x04040062 0x094e004e 0x2 >, + < 1958400000 0x04040066 0x09520052 0x2 >, + < 2035200000 0x0404006a 0x09550055 0x3 >, + < 2112000000 0x0404006e 0x0a580058 0x3 >, + < 2208000000 0x04040073 0x0a5c005c 0x3 >; }; &msm_cpufreq { @@ -198,24 +226,59 @@ &apc0_pwrcl_vreg { regulator-max-microvolt = <23>; - qcom,cpr-corners = <22>; - qcom,cpr-corner-fmax-map = <8 11 18 22>; + + qcom,cpr-fuse-combos = <16>; + qcom,cpr-speed-bins = <2>; + qcom,cpr-speed-bin-corners = <22 22>; + qcom,cpr-corners = + /* Speed bin 0 */ + <22 22 22 22 22 22 22 22>, + /* Speed bin 1 */ + <22 22 22 22 22 22 22 22>; + + qcom,cpr-corner-fmax-map = + /* Speed bin 0 */ + <8 11 18 22>, + /* Speed bin 1 */ + <8 11 18 22>; qcom,cpr-voltage-ceiling = - <688000 688000 688000 688000 688000 - 688000 688000 688000 756000 756000 - 756000 828000 828000 828000 828000 + /* Speed bin 0 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 828000 828000 828000 952000 952000 - 1024000 1024000>; + 1056000 1056000>, + /* Speed bin 1 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 952000 952000 + 1056000 1056000>; qcom,cpr-voltage-floor = + /* Speed bin 0 */ <568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 632000 632000 632000 632000 632000 632000 632000 712000 712000 - 756000 756000>; + 772000 772000>, + /* Speed bin 1 */ + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 632000 632000 632000 632000 + 632000 632000 632000 712000 712000 + 772000 772000>; qcom,cpr-floor-to-ceiling-max-range = + /* Speed bin 0 */ + <55000 55000 55000 55000 + 55000 55000 55000 55000 + 55000 55000 55000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000>, + /* Speed bin 1 */ <55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 65000 @@ -224,6 +287,16 @@ 65000 65000>; qcom,corner-frequencies = + /* Speed bin 0 */ + <300000000 364800000 441600000 + 518400000 595200000 672000000 + 748800000 825600000 883200000 + 960000000 1036800000 1094400000 + 1171200000 1248000000 1324800000 + 1401600000 1478400000 1555200000 + 1670400000 1747200000 1824000000 + 1900800000>, + /* Speed bin 1 */ <300000000 364800000 441600000 518400000 595200000 672000000 748800000 825600000 883200000 @@ -248,6 +321,16 @@ 1559 1392>; qcom,cpr-open-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + /* Speed bin 1 */ <40000 24000 0 0>, <40000 24000 0 0>, <40000 24000 0 0>, @@ -258,6 +341,16 @@ <40000 24000 0 0>; qcom,cpr-closed-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + /* Speed bin 1 */ <20000 26000 0 0>, <20000 26000 0 0>, <20000 26000 0 0>, @@ -278,26 +371,56 @@ &apc1_perfcl_vreg { regulator-max-microvolt = <31>; - qcom,cpr-corners = <30>; - qcom,cpr-corner-fmax-map = <8 12 20 30>; + + qcom,cpr-fuse-combos = <16>; + qcom,cpr-speed-bins = <2>; + qcom,cpr-speed-bin-corners = <30 26>; + qcom,cpr-corners = + /* Speed bin 0 */ + <30 30 30 30 30 30 30 30>, + /* Speed bin 1 */ + <26 26 26 26 26 26 26 26>; + + qcom,cpr-corner-fmax-map = + /* Speed bin 0 */ + <8 12 20 30>, + /* Speed bin 1 */ + <8 12 20 26>; qcom,cpr-voltage-ceiling = - <688000 688000 688000 688000 688000 - 688000 688000 688000 756000 756000 - 756000 756000 828000 828000 828000 + /* Speed bin 0 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 828000 828000 828000 828000 828000 - 952000 952000 952000 1024000 1024000 - 1024000 1024000 1024000 1024000 1024000>; + 952000 952000 952000 1056000 1056000 + 1056000 1056000 1056000 1056000 1056000>, + /* Speed bin 1 */ + <828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 952000 952000 952000 1056000 1056000 + 1056000>; qcom,cpr-voltage-floor = + /* Speed bin 0 */ + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 568000 632000 632000 632000 + 632000 632000 632000 632000 632000 + 712000 712000 712000 772000 772000 + 772000 772000 772000 772000 772000>, + /* Speed bin 1 */ <568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 568000 632000 632000 632000 632000 632000 632000 632000 632000 - 712000 712000 712000 756000 756000 - 756000 756000 756000 756000 756000>; + 712000 712000 712000 772000 772000 + 772000>; qcom,cpr-floor-to-ceiling-max-range = + /* Speed bin 0 */ <55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 55000 @@ -305,9 +428,18 @@ 65000 65000 65000 65000 65000 65000 65000 65000 65000 65000 65000 65000 + 65000 65000>, + /* Speed bin 1 */ + <55000 55000 55000 55000 + 55000 55000 55000 55000 + 55000 55000 55000 55000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 65000 65000>; qcom,corner-frequencies = + /* Speed bin 0 */ <300000000 345600000 422400000 499200000 576000000 652800000 729600000 806400000 902400000 @@ -317,7 +449,17 @@ 1651200000 1728000000 1804800000 1881600000 1958400000 2035200000 2112000000 2188800000 2265600000 - 2342400000 2419200000 2496000000>; + 2342400000 2419200000 2496000000>, + /* Speed bin 1 */ + <300000000 345600000 422400000 + 499200000 576000000 652800000 + 729600000 806400000 902400000 + 979200000 1056000000 1132800000 + 1190400000 1267200000 1344000000 + 1420800000 1497600000 1574400000 + 1651200000 1728000000 1804800000 + 1881600000 1958400000 2035200000 + 2112000000 2208000000>; qcom,cpr-ro-scaling-factor = <4001 4019 3747 3758 3564 3480 2336 @@ -334,6 +476,16 @@ 1559 1392>; qcom,cpr-open-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + /* Speed bin 1 */ <8000 0 0 52000>, <8000 0 0 52000>, <8000 0 0 52000>, @@ -344,6 +496,16 @@ <8000 0 0 52000>; qcom,cpr-closed-loop-voltage-fuse-adjustment = + /* Speed bin 0 */ + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + /* Speed bin 1 */ <0 0 0 50000>, <0 0 0 50000>, <0 0 0 50000>, @@ -373,8 +535,8 @@ qcom,cpr-corner-fmax-map = <1 3 5 8>; qcom,cpr-voltage-ceiling = - <616000 676000 740000 800000 828000 - 884000 952000 1024000>; + <656000 716000 772000 880000 908000 + 948000 1016000 1088000>; qcom,cpr-voltage-floor = <516000 516000 532000 584000 632000 @@ -445,14 +607,23 @@ }; &qusb_phy0 { + reg = <0x0c012000 0x2a8>, + <0x01fcb24c 0x4>, + <0x00784238 0x4>; + reg-names = "qusb_phy_base", + "tcsr_clamp_dig_n_1p8", + "efuse_addr"; + qcom,efuse-bit-pos = <16>; + qcom,efuse-num-bits = <4>; qcom,qusb-phy-init-seq = /* <value reg_offset> */ - <0x13 0x04 - 0x7c 0x18c - 0x80 0x2c - 0x0a 0x184 - 0x00 0x240 - 0x19 0xb4>; + <0x13 0x04 /* analog_controls_two */ + 0x7c 0x18c /* pll_clock_inverter */ + 0x80 0x2c /* pll_cmode */ + 0x0a 0x184 /* pll_lock_delay */ + 0xa5 0x23c /* tune1 */ + 0x09 0x240 /* tune2 */ + 0x19 0xb4>; /* digital_timers_two */ }; &msm_vidc { @@ -570,3 +741,38 @@ }; }; }; + +&ufs1 { + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + clocks = + <&clock_gcc clk_gcc_ufs_axi_hw_ctl_clk>, + <&clock_gcc clk_gcc_aggre1_ufs_axi_clk>, + <&clock_gcc clk_gcc_ufs_ahb_clk>, + <&clock_gcc clk_gcc_ufs_unipro_core_hw_ctl_clk>, + <&clock_gcc clk_gcc_ufs_ice_core_hw_ctl_clk>, + <&clock_gcc clk_ln_bb_clk1>, + <&clock_gcc clk_gcc_ufs_tx_symbol_0_clk>, + <&clock_gcc clk_gcc_ufs_rx_symbol_0_clk>, + <&clock_gcc clk_gcc_ufs_rx_symbol_1_clk>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + lanes-per-direction = <2>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index f830b2172050..4098c4185272 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -737,6 +737,7 @@ vdd_dig-supply = <&pmcobalt_s1_level>; vdd_dig_ao-supply = <&pmcobalt_s1_level_ao>; #clock-cells = <1>; + #reset-cells = <1>; }; clock_mmss: qcom,mmsscc@c8c0000 { @@ -760,6 +761,7 @@ <&mdss_dp_pll clk_vco_divided_clk_src_mux>, <&mdss_hdmi_pll clk_hdmi_vco_clk>; #clock-cells = <1>; + #reset-cells = <1>; }; clock_gpu: qcom,gpucc@5065000 { @@ -802,12 +804,13 @@ clock_cpu: qcom,cpu-clock-cobalt@179c0000 { compatible = "qcom,cpu-clock-osm"; - reg = <0x179C0000 0x4000>, + reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, <0x17816000 0x1000>, - <0x179D1000 0x1000>; + <0x179d1000 0x1000>, + <0x00784130 0x8>; reg-names = "osm", "pwrcl_pll", "perfcl_pll", - "apcs_common"; + "apcs_common", "perfcl_efuse"; vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; vdd-perfcl-supply = <&apc1_perfcl_vreg>; @@ -1518,7 +1521,7 @@ gdsc-vdd-supply = <&gdsc_pcie_0>; vreg-1.8-supply = <&pmcobalt_l2>; vreg-0.9-supply = <&pmcobalt_l1>; - vreg-cx-supply = <&pmcobalt_s1_level_ao>; + vreg-cx-supply = <&pmcobalt_s1_level>; qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; qcom,vreg-0.9-voltage-level = <880000 880000 24000>; @@ -1723,8 +1726,9 @@ <0 0>; lanes-per-direction = <1>; + qcom,msm-bus,name = "ufs1"; - qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-cases = <22>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = <95 512 0 0>, <1 650 0 0>, /* No vote */ @@ -1732,17 +1736,30 @@ <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */ <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */ <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */ + <95 512 1844 0>, <1 650 1000 0>, /* PWM G1 L2 */ + <95 512 3688 0>, <1 650 1000 0>, /* PWM G2 L2 */ + <95 512 7376 0>, <1 650 1000 0>, /* PWM G3 L2 */ + <95 512 14752 0>, <1 650 1000 0>, /* PWM G4 L2 */ <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */ <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */ <95 512 511181 0>, <1 650 1000 0>, /* HS G3 RA */ + <95 512 255591 0>, <1 650 1000 0>, /* HS G1 RA L2 */ + <95 512 511181 0>, <1 650 1000 0>, /* HS G2 RA L2 */ + <95 512 1022362 0>, <1 650 1000 0>, /* HS G3 RA L2 */ <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */ <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */ <95 512 596378 0>, <1 650 1000 0>, /* HS G3 RB */ + <95 512 298189 0>, <1 650 1000 0>, /* HS G1 RB L2 */ + <95 512 596378 0>, <1 650 1000 0>, /* HS G2 RB L2 */ + <95 512 1192756 0>, <1 650 1000 0>, /* HS G3 RB L2 */ <95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */ qcom,bus-vector-names = "MIN", "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", "MAX"; /* PM QoS */ @@ -1835,15 +1852,18 @@ qusb_phy0: qusb@c012000 { compatible = "qcom,qusb2phy-v2"; - reg = <0x0c012000 0x2a8>; - reg-names = "qusb_phy_base"; + reg = <0x0c012000 0x2a8>, + <0x01fcb24c 0x4>; + reg-names = "qusb_phy_base", + "tcsr_clamp_dig_n_1p8"; vdd-supply = <&pmcobalt_l1>; vdda18-supply = <&pmcobalt_l12>; vdda33-supply = <&pmcobalt_l24>; qcom,vdd-voltage-level = <0 880000 880000>; qcom,qusb-phy-init-seq = /* <value reg_offset> */ - <0x13 0x04 + <0x80 0x0 + 0x13 0x04 0x7c 0x18c 0x80 0x2c 0x0a 0x184 diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts index 6631d31bac6d..0d694a6cd9fa 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -22,7 +22,7 @@ qcom,board-id = <15 0>; }; -&uartblsp2dm1 { +&uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_active>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts index 9840343fc3a7..eaaa1b407425 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts @@ -22,7 +22,7 @@ qcom,board-id = <16 0>; }; -&uartblsp2dm1 { +&uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_active>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index e46041cdd501..44d8e089837c 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -23,7 +23,7 @@ interrupt-parent = <&intc>; aliases { - serial0 = &uartblsp2dm1; + serial0 = &uartblsp1dm1; }; chosen { @@ -246,6 +246,16 @@ 3200 3200 3200 3200 3200 3200>; }; + uartblsp1dm1: serial@0c170000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xc170000 0x1000>; + interrupts = <0 108 0>; + status = "disabled"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + }; + uartblsp2dm1: serial@0c1b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xc1b0000 0x1000>; @@ -472,6 +482,27 @@ qcom,glinkpkt-ch-name = "DATA40_CNTL"; qcom,glinkpkt-dev-name = "smdcntl8"; }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; }; qcom,ipc_router { diff --git a/arch/arm/boot/dts/qcom/msmhamster.dtsi b/arch/arm/boot/dts/qcom/msmhamster.dtsi index 4669fa519f5d..952740ae54e8 100644 --- a/arch/arm/boot/dts/qcom/msmhamster.dtsi +++ b/arch/arm/boot/dts/qcom/msmhamster.dtsi @@ -70,3 +70,7 @@ qcom,sensors = <7>; qcom,slope = <2901 2846 3200 3200 3200 3200 3200>; }; + +&slv_ebi { + qcom,buswidth = <4>; +}; diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h index c35c349da069..194c91b610ff 100644 --- a/arch/arm/include/asm/kvm_asm.h +++ b/arch/arm/include/asm/kvm_asm.h @@ -79,8 +79,6 @@ #define rr_lo_hi(a1, a2) a1, a2 #endif -#define kvm_ksym_ref(kva) (kva) - #ifndef __ASSEMBLY__ struct kvm; struct kvm_vcpu; diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 70e6d557c75f..e06fd299de08 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -969,7 +969,7 @@ static void cpu_init_hyp_mode(void *dummy) pgd_ptr = kvm_mmu_get_httbr(); stack_page = __this_cpu_read(kvm_arm_hyp_stack_page); hyp_stack_ptr = stack_page + PAGE_SIZE; - vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector); + vector_ptr = (unsigned long)__kvm_hyp_vector; __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); @@ -1061,8 +1061,7 @@ static int init_hyp_mode(void) /* * Map the Hyp-code called directly from the host */ - err = create_hyp_mappings(kvm_ksym_ref(__kvm_hyp_code_start), - kvm_ksym_ref(__kvm_hyp_code_end)); + err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end); if (err) { kvm_err("Cannot map world-switch code\n"); goto out_free_mappings; diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 318394ed5c7a..47905a50e075 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -220,13 +220,13 @@ static void cns3xxx_write_config(struct cns3xxx_pcie *cnspci, u32 mask = (0x1ull << (size * 8)) - 1; int shift = (where % 4) * 8; - v = readl_relaxed(base); + v = readl_relaxed(base + (where & 0xffc)); v &= ~(mask << shift); v |= (val & mask) << shift; - writel_relaxed(v, base); - readl_relaxed(base); + writel_relaxed(v, base + (where & 0xffc)); + readl_relaxed(base + (where & 0xffc)); } static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index bfd8bb371477..3a10f1a8317a 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -26,7 +26,6 @@ menuconfig ARCH_EXYNOS select S5P_DEV_MFC select SRAM select THERMAL - select THERMAL_OF select MFD_SYSCON help Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index 875a2bab64f6..7c21760f590f 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -92,7 +92,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) if (IS_ERR(pd->clk[i])) break; - if (IS_ERR(pd->pclk[i])) + if (IS_ERR(pd->clk[i])) continue; /* Skip on first power up */ if (clk_set_parent(pd->clk[i], pd->pclk[i])) pr_err("%s: error setting parent to clock%d\n", diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 2a3db0bd9e15..aa7b379e2661 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -34,7 +34,6 @@ #include "pm.h" #include "control.h" #include "common.h" -#include "soc.h" /* Mach specific information to be recorded in the C-state driver_data */ struct omap3_idle_statedata { @@ -316,69 +315,6 @@ static struct cpuidle_driver omap3_idle_driver = { .safe_state_index = 0, }; -/* - * Numbers based on measurements made in October 2009 for PM optimized kernel - * with CPU freq enabled on device Nokia N900. Assumes OPP2 (main idle OPP, - * and worst case latencies). - */ -static struct cpuidle_driver omap3430_idle_driver = { - .name = "omap3430_idle", - .owner = THIS_MODULE, - .states = { - { - .enter = omap3_enter_idle_bm, - .exit_latency = 110 + 162, - .target_residency = 5, - .name = "C1", - .desc = "MPU ON + CORE ON", - }, - { - .enter = omap3_enter_idle_bm, - .exit_latency = 106 + 180, - .target_residency = 309, - .name = "C2", - .desc = "MPU ON + CORE ON", - }, - { - .enter = omap3_enter_idle_bm, - .exit_latency = 107 + 410, - .target_residency = 46057, - .name = "C3", - .desc = "MPU RET + CORE ON", - }, - { - .enter = omap3_enter_idle_bm, - .exit_latency = 121 + 3374, - .target_residency = 46057, - .name = "C4", - .desc = "MPU OFF + CORE ON", - }, - { - .enter = omap3_enter_idle_bm, - .exit_latency = 855 + 1146, - .target_residency = 46057, - .name = "C5", - .desc = "MPU RET + CORE RET", - }, - { - .enter = omap3_enter_idle_bm, - .exit_latency = 7580 + 4134, - .target_residency = 484329, - .name = "C6", - .desc = "MPU OFF + CORE RET", - }, - { - .enter = omap3_enter_idle_bm, - .exit_latency = 7505 + 15274, - .target_residency = 484329, - .name = "C7", - .desc = "MPU OFF + CORE OFF", - }, - }, - .state_count = ARRAY_SIZE(omap3_idle_data), - .safe_state_index = 0, -}; - /* Public functions */ /** @@ -397,8 +333,5 @@ int __init omap3_idle_init(void) if (!mpu_pd || !core_pd || !per_pd || !cam_pd) return -ENODEV; - if (cpu_is_omap3430()) - return cpuidle_register(&omap3430_idle_driver, NULL); - else - return cpuidle_register(&omap3_idle_driver, NULL); + return cpuidle_register(&omap3_idle_driver, NULL); } diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 3a911d8dea8b..3eaeaca5da05 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -368,7 +368,6 @@ void __init omap5_map_io(void) void __init dra7xx_map_io(void) { iotable_init(dra7xx_io_desc, ARRAY_SIZE(dra7xx_io_desc)); - omap_barriers_init(); } #endif /* diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 147c90e70b2e..8e0bd5939e5a 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1416,7 +1416,9 @@ static void _enable_sysc(struct omap_hwmod *oh) (sf & SYSC_HAS_CLOCKACTIVITY)) _set_clockactivity(oh, oh->class->sysc->clockact, &v); - _write_sysconfig(v, oh); + /* If the cached value is the same as the new value, skip the write */ + if (oh->_sysc_cache != v) + _write_sysconfig(v, oh); /* * Set the autoidle bit only after setting the smartidle bit @@ -1479,9 +1481,7 @@ static void _idle_sysc(struct omap_hwmod *oh) _set_master_standbymode(oh, idlemode, &v); } - /* If the cached value is the same as the new value, skip the write */ - if (oh->_sysc_cache != v) - _write_sysconfig(v, oh); + _write_sysconfig(v, oh); } /** diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 56e55fd37d13..9ab8932403e5 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -1,7 +1,6 @@ menuconfig ARCH_SIRF bool "CSR SiRF" if ARCH_MULTI_V7 select ARCH_HAS_RESET_CONTROLLER - select RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB select GENERIC_IRQ_CHIP select NO_IOPORT_MAP diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index 69261c70e1dd..d6ed9ac56bf1 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -16,6 +16,7 @@ config ARCH_MSMFALCON select MULTI_IRQ_HANDLER select HAVE_ARM_ARCH_TIMER select MAY_HAVE_SPARSE_IRQ + select COMMON_CLK_MSM select PINCTRL_MSM_TLMM select USE_PINCTRL_IRQ select MSM_PM if PM diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S index c160fa3007e9..5d94b7a2fb10 100644 --- a/arch/arm/mach-socfpga/headsmp.S +++ b/arch/arm/mach-socfpga/headsmp.S @@ -13,7 +13,6 @@ #include <asm/assembler.h> .arch armv7-a - .arm ENTRY(secondary_trampoline) /* CPU1 will always fetch from 0x0 when it is brought out of reset. diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 65fbf6633e28..0314b80695ca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -51,7 +51,6 @@ config ARM64 select HAVE_ALIGNED_STRUCT_PAGE if SLUB select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_BITREVERSE - select HAVE_ARCH_HUGE_VMAP select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48) select HAVE_ARCH_KGDB @@ -425,7 +424,6 @@ config ARM64_ERRATUM_843419 bool "Cortex-A53: 843419: A load or store might access an incorrect address" depends on MODULES default y - select ARM64_MODULE_CMODEL_LARGE help This option builds kernel modules using the large memory model in order to avoid the use of the ADRP instruction, which can cause @@ -603,9 +601,6 @@ config ARCH_NR_GPIO source kernel/Kconfig.preempt source kernel/Kconfig.hz -config ARCH_SUPPORTS_DEBUG_PAGEALLOC - def_bool y - config ARCH_HAS_HOLES_MEMORYMODEL def_bool y if SPARSEMEM @@ -656,6 +651,9 @@ config PERF_EVENTS_RESET_PMU_DEBUGFS config SYS_SUPPORTS_HUGETLBFS def_bool y +config ARCH_WANT_GENERAL_HUGETLB + def_bool y + config ARCH_WANT_HUGE_PMD_SHARE def_bool y if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36) @@ -828,93 +826,10 @@ config ARM64_LSE_ATOMICS endmenu -config ARM64_UAO - bool "Enable support for User Access Override (UAO)" - default y - help - User Access Override (UAO; part of the ARMv8.2 Extensions) - causes the 'unprivileged' variant of the load/store instructions to - be overriden to be privileged. - - This option changes get_user() and friends to use the 'unprivileged' - variant of the load/store instructions. This ensures that user-space - really did have access to the supplied memory. When addr_limit is - set to kernel memory the UAO bit will be set, allowing privileged - access to kernel memory. - - Choosing this option will cause copy_to_user() et al to use user-space - memory permissions. - - The feature is detected at runtime, the kernel will use the - regular load/store instructions if the cpu does not implement the - feature. - -config ARM64_MODULE_CMODEL_LARGE - bool - -config ARM64_MODULE_PLTS - bool - select ARM64_MODULE_CMODEL_LARGE - select HAVE_MOD_ARCH_SPECIFIC - -config RELOCATABLE - bool - help - This builds the kernel as a Position Independent Executable (PIE), - which retains all relocation metadata required to relocate the - kernel binary at runtime to a different virtual address than the - address it was linked at. - Since AArch64 uses the RELA relocation format, this requires a - relocation pass at runtime even if the kernel is loaded at the - same address it was linked at. - -config RANDOMIZE_BASE - bool "Randomize the address of the kernel image" - select ARM64_MODULE_PLTS - select RELOCATABLE - help - Randomizes the virtual address at which the kernel image is - loaded, as a security feature that deters exploit attempts - relying on knowledge of the location of kernel internals. - - It is the bootloader's job to provide entropy, by passing a - random u64 value in /chosen/kaslr-seed at kernel entry. - - When booting via the UEFI stub, it will invoke the firmware's - EFI_RNG_PROTOCOL implementation (if available) to supply entropy - to the kernel proper. In addition, it will randomise the physical - location of the kernel Image as well. - - If unsure, say N. - -config RANDOMIZE_MODULE_REGION_FULL - bool "Randomize the module region independently from the core kernel" - depends on RANDOMIZE_BASE - default y - help - Randomizes the location of the module region without considering the - location of the core kernel. This way, it is impossible for modules - to leak information about the location of core kernel data structures - but it does imply that function calls between modules and the core - kernel will need to be resolved via veneers in the module PLT. - - When this option is not set, the module region will be randomized over - a limited range that contains the [_stext, _etext] interval of the - core kernel, so branch relocations are always in range. - endmenu menu "Boot options" -config ARM64_ACPI_PARKING_PROTOCOL - bool "Enable support for the ARM64 ACPI parking protocol" - depends on ACPI - help - Enable support for the ARM64 ACPI parking protocol. If disabled - the kernel will not allow booting through the ARM64 ACPI parking - protocol even if the corresponding data is present in the ACPI - MADT table. - config CMDLINE string "Default kernel command string" default "" diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 14c74a66c58e..285b32fa41c1 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -15,10 +15,6 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S GZFLAGS :=-9 -ifneq ($(CONFIG_RELOCATABLE),) -LDFLAGS_vmlinux += -pie -endif - KBUILD_DEFCONFIG := defconfig # Check for binutils support for specific extensions @@ -33,7 +29,6 @@ endif KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) KBUILD_CFLAGS += -fno-pic KBUILD_CFLAGS += $(call cc-option, -mpc-relative-literal-loads) -KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_AFLAGS += $(lseinstr) ifeq ($(CONFIG_CPU_BIG_ENDIAN), y) @@ -48,14 +43,10 @@ endif CHECKFLAGS += -D__aarch64__ -ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y) +ifeq ($(CONFIG_ARM64_ERRATUM_843419), y) KBUILD_CFLAGS_MODULE += -mcmodel=large endif -ifeq ($(CONFIG_ARM64_MODULE_PLTS),y) -KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/arm64/kernel/module.lds -endif - # Default value head-y := arch/arm64/kernel/head.o diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index f48abaf656d6..3adda1fc4109 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -376,9 +376,9 @@ CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y CONFIG_MSM_JPEGDMA=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_MSM_VIDC_VMEM=y -CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_VIDC_V4L2=m +CONFIG_MSM_VIDC_VMEM=m +CONFIG_MSM_VIDC_GOVERNORS=m CONFIG_MSM_SDE_ROTATOR=y CONFIG_QCOM_KGSL=y CONFIG_FB=y @@ -483,6 +483,7 @@ CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_COMMON_LOG=y CONFIG_MSM_SMEM=y CONFIG_QPNP_HAPTIC=y CONFIG_MSM_SMD=y @@ -541,6 +542,7 @@ CONFIG_DEVFREQ_SPDM=y CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y +CONFIG_QCOM_TADC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y @@ -573,6 +575,7 @@ CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_DEBUG_RODATA=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_LINKS_AND_SINKS=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_QCOM_REPLICATOR=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index f8ab577b4b84..686e1c22c5ae 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -379,9 +379,9 @@ CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y CONFIG_MSM_JPEGDMA=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_MSM_VIDC_VMEM=y -CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_VIDC_V4L2=m +CONFIG_MSM_VIDC_VMEM=m +CONFIG_MSM_VIDC_GOVERNORS=m CONFIG_MSM_SDE_ROTATOR=y CONFIG_QCOM_KGSL=y CONFIG_FB=y @@ -560,6 +560,7 @@ CONFIG_DEVFREQ_SPDM=y CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y +CONFIG_QCOM_TADC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y @@ -637,6 +638,7 @@ CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_DEBUG_RODATA=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_REMOTE_ETM=y diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index aee323b13802..caafd63b8092 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -87,26 +87,9 @@ void __init acpi_init_cpus(void); static inline void acpi_init_cpus(void) { } #endif /* CONFIG_ACPI */ -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL -bool acpi_parking_protocol_valid(int cpu); -void __init -acpi_set_mailbox_entry(int cpu, struct acpi_madt_generic_interrupt *processor); -#else -static inline bool acpi_parking_protocol_valid(int cpu) { return false; } -static inline void -acpi_set_mailbox_entry(int cpu, struct acpi_madt_generic_interrupt *processor) -{} -#endif - static inline const char *acpi_get_enable_method(int cpu) { - if (acpi_psci_present()) - return "psci"; - - if (acpi_parking_protocol_valid(cpu)) - return "parking-protocol"; - - return NULL; + return acpi_psci_present() ? "psci" : NULL; } #ifdef CONFIG_ACPI_APEI diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index beccbdefa106..d56ec0715157 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -1,8 +1,6 @@ #ifndef __ASM_ALTERNATIVE_H #define __ASM_ALTERNATIVE_H -#include <asm/cpufeature.h> - #ifndef __ASSEMBLY__ #include <linux/init.h> @@ -21,6 +19,7 @@ struct alt_instr { void __init apply_alternatives_all(void); void apply_alternatives(void *start, size_t length); +void free_alternatives_memory(void); #define ALTINSTR_ENTRY(feature) \ " .word 661b - .\n" /* label */ \ @@ -65,8 +64,6 @@ void apply_alternatives(void *start, size_t length); #else -#include <asm/assembler.h> - .macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len .word \orig_offset - . .word \alt_offset - . @@ -140,65 +137,6 @@ void apply_alternatives(void *start, size_t length); alternative_insn insn1, insn2, cap, IS_ENABLED(cfg) -/* - * Generate the assembly for UAO alternatives with exception table entries. - * This is complicated as there is no post-increment or pair versions of the - * unprivileged instructions, and USER() only works for single instructions. - */ -#ifdef CONFIG_ARM64_UAO - .macro uao_ldp l, reg1, reg2, addr, post_inc - alternative_if_not ARM64_HAS_UAO -8888: ldp \reg1, \reg2, [\addr], \post_inc; -8889: nop; - nop; - alternative_else - ldtr \reg1, [\addr]; - ldtr \reg2, [\addr, #8]; - add \addr, \addr, \post_inc; - alternative_endif - - _asm_extable 8888b,\l; - _asm_extable 8889b,\l; - .endm - - .macro uao_stp l, reg1, reg2, addr, post_inc - alternative_if_not ARM64_HAS_UAO -8888: stp \reg1, \reg2, [\addr], \post_inc; -8889: nop; - nop; - alternative_else - sttr \reg1, [\addr]; - sttr \reg2, [\addr, #8]; - add \addr, \addr, \post_inc; - alternative_endif - - _asm_extable 8888b,\l; - _asm_extable 8889b,\l; - .endm - - .macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc - alternative_if_not ARM64_HAS_UAO -8888: \inst \reg, [\addr], \post_inc; - nop; - alternative_else - \alt_inst \reg, [\addr]; - add \addr, \addr, \post_inc; - alternative_endif - - _asm_extable 8888b,\l; - .endm -#else - .macro uao_ldp l, reg1, reg2, addr, post_inc - USER(\l, ldp \reg1, \reg2, [\addr], \post_inc) - .endm - .macro uao_stp l, reg1, reg2, addr, post_inc - USER(\l, stp \reg1, \reg2, [\addr], \post_inc) - .endm - .macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc - USER(\l, \inst \reg, [\addr], \post_inc) - .endm -#endif - #endif /* __ASSEMBLY__ */ /* diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index fcaf3cce639a..09f13a96941b 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -106,19 +106,12 @@ dmb \opt .endm -/* - * Emit an entry into the exception table - */ - .macro _asm_extable, from, to - .pushsection __ex_table, "a" - .align 3 - .long (\from - .), (\to - .) - .popsection - .endm - #define USER(l, x...) \ 9999: x; \ - _asm_extable 9999b, l + .section __ex_table,"a"; \ + .align 3; \ + .quad 9999b,l; \ + .previous /* * Register aliases. @@ -212,17 +205,6 @@ lr .req x30 // link register str \src, [\tmp, :lo12:\sym] .endm - /* - * @sym: The name of the per-cpu variable - * @reg: Result of per_cpu(sym, smp_processor_id()) - * @tmp: scratch register - */ - .macro this_cpu_ptr, sym, reg, tmp - adr_l \reg, \sym - mrs \tmp, tpidr_el1 - add \reg, \reg, \tmp - .endm - /* * Annotate a function as position independent, i.e., safe to be called before * the kernel virtual mapping is activated. @@ -234,15 +216,4 @@ lr .req x30 // link register .size __pi_##x, . - x; \ ENDPROC(x) - /* - * Emit a 64-bit absolute little endian symbol reference in a way that - * ensures that it will be resolved at build time, even when building a - * PIE binary. This requires cooperation from the linker script, which - * must emit the lo32/hi32 halves individually. - */ - .macro le64sym, sym - .long \sym\()_lo32 - .long \sym\()_hi32 - .endm - #endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 39c1d340fec5..197e06afbf71 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -36,7 +36,7 @@ static inline void atomic_andnot(int i, atomic_t *v) " stclr %w[i], %[v]\n") : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic_or(int i, atomic_t *v) @@ -48,7 +48,7 @@ static inline void atomic_or(int i, atomic_t *v) " stset %w[i], %[v]\n") : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic_xor(int i, atomic_t *v) @@ -60,7 +60,7 @@ static inline void atomic_xor(int i, atomic_t *v) " steor %w[i], %[v]\n") : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic_add(int i, atomic_t *v) @@ -72,7 +72,7 @@ static inline void atomic_add(int i, atomic_t *v) " stadd %w[i], %[v]\n") : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } #define ATOMIC_OP_ADD_RETURN(name, mb, cl...) \ @@ -90,7 +90,7 @@ static inline int atomic_add_return##name(int i, atomic_t *v) \ " add %w[i], %w[i], w30") \ : [i] "+r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + : "x30" , ##cl); \ \ return w0; \ } @@ -116,7 +116,7 @@ static inline void atomic_and(int i, atomic_t *v) " stclr %w[i], %[v]") : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic_sub(int i, atomic_t *v) @@ -133,7 +133,7 @@ static inline void atomic_sub(int i, atomic_t *v) " stadd %w[i], %[v]") : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } #define ATOMIC_OP_SUB_RETURN(name, mb, cl...) \ @@ -153,7 +153,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v) \ " add %w[i], %w[i], w30") \ : [i] "+r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ - : __LL_SC_CLOBBERS , ##cl); \ + : "x30" , ##cl); \ \ return w0; \ } @@ -177,7 +177,7 @@ static inline void atomic64_andnot(long i, atomic64_t *v) " stclr %[i], %[v]\n") : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic64_or(long i, atomic64_t *v) @@ -189,7 +189,7 @@ static inline void atomic64_or(long i, atomic64_t *v) " stset %[i], %[v]\n") : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic64_xor(long i, atomic64_t *v) @@ -201,7 +201,7 @@ static inline void atomic64_xor(long i, atomic64_t *v) " steor %[i], %[v]\n") : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic64_add(long i, atomic64_t *v) @@ -213,7 +213,7 @@ static inline void atomic64_add(long i, atomic64_t *v) " stadd %[i], %[v]\n") : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...) \ @@ -231,7 +231,7 @@ static inline long atomic64_add_return##name(long i, atomic64_t *v) \ " add %[i], %[i], x30") \ : [i] "+r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + : "x30" , ##cl); \ \ return x0; \ } @@ -257,7 +257,7 @@ static inline void atomic64_and(long i, atomic64_t *v) " stclr %[i], %[v]") : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } static inline void atomic64_sub(long i, atomic64_t *v) @@ -274,7 +274,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) " stadd %[i], %[v]") : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1) - : __LL_SC_CLOBBERS); + : "x30"); } #define ATOMIC64_OP_SUB_RETURN(name, mb, cl...) \ @@ -294,7 +294,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \ " add %[i], %[i], x30") \ : [i] "+r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + : "x30" , ##cl); \ \ return x0; \ } @@ -330,7 +330,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) "2:") : [ret] "+&r" (x0), [v] "+Q" (v->counter) : - : __LL_SC_CLOBBERS, "cc", "memory"); + : "x30", "cc", "memory"); return x0; } @@ -359,7 +359,7 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr, \ " mov %" #w "[ret], " #w "30") \ : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr) \ : [old] "r" (x1), [new] "r" (x2) \ - : __LL_SC_CLOBBERS, ##cl); \ + : "x30" , ##cl); \ \ return x0; \ } @@ -416,7 +416,7 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ [v] "+Q" (*(unsigned long *)ptr) \ : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ - : __LL_SC_CLOBBERS, ##cl); \ + : "x30" , ##cl); \ \ return x0; \ } diff --git a/arch/arm64/include/asm/boot.h b/arch/arm64/include/asm/boot.h index ebf2481889c3..81151b67b26b 100644 --- a/arch/arm64/include/asm/boot.h +++ b/arch/arm64/include/asm/boot.h @@ -11,10 +11,4 @@ #define MIN_FDT_ALIGN 8 #define MAX_FDT_SIZE SZ_2M -/* - * arm64 requires the kernel image to placed - * TEXT_OFFSET bytes beyond a 2 MB aligned base - */ -#define MIN_KIMG_ALIGN SZ_2M - #endif diff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h deleted file mode 100644 index ed693c5bcec0..000000000000 --- a/arch/arm64/include/asm/brk-imm.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2012 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_BRK_IMM_H -#define __ASM_BRK_IMM_H - -/* - * #imm16 values used for BRK instruction generation - * Allowed values for kgdb are 0x400 - 0x7ff - * 0x100: for triggering a fault on purpose (reserved) - * 0x400: for dynamic BRK instruction - * 0x401: for compile time BRK instruction - * 0x800: kernel-mode BUG() and WARN() traps - */ -#define FAULT_BRK_IMM 0x100 -#define KGDB_DYN_DBG_BRK_IMM 0x400 -#define KGDB_COMPILED_DBG_BRK_IMM 0x401 -#define BUG_BRK_IMM 0x800 - -#endif diff --git a/arch/arm64/include/asm/bug.h b/arch/arm64/include/asm/bug.h index 561190d15881..4a748ce9ba1a 100644 --- a/arch/arm64/include/asm/bug.h +++ b/arch/arm64/include/asm/bug.h @@ -18,7 +18,7 @@ #ifndef _ARCH_ARM64_ASM_BUG_H #define _ARCH_ARM64_ASM_BUG_H -#include <asm/brk-imm.h> +#include <asm/debug-monitors.h> #ifdef CONFIG_GENERIC_BUG #define HAVE_ARCH_BUG diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index df06d37374cc..a7d7d360a514 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -73,7 +73,6 @@ extern void flush_cache_all(void); extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_icache_range(unsigned long start, unsigned long end); extern void __flush_dcache_area(void *addr, size_t len); -extern void __clean_dcache_area_pou(void *addr, size_t len); extern long __flush_cache_user_range(unsigned long start, unsigned long end); static inline void flush_cache_mm(struct mm_struct *mm) diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 510c7b404454..9ea611ea69df 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -19,6 +19,7 @@ #define __ASM_CMPXCHG_H #include <linux/bug.h> +#include <linux/mmdebug.h> #include <asm/atomic.h> #include <asm/barrier.h> diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index 13a6103130cd..b5e9cee4b5f8 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h @@ -36,7 +36,6 @@ struct cpuinfo_arm64 { u64 reg_id_aa64isar1; u64 reg_id_aa64mmfr0; u64 reg_id_aa64mmfr1; - u64 reg_id_aa64mmfr2; u64 reg_id_aa64pfr0; u64 reg_id_aa64pfr1; diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 44e8b3d76fb7..2e73ef7b9239 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -30,11 +30,8 @@ #define ARM64_HAS_LSE_ATOMICS 5 #define ARM64_WORKAROUND_CAVIUM_23154 6 #define ARM64_WORKAROUND_834220 7 -#define ARM64_HAS_NO_HW_PREFETCH 8 -#define ARM64_HAS_UAO 9 -#define ARM64_ALT_PAN_NOT_UAO 10 -#define ARM64_NCAPS 11 +#define ARM64_NCAPS 8 #ifndef __ASSEMBLY__ @@ -181,7 +178,7 @@ u64 read_system_reg(u32 id); static inline bool cpu_supports_mixed_endian_el0(void) { - return id_aa64mmfr0_mixed_endian_el0(read_cpuid(SYS_ID_AA64MMFR0_EL1)); + return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); } static inline bool system_supports_mixed_endian_el0(void) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 1ddc9c930097..a2014784cab2 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -36,6 +36,12 @@ #define MMFR0_16KGRAN_SHFT 20 #define MMFR0_EL1_16KGRAN_MASK (MMFR0_16KGRAN_SIZE << MMFR0_16KGRAN_SHFT) +#define read_cpuid(reg) ({ \ + u64 __val; \ + asm("mrs %0, " #reg : "=r" (__val)); \ + __val; \ +}) + #define MIDR_REVISION_MASK 0xf #define MIDR_REVISION(midr) ((midr) & MIDR_REVISION_MASK) #define MIDR_PARTNUM_SHIFT 4 @@ -55,22 +61,11 @@ #define MIDR_IMPLEMENTOR(midr) \ (((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT) -#define MIDR_CPU_MODEL(imp, partnum) \ +#define MIDR_CPU_PART(imp, partnum) \ (((imp) << MIDR_IMPLEMENTOR_SHIFT) | \ (0xf << MIDR_ARCHITECTURE_SHIFT) | \ ((partnum) << MIDR_PARTNUM_SHIFT)) -#define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ - MIDR_ARCHITECTURE_MASK) - -#define MIDR_IS_CPU_MODEL_RANGE(midr, model, rv_min, rv_max) \ -({ \ - u32 _model = (midr) & MIDR_CPU_MODEL_MASK; \ - u32 rv = (midr) & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK); \ - \ - _model == (model) && rv >= (rv_min) && rv <= (rv_max); \ - }) - #define ARM_CPU_IMP_ARM 0x41 #define ARM_CPU_IMP_APM 0x50 #define ARM_CPU_IMP_CAVIUM 0x43 @@ -88,22 +83,8 @@ #define CAVIUM_CPU_PART_THUNDERX 0x0A1 -#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) -#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) -#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) -#define MIDR_KRYO2XX_SILVER \ - MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_SILVER) - #ifndef __ASSEMBLY__ -#include <asm/sysreg.h> - -#define read_cpuid(reg) ({ \ - u64 __val; \ - asm("mrs_s %0, " __stringify(reg) : "=r" (__val)); \ - __val; \ -}) - /* * The CPU ID never changes at run time, so we might as well tell the * compiler that it's constant. Use this function to read the CPU ID @@ -111,12 +92,12 @@ */ static inline u32 __attribute_const__ read_cpuid_id(void) { - return read_cpuid(SYS_MIDR_EL1); + return read_cpuid(MIDR_EL1); } static inline u64 __attribute_const__ read_cpuid_mpidr(void) { - return read_cpuid(SYS_MPIDR_EL1); + return read_cpuid(MPIDR_EL1); } static inline unsigned int __attribute_const__ read_cpuid_implementor(void) @@ -131,7 +112,7 @@ static inline unsigned int __attribute_const__ read_cpuid_part_number(void) static inline u32 __attribute_const__ read_cpuid_cachetype(void) { - return read_cpuid(SYS_CTR_EL0); + return read_cpuid(CTR_EL0); } #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 2fcb9b7c876c..279c85b5ec09 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -20,7 +20,6 @@ #include <linux/errno.h> #include <linux/types.h> -#include <asm/brk-imm.h> #include <asm/esr.h> #include <asm/insn.h> #include <asm/ptrace.h> @@ -48,6 +47,19 @@ #define BREAK_INSTR_SIZE AARCH64_INSN_SIZE /* + * #imm16 values used for BRK instruction generation + * Allowed values for kgbd are 0x400 - 0x7ff + * 0x100: for triggering a fault on purpose (reserved) + * 0x400: for dynamic BRK instruction + * 0x401: for compile time BRK instruction + * 0x800: kernel-mode BUG() and WARN() traps + */ +#define FAULT_BRK_IMM 0x100 +#define KGDB_DYN_DBG_BRK_IMM 0x400 +#define KGDB_COMPILED_DBG_BRK_IMM 0x401 +#define BUG_BRK_IMM 0x800 + +/* * BRK instruction encoding * The #imm16 value should be placed at bits[20:5] within BRK ins */ diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 24ed037f09fd..faad6df49e5b 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -24,6 +24,15 @@ #include <asm/ptrace.h> #include <asm/user.h> +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) +#define ELF_CORE_COPY_REGS(dest, regs) \ + *(struct user_pt_regs *)&(dest) = (regs)->user_regs; + +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; +typedef struct user_fpsimd_state elf_fpregset_t; + /* * AArch64 static relocation types. */ @@ -77,8 +86,6 @@ #define R_AARCH64_MOVW_PREL_G2_NC 292 #define R_AARCH64_MOVW_PREL_G3 293 -#define R_AARCH64_RELATIVE 1027 - /* * These are used to set parameters in the core dumps. */ @@ -120,17 +127,6 @@ */ #define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) -#ifndef __ASSEMBLY__ - -typedef unsigned long elf_greg_t; - -#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) -#define ELF_CORE_COPY_REGS(dest, regs) \ - *(struct user_pt_regs *)&(dest) = (regs)->user_regs; - -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -typedef struct user_fpsimd_state elf_fpregset_t; - /* * When the program starts, a1 contains a pointer to a function to be * registered with atexit, as per the SVR4 ABI. A value of 0 means we have no @@ -190,6 +186,4 @@ extern int aarch32_setup_vectors_page(struct linux_binprm *bprm, #endif /* CONFIG_COMPAT */ -#endif /* !__ASSEMBLY__ */ - #endif diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index 1a617d46fce9..309704544d22 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -62,16 +62,6 @@ enum fixed_addresses { FIX_BTMAP_END = __end_of_permanent_fixed_addresses, FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, - - /* - * Used for kernel page table creation, so unmapped memory may be used - * for tables. - */ - FIX_PTE, - FIX_PMD, - FIX_PUD, - FIX_PGD, - __end_of_fixed_addresses }; diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h index 3c60f37e48ab..c5534facf941 100644 --- a/arch/arm64/include/asm/ftrace.h +++ b/arch/arm64/include/asm/ftrace.h @@ -28,8 +28,6 @@ struct dyn_arch_ftrace { extern unsigned long ftrace_graph_call; -extern void return_to_handler(void); - static inline unsigned long ftrace_call_adjust(unsigned long addr) { /* diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index f2585cdd32c2..007a69fc4f40 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -42,8 +42,10 @@ "4: mov %w0, %w5\n" \ " b 3b\n" \ " .popsection\n" \ - _ASM_EXTABLE(1b, 4b) \ - _ASM_EXTABLE(2b, 4b) \ +" .pushsection __ex_table,\"a\"\n" \ +" .align 3\n" \ +" .quad 1b, 4b, 2b, 4b\n" \ +" .popsection\n" \ ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ @@ -119,7 +121,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; asm volatile("// futex_atomic_cmpxchg_inatomic\n" -ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN) " prfm pstl1strm, %2\n" "1: ldxr %w1, %2\n" " sub %w3, %w1, %w4\n" @@ -132,9 +133,10 @@ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN) "4: mov %w0, %w6\n" " b 3b\n" " .popsection\n" - _ASM_EXTABLE(1b, 4b) - _ASM_EXTABLE(2b, 4b) -ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN) +" .pushsection __ex_table,\"a\"\n" +" .align 3\n" +" .quad 1b, 4b, 2b, 4b\n" +" .popsection\n" : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp) : "r" (oldval), "r" (newval), "Ir" (-EFAULT) : "memory"); diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h index bbc1e35aa601..bb4052e85dba 100644 --- a/arch/arm64/include/asm/hugetlb.h +++ b/arch/arm64/include/asm/hugetlb.h @@ -26,7 +26,36 @@ static inline pte_t huge_ptep_get(pte_t *ptep) return *ptep; } +static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + set_pte_at(mm, addr, ptep, pte); +} + +static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ + ptep_clear_flush(vma, addr, ptep); +} + +static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + ptep_set_wrprotect(mm, addr, ptep); +} +static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + return ptep_get_and_clear(mm, addr, ptep); +} + +static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty) +{ + return ptep_set_access_flags(vma, addr, ptep, pte, dirty); +} static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end, @@ -68,19 +97,4 @@ static inline void arch_clear_hugepage_flags(struct page *page) clear_bit(PG_dcache_clean, &page->flags); } -extern pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma, - struct page *page, int writable); -#define arch_make_huge_pte arch_make_huge_pte -extern void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pte); -extern int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, - pte_t pte, int dirty); -extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm, - unsigned long addr, pte_t *ptep); -extern void huge_ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep); -extern void huge_ptep_clear_flush(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep); - #endif /* __ASM_HUGETLB_H */ diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 3e1c0e7ef082..a8464c18ef88 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -1,45 +1,10 @@ #ifndef __ASM_IRQ_H #define __ASM_IRQ_H -#define IRQ_STACK_SIZE THREAD_SIZE -#define IRQ_STACK_START_SP THREAD_START_SP - -#ifndef __ASSEMBLER__ - -#include <linux/percpu.h> - #include <asm-generic/irq.h> -#include <asm/thread_info.h> struct pt_regs; -DECLARE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack); - -/* - * The highest address on the stack, and the first to be used. Used to - * find the dummy-stack frame put down by el?_irq() in entry.S, which - * is structured as follows: - * - * ------------ - * | | <- irq_stack_ptr - * top ------------ - * | x19 | <- irq_stack_ptr - 0x08 - * ------------ - * | x29 | <- irq_stack_ptr - 0x10 - * ------------ - * - * where x19 holds a copy of the task stack pointer where the struct pt_regs - * from kernel_entry can be found. - * - */ -#define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP) - -/* - * The offset from irq_stack_ptr where entry.S will store the original - * stack pointer. Used by unwind_frame() and dump_backtrace(). - */ -#define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08))) - extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); static inline int nr_legacy_irqs(void) @@ -50,14 +15,4 @@ static inline int nr_legacy_irqs(void) void arch_trigger_all_cpu_backtrace(void); #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace -static inline bool on_irq_stack(unsigned long sp, int cpu) -{ - /* variable names the same as kernel/stacktrace.c */ - unsigned long low = (unsigned long)per_cpu(irq_stack, cpu); - unsigned long high = low + IRQ_STACK_START_SP; - - return (low <= sp && sp <= high); -} - -#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h index 71ad0f93eb71..2774fa384c47 100644 --- a/arch/arm64/include/asm/kasan.h +++ b/arch/arm64/include/asm/kasan.h @@ -7,14 +7,13 @@ #include <linux/linkage.h> #include <asm/memory.h> -#include <asm/pgtable-types.h> /* * KASAN_SHADOW_START: beginning of the kernel virtual addresses. * KASAN_SHADOW_END: KASAN_SHADOW_START + 1/8 of kernel virtual addresses. */ #define KASAN_SHADOW_START (VA_START) -#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE) +#define KASAN_SHADOW_END (KASAN_SHADOW_START + (1UL << (VA_BITS - 3))) /* * This value is used to map an address to the corresponding shadow @@ -29,12 +28,10 @@ #define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << (64 - 3))) void kasan_init(void); -void kasan_copy_shadow(pgd_t *pgdir); asmlinkage void kasan_early_init(void); #else static inline void kasan_init(void) { } -static inline void kasan_copy_shadow(pgd_t *pgdir) { } #endif #endif diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h index 5c6375d8528b..a459714ee29e 100644 --- a/arch/arm64/include/asm/kernel-pgtable.h +++ b/arch/arm64/include/asm/kernel-pgtable.h @@ -79,17 +79,5 @@ #define SWAPPER_MM_MMUFLAGS (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS) #endif -/* - * To make optimal use of block mappings when laying out the linear - * mapping, round down the base of physical memory to a size that can - * be mapped efficiently, i.e., either PUD_SIZE (4k granule) or PMD_SIZE - * (64k granule), or a multiple that can be mapped using contiguous bits - * in the page tables: 32 * PMD_SIZE (16k granule) - */ -#ifdef CONFIG_ARM64_64K_PAGES -#define ARM64_MEMSTART_ALIGN SZ_512M -#else -#define ARM64_MEMSTART_ALIGN SZ_1G -#endif #endif /* __ASM_KERNEL_PGTABLE_H */ diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 419bc6661b5c..5e377101f919 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -102,8 +102,6 @@ #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0 #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT) -#define kvm_ksym_ref(sym) phys_to_virt((u64)&sym - kimage_voffset) - #ifndef __ASSEMBLY__ struct kvm; struct kvm_vcpu; diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 90c6368ad7c8..a35ce7266aac 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -222,7 +222,7 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, struct kvm_vcpu *kvm_arm_get_running_vcpu(void); struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void); -u64 __kvm_call_hyp(void *hypfn, ...); +u64 kvm_call_hyp(void *hypfn, ...); void force_vm_exit(const cpumask_t *mask); void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot); @@ -243,8 +243,8 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr, * Call initialization code, and switch to the full blown * HYP code. */ - __kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr, - hyp_stack_ptr, vector_ptr); + kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr, + hyp_stack_ptr, vector_ptr); } static inline void kvm_arch_hardware_disable(void) {} @@ -258,6 +258,4 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); -#define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__) - #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h index 23acc00be32d..3de42d68611d 100644 --- a/arch/arm64/include/asm/lse.h +++ b/arch/arm64/include/asm/lse.h @@ -26,7 +26,6 @@ __asm__(".arch_extension lse"); /* Macro for constructing calls to out-of-line ll/sc atomics */ #define __LL_SC_CALL(op) "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n" -#define __LL_SC_CLOBBERS "x16", "x17", "x30" /* In-line patching at runtime */ #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 12f8a00fb3f1..853953cd1f08 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -24,7 +24,6 @@ #include <linux/compiler.h> #include <linux/const.h> #include <linux/types.h> -#include <asm/bug.h> #include <asm/sizes.h> /* @@ -46,15 +45,15 @@ * VA_START - the first kernel virtual address. * TASK_SIZE - the maximum size of a user space task. * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. + * The module space lives between the addresses given by TASK_SIZE + * and PAGE_OFFSET - it must be within 128MB of the kernel text. */ #define VA_BITS (CONFIG_ARM64_VA_BITS) #define VA_START (UL(0xffffffffffffffff) << VA_BITS) #define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) -#define KIMAGE_VADDR (MODULES_END) -#define MODULES_END (MODULES_VADDR + MODULES_VSIZE) -#define MODULES_VADDR (VA_START + KASAN_SHADOW_SIZE) -#define MODULES_VSIZE (SZ_128M) -#define PCI_IO_END (PAGE_OFFSET - SZ_2M) +#define MODULES_END (PAGE_OFFSET) +#define MODULES_VADDR (MODULES_END - SZ_64M) +#define PCI_IO_END (MODULES_VADDR - SZ_2M) #define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE) #define FIXADDR_TOP (PCI_IO_START - SZ_2M) #define TASK_SIZE_64 (UL(1) << VA_BITS) @@ -72,27 +71,12 @@ #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4)) /* - * The size of the KASAN shadow region. This should be 1/8th of the - * size of the entire kernel virtual address space. - */ -#ifdef CONFIG_KASAN -#define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - 3)) -#else -#define KASAN_SHADOW_SIZE (0) -#endif - -/* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. */ -#define __virt_to_phys(x) ({ \ - phys_addr_t __x = (phys_addr_t)(x); \ - __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET : \ - (__x - kimage_voffset); }) - -#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) -#define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset)) +#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET)) +#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET)) /* * Convert a page to/from a physical address @@ -116,40 +100,19 @@ #define MT_S2_NORMAL 0xf #define MT_S2_DEVICE_nGnRE 0x1 -#ifdef CONFIG_ARM64_4K_PAGES -#define IOREMAP_MAX_ORDER (PUD_SHIFT) -#else -#define IOREMAP_MAX_ORDER (PMD_SHIFT) -#endif - -#ifdef CONFIG_BLK_DEV_INITRD -#define __early_init_dt_declare_initrd(__start, __end) \ - do { \ - initrd_start = (__start); \ - initrd_end = (__end); \ - } while (0) -#endif - #ifndef __ASSEMBLY__ -#include <linux/bitops.h> -#include <linux/mmdebug.h> - -extern s64 memstart_addr; +extern phys_addr_t memstart_addr; /* PHYS_OFFSET - the physical address of the start of memory. */ -#define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; }) - -/* the virtual base of the kernel image (minus TEXT_OFFSET) */ -extern u64 kimage_vaddr; - -/* the offset between the kernel virtual and physical mappings */ -extern u64 kimage_voffset; +#define PHYS_OFFSET ({ memstart_addr; }) /* - * Allow all memory at the discovery stage. We will clip it later. + * The maximum physical address that the linear direct mapping + * of system RAM can cover. (PAGE_OFFSET can be interpreted as + * a 2's complement signed quantity and negated to derive the + * maximum size of the linear mapping.) */ -#define MIN_MEMBLOCK_ADDR 0 -#define MAX_MEMBLOCK_ADDR U64_MAX +#define MAX_MEMBLOCK_ADDR ({ memstart_addr - PAGE_OFFSET - 1; }) /* * PFNs are used to describe any physical page; this means diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index a00f7cf35bbd..24165784b803 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -27,7 +27,6 @@ #include <asm-generic/mm_hooks.h> #include <asm/cputype.h> #include <asm/pgtable.h> -#include <asm/tlbflush.h> #ifdef CONFIG_PID_IN_CONTEXTIDR static inline void contextidr_thread_switch(struct task_struct *next) @@ -49,7 +48,7 @@ static inline void contextidr_thread_switch(struct task_struct *next) */ static inline void cpu_set_reserved_ttbr0(void) { - unsigned long ttbr = virt_to_phys(empty_zero_page); + unsigned long ttbr = page_to_phys(empty_zero_page); asm( " msr ttbr0_el1, %0 // set TTBR0\n" @@ -74,7 +73,7 @@ static inline bool __cpu_uses_extended_idmap(void) /* * Set TCR.T0SZ to its default value (based on VA_BITS) */ -static inline void __cpu_set_tcr_t0sz(unsigned long t0sz) +static inline void cpu_set_default_tcr_t0sz(void) { unsigned long tcr; @@ -87,62 +86,7 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz) " msr tcr_el1, %0 ;" " isb" : "=&r" (tcr) - : "r"(t0sz), "I"(TCR_T0SZ_OFFSET), "I"(TCR_TxSZ_WIDTH)); -} - -#define cpu_set_default_tcr_t0sz() __cpu_set_tcr_t0sz(TCR_T0SZ(VA_BITS)) -#define cpu_set_idmap_tcr_t0sz() __cpu_set_tcr_t0sz(idmap_t0sz) - -/* - * Remove the idmap from TTBR0_EL1 and install the pgd of the active mm. - * - * The idmap lives in the same VA range as userspace, but uses global entries - * and may use a different TCR_EL1.T0SZ. To avoid issues resulting from - * speculative TLB fetches, we must temporarily install the reserved page - * tables while we invalidate the TLBs and set up the correct TCR_EL1.T0SZ. - * - * If current is a not a user task, the mm covers the TTBR1_EL1 page tables, - * which should not be installed in TTBR0_EL1. In this case we can leave the - * reserved page tables in place. - */ -static inline void cpu_uninstall_idmap(void) -{ - struct mm_struct *mm = current->active_mm; - - cpu_set_reserved_ttbr0(); - local_flush_tlb_all(); - cpu_set_default_tcr_t0sz(); - - if (mm != &init_mm) - cpu_switch_mm(mm->pgd, mm); -} - -static inline void cpu_install_idmap(void) -{ - cpu_set_reserved_ttbr0(); - local_flush_tlb_all(); - cpu_set_idmap_tcr_t0sz(); - - cpu_switch_mm(idmap_pg_dir, &init_mm); -} - -/* - * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD, - * avoiding the possibility of conflicting TLB entries being allocated. - */ -static inline void cpu_replace_ttbr1(pgd_t *pgd) -{ - typedef void (ttbr_replace_func)(phys_addr_t); - extern ttbr_replace_func idmap_cpu_replace_ttbr1; - ttbr_replace_func *replace_phys; - - phys_addr_t pgd_phys = virt_to_phys(pgd); - - replace_phys = (void *)virt_to_phys(idmap_cpu_replace_ttbr1); - - cpu_install_idmap(); - replace_phys(pgd_phys); - cpu_uninstall_idmap(); + : "r"(TCR_T0SZ(VA_BITS)), "I"(TCR_T0SZ_OFFSET), "I"(TCR_TxSZ_WIDTH)); } /* diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index e12af6754634..e80e232b730e 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -20,21 +20,4 @@ #define MODULE_ARCH_VERMAGIC "aarch64" -#ifdef CONFIG_ARM64_MODULE_PLTS -struct mod_arch_specific { - struct elf64_shdr *plt; - int plt_num_entries; - int plt_max_entries; -}; -#endif - -u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela, - Elf64_Sym *sym); - -#ifdef CONFIG_RANDOMIZE_BASE -extern u64 module_alloc_base; -#else -#define module_alloc_base ((u64)_etext - MODULES_VSIZE) -#endif - #endif /* __ASM_MODULE_H */ diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index ff98585d085a..c15053902942 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -42,20 +42,11 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) free_page((unsigned long)pmd); } -static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot) -{ - set_pud(pud, __pud(pmd | prot)); -} - static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) { - __pud_populate(pud, __pa(pmd), PMD_TYPE_TABLE); -} -#else -static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot) -{ - BUILD_BUG(); + set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); } + #endif /* CONFIG_PGTABLE_LEVELS > 2 */ #if CONFIG_PGTABLE_LEVELS > 3 @@ -71,20 +62,11 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud) free_page((unsigned long)pud); } -static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot) -{ - set_pgd(pgdp, __pgd(pud | prot)); -} - static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) { - __pgd_populate(pgd, __pa(pud), PUD_TYPE_TABLE); -} -#else -static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot) -{ - BUILD_BUG(); + set_pgd(pgd, __pgd(__pa(pud) | PUD_TYPE_TABLE)); } + #endif /* CONFIG_PGTABLE_LEVELS > 3 */ extern pgd_t *pgd_alloc(struct mm_struct *mm); diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index 5c25b831273d..d6739e836f7b 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -90,23 +90,7 @@ /* * Contiguous page definitions. */ -#ifdef CONFIG_ARM64_64K_PAGES -#define CONT_PTE_SHIFT 5 -#define CONT_PMD_SHIFT 5 -#elif defined(CONFIG_ARM64_16K_PAGES) -#define CONT_PTE_SHIFT 7 -#define CONT_PMD_SHIFT 5 -#else -#define CONT_PTE_SHIFT 4 -#define CONT_PMD_SHIFT 4 -#endif - -#define CONT_PTES (1 << CONT_PTE_SHIFT) -#define CONT_PTE_SIZE (CONT_PTES * PAGE_SIZE) -#define CONT_PTE_MASK (~(CONT_PTE_SIZE - 1)) -#define CONT_PMDS (1 << CONT_PMD_SHIFT) -#define CONT_PMD_SIZE (CONT_PMDS * PMD_SIZE) -#define CONT_PMD_MASK (~(CONT_PMD_SIZE - 1)) +#define CONT_PTES (_AC(1, UL) << CONT_SHIFT) /* the the numerical offset of the PTE within a range of CONT_PTES */ #define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_PTES-1)) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index c3c2518eecfe..eaa9cabf4066 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -36,13 +36,19 @@ * * VMEMAP_SIZE: allows the whole linear region to be covered by a struct page array * (rounded up to PUD_SIZE). - * VMALLOC_START: beginning of the kernel vmalloc space + * VMALLOC_START: beginning of the kernel VA space * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space, * fixed mappings and modules */ #define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE) -#define VMALLOC_START (MODULES_END) +#ifndef CONFIG_KASAN +#define VMALLOC_START (VA_START) +#else +#include <asm/kasan.h> +#define VMALLOC_START (KASAN_SHADOW_END + SZ_64K) +#endif + #define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K) #define VMEMMAP_START (VMALLOC_END + SZ_64K) @@ -53,7 +59,6 @@ #ifndef __ASSEMBLY__ -#include <asm/fixmap.h> #include <linux/mmdebug.h> extern void __pte_error(const char *file, int line, unsigned long val); @@ -64,11 +69,11 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) -#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) -#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE)) -#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC)) -#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT)) -#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL)) +#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) +#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) +#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC)) +#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_WT)) +#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL)) #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE)) #define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) @@ -78,7 +83,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY) -#define PAGE_KERNEL_ROX __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY) +#define PAGE_KERNEL_ROX __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY) #define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT) @@ -118,8 +123,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val); * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. */ -extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) +extern struct page *empty_zero_page; +#define ZERO_PAGE(vaddr) (empty_zero_page) #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) @@ -131,6 +136,16 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) +/* Find an entry in the third-level page table. */ +#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr)) + +#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) +#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr)) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) + /* * The following only work if pte_present(). Undefined behaviour otherwise. */ @@ -140,7 +155,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE)) #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) #define pte_cont(pte) (!!(pte_val(pte) & PTE_CONT)) -#define pte_user(pte) (!!(pte_val(pte) & PTE_USER)) #ifdef CONFIG_ARM64_HW_AFDBM #define pte_hw_dirty(pte) (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY)) @@ -151,18 +165,10 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte)) #define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID)) +#define pte_valid_user(pte) \ + ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) #define pte_valid_not_user(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID) -#define pte_valid_young(pte) \ - ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF)) - -/* - * Could the pte be present in the TLB? We must check mm_tlb_flush_pending - * so that we don't erroneously return false for pages that have been - * remapped as PROT_NONE but are yet to be flushed from the TLB. - */ -#define pte_accessible(mm, pte) \ - (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte)) static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot) { @@ -213,8 +219,7 @@ static inline pte_t pte_mkspecial(pte_t pte) static inline pte_t pte_mkcont(pte_t pte) { - pte = set_pte_bit(pte, __pgprot(PTE_CONT)); - return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE)); + return set_pte_bit(pte, __pgprot(PTE_CONT)); } static inline pte_t pte_mknoncont(pte_t pte) @@ -222,11 +227,6 @@ static inline pte_t pte_mknoncont(pte_t pte) return clear_pte_bit(pte, __pgprot(PTE_CONT)); } -static inline pmd_t pmd_mkcont(pmd_t pmd) -{ - return __pmd(pmd_val(pmd) | PMD_SECT_CONT); -} - static inline void set_pte(pte_t *ptep, pte_t pte) { *ptep = pte; @@ -264,13 +264,13 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { - if (pte_present(pte)) { + if (pte_valid_user(pte)) { + if (!pte_special(pte) && pte_exec(pte)) + __sync_icache_dcache(pte, addr); if (pte_sw_dirty(pte) && pte_write(pte)) pte_val(pte) &= ~PTE_RDONLY; else pte_val(pte) |= PTE_RDONLY; - if (pte_user(pte) && pte_exec(pte) && !pte_special(pte)) - __sync_icache_dcache(pte, addr); } /* @@ -300,7 +300,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, /* * Hugetlb definitions. */ -#define HUGE_MAX_HSTATE 4 +#define HUGE_MAX_HSTATE 2 #define HPAGE_SHIFT PMD_SHIFT #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE - 1)) @@ -354,7 +354,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, #define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd))) #define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) #define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) -#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd))) #define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) #define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) #define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK)) @@ -427,31 +426,13 @@ static inline void pmd_clear(pmd_t *pmdp) set_pmd(pmdp, __pmd(0)); } -static inline phys_addr_t pmd_page_paddr(pmd_t pmd) +static inline pte_t *pmd_page_vaddr(pmd_t pmd) { - return pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK; + return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); } -/* Find an entry in the third-level page table. */ -#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) - -#define pte_offset_phys(dir,addr) (pmd_page_paddr(*(dir)) + pte_index(addr) * sizeof(pte_t)) -#define pte_offset_kernel(dir,addr) ((pte_t *)__va(pte_offset_phys((dir), (addr)))) - -#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) -#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr)) -#define pte_unmap(pte) do { } while (0) -#define pte_unmap_nested(pte) do { } while (0) - -#define pte_set_fixmap(addr) ((pte_t *)set_fixmap_offset(FIX_PTE, addr)) -#define pte_set_fixmap_offset(pmd, addr) pte_set_fixmap(pte_offset_phys(pmd, addr)) -#define pte_clear_fixmap() clear_fixmap(FIX_PTE) - #define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) -/* use ONLY for statically allocated translation tables */ -#define pte_offset_kimg(dir,addr) ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr)))) - /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. @@ -478,37 +459,21 @@ static inline void pud_clear(pud_t *pudp) set_pud(pudp, __pud(0)); } -static inline phys_addr_t pud_page_paddr(pud_t pud) +static inline pmd_t *pud_page_vaddr(pud_t pud) { - return pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK; + return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); } /* Find an entry in the second-level page table. */ #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) -#define pmd_offset_phys(dir, addr) (pud_page_paddr(*(dir)) + pmd_index(addr) * sizeof(pmd_t)) -#define pmd_offset(dir, addr) ((pmd_t *)__va(pmd_offset_phys((dir), (addr)))) - -#define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr)) -#define pmd_set_fixmap_offset(pud, addr) pmd_set_fixmap(pmd_offset_phys(pud, addr)) -#define pmd_clear_fixmap() clear_fixmap(FIX_PMD) +static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) +{ + return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr); +} #define pud_page(pud) pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK)) -/* use ONLY for statically allocated translation tables */ -#define pmd_offset_kimg(dir,addr) ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr)))) - -#else - -#define pud_page_paddr(pud) ({ BUILD_BUG(); 0; }) - -/* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */ -#define pmd_set_fixmap(addr) NULL -#define pmd_set_fixmap_offset(pudp, addr) ((pmd_t *)pudp) -#define pmd_clear_fixmap() - -#define pmd_offset_kimg(dir,addr) ((pmd_t *)dir) - #endif /* CONFIG_PGTABLE_LEVELS > 2 */ #if CONFIG_PGTABLE_LEVELS > 3 @@ -530,37 +495,21 @@ static inline void pgd_clear(pgd_t *pgdp) set_pgd(pgdp, __pgd(0)); } -static inline phys_addr_t pgd_page_paddr(pgd_t pgd) +static inline pud_t *pgd_page_vaddr(pgd_t pgd) { - return pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK; + return __va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK); } /* Find an entry in the frst-level page table. */ #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) -#define pud_offset_phys(dir, addr) (pgd_page_paddr(*(dir)) + pud_index(addr) * sizeof(pud_t)) -#define pud_offset(dir, addr) ((pud_t *)__va(pud_offset_phys((dir), (addr)))) - -#define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr)) -#define pud_set_fixmap_offset(pgd, addr) pud_set_fixmap(pud_offset_phys(pgd, addr)) -#define pud_clear_fixmap() clear_fixmap(FIX_PUD) +static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr) +{ + return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr); +} #define pgd_page(pgd) pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK)) -/* use ONLY for statically allocated translation tables */ -#define pud_offset_kimg(dir,addr) ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr)))) - -#else - -#define pgd_page_paddr(pgd) ({ BUILD_BUG(); 0;}) - -/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */ -#define pud_set_fixmap(addr) NULL -#define pud_set_fixmap_offset(pgdp, addr) ((pud_t *)pgdp) -#define pud_clear_fixmap() - -#define pud_offset_kimg(dir,addr) ((pud_t *)dir) - #endif /* CONFIG_PGTABLE_LEVELS > 3 */ #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) @@ -568,16 +517,11 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd) /* to find an entry in a page-table-directory */ #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) -#define pgd_offset_raw(pgd, addr) ((pgd) + pgd_index(addr)) - -#define pgd_offset(mm, addr) (pgd_offset_raw((mm)->pgd, (addr))) +#define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr)) /* to find an entry in a kernel page-table-directory */ #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) -#define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr)) -#define pgd_clear_fixmap() clear_fixmap(FIX_PGD) - static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | @@ -697,7 +641,6 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; * bits 0-1: present (must be zero) * bits 2-7: swap type * bits 8-57: swap offset - * bit 58: PTE_PROT_NONE (must be zero) */ #define __SWP_TYPE_SHIFT 2 #define __SWP_TYPE_BITS 6 @@ -723,8 +666,7 @@ extern int kern_addr_valid(unsigned long addr); #include <asm-generic/pgtable.h> -void pgd_cache_init(void); -#define pgtable_cache_init pgd_cache_init +#define pgtable_cache_init() do { } while (0) /* * On AArch64, the cache coherency is handled via the set_pte_at() function. diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index c97d01eb219f..c8c7c4d38171 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -29,10 +29,8 @@ #include <linux/string.h> -#include <asm/alternative.h> #include <asm/fpsimd.h> #include <asm/hw_breakpoint.h> -#include <asm/lse.h> #include <asm/pgtable-hwdef.h> #include <asm/ptrace.h> #include <asm/types.h> @@ -182,11 +180,9 @@ static inline void prefetchw(const void *ptr) } #define ARCH_HAS_SPINLOCK_PREFETCH -static inline void spin_lock_prefetch(const void *ptr) +static inline void spin_lock_prefetch(const void *x) { - asm volatile(ARM64_LSE_ATOMIC_INSN( - "prfm pstl1strm, %a0", - "nop") : : "p" (ptr)); + prefetchw(x); } #define HAVE_ARCH_PICK_MMAP_LAYOUT @@ -194,6 +190,5 @@ static inline void spin_lock_prefetch(const void *ptr) #endif void cpu_enable_pan(void *__unused); -void cpu_enable_uao(void *__unused); #endif /* __ASM_PROCESSOR_H */ diff --git a/arch/arm64/include/asm/shmparam.h b/arch/arm64/include/asm/shmparam.h index e368a55ebd22..4df608a8459e 100644 --- a/arch/arm64/include/asm/shmparam.h +++ b/arch/arm64/include/asm/shmparam.h @@ -21,7 +21,7 @@ * alignment value. Since we don't have aliasing D-caches, the rest of * the time we can safely use PAGE_SIZE. */ -#define COMPAT_SHMLBA (4 * PAGE_SIZE) +#define COMPAT_SHMLBA 0x4000 #include <asm-generic/shmparam.h> diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 2013a4dc5124..c63c432f1a82 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -63,15 +63,7 @@ extern void secondary_entry(void); extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); - -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask); -#else -static inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask) -{ - BUILD_BUG(); -} -#endif extern int __cpu_disable(void); diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index 7b369923b2eb..be4d2f9b7e8c 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h @@ -26,28 +26,9 @@ * The memory barriers are implicit with the load-acquire and store-release * instructions. */ -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) -{ - unsigned int tmp; - arch_spinlock_t lockval; - asm volatile( -" sevl\n" -"1: wfe\n" -"2: ldaxr %w0, %2\n" -" eor %w1, %w0, %w0, ror #16\n" -" cbnz %w1, 1b\n" - ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ -" stxr %w1, %w0, %2\n" -" cbnz %w1, 2b\n", /* Serialise against any concurrent lockers */ - /* LSE atomics */ -" nop\n" -" nop\n") - : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock) - : - : "memory"); -} +#define arch_spin_unlock_wait(lock) \ + do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index 801a16dbbdf6..7318f6d54aa9 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -16,19 +16,14 @@ #ifndef __ASM_STACKTRACE_H #define __ASM_STACKTRACE_H -struct task_struct; - struct stackframe { unsigned long fp; unsigned long sp; unsigned long pc; -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - unsigned int graph; -#endif }; -extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); -extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, +extern int unwind_frame(struct stackframe *frame); +extern void walk_stackframe(struct stackframe *frame, int (*fn)(struct stackframe *, void *), void *data); #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index b9fd8ec79033..d48ab5b41f52 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -70,19 +70,15 @@ #define SYS_ID_AA64MMFR0_EL1 sys_reg(3, 0, 0, 7, 0) #define SYS_ID_AA64MMFR1_EL1 sys_reg(3, 0, 0, 7, 1) -#define SYS_ID_AA64MMFR2_EL1 sys_reg(3, 0, 0, 7, 2) #define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0) #define SYS_CTR_EL0 sys_reg(3, 3, 0, 0, 1) #define SYS_DCZID_EL0 sys_reg(3, 3, 0, 0, 7) #define REG_PSTATE_PAN_IMM sys_reg(0, 0, 4, 0, 4) -#define REG_PSTATE_UAO_IMM sys_reg(0, 0, 4, 0, 3) #define SET_PSTATE_PAN(x) __inst_arm(0xd5000000 | REG_PSTATE_PAN_IMM |\ (!!x)<<8 | 0x1f) -#define SET_PSTATE_UAO(x) __inst_arm(0xd5000000 | REG_PSTATE_UAO_IMM |\ - (!!x)<<8 | 0x1f) /* SCTLR_EL1 */ #define SCTLR_EL1_CP15BEN (0x1 << 5) @@ -139,9 +135,6 @@ #define ID_AA64MMFR1_VMIDBITS_SHIFT 4 #define ID_AA64MMFR1_HADBS_SHIFT 0 -/* id_aa64mmfr2 */ -#define ID_AA64MMFR2_UAO_SHIFT 4 - /* id_aa64dfr0 */ #define ID_AA64DFR0_CTX_CMPS_SHIFT 28 #define ID_AA64DFR0_WRPS_SHIFT 20 @@ -201,32 +194,32 @@ #ifdef __ASSEMBLY__ .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 - .equ .L__reg_num_x\num, \num + .equ __reg_num_x\num, \num .endr - .equ .L__reg_num_xzr, 31 + .equ __reg_num_xzr, 31 .macro mrs_s, rt, sreg - .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt) + .inst 0xd5200000|(\sreg)|(__reg_num_\rt) .endm .macro msr_s, sreg, rt - .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt) + .inst 0xd5000000|(\sreg)|(__reg_num_\rt) .endm #else asm( " .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" -" .equ .L__reg_num_x\\num, \\num\n" +" .equ __reg_num_x\\num, \\num\n" " .endr\n" -" .equ .L__reg_num_xzr, 31\n" +" .equ __reg_num_xzr, 31\n" "\n" " .macro mrs_s, rt, sreg\n" -" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" +" .inst 0xd5200000|(\\sreg)|(__reg_num_\\rt)\n" " .endm\n" "\n" " .macro msr_s, sreg, rt\n" -" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" +" .inst 0xd5000000|(\\sreg)|(__reg_num_\\rt)\n" " .endm\n" ); diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 4a9e82e4f724..bfef76e14e2d 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -73,16 +73,10 @@ register unsigned long current_stack_pointer asm ("sp"); */ static inline struct thread_info *current_thread_info(void) __attribute_const__; -/* - * struct thread_info can be accessed directly via sp_el0. - */ static inline struct thread_info *current_thread_info(void) { - unsigned long sp_el0; - - asm ("mrs %0, sp_el0" : "=r" (sp_el0)); - - return (struct thread_info *)sp_el0; + return (struct thread_info *) + (current_stack_pointer & ~(THREAD_SIZE - 1)); } #define thread_saved_pc(tsk) \ diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 0685d74572af..b2ede967fe7d 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -36,11 +36,11 @@ #define VERIFY_WRITE 1 /* - * The exception table consists of pairs of relative offsets: the first - * is the relative offset to an instruction that is allowed to fault, - * and the second is the relative offset at which the program should - * continue. No registers are modified, so it is entirely up to the - * continuation code to figure out what to do. + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. * * All the routines below use bits of fixup code that are out of line * with the main instruction path. This means when everything is well, @@ -50,11 +50,9 @@ struct exception_table_entry { - int insn, fixup; + unsigned long insn, fixup; }; -#define ARCH_HAS_RELATIVE_EXTABLE - extern int fixup_exception(struct pt_regs *regs); #define KERNEL_DS (-1UL) @@ -66,16 +64,6 @@ extern int fixup_exception(struct pt_regs *regs); static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; - - /* - * Enable/disable UAO so that copy_to_user() etc can access - * kernel memory with the unprivileged instructions. - */ - if (IS_ENABLED(CONFIG_ARM64_UAO) && fs == KERNEL_DS) - asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO)); - else - asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO, - CONFIG_ARM64_UAO)); } #define segment_eq(a, b) ((a) == (b)) @@ -117,12 +105,6 @@ static inline void set_fs(mm_segment_t fs) #define access_ok(type, addr, size) __range_ok(addr, size) #define user_addr_max get_fs -#define _ASM_EXTABLE(from, to) \ - " .pushsection __ex_table, \"a\"\n" \ - " .align 3\n" \ - " .long (" #from " - .), (" #to " - .)\n" \ - " .popsection\n" - /* * The "__xxx" versions of the user access functions do not verify the address * space - it must have been done previously with a separate "access_ok()" @@ -131,10 +113,9 @@ static inline void set_fs(mm_segment_t fs) * The "__xxx_error" versions set the third argument to -EFAULT if an error * occurs, and leave it unchanged on success. */ -#define __get_user_asm(instr, alt_instr, reg, x, addr, err, feature) \ +#define __get_user_asm(instr, reg, x, addr, err) \ asm volatile( \ - "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \ - alt_instr " " reg "1, [%2]\n", feature) \ + "1: " instr " " reg "1, [%2]\n" \ "2:\n" \ " .section .fixup, \"ax\"\n" \ " .align 2\n" \ @@ -142,7 +123,10 @@ static inline void set_fs(mm_segment_t fs) " mov %1, #0\n" \ " b 2b\n" \ " .previous\n" \ - _ASM_EXTABLE(1b, 3b) \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .quad 1b, 3b\n" \ + " .previous" \ : "+r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT)) @@ -150,30 +134,26 @@ static inline void set_fs(mm_segment_t fs) do { \ unsigned long __gu_val; \ __chk_user_ptr(ptr); \ - asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN)); \ switch (sizeof(*(ptr))) { \ case 1: \ - __get_user_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __get_user_asm("ldrb", "%w", __gu_val, (ptr), (err)); \ break; \ case 2: \ - __get_user_asm("ldrh", "ldtrh", "%w", __gu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __get_user_asm("ldrh", "%w", __gu_val, (ptr), (err)); \ break; \ case 4: \ - __get_user_asm("ldr", "ldtr", "%w", __gu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __get_user_asm("ldr", "%w", __gu_val, (ptr), (err)); \ break; \ case 8: \ - __get_user_asm("ldr", "ldtr", "%", __gu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __get_user_asm("ldr", "%", __gu_val, (ptr), (err)); \ break; \ default: \ BUILD_BUG(); \ } \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ - asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN)); \ } while (0) @@ -201,17 +181,19 @@ do { \ ((x) = 0, -EFAULT); \ }) -#define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature) \ +#define __put_user_asm(instr, reg, x, addr, err) \ asm volatile( \ - "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \ - alt_instr " " reg "1, [%2]\n", feature) \ + "1: " instr " " reg "1, [%2]\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ "3: mov %w0, %3\n" \ " b 2b\n" \ " .previous\n" \ - _ASM_EXTABLE(1b, 3b) \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .quad 1b, 3b\n" \ + " .previous" \ : "+r" (err) \ : "r" (x), "r" (addr), "i" (-EFAULT)) @@ -219,29 +201,25 @@ do { \ do { \ __typeof__(*(ptr)) __pu_val = (x); \ __chk_user_ptr(ptr); \ - asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN)); \ switch (sizeof(*(ptr))) { \ case 1: \ - __put_user_asm("strb", "sttrb", "%w", __pu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __put_user_asm("strb", "%w", __pu_val, (ptr), (err)); \ break; \ case 2: \ - __put_user_asm("strh", "sttrh", "%w", __pu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __put_user_asm("strh", "%w", __pu_val, (ptr), (err)); \ break; \ case 4: \ - __put_user_asm("str", "sttr", "%w", __pu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __put_user_asm("str", "%w", __pu_val, (ptr), (err)); \ break; \ case 8: \ - __put_user_asm("str", "sttr", "%", __pu_val, (ptr), \ - (err), ARM64_HAS_UAO); \ + __put_user_asm("str", "%", __pu_val, (ptr), (err)); \ break; \ default: \ BUILD_BUG(); \ } \ - asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN)); \ } while (0) diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h index 2b79b8a89457..aab5bf09e9d9 100644 --- a/arch/arm64/include/asm/word-at-a-time.h +++ b/arch/arm64/include/asm/word-at-a-time.h @@ -16,8 +16,6 @@ #ifndef __ASM_WORD_AT_A_TIME_H #define __ASM_WORD_AT_A_TIME_H -#include <asm/uaccess.h> - #ifndef __AARCH64EB__ #include <linux/kernel.h> @@ -83,7 +81,10 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) #endif " b 2b\n" " .popsection\n" - _ASM_EXTABLE(1b, 3b) + " .pushsection __ex_table,\"a\"\n" + " .align 3\n" + " .quad 1b, 3b\n" + " .popsection" : "=&r" (ret), "=&r" (offset) : "r" (addr), "Q" (*(unsigned long *)addr)); diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index b5c3933ed441..208db3df135a 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -45,7 +45,6 @@ #define PSR_A_BIT 0x00000100 #define PSR_D_BIT 0x00000200 #define PSR_PAN_BIT 0x00400000 -#define PSR_UAO_BIT 0x00800000 #define PSR_Q_BIT 0x08000000 #define PSR_V_BIT 0x10000000 #define PSR_C_BIT 0x20000000 diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index f6e0269de4c7..9f7794c5743f 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -30,7 +30,6 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ ../../arm/kernel/opcodes.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o -arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_debug.o \ perf_trace_counters.o \ @@ -44,8 +43,6 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o -arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o -arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/acpi_parking_protocol.c b/arch/arm64/kernel/acpi_parking_protocol.c deleted file mode 100644 index 4b1e5a7a98da..000000000000 --- a/arch/arm64/kernel/acpi_parking_protocol.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * ARM64 ACPI Parking Protocol implementation - * - * Authors: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - * Mark Salter <msalter@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include <linux/acpi.h> -#include <linux/types.h> - -#include <asm/cpu_ops.h> - -struct cpu_mailbox_entry { - phys_addr_t mailbox_addr; - u8 version; - u8 gic_cpu_id; -}; - -static struct cpu_mailbox_entry cpu_mailbox_entries[NR_CPUS]; - -void __init acpi_set_mailbox_entry(int cpu, - struct acpi_madt_generic_interrupt *p) -{ - struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu]; - - cpu_entry->mailbox_addr = p->parked_address; - cpu_entry->version = p->parking_version; - cpu_entry->gic_cpu_id = p->cpu_interface_number; -} - -bool acpi_parking_protocol_valid(int cpu) -{ - struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu]; - - return cpu_entry->mailbox_addr && cpu_entry->version; -} - -static int acpi_parking_protocol_cpu_init(unsigned int cpu) -{ - pr_debug("%s: ACPI parked addr=%llx\n", __func__, - cpu_mailbox_entries[cpu].mailbox_addr); - - return 0; -} - -static int acpi_parking_protocol_cpu_prepare(unsigned int cpu) -{ - return 0; -} - -struct parking_protocol_mailbox { - __le32 cpu_id; - __le32 reserved; - __le64 entry_point; -}; - -static int acpi_parking_protocol_cpu_boot(unsigned int cpu) -{ - struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu]; - struct parking_protocol_mailbox __iomem *mailbox; - __le32 cpu_id; - - /* - * Map mailbox memory with attribute device nGnRE (ie ioremap - - * this deviates from the parking protocol specifications since - * the mailboxes are required to be mapped nGnRnE; the attribute - * discrepancy is harmless insofar as the protocol specification - * is concerned). - * If the mailbox is mistakenly allocated in the linear mapping - * by FW ioremap will fail since the mapping will be prevented - * by the kernel (it clashes with the linear mapping attributes - * specifications). - */ - mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox)); - if (!mailbox) - return -EIO; - - cpu_id = readl_relaxed(&mailbox->cpu_id); - /* - * Check if firmware has set-up the mailbox entry properly - * before kickstarting the respective cpu. - */ - if (cpu_id != ~0U) { - iounmap(mailbox); - return -ENXIO; - } - - /* - * We write the entry point and cpu id as LE regardless of the - * native endianness of the kernel. Therefore, any boot-loaders - * that read this address need to convert this address to the - * Boot-Loader's endianness before jumping. - */ - writeq_relaxed(__pa(secondary_entry), &mailbox->entry_point); - writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id); - - arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - - iounmap(mailbox); - - return 0; -} - -static void acpi_parking_protocol_cpu_postboot(void) -{ - int cpu = smp_processor_id(); - struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu]; - struct parking_protocol_mailbox __iomem *mailbox; - __le64 entry_point; - - /* - * Map mailbox memory with attribute device nGnRE (ie ioremap - - * this deviates from the parking protocol specifications since - * the mailboxes are required to be mapped nGnRnE; the attribute - * discrepancy is harmless insofar as the protocol specification - * is concerned). - * If the mailbox is mistakenly allocated in the linear mapping - * by FW ioremap will fail since the mapping will be prevented - * by the kernel (it clashes with the linear mapping attributes - * specifications). - */ - mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox)); - if (!mailbox) - return; - - entry_point = readl_relaxed(&mailbox->entry_point); - /* - * Check if firmware has cleared the entry_point as expected - * by the protocol specification. - */ - WARN_ON(entry_point); - - iounmap(mailbox); -} - -const struct cpu_operations acpi_parking_protocol_ops = { - .name = "parking-protocol", - .cpu_init = acpi_parking_protocol_cpu_init, - .cpu_prepare = acpi_parking_protocol_cpu_prepare, - .cpu_boot = acpi_parking_protocol_cpu_boot, - .cpu_postboot = acpi_parking_protocol_cpu_postboot -}; diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index e6cb1dc63a2a..47a8caf28bcc 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -158,3 +158,9 @@ void apply_alternatives(void *start, size_t length) __apply_alternatives(®ion); } + +void free_alternatives_memory(void) +{ + free_reserved_area(__alt_instructions, __alt_instructions_end, + 0, "alternatives"); +} diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index c37202c0c838..937f5e58a4d3 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -62,7 +62,7 @@ struct insn_emulation { }; static LIST_HEAD(insn_emulation); -static int nr_insn_emulated __initdata; +static int nr_insn_emulated; static DEFINE_RAW_SPINLOCK(insn_emulation_lock); static void register_emulation_hooks(struct insn_emulation_ops *ops) @@ -173,7 +173,7 @@ static int update_insn_emulation_mode(struct insn_emulation *insn, return ret; } -static void __init register_insn_emulation(struct insn_emulation_ops *ops) +static void register_insn_emulation(struct insn_emulation_ops *ops) { unsigned long flags; struct insn_emulation *insn; @@ -237,7 +237,7 @@ static struct ctl_table ctl_abi[] = { { } }; -static void __init register_insn_emulation_sysctl(struct ctl_table *table) +static void register_insn_emulation_sysctl(struct ctl_table *table) { unsigned long flags; int i = 0; @@ -297,8 +297,11 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table) "4: mov %w0, %w5\n" \ " b 3b\n" \ " .popsection" \ - _ASM_EXTABLE(0b, 4b) \ - _ASM_EXTABLE(1b, 4b) \ + " .pushsection __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .quad 0b, 4b\n" \ + " .quad 1b, 4b\n" \ + " .popsection\n" \ ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ : "=&r" (res), "+r" (data), "=&r" (temp) \ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 1555520bbb74..34aa4b3b47e9 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -21,12 +21,26 @@ #include <asm/cputype.h> #include <asm/cpufeature.h> +#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) +#define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) +#define MIDR_THUNDERX MIDR_CPU_PART(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) +#define MIDR_KRYO2XX_SILVER \ + MIDR_CPU_PART(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_SILVER) + +#define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ + MIDR_ARCHITECTURE_MASK) + static bool __maybe_unused is_affected_midr_range(const struct arm64_cpu_capabilities *entry) { - return MIDR_IS_CPU_MODEL_RANGE(read_cpuid_id(), entry->midr_model, - entry->midr_range_min, - entry->midr_range_max); + u32 midr = read_cpuid_id(); + + if ((midr & CPU_MODEL_MASK) != entry->midr_model) + return false; + + midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK; + + return (midr >= entry->midr_range_min && midr <= entry->midr_range_max); } #define MIDR_RANGE(model, min, max) \ diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c index c7cfb8fe06f9..b6bd7d447768 100644 --- a/arch/arm64/kernel/cpu_ops.c +++ b/arch/arm64/kernel/cpu_ops.c @@ -25,30 +25,19 @@ #include <asm/smp_plat.h> extern const struct cpu_operations smp_spin_table_ops; -extern const struct cpu_operations acpi_parking_protocol_ops; extern const struct cpu_operations cpu_psci_ops; const struct cpu_operations *cpu_ops[NR_CPUS]; -static const struct cpu_operations *dt_supported_cpu_ops[] __initconst = { +static const struct cpu_operations *supported_cpu_ops[] __initconst = { &smp_spin_table_ops, &cpu_psci_ops, NULL, }; -static const struct cpu_operations *acpi_supported_cpu_ops[] __initconst = { -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL - &acpi_parking_protocol_ops, -#endif - &cpu_psci_ops, - NULL, -}; - static const struct cpu_operations * __init cpu_get_ops(const char *name) { - const struct cpu_operations **ops; - - ops = acpi_disabled ? dt_supported_cpu_ops : acpi_supported_cpu_ops; + const struct cpu_operations **ops = supported_cpu_ops; while (*ops) { if (!strcmp(name, (*ops)->name)) @@ -86,16 +75,8 @@ static const char *__init cpu_read_enable_method(int cpu) } } else { enable_method = acpi_get_enable_method(cpu); - if (!enable_method) { - /* - * In ACPI systems the boot CPU does not require - * checking the enable method since for some - * boot protocol (ie parking protocol) it need not - * be initialized. Don't warn spuriously. - */ - if (cpu != 0) - pr_err("Unsupported ACPI enable-method\n"); - } + if (!enable_method) + pr_err("Unsupported ACPI enable-method\n"); } return enable_method; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 7566cad9fa1d..0669c63281ea 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -67,10 +67,6 @@ DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); .width = 0, \ } -/* meta feature for alternatives */ -static bool __maybe_unused -cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry); - static struct arm64_ftr_bits ftr_id_aa64isar0[] = { ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0), @@ -127,11 +123,6 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr1[] = { ARM64_FTR_END, }; -static struct arm64_ftr_bits ftr_id_aa64mmfr2[] = { - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0), - ARM64_FTR_END, -}; - static struct arm64_ftr_bits ftr_ctr[] = { U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */ ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0), @@ -293,7 +284,6 @@ static struct arm64_ftr_reg arm64_ftr_regs[] = { /* Op1 = 0, CRn = 0, CRm = 7 */ ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0), ARM64_FTR_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1), - ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2), /* Op1 = 3, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_CTR_EL0, ftr_ctr), @@ -418,7 +408,6 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1); init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0); init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1); - init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2); init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0); init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1); init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0); @@ -528,8 +517,6 @@ void update_cpu_features(int cpu, info->reg_id_aa64mmfr0, boot->reg_id_aa64mmfr0); taint |= check_update_ftr_reg(SYS_ID_AA64MMFR1_EL1, cpu, info->reg_id_aa64mmfr1, boot->reg_id_aa64mmfr1); - taint |= check_update_ftr_reg(SYS_ID_AA64MMFR2_EL1, cpu, - info->reg_id_aa64mmfr2, boot->reg_id_aa64mmfr2); /* * EL3 is not our concern. @@ -634,18 +621,6 @@ static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry) return has_sre; } -static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry) -{ - u32 midr = read_cpuid_id(); - u32 rv_min, rv_max; - - /* Cavium ThunderX pass 1.x and 2.x */ - rv_min = 0; - rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK; - - return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max); -} - static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -676,28 +651,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .min_field_value = 2, }, #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ - { - .desc = "Software prefetching using PRFM", - .capability = ARM64_HAS_NO_HW_PREFETCH, - .matches = has_no_hw_prefetch, - }, -#ifdef CONFIG_ARM64_UAO - { - .desc = "User Access Override", - .capability = ARM64_HAS_UAO, - .matches = has_cpuid_feature, - .sys_reg = SYS_ID_AA64MMFR2_EL1, - .field_pos = ID_AA64MMFR2_UAO_SHIFT, - .min_field_value = 1, - .enable = cpu_enable_uao, - }, -#endif /* CONFIG_ARM64_UAO */ -#ifdef CONFIG_ARM64_PAN - { - .capability = ARM64_ALT_PAN_NOT_UAO, - .matches = cpufeature_pan_not_uao, - }, -#endif /* CONFIG_ARM64_PAN */ {}, }; @@ -731,7 +684,7 @@ static const struct arm64_cpu_capabilities arm64_hwcaps[] = { {}, }; -static void __init cap_set_hwcap(const struct arm64_cpu_capabilities *cap) +static void cap_set_hwcap(const struct arm64_cpu_capabilities *cap) { switch (cap->hwcap_type) { case CAP_HWCAP: @@ -776,12 +729,12 @@ static bool __maybe_unused cpus_have_hwcap(const struct arm64_cpu_capabilities * return rc; } -static void __init setup_cpu_hwcaps(void) +static void setup_cpu_hwcaps(void) { int i; const struct arm64_cpu_capabilities *hwcaps = arm64_hwcaps; - for (i = 0; hwcaps[i].matches; i++) + for (i = 0; hwcaps[i].desc; i++) if (hwcaps[i].matches(&hwcaps[i])) cap_set_hwcap(&hwcaps[i]); } @@ -791,11 +744,11 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, { int i; - for (i = 0; caps[i].matches; i++) { + for (i = 0; caps[i].desc; i++) { if (!caps[i].matches(&caps[i])) continue; - if (!cpus_have_cap(caps[i].capability) && caps[i].desc) + if (!cpus_have_cap(caps[i].capability)) pr_info("%s %s\n", info, caps[i].desc); cpus_set_cap(caps[i].capability); } @@ -805,12 +758,11 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, * Run through the enabled capabilities and enable() it on all active * CPUs */ -static void __init -enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) +static void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) { int i; - for (i = 0; caps[i].matches; i++) + for (i = 0; caps[i].desc; i++) if (caps[i].enable && cpus_have_cap(caps[i].capability)) on_each_cpu(caps[i].enable, NULL, true); } @@ -838,36 +790,35 @@ static inline void set_sys_caps_initialised(void) static u64 __raw_read_system_reg(u32 sys_id) { switch (sys_id) { - case SYS_ID_PFR0_EL1: return read_cpuid(SYS_ID_PFR0_EL1); - case SYS_ID_PFR1_EL1: return read_cpuid(SYS_ID_PFR1_EL1); - case SYS_ID_DFR0_EL1: return read_cpuid(SYS_ID_DFR0_EL1); - case SYS_ID_MMFR0_EL1: return read_cpuid(SYS_ID_MMFR0_EL1); - case SYS_ID_MMFR1_EL1: return read_cpuid(SYS_ID_MMFR1_EL1); - case SYS_ID_MMFR2_EL1: return read_cpuid(SYS_ID_MMFR2_EL1); - case SYS_ID_MMFR3_EL1: return read_cpuid(SYS_ID_MMFR3_EL1); - case SYS_ID_ISAR0_EL1: return read_cpuid(SYS_ID_ISAR0_EL1); - case SYS_ID_ISAR1_EL1: return read_cpuid(SYS_ID_ISAR1_EL1); - case SYS_ID_ISAR2_EL1: return read_cpuid(SYS_ID_ISAR2_EL1); - case SYS_ID_ISAR3_EL1: return read_cpuid(SYS_ID_ISAR3_EL1); - case SYS_ID_ISAR4_EL1: return read_cpuid(SYS_ID_ISAR4_EL1); - case SYS_ID_ISAR5_EL1: return read_cpuid(SYS_ID_ISAR4_EL1); - case SYS_MVFR0_EL1: return read_cpuid(SYS_MVFR0_EL1); - case SYS_MVFR1_EL1: return read_cpuid(SYS_MVFR1_EL1); - case SYS_MVFR2_EL1: return read_cpuid(SYS_MVFR2_EL1); - - case SYS_ID_AA64PFR0_EL1: return read_cpuid(SYS_ID_AA64PFR0_EL1); - case SYS_ID_AA64PFR1_EL1: return read_cpuid(SYS_ID_AA64PFR0_EL1); - case SYS_ID_AA64DFR0_EL1: return read_cpuid(SYS_ID_AA64DFR0_EL1); - case SYS_ID_AA64DFR1_EL1: return read_cpuid(SYS_ID_AA64DFR0_EL1); - case SYS_ID_AA64MMFR0_EL1: return read_cpuid(SYS_ID_AA64MMFR0_EL1); - case SYS_ID_AA64MMFR1_EL1: return read_cpuid(SYS_ID_AA64MMFR1_EL1); - case SYS_ID_AA64MMFR2_EL1: return read_cpuid(SYS_ID_AA64MMFR2_EL1); - case SYS_ID_AA64ISAR0_EL1: return read_cpuid(SYS_ID_AA64ISAR0_EL1); - case SYS_ID_AA64ISAR1_EL1: return read_cpuid(SYS_ID_AA64ISAR1_EL1); - - case SYS_CNTFRQ_EL0: return read_cpuid(SYS_CNTFRQ_EL0); - case SYS_CTR_EL0: return read_cpuid(SYS_CTR_EL0); - case SYS_DCZID_EL0: return read_cpuid(SYS_DCZID_EL0); + case SYS_ID_PFR0_EL1: return (u64)read_cpuid(ID_PFR0_EL1); + case SYS_ID_PFR1_EL1: return (u64)read_cpuid(ID_PFR1_EL1); + case SYS_ID_DFR0_EL1: return (u64)read_cpuid(ID_DFR0_EL1); + case SYS_ID_MMFR0_EL1: return (u64)read_cpuid(ID_MMFR0_EL1); + case SYS_ID_MMFR1_EL1: return (u64)read_cpuid(ID_MMFR1_EL1); + case SYS_ID_MMFR2_EL1: return (u64)read_cpuid(ID_MMFR2_EL1); + case SYS_ID_MMFR3_EL1: return (u64)read_cpuid(ID_MMFR3_EL1); + case SYS_ID_ISAR0_EL1: return (u64)read_cpuid(ID_ISAR0_EL1); + case SYS_ID_ISAR1_EL1: return (u64)read_cpuid(ID_ISAR1_EL1); + case SYS_ID_ISAR2_EL1: return (u64)read_cpuid(ID_ISAR2_EL1); + case SYS_ID_ISAR3_EL1: return (u64)read_cpuid(ID_ISAR3_EL1); + case SYS_ID_ISAR4_EL1: return (u64)read_cpuid(ID_ISAR4_EL1); + case SYS_ID_ISAR5_EL1: return (u64)read_cpuid(ID_ISAR4_EL1); + case SYS_MVFR0_EL1: return (u64)read_cpuid(MVFR0_EL1); + case SYS_MVFR1_EL1: return (u64)read_cpuid(MVFR1_EL1); + case SYS_MVFR2_EL1: return (u64)read_cpuid(MVFR2_EL1); + + case SYS_ID_AA64PFR0_EL1: return (u64)read_cpuid(ID_AA64PFR0_EL1); + case SYS_ID_AA64PFR1_EL1: return (u64)read_cpuid(ID_AA64PFR0_EL1); + case SYS_ID_AA64DFR0_EL1: return (u64)read_cpuid(ID_AA64DFR0_EL1); + case SYS_ID_AA64DFR1_EL1: return (u64)read_cpuid(ID_AA64DFR0_EL1); + case SYS_ID_AA64MMFR0_EL1: return (u64)read_cpuid(ID_AA64MMFR0_EL1); + case SYS_ID_AA64MMFR1_EL1: return (u64)read_cpuid(ID_AA64MMFR1_EL1); + case SYS_ID_AA64ISAR0_EL1: return (u64)read_cpuid(ID_AA64ISAR0_EL1); + case SYS_ID_AA64ISAR1_EL1: return (u64)read_cpuid(ID_AA64ISAR1_EL1); + + case SYS_CNTFRQ_EL0: return (u64)read_cpuid(CNTFRQ_EL0); + case SYS_CTR_EL0: return (u64)read_cpuid(CTR_EL0); + case SYS_DCZID_EL0: return (u64)read_cpuid(DCZID_EL0); default: BUG(); return 0; @@ -917,7 +868,7 @@ void verify_local_cpu_capabilities(void) return; caps = arm64_features; - for (i = 0; caps[i].matches; i++) { + for (i = 0; caps[i].desc; i++) { if (!cpus_have_cap(caps[i].capability) || !caps[i].sys_reg) continue; /* @@ -930,7 +881,7 @@ void verify_local_cpu_capabilities(void) caps[i].enable(NULL); } - for (i = 0, caps = arm64_hwcaps; caps[i].matches; i++) { + for (i = 0, caps = arm64_hwcaps; caps[i].desc; i++) { if (!cpus_have_hwcap(&caps[i])) continue; if (!feature_matches(__raw_read_system_reg(caps[i].sys_reg), &caps[i])) @@ -946,7 +897,7 @@ static inline void set_sys_caps_initialised(void) #endif /* CONFIG_HOTPLUG_CPU */ -static void __init setup_feature_capabilities(void) +static void setup_feature_capabilities(void) { update_cpu_capabilities(arm64_features, "detected feature:"); enable_cpu_capabilities(arm64_features); @@ -976,9 +927,3 @@ void __init setup_cpu_features(void) pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n", L1_CACHE_BYTES, cls); } - -static bool __maybe_unused -cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry) -{ - return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); -} diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 48281e4a719f..3691553f218e 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -211,41 +211,40 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) { info->reg_cntfrq = arch_timer_get_cntfrq(); info->reg_ctr = read_cpuid_cachetype(); - info->reg_dczid = read_cpuid(SYS_DCZID_EL0); + info->reg_dczid = read_cpuid(DCZID_EL0); info->reg_midr = read_cpuid_id(); - info->reg_id_aa64dfr0 = read_cpuid(SYS_ID_AA64DFR0_EL1); - info->reg_id_aa64dfr1 = read_cpuid(SYS_ID_AA64DFR1_EL1); - info->reg_id_aa64isar0 = read_cpuid(SYS_ID_AA64ISAR0_EL1); - info->reg_id_aa64isar1 = read_cpuid(SYS_ID_AA64ISAR1_EL1); + info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1); + info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1); + info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1); + info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1); /* * Explicitly mask out 16KB granule since we donot * want to support it */ - info->reg_id_aa64mmfr0 = read_cpuid(SYS_ID_AA64MMFR0_EL1) & + info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1) & (~MMFR0_EL1_16KGRAN_MASK); - info->reg_id_aa64mmfr1 = read_cpuid(SYS_ID_AA64MMFR1_EL1); - info->reg_id_aa64mmfr2 = read_cpuid(SYS_ID_AA64MMFR2_EL1); - info->reg_id_aa64pfr0 = read_cpuid(SYS_ID_AA64PFR0_EL1); - info->reg_id_aa64pfr1 = read_cpuid(SYS_ID_AA64PFR1_EL1); - - info->reg_id_dfr0 = read_cpuid(SYS_ID_DFR0_EL1); - info->reg_id_isar0 = read_cpuid(SYS_ID_ISAR0_EL1); - info->reg_id_isar1 = read_cpuid(SYS_ID_ISAR1_EL1); - info->reg_id_isar2 = read_cpuid(SYS_ID_ISAR2_EL1); - info->reg_id_isar3 = read_cpuid(SYS_ID_ISAR3_EL1); - info->reg_id_isar4 = read_cpuid(SYS_ID_ISAR4_EL1); - info->reg_id_isar5 = read_cpuid(SYS_ID_ISAR5_EL1); - info->reg_id_mmfr0 = read_cpuid(SYS_ID_MMFR0_EL1); - info->reg_id_mmfr1 = read_cpuid(SYS_ID_MMFR1_EL1); - info->reg_id_mmfr2 = read_cpuid(SYS_ID_MMFR2_EL1); - info->reg_id_mmfr3 = read_cpuid(SYS_ID_MMFR3_EL1); - info->reg_id_pfr0 = read_cpuid(SYS_ID_PFR0_EL1); - info->reg_id_pfr1 = read_cpuid(SYS_ID_PFR1_EL1); - - info->reg_mvfr0 = read_cpuid(SYS_MVFR0_EL1); - info->reg_mvfr1 = read_cpuid(SYS_MVFR1_EL1); - info->reg_mvfr2 = read_cpuid(SYS_MVFR2_EL1); + info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1); + info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1); + info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1); + + info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1); + info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1); + info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1); + info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1); + info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1); + info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1); + info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1); + info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1); + info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1); + info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1); + info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1); + info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1); + info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1); + + info->reg_mvfr0 = read_cpuid(MVFR0_EL1); + info->reg_mvfr1 = read_cpuid(MVFR1_EL1); + info->reg_mvfr2 = read_cpuid(MVFR2_EL1); cpuinfo_detect_icache_policy(info); diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S index f82036e02485..a773db92908b 100644 --- a/arch/arm64/kernel/efi-entry.S +++ b/arch/arm64/kernel/efi-entry.S @@ -61,7 +61,7 @@ ENTRY(entry) */ mov x20, x0 // DTB address ldr x0, [sp, #16] // relocated _text address - movz x21, #:abs_g0:stext_offset + ldr x21, =stext_offset add x21, x0, x21 /* diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index b67e70c34888..e3131b39fbf2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -27,7 +27,6 @@ #include <asm/cpufeature.h> #include <asm/errno.h> #include <asm/esr.h> -#include <asm/irq.h> #include <asm/thread_info.h> #include <asm/unistd.h> @@ -89,12 +88,9 @@ .if \el == 0 mrs x21, sp_el0 - mov tsk, sp - and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear, + get_thread_info tsk // Ensure MDSCR_EL1.SS is clear, ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug disable_step_tsk x19, x20 // exceptions when scheduling. - - mov x29, xzr // fp pointed to user-space .else add x21, sp, #S_FRAME_SIZE .endif @@ -112,13 +108,6 @@ .endif /* - * Set sp_el0 to current thread_info. - */ - .if \el == 0 - msr sp_el0, tsk - .endif - - /* * Registers that may be useful after this macro is invoked: * * x21 - aborted SP @@ -175,44 +164,8 @@ alternative_endif .endm .macro get_thread_info, rd - mrs \rd, sp_el0 - .endm - - .macro irq_stack_entry - mov x19, sp // preserve the original sp - - /* - * Compare sp with the current thread_info, if the top - * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and - * should switch to the irq stack. - */ - and x25, x19, #~(THREAD_SIZE - 1) - cmp x25, tsk - b.ne 9998f - - this_cpu_ptr irq_stack, x25, x26 - mov x26, #IRQ_STACK_START_SP - add x26, x25, x26 - - /* switch to the irq stack */ - mov sp, x26 - - /* - * Add a dummy stack frame, this non-standard format is fixed up - * by unwind_frame() - */ - stp x29, x19, [sp, #-16]! - mov x29, sp - -9998: - .endm - - /* - * x19 should be preserved between irq_stack_entry and - * irq_stack_exit. - */ - .macro irq_stack_exit - mov sp, x19 + mov \rd, sp + and \rd, \rd, #~(THREAD_SIZE - 1) // top of stack .endm /* @@ -230,11 +183,10 @@ tsk .req x28 // current thread_info * Interrupt handling. */ .macro irq_handler - ldr_l x1, handle_arch_irq + adrp x1, handle_arch_irq + ldr x1, [x1, #:lo12:handle_arch_irq] mov x0, sp - irq_stack_entry blr x1 - irq_stack_exit .endm .text @@ -406,10 +358,10 @@ el1_irq: bl trace_hardirqs_off #endif - get_thread_info tsk irq_handler #ifdef CONFIG_PREEMPT + get_thread_info tsk ldr w24, [tsk, #TI_PREEMPT] // get preempt count cbnz w24, 1f // preempt count != 0 ldr x0, [tsk, #TI_FLAGS] // get flags @@ -674,8 +626,6 @@ ENTRY(cpu_switch_to) mov v15.16b, v15.16b #endif mov sp, x9 - and x9, x9, #~(THREAD_SIZE - 1) - msr sp_el0, x9 ret ENDPROC(cpu_switch_to) @@ -703,14 +653,14 @@ ret_fast_syscall_trace: work_pending: tbnz x1, #TIF_NEED_RESCHED, work_resched /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */ + ldr x2, [sp, #S_PSTATE] mov x0, sp // 'regs' + tst x2, #PSR_MODE_MASK // user mode regs? + b.ne no_work_pending // returning to kernel enable_irq // enable interrupts for do_notify_resume() bl do_notify_resume b ret_to_user work_resched: -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off // the IRQs are off here, inform the tracing code -#endif bl schedule /* @@ -722,6 +672,7 @@ ret_to_user: and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending enable_step_tsk x1, x2 +no_work_pending: kernel_exit 0 ENDPROC(ret_to_user) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index acc1afd5c749..4c46c54a3ad7 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -289,7 +289,7 @@ static struct notifier_block fpsimd_cpu_pm_notifier_block = { .notifier_call = fpsimd_cpu_pm_notifier, }; -static void __init fpsimd_pm_init(void) +static void fpsimd_pm_init(void) { cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block); } diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c index ebecf9aa33d1..c851be795080 100644 --- a/arch/arm64/kernel/ftrace.c +++ b/arch/arm64/kernel/ftrace.c @@ -29,11 +29,12 @@ static int ftrace_modify_code(unsigned long pc, u32 old, u32 new, /* * Note: - * We are paranoid about modifying text, as if a bug were to happen, it - * could cause us to read or write to someplace that could cause harm. - * Carefully read and modify the code with aarch64_insn_*() which uses - * probe_kernel_*(), and make sure what we read is what we expected it - * to be before modifying it. + * Due to modules and __init, code can disappear and change, + * we need to protect against faulting as well as code changing. + * We do this by aarch64_insn_*() which use the probe_kernel_*(). + * + * No lock is held here because all the modifications are run + * through stop_machine(). */ if (validate) { if (aarch64_insn_read((void *)pc, &replaced)) @@ -92,11 +93,6 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, return ftrace_modify_code(pc, old, new, true); } -void arch_ftrace_update_code(int command) -{ - ftrace_modify_all_code(command); -} - int __init ftrace_dyn_arch_init(void) { return 0; @@ -129,20 +125,23 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, * on other archs. It's unlikely on AArch64. */ old = *parent; + *parent = return_hooker; trace.func = self_addr; trace.depth = current->curr_ret_stack + 1; /* Only trace if the calling function expects to */ - if (!ftrace_graph_entry(&trace)) + if (!ftrace_graph_entry(&trace)) { + *parent = old; return; + } err = ftrace_push_return_trace(old, self_addr, &trace.depth, frame_pointer); - if (err == -EBUSY) + if (err == -EBUSY) { + *parent = old; return; - else - *parent = return_hooker; + } } #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index a88a15447c3b..b685257926f0 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -29,7 +29,6 @@ #include <asm/asm-offsets.h> #include <asm/cache.h> #include <asm/cputype.h> -#include <asm/elf.h> #include <asm/kernel-pgtable.h> #include <asm/memory.h> #include <asm/pgtable-hwdef.h> @@ -68,11 +67,12 @@ * in the entry routines. */ __HEAD -_head: + /* * DO NOT MODIFY. Image header expected by Linux boot-loaders. */ #ifdef CONFIG_EFI +efi_head: /* * This add instruction has no meaningful effect except that * its opcode forms the magic "MZ" signature required by UEFI. @@ -83,9 +83,9 @@ _head: b stext // branch to kernel start, magic .long 0 // reserved #endif - le64sym _kernel_offset_le // Image load offset from start of RAM, little-endian - le64sym _kernel_size_le // Effective size of kernel image, little-endian - le64sym _kernel_flags_le // Informative flags, little-endian + .quad _kernel_offset_le // Image load offset from start of RAM, little-endian + .quad _kernel_size_le // Effective size of kernel image, little-endian + .quad _kernel_flags_le // Informative flags, little-endian .quad 0 // reserved .quad 0 // reserved .quad 0 // reserved @@ -94,14 +94,14 @@ _head: .byte 0x4d .byte 0x64 #ifdef CONFIG_EFI - .long pe_header - _head // Offset to the PE header. + .long pe_header - efi_head // Offset to the PE header. #else .word 0 // reserved #endif #ifdef CONFIG_EFI .globl __efistub_stext_offset - .set __efistub_stext_offset, stext - _head + .set __efistub_stext_offset, stext - efi_head .align 3 pe_header: .ascii "PE" @@ -124,7 +124,7 @@ optional_header: .long _end - stext // SizeOfCode .long 0 // SizeOfInitializedData .long 0 // SizeOfUninitializedData - .long __efistub_entry - _head // AddressOfEntryPoint + .long __efistub_entry - efi_head // AddressOfEntryPoint .long __efistub_stext_offset // BaseOfCode extra_header_fields: @@ -139,7 +139,7 @@ extra_header_fields: .short 0 // MinorSubsystemVersion .long 0 // Win32VersionValue - .long _end - _head // SizeOfImage + .long _end - efi_head // SizeOfImage // Everything before the kernel image is considered part of the header .long __efistub_stext_offset // SizeOfHeaders @@ -210,7 +210,6 @@ section_table: ENTRY(stext) bl preserve_boot_args bl el2_setup // Drop to EL1, w20=cpu_boot_mode - mov x23, xzr // KASLR offset, defaults to 0 adrp x24, __PHYS_OFFSET bl set_cpu_boot_mode_flag bl __create_page_tables // x25=TTBR0, x26=TTBR1 @@ -220,13 +219,11 @@ ENTRY(stext) * On return, the CPU will be ready for the MMU to be turned on and * the TCR will have been set. */ - ldr x27, 0f // address to jump to after + ldr x27, =__mmap_switched // address to jump to after // MMU has been enabled adr_l lr, __enable_mmu // return (PIC) address b __cpu_setup // initialise processor ENDPROC(stext) - .align 3 -0: .quad __mmap_switched - (_head - TEXT_OFFSET) + KIMAGE_VADDR /* * Preserve the arguments passed by the bootloader in x0 .. x3 @@ -314,7 +311,7 @@ ENDPROC(preserve_boot_args) __create_page_tables: adrp x25, idmap_pg_dir adrp x26, swapper_pg_dir - mov x28, lr + mov x27, lr /* * Invalidate the idmap and swapper page tables to avoid potential @@ -392,11 +389,9 @@ __create_page_tables: * Map the kernel image (starting with PHYS_OFFSET). */ mov x0, x26 // swapper_pg_dir - ldr x5, =KIMAGE_VADDR - add x5, x5, x23 // add KASLR displacement + mov x5, #PAGE_OFFSET create_pgd_entry x0, x5, x3, x6 - ldr w6, kernel_img_size - add x6, x6, x5 + ldr x6, =KERNEL_END // __va(KERNEL_END) mov x3, x24 // phys offset create_block_map x0, x7, x3, x5, x6 @@ -410,11 +405,9 @@ __create_page_tables: dmb sy bl __inval_cache_range - ret x28 + mov lr, x27 + ret ENDPROC(__create_page_tables) - -kernel_img_size: - .long _end - (_head - TEXT_OFFSET) .ltorg /* @@ -422,81 +415,21 @@ kernel_img_size: */ .set initial_sp, init_thread_union + THREAD_START_SP __mmap_switched: - mov x28, lr // preserve LR - adr_l x8, vectors // load VBAR_EL1 with virtual - msr vbar_el1, x8 // vector table address - isb + adr_l x6, __bss_start + adr_l x7, __bss_stop - // Clear BSS - adr_l x0, __bss_start - mov x1, xzr - adr_l x2, __bss_stop - sub x2, x2, x0 - bl __pi_memset - dsb ishst // Make zero page visible to PTW - -#ifdef CONFIG_RELOCATABLE - - /* - * Iterate over each entry in the relocation table, and apply the - * relocations in place. - */ - adr_l x8, __dynsym_start // start of symbol table - adr_l x9, __reloc_start // start of reloc table - adr_l x10, __reloc_end // end of reloc table - -0: cmp x9, x10 +1: cmp x6, x7 b.hs 2f - ldp x11, x12, [x9], #24 - ldr x13, [x9, #-8] - cmp w12, #R_AARCH64_RELATIVE - b.ne 1f - add x13, x13, x23 // relocate - str x13, [x11, x23] - b 0b - -1: cmp w12, #R_AARCH64_ABS64 - b.ne 0b - add x12, x12, x12, lsl #1 // symtab offset: 24x top word - add x12, x8, x12, lsr #(32 - 3) // ... shifted into bottom word - ldrsh w14, [x12, #6] // Elf64_Sym::st_shndx - ldr x15, [x12, #8] // Elf64_Sym::st_value - cmp w14, #-0xf // SHN_ABS (0xfff1) ? - add x14, x15, x23 // relocate - csel x15, x14, x15, ne - add x15, x13, x15 - str x15, [x11, x23] - b 0b - -2: adr_l x8, kimage_vaddr // make relocated kimage_vaddr - dc cvac, x8 // value visible to secondaries - dsb sy // with MMU off -#endif - + str xzr, [x6], #8 // Clear BSS + b 1b +2: adr_l sp, initial_sp, x4 - mov x4, sp - and x4, x4, #~(THREAD_SIZE - 1) - msr sp_el0, x4 // Save thread_info str_l x21, __fdt_pointer, x5 // Save FDT pointer - - ldr_l x4, kimage_vaddr // Save the offset between - sub x4, x4, x24 // the kernel virtual and - str_l x4, kimage_voffset, x5 // physical mappings - + str_l x24, memstart_addr, x6 // Save PHYS_OFFSET mov x29, #0 #ifdef CONFIG_KASAN bl kasan_early_init #endif -#ifdef CONFIG_RANDOMIZE_BASE - cbnz x23, 0f // already running randomized? - mov x0, x21 // pass FDT address in x0 - bl kaslr_early_init // parse FDT for KASLR options - cbz x0, 0f // KASLR disabled? just proceed - mov x23, x0 // record KASLR offset - ret x28 // we must enable KASLR, return - // to __enable_mmu() -0: -#endif b start_kernel ENDPROC(__mmap_switched) @@ -505,10 +438,6 @@ ENDPROC(__mmap_switched) * hotplug and needs to have the same protections as the text region */ .section ".text","ax" - -ENTRY(kimage_vaddr) - .quad _text - TEXT_OFFSET - /* * If we're fortunate enough to boot at EL2, ensure that the world is * sane before dropping to EL1. @@ -674,22 +603,14 @@ ENTRY(secondary_startup) adrp x26, swapper_pg_dir bl __cpu_setup // initialise processor - ldr x8, kimage_vaddr - ldr w9, 0f - sub x27, x8, w9, sxtw // address to jump to after enabling the MMU + ldr x21, =secondary_data + ldr x27, =__secondary_switched // address to jump to after enabling the MMU b __enable_mmu ENDPROC(secondary_startup) -0: .long (_text - TEXT_OFFSET) - __secondary_switched ENTRY(__secondary_switched) - adr_l x5, vectors - msr vbar_el1, x5 - isb - - ldr_l x0, secondary_data // get secondary_data.stack + ldr x0, [x21] // get secondary_data.stack mov sp, x0 - and x0, x0, #~(THREAD_SIZE - 1) - msr sp_el0, x0 // save thread_info mov x29, #0 b secondary_start_kernel ENDPROC(__secondary_switched) @@ -707,11 +628,12 @@ ENDPROC(__secondary_switched) */ .section ".idmap.text", "ax" __enable_mmu: - mrs x18, sctlr_el1 // preserve old SCTLR_EL1 value mrs x1, ID_AA64MMFR0_EL1 ubfx x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4 cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED b.ne __no_granule_support + ldr x5, =vectors + msr vbar_el1, x5 msr ttbr0_el1, x25 // load TTBR0 msr ttbr1_el1, x26 // load TTBR1 isb @@ -725,26 +647,6 @@ __enable_mmu: ic iallu dsb nsh isb -#ifdef CONFIG_RANDOMIZE_BASE - mov x19, x0 // preserve new SCTLR_EL1 value - blr x27 - - /* - * If we return here, we have a KASLR displacement in x23 which we need - * to take into account by discarding the current kernel mapping and - * creating a new one. - */ - msr sctlr_el1, x18 // disable the MMU - isb - bl __create_page_tables // recreate kernel mapping - - msr sctlr_el1, x19 // re-enable the MMU - isb - ic iallu // flush instructions fetched - dsb nsh // via old mapping - isb - add x27, x27, x23 // relocated __mmap_switched -#endif br x27 ENDPROC(__enable_mmu) diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h index db1bf57948f1..bc2abb8b1599 100644 --- a/arch/arm64/kernel/image.h +++ b/arch/arm64/kernel/image.h @@ -26,40 +26,31 @@ * There aren't any ELF relocations we can use to endian-swap values known only * at link time (e.g. the subtraction of two symbol addresses), so we must get * the linker to endian-swap certain values before emitting them. - * - * Note that, in order for this to work when building the ELF64 PIE executable - * (for KASLR), these values should not be referenced via R_AARCH64_ABS64 - * relocations, since these are fixed up at runtime rather than at build time - * when PIE is in effect. So we need to split them up in 32-bit high and low - * words. */ #ifdef CONFIG_CPU_BIG_ENDIAN -#define DATA_LE32(data) \ - ((((data) & 0x000000ff) << 24) | \ - (((data) & 0x0000ff00) << 8) | \ - (((data) & 0x00ff0000) >> 8) | \ - (((data) & 0xff000000) >> 24)) +#define DATA_LE64(data) \ + ((((data) & 0x00000000000000ff) << 56) | \ + (((data) & 0x000000000000ff00) << 40) | \ + (((data) & 0x0000000000ff0000) << 24) | \ + (((data) & 0x00000000ff000000) << 8) | \ + (((data) & 0x000000ff00000000) >> 8) | \ + (((data) & 0x0000ff0000000000) >> 24) | \ + (((data) & 0x00ff000000000000) >> 40) | \ + (((data) & 0xff00000000000000) >> 56)) #else -#define DATA_LE32(data) ((data) & 0xffffffff) +#define DATA_LE64(data) ((data) & 0xffffffffffffffff) #endif -#define DEFINE_IMAGE_LE64(sym, data) \ - sym##_lo32 = DATA_LE32((data) & 0xffffffff); \ - sym##_hi32 = DATA_LE32((data) >> 32) - #ifdef CONFIG_CPU_BIG_ENDIAN -#define __HEAD_FLAG_BE 1 +#define __HEAD_FLAG_BE 1 #else -#define __HEAD_FLAG_BE 0 +#define __HEAD_FLAG_BE 0 #endif -#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2) - -#define __HEAD_FLAG_PHYS_BASE 1 +#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2) -#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \ - (__HEAD_FLAG_PAGE_SIZE << 1) | \ - (__HEAD_FLAG_PHYS_BASE << 3)) +#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \ + (__HEAD_FLAG_PAGE_SIZE << 1)) /* * These will output as part of the Image header, which should be little-endian @@ -67,23 +58,13 @@ * endian swapped in head.S, all are done here for consistency. */ #define HEAD_SYMBOLS \ - DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text); \ - DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \ - DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS); + _kernel_size_le = DATA_LE64(_end - _text); \ + _kernel_offset_le = DATA_LE64(TEXT_OFFSET); \ + _kernel_flags_le = DATA_LE64(__HEAD_FLAGS); #ifdef CONFIG_EFI /* - * Prevent the symbol aliases below from being emitted into the kallsyms - * table, by forcing them to be absolute symbols (which are conveniently - * ignored by scripts/kallsyms) rather than section relative symbols. - * The distinction is only relevant for partial linking, and only for symbols - * that are defined within a section declaration (which is not the case for - * the definitions below) so the resulting values will be identical. - */ -#define KALLSYMS_HIDE(sym) ABSOLUTE(sym) - -/* * The EFI stub has its own symbol namespace prefixed by __efistub_, to * isolate it from the kernel proper. The following symbols are legally * accessed by the stub, so provide some aliases to make them accessible. @@ -92,25 +73,25 @@ * linked at. The routines below are all implemented in assembler in a * position independent manner */ -__efistub_memcmp = KALLSYMS_HIDE(__pi_memcmp); -__efistub_memchr = KALLSYMS_HIDE(__pi_memchr); -__efistub_memcpy = KALLSYMS_HIDE(__pi_memcpy); -__efistub_memmove = KALLSYMS_HIDE(__pi_memmove); -__efistub_memset = KALLSYMS_HIDE(__pi_memset); -__efistub_strlen = KALLSYMS_HIDE(__pi_strlen); -__efistub_strcmp = KALLSYMS_HIDE(__pi_strcmp); -__efistub_strncmp = KALLSYMS_HIDE(__pi_strncmp); -__efistub___flush_dcache_area = KALLSYMS_HIDE(__pi___flush_dcache_area); +__efistub_memcmp = __pi_memcmp; +__efistub_memchr = __pi_memchr; +__efistub_memcpy = __pi_memcpy; +__efistub_memmove = __pi_memmove; +__efistub_memset = __pi_memset; +__efistub_strlen = __pi_strlen; +__efistub_strcmp = __pi_strcmp; +__efistub_strncmp = __pi_strncmp; +__efistub___flush_dcache_area = __pi___flush_dcache_area; #ifdef CONFIG_KASAN -__efistub___memcpy = KALLSYMS_HIDE(__pi_memcpy); -__efistub___memmove = KALLSYMS_HIDE(__pi_memmove); -__efistub___memset = KALLSYMS_HIDE(__pi_memset); +__efistub___memcpy = __pi_memcpy; +__efistub___memmove = __pi_memmove; +__efistub___memset = __pi_memset; #endif -__efistub__text = KALLSYMS_HIDE(_text); -__efistub__end = KALLSYMS_HIDE(_end); -__efistub__edata = KALLSYMS_HIDE(_edata); +__efistub__text = _text; +__efistub__end = _end; +__efistub__edata = _edata; #endif diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c index aeb0f25c9289..471fb3cb8c5f 100644 --- a/arch/arm64/kernel/io.c +++ b/arch/arm64/kernel/io.c @@ -28,21 +28,21 @@ void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) { while (count && (!IS_ALIGNED((unsigned long)from, 8) || !IS_ALIGNED((unsigned long)to, 8))) { - *(u8 *)to = __raw_readb(from); + *(u8 *)to = __raw_readb_no_log(from); from++; to++; count--; } while (count >= 8) { - *(u64 *)to = __raw_readq(from); + *(u64 *)to = __raw_readq_no_log(from); from += 8; to += 8; count -= 8; } while (count) { - *(u8 *)to = __raw_readb(from); + *(u8 *)to = __raw_readb_no_log(from); from++; to++; count--; @@ -57,21 +57,21 @@ void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) { while (count && (!IS_ALIGNED((unsigned long)to, 8) || !IS_ALIGNED((unsigned long)from, 8))) { - __raw_writeb(*(volatile u8 *)from, to); + __raw_writeb_no_log(*(volatile u8 *)from, to); from++; to++; count--; } while (count >= 8) { - __raw_writeq(*(volatile u64 *)from, to); + __raw_writeq_no_log(*(volatile u64 *)from, to); from += 8; to += 8; count -= 8; } while (count) { - __raw_writeb(*(volatile u8 *)from, to); + __raw_writeb_no_log(*(volatile u8 *)from, to); from++; to++; count--; @@ -91,19 +91,19 @@ void __memset_io(volatile void __iomem *dst, int c, size_t count) qc |= qc << 32; while (count && !IS_ALIGNED((unsigned long)dst, 8)) { - __raw_writeb(c, dst); + __raw_writeb_no_log(c, dst); dst++; count--; } while (count >= 8) { - __raw_writeq(qc, dst); + __raw_writeq_no_log(qc, dst); dst += 8; count -= 8; } while (count) { - __raw_writeb(c, dst); + __raw_writeb_no_log(c, dst); dst++; count--; } diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 2386b26c0712..9f17ec071ee0 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -30,9 +30,6 @@ unsigned long irq_err_count; -/* irq stack only needs to be 16 byte aligned - not IRQ_STACK_SIZE aligned. */ -DEFINE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack) __aligned(16); - int arch_show_interrupts(struct seq_file *p, int prec) { show_ipi_list(p, prec); diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c deleted file mode 100644 index 582983920054..000000000000 --- a/arch/arm64/kernel/kaslr.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/crc32.h> -#include <linux/init.h> -#include <linux/libfdt.h> -#include <linux/mm_types.h> -#include <linux/sched.h> -#include <linux/types.h> - -#include <asm/fixmap.h> -#include <asm/kernel-pgtable.h> -#include <asm/memory.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/sections.h> - -u64 __read_mostly module_alloc_base; -u16 __initdata memstart_offset_seed; - -static __init u64 get_kaslr_seed(void *fdt) -{ - int node, len; - u64 *prop; - u64 ret; - - node = fdt_path_offset(fdt, "/chosen"); - if (node < 0) - return 0; - - prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len); - if (!prop || len != sizeof(u64)) - return 0; - - ret = fdt64_to_cpu(*prop); - *prop = 0; - return ret; -} - -static __init const u8 *get_cmdline(void *fdt) -{ - static __initconst const u8 default_cmdline[] = CONFIG_CMDLINE; - - if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) { - int node; - const u8 *prop; - - node = fdt_path_offset(fdt, "/chosen"); - if (node < 0) - goto out; - - prop = fdt_getprop(fdt, node, "bootargs", NULL); - if (!prop) - goto out; - return prop; - } -out: - return default_cmdline; -} - -extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, - pgprot_t prot); - -/* - * This routine will be executed with the kernel mapped at its default virtual - * address, and if it returns successfully, the kernel will be remapped, and - * start_kernel() will be executed from a randomized virtual offset. The - * relocation will result in all absolute references (e.g., static variables - * containing function pointers) to be reinitialized, and zero-initialized - * .bss variables will be reset to 0. - */ -u64 __init kaslr_early_init(u64 dt_phys) -{ - void *fdt; - u64 seed, offset, mask, module_range; - const u8 *cmdline, *str; - int size; - - /* - * Set a reasonable default for module_alloc_base in case - * we end up running with module randomization disabled. - */ - module_alloc_base = (u64)_etext - MODULES_VSIZE; - - /* - * Try to map the FDT early. If this fails, we simply bail, - * and proceed with KASLR disabled. We will make another - * attempt at mapping the FDT in setup_machine() - */ - early_fixmap_init(); - fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL); - if (!fdt) - return 0; - - /* - * Retrieve (and wipe) the seed from the FDT - */ - seed = get_kaslr_seed(fdt); - if (!seed) - return 0; - - /* - * Check if 'nokaslr' appears on the command line, and - * return 0 if that is the case. - */ - cmdline = get_cmdline(fdt); - str = strstr(cmdline, "nokaslr"); - if (str == cmdline || (str > cmdline && *(str - 1) == ' ')) - return 0; - - /* - * OK, so we are proceeding with KASLR enabled. Calculate a suitable - * kernel image offset from the seed. Let's place the kernel in the - * lower half of the VMALLOC area (VA_BITS - 2). - * Even if we could randomize at page granularity for 16k and 64k pages, - * let's always round to 2 MB so we don't interfere with the ability to - * map using contiguous PTEs - */ - mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1); - offset = seed & mask; - - /* use the top 16 bits to randomize the linear region */ - memstart_offset_seed = seed >> 48; - - /* - * The kernel Image should not extend across a 1GB/32MB/512MB alignment - * boundary (for 4KB/16KB/64KB granule kernels, respectively). If this - * happens, increase the KASLR offset by the size of the kernel image. - */ - if ((((u64)_text + offset) >> SWAPPER_TABLE_SHIFT) != - (((u64)_end + offset) >> SWAPPER_TABLE_SHIFT)) - offset = (offset + (u64)(_end - _text)) & mask; - - if (IS_ENABLED(CONFIG_KASAN)) - /* - * KASAN does not expect the module region to intersect the - * vmalloc region, since shadow memory is allocated for each - * module at load time, whereas the vmalloc region is shadowed - * by KASAN zero pages. So keep modules out of the vmalloc - * region if KASAN is enabled. - */ - return offset; - - if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) { - /* - * Randomize the module region independently from the core - * kernel. This prevents modules from leaking any information - * about the address of the kernel itself, but results in - * branches between modules and the core kernel that are - * resolved via PLTs. (Branches between modules will be - * resolved normally.) - */ - module_range = VMALLOC_END - VMALLOC_START - MODULES_VSIZE; - module_alloc_base = VMALLOC_START; - } else { - /* - * Randomize the module region by setting module_alloc_base to - * a PAGE_SIZE multiple in the range [_etext - MODULES_VSIZE, - * _stext) . This guarantees that the resulting region still - * covers [_stext, _etext], and that all relative branches can - * be resolved without veneers. - */ - module_range = MODULES_VSIZE - (u64)(_etext - _stext); - module_alloc_base = (u64)_etext + offset - MODULES_VSIZE; - } - - /* use the lower 21 bits to randomize the base of the module region */ - module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21; - module_alloc_base &= PAGE_MASK; - - return offset; -} diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c deleted file mode 100644 index 1ce90d8450ae..000000000000 --- a/arch/arm64/kernel/module-plts.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2014-2016 Linaro Ltd. <ard.biesheuvel@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/elf.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sort.h> - -struct plt_entry { - /* - * A program that conforms to the AArch64 Procedure Call Standard - * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or - * IP1 (x17) may be inserted at any branch instruction that is - * exposed to a relocation that supports long branches. Since that - * is exactly what we are dealing with here, we are free to use x16 - * as a scratch register in the PLT veneers. - */ - __le32 mov0; /* movn x16, #0x.... */ - __le32 mov1; /* movk x16, #0x...., lsl #16 */ - __le32 mov2; /* movk x16, #0x...., lsl #32 */ - __le32 br; /* br x16 */ -}; - -u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela, - Elf64_Sym *sym) -{ - struct plt_entry *plt = (struct plt_entry *)mod->arch.plt->sh_addr; - int i = mod->arch.plt_num_entries; - u64 val = sym->st_value + rela->r_addend; - - /* - * We only emit PLT entries against undefined (SHN_UNDEF) symbols, - * which are listed in the ELF symtab section, but without a type - * or a size. - * So, similar to how the module loader uses the Elf64_Sym::st_value - * field to store the resolved addresses of undefined symbols, let's - * borrow the Elf64_Sym::st_size field (whose value is never used by - * the module loader, even for symbols that are defined) to record - * the address of a symbol's associated PLT entry as we emit it for a - * zero addend relocation (which is the only kind we have to deal with - * in practice). This allows us to find duplicates without having to - * go through the table every time. - */ - if (rela->r_addend == 0 && sym->st_size != 0) { - BUG_ON(sym->st_size < (u64)plt || sym->st_size >= (u64)&plt[i]); - return sym->st_size; - } - - mod->arch.plt_num_entries++; - BUG_ON(mod->arch.plt_num_entries > mod->arch.plt_max_entries); - - /* - * MOVK/MOVN/MOVZ opcode: - * +--------+------------+--------+-----------+-------------+---------+ - * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] | - * +--------+------------+--------+-----------+-------------+---------+ - * - * Rd := 0x10 (x16) - * hw := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32) - * opc := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ) - * sf := 1 (64-bit variant) - */ - plt[i] = (struct plt_entry){ - cpu_to_le32(0x92800010 | (((~val ) & 0xffff)) << 5), - cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5), - cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5), - cpu_to_le32(0xd61f0200) - }; - - if (rela->r_addend == 0) - sym->st_size = (u64)&plt[i]; - - return (u64)&plt[i]; -} - -#define cmp_3way(a,b) ((a) < (b) ? -1 : (a) > (b)) - -static int cmp_rela(const void *a, const void *b) -{ - const Elf64_Rela *x = a, *y = b; - int i; - - /* sort by type, symbol index and addend */ - i = cmp_3way(ELF64_R_TYPE(x->r_info), ELF64_R_TYPE(y->r_info)); - if (i == 0) - i = cmp_3way(ELF64_R_SYM(x->r_info), ELF64_R_SYM(y->r_info)); - if (i == 0) - i = cmp_3way(x->r_addend, y->r_addend); - return i; -} - -static bool duplicate_rel(const Elf64_Rela *rela, int num) -{ - /* - * Entries are sorted by type, symbol index and addend. That means - * that, if a duplicate entry exists, it must be in the preceding - * slot. - */ - return num > 0 && cmp_rela(rela + num, rela + num - 1) == 0; -} - -static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num) -{ - unsigned int ret = 0; - Elf64_Sym *s; - int i; - - for (i = 0; i < num; i++) { - switch (ELF64_R_TYPE(rela[i].r_info)) { - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: - /* - * We only have to consider branch targets that resolve - * to undefined symbols. This is not simply a heuristic, - * it is a fundamental limitation, since the PLT itself - * is part of the module, and needs to be within 128 MB - * as well, so modules can never grow beyond that limit. - */ - s = syms + ELF64_R_SYM(rela[i].r_info); - if (s->st_shndx != SHN_UNDEF) - break; - - /* - * Jump relocations with non-zero addends against - * undefined symbols are supported by the ELF spec, but - * do not occur in practice (e.g., 'jump n bytes past - * the entry point of undefined function symbol f'). - * So we need to support them, but there is no need to - * take them into consideration when trying to optimize - * this code. So let's only check for duplicates when - * the addend is zero: this allows us to record the PLT - * entry address in the symbol table itself, rather than - * having to search the list for duplicates each time we - * emit one. - */ - if (rela[i].r_addend != 0 || !duplicate_rel(rela, i)) - ret++; - break; - } - } - return ret; -} - -int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, - char *secstrings, struct module *mod) -{ - unsigned long plt_max_entries = 0; - Elf64_Sym *syms = NULL; - int i; - - /* - * Find the empty .plt section so we can expand it to store the PLT - * entries. Record the symtab address as well. - */ - for (i = 0; i < ehdr->e_shnum; i++) { - if (strcmp(".plt", secstrings + sechdrs[i].sh_name) == 0) - mod->arch.plt = sechdrs + i; - else if (sechdrs[i].sh_type == SHT_SYMTAB) - syms = (Elf64_Sym *)sechdrs[i].sh_addr; - } - - if (!mod->arch.plt) { - pr_err("%s: module PLT section missing\n", mod->name); - return -ENOEXEC; - } - if (!syms) { - pr_err("%s: module symtab section missing\n", mod->name); - return -ENOEXEC; - } - - for (i = 0; i < ehdr->e_shnum; i++) { - Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset; - int numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela); - Elf64_Shdr *dstsec = sechdrs + sechdrs[i].sh_info; - - if (sechdrs[i].sh_type != SHT_RELA) - continue; - - /* ignore relocations that operate on non-exec sections */ - if (!(dstsec->sh_flags & SHF_EXECINSTR)) - continue; - - /* sort by type, symbol index and addend */ - sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL); - - plt_max_entries += count_plts(syms, rels, numrels); - } - - mod->arch.plt->sh_type = SHT_NOBITS; - mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; - mod->arch.plt->sh_addralign = L1_CACHE_BYTES; - mod->arch.plt->sh_size = plt_max_entries * sizeof(struct plt_entry); - mod->arch.plt_num_entries = 0; - mod->arch.plt_max_entries = plt_max_entries; - return 0; -} diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 7f316982ce00..f4bc779e62e8 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -30,30 +30,17 @@ #include <asm/insn.h> #include <asm/sections.h> +#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX +#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16 + void *module_alloc(unsigned long size) { void *p; - p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, - module_alloc_base + MODULES_VSIZE, + p = __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR, MODULES_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, __builtin_return_address(0)); - if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && - !IS_ENABLED(CONFIG_KASAN)) - /* - * KASAN can only deal with module allocations being served - * from the reserved module region, since the remainder of - * the vmalloc region is already backed by zero shadow pages, - * and punching holes into it is non-trivial. Since the module - * region is not randomized when KASAN is enabled, it is even - * less likely that the module region gets exhausted, so we - * can simply omit this fallback in that case. - */ - p = __vmalloc_node_range(size, MODULE_ALIGN, VMALLOC_START, - VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0, - NUMA_NO_NODE, __builtin_return_address(0)); - if (p && (kasan_module_alloc(p, size) < 0)) { vfree(p); return NULL; @@ -88,18 +75,15 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val) static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) { + u64 imm_mask = (1 << len) - 1; s64 sval = do_reloc(op, place, val); switch (len) { case 16: *(s16 *)place = sval; - if (sval < S16_MIN || sval > U16_MAX) - return -ERANGE; break; case 32: *(s32 *)place = sval; - if (sval < S32_MIN || sval > U32_MAX) - return -ERANGE; break; case 64: *(s64 *)place = sval; @@ -108,23 +92,34 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) pr_err("Invalid length (%d) for data relocation\n", len); return 0; } + + /* + * Extract the upper value bits (including the sign bit) and + * shift them to bit 0. + */ + sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); + + /* + * Overflow has occurred if the value is not representable in + * len bits (i.e the bottom len bits are not sign-extended and + * the top bits are not all zero). + */ + if ((u64)(sval + 1) > 2) + return -ERANGE; + return 0; } -enum aarch64_insn_movw_imm_type { - AARCH64_INSN_IMM_MOVNZ, - AARCH64_INSN_IMM_MOVKZ, -}; - static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, - int lsb, enum aarch64_insn_movw_imm_type imm_type) + int lsb, enum aarch64_insn_imm_type imm_type) { - u64 imm; + u64 imm, limit = 0; s64 sval; u32 insn = le32_to_cpu(*(u32 *)place); sval = do_reloc(op, place, val); - imm = sval >> lsb; + sval >>= lsb; + imm = sval & 0xffff; if (imm_type == AARCH64_INSN_IMM_MOVNZ) { /* @@ -133,7 +128,7 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, * immediate is less than zero. */ insn &= ~(3 << 29); - if (sval >= 0) { + if ((s64)imm >= 0) { /* >=0: Set the instruction to MOVZ (opcode 10b). */ insn |= 2 << 29; } else { @@ -145,13 +140,29 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, */ imm = ~imm; } + imm_type = AARCH64_INSN_IMM_MOVK; } /* Update the instruction with the new encoding. */ - insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); + insn = aarch64_insn_encode_immediate(imm_type, insn, imm); *(u32 *)place = cpu_to_le32(insn); - if (imm > U16_MAX) + /* Shift out the immediate field. */ + sval >>= 16; + + /* + * For unsigned immediates, the overflow check is straightforward. + * For signed immediates, the sign bit is actually the bit past the + * most significant bit of the field. + * The AARCH64_INSN_IMM_16 immediate type is unsigned. + */ + if (imm_type != AARCH64_INSN_IMM_16) { + sval++; + limit++; + } + + /* Check the upper bits depending on the sign of the immediate. */ + if ((u64)sval > limit) return -ERANGE; return 0; @@ -256,25 +267,25 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, overflow_check = false; case R_AARCH64_MOVW_UABS_G0: ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_16); break; case R_AARCH64_MOVW_UABS_G1_NC: overflow_check = false; case R_AARCH64_MOVW_UABS_G1: ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_16); break; case R_AARCH64_MOVW_UABS_G2_NC: overflow_check = false; case R_AARCH64_MOVW_UABS_G2: ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_16); break; case R_AARCH64_MOVW_UABS_G3: /* We're using the top bits so we can't overflow. */ overflow_check = false; ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_16); break; case R_AARCH64_MOVW_SABS_G0: ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, @@ -291,7 +302,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_AARCH64_MOVW_PREL_G0_NC: overflow_check = false; ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_MOVK); break; case R_AARCH64_MOVW_PREL_G0: ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, @@ -300,7 +311,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_AARCH64_MOVW_PREL_G1_NC: overflow_check = false; ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_MOVK); break; case R_AARCH64_MOVW_PREL_G1: ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, @@ -309,7 +320,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_AARCH64_MOVW_PREL_G2_NC: overflow_check = false; ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, - AARCH64_INSN_IMM_MOVKZ); + AARCH64_INSN_IMM_MOVK); break; case R_AARCH64_MOVW_PREL_G2: ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, @@ -377,13 +388,6 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_AARCH64_CALL26: ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, AARCH64_INSN_IMM_26); - - if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && - ovf == -ERANGE) { - val = module_emit_plt_entry(me, &rel[i], sym); - ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, - 26, AARCH64_INSN_IMM_26); - } break; default: diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds deleted file mode 100644 index 8949f6c6f729..000000000000 --- a/arch/arm64/kernel/module.lds +++ /dev/null @@ -1,3 +0,0 @@ -SECTIONS { - .plt (NOLOAD) : { BYTE(0) } -} diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c index ff4665462a02..3aa74830cc69 100644 --- a/arch/arm64/kernel/perf_callchain.c +++ b/arch/arm64/kernel/perf_callchain.c @@ -164,11 +164,8 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, frame.fp = regs->regs[29]; frame.sp = regs->sp; frame.pc = regs->pc; -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = current->curr_ret_stack; -#endif - walk_stackframe(current, &frame, callchain_trace, entry); + walk_stackframe(&frame, callchain_trace, entry); } unsigned long perf_instruction_pointer(struct pt_regs *regs) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 496e2e33bbec..129fb3f8c322 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -46,7 +46,6 @@ #include <linux/notifier.h> #include <trace/events/power.h> -#include <asm/alternative.h> #include <asm/compat.h> #include <asm/cacheflush.h> #include <asm/fpsimd.h> @@ -351,9 +350,6 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, } else { memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h; - if (IS_ENABLED(CONFIG_ARM64_UAO) && - cpus_have_cap(ARM64_HAS_UAO)) - childregs->pstate |= PSR_UAO_BIT; p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; } @@ -382,17 +378,6 @@ static void tls_thread_switch(struct task_struct *next) : : "r" (tpidr), "r" (tpidrro)); } -/* Restore the UAO state depending on next's addr_limit */ -static void uao_thread_switch(struct task_struct *next) -{ - if (IS_ENABLED(CONFIG_ARM64_UAO)) { - if (task_thread_info(next)->addr_limit == KERNEL_DS) - asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO)); - else - asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO)); - } -} - /* * Thread switching. */ @@ -405,7 +390,6 @@ struct task_struct *__switch_to(struct task_struct *prev, tls_thread_switch(next); hw_breakpoint_thread_switch(next); contextidr_thread_switch(next); - uao_thread_switch(next); /* * Complete any pending TLB or cache maintenance on this CPU in case @@ -430,14 +414,11 @@ unsigned long get_wchan(struct task_struct *p) frame.fp = thread_saved_fp(p); frame.sp = thread_saved_sp(p); frame.pc = thread_saved_pc(p); -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = p->curr_ret_stack; -#endif stack_page = (unsigned long)task_stack_page(p); do { if (frame.sp < stack_page || frame.sp >= stack_page + THREAD_SIZE || - unwind_frame(p, &frame)) + unwind_frame(&frame)) return 0; if (!in_sched_functions(frame.pc)) return frame.pc; diff --git a/arch/arm64/kernel/return_address.c b/arch/arm64/kernel/return_address.c index 1718706fde83..6c4fd2810ecb 100644 --- a/arch/arm64/kernel/return_address.c +++ b/arch/arm64/kernel/return_address.c @@ -43,11 +43,8 @@ void *return_address(unsigned int level) frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_stack_pointer; frame.pc = (unsigned long)return_address; /* dummy */ -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = current->curr_ret_stack; -#endif - walk_stackframe(current, &frame, save_return_addr, &data); + walk_stackframe(&frame, save_return_addr, &data); if (!data.level) return data.addr; diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index d1e01e6498bb..cd4eb7ee618c 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -63,7 +63,6 @@ #include <asm/memblock.h> #include <asm/efi.h> #include <asm/xen/hypervisor.h> -#include <asm/mmu_context.h> unsigned int boot_reason; EXPORT_SYMBOL(boot_reason); @@ -328,12 +327,6 @@ void __init setup_arch(char **cmdline_p) */ local_async_enable(); - /* - * TTBR0 is only used for the identity mapping at this stage. Make it - * point to zero page to avoid speculatively fetching new entries. - */ - cpu_uninstall_idmap(); - efi_init(); arm64_memblock_init(); @@ -409,32 +402,3 @@ void arch_setup_pdev_archdata(struct platform_device *pdev) pdev->archdata.dma_mask = DMA_BIT_MASK(32); pdev->dev.dma_mask = &pdev->archdata.dma_mask; } - -/* - * Dump out kernel offset information on panic. - */ -static int dump_kernel_offset(struct notifier_block *self, unsigned long v, - void *p) -{ - u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR; - - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) { - pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n", - kaslr_offset, KIMAGE_VADDR); - } else { - pr_emerg("Kernel Offset: disabled\n"); - } - return 0; -} - -static struct notifier_block kernel_offset_notifier = { - .notifier_call = dump_kernel_offset -}; - -static int __init register_kernel_offset_dumper(void) -{ - atomic_notifier_chain_register(&panic_notifier_list, - &kernel_offset_notifier); - return 0; -} -__initcall(register_kernel_offset_dumper); diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index e33fe33876ab..f586f7c875e2 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -173,9 +173,6 @@ ENTRY(cpu_resume) /* load physical address of identity map page table in x1 */ adrp x1, idmap_pg_dir mov sp, x2 - /* save thread_info */ - and x2, x2, #~(THREAD_SIZE - 1) - msr sp_el0, x2 /* * cpu_do_resume expects x0 to contain context physical address * pointer and x1 to contain physical address of 1:1 page tables diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index b2f5631c3785..08e78e47be95 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -154,7 +154,9 @@ asmlinkage void secondary_start_kernel(void) * TTBR0 is only used for the identity mapping at this stage. Make it * point to zero page to avoid speculatively fetching new entries. */ - cpu_uninstall_idmap(); + cpu_set_reserved_ttbr0(); + local_flush_tlb_all(); + cpu_set_default_tcr_t0sz(); preempt_disable(); trace_hardirqs_off(); @@ -457,17 +459,6 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) /* map the logical cpu id to cpu MPIDR */ cpu_logical_map(cpu_count) = hwid; - /* - * Set-up the ACPI parking protocol cpu entries - * while initializing the cpu_logical_map to - * avoid parsing MADT entries multiple times for - * nothing (ie a valid cpu_logical_map entry should - * contain a valid parking protocol data set to - * initialize the cpu if the parking protocol is - * the only available enable method). - */ - acpi_set_mailbox_entry(cpu_count, processor); - cpu_count++; } @@ -710,12 +701,10 @@ void arch_send_call_function_single_ipi(int cpu) smp_cross_call_common(cpumask_of(cpu), IPI_CALL_FUNC); } -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL void arch_send_wakeup_ipi_mask(const struct cpumask *mask) { - smp_cross_call(mask, IPI_WAKEUP); + smp_cross_call_common(mask, IPI_WAKEUP); } -#endif #ifdef CONFIG_IRQ_WORK void arch_irq_work_raise(void) @@ -866,17 +855,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs) break; #endif - case IPI_CPU_BACKTRACE: - ipi_cpu_backtrace(cpu, regs); + case IPI_WAKEUP: break; -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL - case IPI_WAKEUP: - WARN_ONCE(!acpi_parking_protocol_valid(cpu), - "CPU%u: Wake-up IPI outside the ACPI parking protocol\n", - cpu); + case IPI_CPU_BACKTRACE: + ipi_cpu_backtrace(cpu, regs); break; -#endif default: pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 85aea381fbf6..665c7fedc65b 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -18,11 +18,9 @@ #include <linux/kasan.h> #include <linux/kernel.h> #include <linux/export.h> -#include <linux/ftrace.h> #include <linux/sched.h> #include <linux/stacktrace.h> -#include <asm/irq.h> #include <asm/stacktrace.h> /* @@ -38,29 +36,15 @@ * ldp x29, x30, [sp] * add sp, sp, #0x10 */ -int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) +int notrace unwind_frame(struct stackframe *frame) { unsigned long high, low; unsigned long fp = frame->fp; - unsigned long irq_stack_ptr; - - /* - * Switching between stacks is valid when tracing current and in - * non-preemptible context. - */ - if (tsk == current && !preemptible()) - irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id()); - else - irq_stack_ptr = 0; low = frame->sp; - /* irq stacks are not THREAD_SIZE aligned */ - if (on_irq_stack(frame->sp, raw_smp_processor_id())) - high = irq_stack_ptr; - else - high = ALIGN(low, THREAD_SIZE) - 0x20; + high = ALIGN(low, THREAD_SIZE); - if (fp < low || fp > high || fp & 0xf) + if (fp < low || fp > high - 0x18 || fp & 0xf) return -EINVAL; kasan_disable_current(); @@ -69,55 +53,12 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) frame->fp = *(unsigned long *)(fp); frame->pc = *(unsigned long *)(fp + 8); -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - if (tsk && tsk->ret_stack && - (frame->pc == (unsigned long)return_to_handler)) { - /* - * This is a case where function graph tracer has - * modified a return address (LR) in a stack frame - * to hook a function return. - * So replace it to an original value. - */ - frame->pc = tsk->ret_stack[frame->graph--].ret; - } -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - - /* - * Check whether we are going to walk through from interrupt stack - * to task stack. - * If we reach the end of the stack - and its an interrupt stack, - * unpack the dummy frame to find the original elr. - * - * Check the frame->fp we read from the bottom of the irq_stack, - * and the original task stack pointer are both in current->stack. - */ - if (frame->sp == irq_stack_ptr) { - struct pt_regs *irq_args; - unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); - - if (object_is_on_stack((void *)orig_sp) && - object_is_on_stack((void *)frame->fp)) { - frame->sp = orig_sp; - - /* orig_sp is the saved pt_regs, find the elr */ - irq_args = (struct pt_regs *)orig_sp; - frame->pc = irq_args->pc; - } else { - /* - * This frame has a non-standard format, and we - * didn't fix it, because the data looked wrong. - * Refuse to output this frame. - */ - return -EINVAL; - } - } - kasan_enable_current(); return 0; } -void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, +void notrace walk_stackframe(struct stackframe *frame, int (*fn)(struct stackframe *, void *), void *data) { while (1) { @@ -125,7 +66,7 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, if (fn(frame, data)) break; - ret = unwind_frame(tsk, frame); + ret = unwind_frame(frame); if (ret < 0) break; } @@ -176,11 +117,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) frame.sp = current_stack_pointer; frame.pc = (unsigned long)save_stack_trace_tsk; } -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = tsk->curr_ret_stack; -#endif - walk_stackframe(tsk, &frame, save_trace, &data); + walk_stackframe(&frame, save_trace, &data); if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; } diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 66055392f445..1095aa483a1c 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -60,6 +60,7 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) */ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) { + struct mm_struct *mm = current->active_mm; int ret; unsigned long flags; @@ -86,11 +87,22 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) ret = __cpu_suspend_enter(arg, fn); if (ret == 0) { /* - * We are resuming from reset with the idmap active in TTBR0_EL1. - * We must uninstall the idmap and restore the expected MMU - * state before we can possibly return to userspace. + * We are resuming from reset with TTBR0_EL1 set to the + * idmap to enable the MMU; set the TTBR0 to the reserved + * page tables to prevent speculative TLB allocations, flush + * the local tlb and set the default tcr_el1.t0sz so that + * the TTBR0 address space set-up is properly restored. + * If the current active_mm != &init_mm we entered cpu_suspend + * with mappings in TTBR0 that must be restored, so we switch + * them back to complete the address space configuration + * restoration before returning. */ - cpu_uninstall_idmap(); + cpu_set_reserved_ttbr0(); + local_flush_tlb_all(); + cpu_set_default_tcr_t0sz(); + + if (mm != &init_mm) + cpu_switch_mm(mm->pgd, mm); /* * Restore per-cpu offset before any kernel diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 59779699a1a4..13339b6ffc1a 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -52,11 +52,8 @@ unsigned long profile_pc(struct pt_regs *regs) frame.fp = regs->regs[29]; frame.sp = regs->sp; frame.pc = regs->pc; -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = -1; /* no task info */ -#endif do { - int ret = unwind_frame(NULL, &frame); + int ret = unwind_frame(&frame); if (ret < 0) return 0; } while (in_lock_functions(frame.pc)); diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 48b75ece4c17..7d54c168d19c 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -150,24 +150,17 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) { struct stackframe frame; - unsigned long irq_stack_ptr; - int skip; - - /* - * Switching between stacks is valid when tracing current and in - * non-preemptible context. - */ - if (tsk == current && !preemptible()) - irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id()); - else - irq_stack_ptr = 0; pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); if (!tsk) tsk = current; - if (tsk == current) { + if (regs) { + frame.fp = regs->regs[29]; + frame.sp = regs->sp; + frame.pc = regs->pc; + } else if (tsk == current) { frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_stack_pointer; frame.pc = (unsigned long)dump_backtrace; @@ -179,49 +172,21 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) frame.sp = thread_saved_sp(tsk); frame.pc = thread_saved_pc(tsk); } -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = tsk->curr_ret_stack; -#endif - skip = !!regs; - printk("Call trace:\n"); + pr_emerg("Call trace:\n"); while (1) { unsigned long where = frame.pc; unsigned long stack; int ret; - /* skip until specified stack frame */ - if (!skip) { - dump_backtrace_entry(where); - } else if (frame.fp == regs->regs[29]) { - skip = 0; - /* - * Mostly, this is the case where this function is - * called in panic/abort. As exception handler's - * stack frame does not contain the corresponding pc - * at which an exception has taken place, use regs->pc - * instead. - */ - dump_backtrace_entry(regs->pc); - } - ret = unwind_frame(tsk, &frame); + dump_backtrace_entry(where); + ret = unwind_frame(&frame); if (ret < 0) break; stack = frame.sp; - if (in_exception_text(where)) { - /* - * If we switched to the irq_stack before calling this - * exception handler, then the pt_regs will be on the - * task stack. The easiest way to tell is if the large - * pt_regs would overlap with the end of the irq_stack. - */ - if (stack < irq_stack_ptr && - (stack + sizeof(struct pt_regs)) > irq_stack_ptr) - stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); - + if (in_exception_text(where)) dump_mem("", "Exception stack", stack, stack + sizeof(struct pt_regs), false); - } } } @@ -537,22 +502,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) void __pte_error(const char *file, int line, unsigned long val) { - pr_err("%s:%d: bad pte %016lx.\n", file, line, val); + pr_crit("%s:%d: bad pte %016lx.\n", file, line, val); } void __pmd_error(const char *file, int line, unsigned long val) { - pr_err("%s:%d: bad pmd %016lx.\n", file, line, val); + pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val); } void __pud_error(const char *file, int line, unsigned long val) { - pr_err("%s:%d: bad pud %016lx.\n", file, line, val); + pr_crit("%s:%d: bad pud %016lx.\n", file, line, val); } void __pgd_error(const char *file, int line, unsigned long val) { - pr_err("%s:%d: bad pgd %016lx.\n", file, line, val); + pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val); } /* GENERIC_BUG traps */ diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 6b562a318f84..b3f48316f888 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -88,16 +88,15 @@ SECTIONS EXIT_CALL *(.discard) *(.discard.*) - *(.interp .dynamic) } - . = KIMAGE_VADDR + TEXT_OFFSET; + . = PAGE_OFFSET + TEXT_OFFSET; .head.text : { _text = .; HEAD_TEXT } - ALIGN_DEBUG_RO_MIN(PAGE_SIZE) + ALIGN_DEBUG_RO .text : { /* Real text segment */ _stext = .; /* Text and read-only data */ __exception_text_start = .; @@ -115,12 +114,14 @@ SECTIONS *(.got) /* Global offset table */ } + ALIGN_DEBUG_RO RO_DATA(PAGE_SIZE) EXCEPTION_TABLE(8) NOTES + ALIGN_DEBUG_RO + _etext = .; /* End of text and rodata section */ ALIGN_DEBUG_RO_MIN(PAGE_SIZE) - _etext = .; /* End of text and rodata section */ __init_begin = .; INIT_TEXT_SECTION(8) @@ -128,6 +129,7 @@ SECTIONS ARM_EXIT_KEEP(EXIT_TEXT) } + ALIGN_DEBUG_RO_MIN(16) .init.data : { INIT_DATA INIT_SETUP(16) @@ -142,6 +144,9 @@ SECTIONS PERCPU_SECTION(L1_CACHE_BYTES) + . = ALIGN(PAGE_SIZE); + __init_end = .; + . = ALIGN(4); .altinstructions : { __alt_instructions = .; @@ -151,25 +156,8 @@ SECTIONS .altinstr_replacement : { *(.altinstr_replacement) } - .rela : ALIGN(8) { - __reloc_start = .; - *(.rela .rela*) - __reloc_end = .; - } - .dynsym : ALIGN(8) { - __dynsym_start = .; - *(.dynsym) - } - .dynstr : { - *(.dynstr) - } - .hash : { - *(.hash) - } . = ALIGN(PAGE_SIZE); - __init_end = .; - _data = .; _sdata = .; RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) @@ -203,4 +191,4 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K, /* * If padding is applied before .head.text, virt<->phys conversions will fail. */ -ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned") +ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned") diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 309e3479dc2c..86c289832272 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -923,7 +923,7 @@ __hyp_panic_str: .align 2 /* - * u64 __kvm_call_hyp(void *hypfn, ...); + * u64 kvm_call_hyp(void *hypfn, ...); * * This is not really a variadic function in the classic C-way and care must * be taken when calling this to ensure parameters are passed in registers @@ -940,10 +940,10 @@ __hyp_panic_str: * used to implement __hyp_get_vectors in the same way as in * arch/arm64/kernel/hyp_stub.S. */ -ENTRY(__kvm_call_hyp) +ENTRY(kvm_call_hyp) hvc #0 ret -ENDPROC(__kvm_call_hyp) +ENDPROC(kvm_call_hyp) .macro invalid_vector label, target .align 2 diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index c86b7909ef31..1a811ecf71da 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile @@ -4,16 +4,15 @@ lib-y := bitops.o clear_user.o delay.o copy_from_user.o \ memcmp.o strcmp.o strncmp.o strlen.o strnlen.o \ strchr.o strrchr.o -# Tell the compiler to treat all general purpose registers (with the -# exception of the IP registers, which are already handled by the caller -# in case of a PLT) as callee-saved, which allows for efficient runtime -# patching of the bl instruction in the caller with an atomic instruction -# when supported by the CPU. Result and argument registers are handled -# correctly, based on the function prototype. +# Tell the compiler to treat all general purpose registers as +# callee-saved, which allows for efficient runtime patching of the bl +# instruction in the caller with an atomic instruction when supported by +# the CPU. Result and argument registers are handled correctly, based on +# the function prototype. lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \ -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ - -fcall-saved-x18 + -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18 diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index 5d1cad3ce6d6..a9723c71c52b 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -33,28 +33,28 @@ * Alignment fixed up by hardware. */ ENTRY(__clear_user) -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) mov x2, x1 // save the size for fixup return subs x1, x1, #8 b.mi 2f 1: -uao_user_alternative 9f, str, sttr, xzr, x0, 8 +USER(9f, str xzr, [x0], #8 ) subs x1, x1, #8 b.pl 1b 2: adds x1, x1, #4 b.mi 3f -uao_user_alternative 9f, str, sttr, wzr, x0, 4 +USER(9f, str wzr, [x0], #4 ) sub x1, x1, #4 3: adds x1, x1, #2 b.mi 4f -uao_user_alternative 9f, strh, sttrh, wzr, x0, 2 +USER(9f, strh wzr, [x0], #2 ) sub x1, x1, #2 4: adds x1, x1, #1 b.mi 5f -uao_user_alternative 9f, strb, sttrb, wzr, x0, 0 +USER(9f, strb wzr, [x0] ) 5: mov x0, #0 -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) ret ENDPROC(__clear_user) diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 17e8306dca29..4699cd74f87e 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -34,7 +34,7 @@ */ .macro ldrb1 ptr, regB, val - uao_user_alternative 9998f, ldrb, ldtrb, \ptr, \regB, \val + USER(9998f, ldrb \ptr, [\regB], \val) .endm .macro strb1 ptr, regB, val @@ -42,7 +42,7 @@ .endm .macro ldrh1 ptr, regB, val - uao_user_alternative 9998f, ldrh, ldtrh, \ptr, \regB, \val + USER(9998f, ldrh \ptr, [\regB], \val) .endm .macro strh1 ptr, regB, val @@ -50,7 +50,7 @@ .endm .macro ldr1 ptr, regB, val - uao_user_alternative 9998f, ldr, ldtr, \ptr, \regB, \val + USER(9998f, ldr \ptr, [\regB], \val) .endm .macro str1 ptr, regB, val @@ -58,7 +58,7 @@ .endm .macro ldp1 ptr, regB, regC, val - uao_ldp 9998f, \ptr, \regB, \regC, \val + USER(9998f, ldp \ptr, \regB, [\regC], \val) .endm .macro stp1 ptr, regB, regC, val @@ -67,11 +67,11 @@ end .req x5 ENTRY(__copy_from_user) -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) add end, x0, x2 #include "copy_template.S" -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) mov x0, #0 // Nothing to copy ret diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index f7292dd08c84..81c8fc93c100 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -35,44 +35,44 @@ * x0 - bytes not copied */ .macro ldrb1 ptr, regB, val - uao_user_alternative 9998f, ldrb, ldtrb, \ptr, \regB, \val + USER(9998f, ldrb \ptr, [\regB], \val) .endm .macro strb1 ptr, regB, val - uao_user_alternative 9998f, strb, sttrb, \ptr, \regB, \val + USER(9998f, strb \ptr, [\regB], \val) .endm .macro ldrh1 ptr, regB, val - uao_user_alternative 9998f, ldrh, ldtrh, \ptr, \regB, \val + USER(9998f, ldrh \ptr, [\regB], \val) .endm .macro strh1 ptr, regB, val - uao_user_alternative 9998f, strh, sttrh, \ptr, \regB, \val + USER(9998f, strh \ptr, [\regB], \val) .endm .macro ldr1 ptr, regB, val - uao_user_alternative 9998f, ldr, ldtr, \ptr, \regB, \val + USER(9998f, ldr \ptr, [\regB], \val) .endm .macro str1 ptr, regB, val - uao_user_alternative 9998f, str, sttr, \ptr, \regB, \val + USER(9998f, str \ptr, [\regB], \val) .endm .macro ldp1 ptr, regB, regC, val - uao_ldp 9998f, \ptr, \regB, \regC, \val + USER(9998f, ldp \ptr, \regB, [\regC], \val) .endm .macro stp1 ptr, regB, regC, val - uao_stp 9998f, \ptr, \regB, \regC, \val + USER(9998f, stp \ptr, \regB, [\regC], \val) .endm end .req x5 ENTRY(__copy_in_user) -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) add end, x0, x2 #include "copy_template.S" -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) mov x0, #0 ret diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S index 4c1e700840b6..512b9a7b980e 100644 --- a/arch/arm64/lib/copy_page.S +++ b/arch/arm64/lib/copy_page.S @@ -18,8 +18,6 @@ #include <linux/const.h> #include <asm/assembler.h> #include <asm/page.h> -#include <asm/cpufeature.h> -#include <asm/alternative.h> /* * Copy a page from src to dest (both are page aligned) @@ -29,65 +27,20 @@ * x1 - src */ ENTRY(copy_page) -alternative_if_not ARM64_HAS_NO_HW_PREFETCH - nop - nop -alternative_else - # Prefetch two cache lines ahead. - prfm pldl1strm, [x1, #128] - prfm pldl1strm, [x1, #256] -alternative_endif - - ldp x2, x3, [x1] + /* Assume cache line size is 64 bytes. */ + prfm pldl1strm, [x1, #64] +1: ldp x2, x3, [x1] ldp x4, x5, [x1, #16] ldp x6, x7, [x1, #32] ldp x8, x9, [x1, #48] - ldp x10, x11, [x1, #64] - ldp x12, x13, [x1, #80] - ldp x14, x15, [x1, #96] - ldp x16, x17, [x1, #112] - - mov x18, #(PAGE_SIZE - 128) - add x1, x1, #128 -1: - subs x18, x18, #128 - -alternative_if_not ARM64_HAS_NO_HW_PREFETCH - nop -alternative_else - prfm pldl1strm, [x1, #384] -alternative_endif - + add x1, x1, #64 + prfm pldl1strm, [x1, #64] stnp x2, x3, [x0] - ldp x2, x3, [x1] stnp x4, x5, [x0, #16] - ldp x4, x5, [x1, #16] stnp x6, x7, [x0, #32] - ldp x6, x7, [x1, #32] stnp x8, x9, [x0, #48] - ldp x8, x9, [x1, #48] - stnp x10, x11, [x0, #64] - ldp x10, x11, [x1, #64] - stnp x12, x13, [x0, #80] - ldp x12, x13, [x1, #80] - stnp x14, x15, [x0, #96] - ldp x14, x15, [x1, #96] - stnp x16, x17, [x0, #112] - ldp x16, x17, [x1, #112] - - add x0, x0, #128 - add x1, x1, #128 - - b.gt 1b - - stnp x2, x3, [x0] - stnp x4, x5, [x0, #16] - stnp x6, x7, [x0, #32] - stnp x8, x9, [x0, #48] - stnp x10, x11, [x0, #64] - stnp x12, x13, [x0, #80] - stnp x14, x15, [x0, #96] - stnp x16, x17, [x0, #112] - + add x0, x0, #64 + tst x1, #(PAGE_SIZE - 1) + b.ne 1b ret ENDPROC(copy_page) diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index 21faae60f988..7512bbbc07ac 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -37,7 +37,7 @@ .endm .macro strb1 ptr, regB, val - uao_user_alternative 9998f, strb, sttrb, \ptr, \regB, \val + USER(9998f, strb \ptr, [\regB], \val) .endm .macro ldrh1 ptr, regB, val @@ -45,7 +45,7 @@ .endm .macro strh1 ptr, regB, val - uao_user_alternative 9998f, strh, sttrh, \ptr, \regB, \val + USER(9998f, strh \ptr, [\regB], \val) .endm .macro ldr1 ptr, regB, val @@ -53,7 +53,7 @@ .endm .macro str1 ptr, regB, val - uao_user_alternative 9998f, str, sttr, \ptr, \regB, \val + USER(9998f, str \ptr, [\regB], \val) .endm .macro ldp1 ptr, regB, regC, val @@ -61,16 +61,16 @@ .endm .macro stp1 ptr, regB, regC, val - uao_stp 9998f, \ptr, \regB, \regC, \val + USER(9998f, stp \ptr, \regB, [\regC], \val) .endm end .req x5 ENTRY(__copy_to_user) -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) add end, x0, x2 #include "copy_template.S" -ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \ +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) mov x0, #0 ret diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 2f06997dcd59..ce32a2229a9d 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -154,32 +154,26 @@ ENDPROC(__flush_cache_user_range) /* * __flush_dcache_area(kaddr, size) * - * Ensure that any D-cache lines for the interval [kaddr, kaddr+size) - * are cleaned and invalidated to the PoC. + * Ensure that the data held in the page kaddr is written back to the + * page in question. * * - kaddr - kernel address * - size - size in question */ ENTRY(__flush_dcache_area) - dcache_by_line_op civac, sy, x0, x1, x2, x3 + dcache_line_size x2, x3 + add x1, x0, x1 + sub x3, x2, #1 + bic x0, x0, x3 +1: dc civac, x0 // clean & invalidate D line / unified line + add x0, x0, x2 + cmp x0, x1 + b.lo 1b + dsb sy ret ENDPIPROC(__flush_dcache_area) /* - * __clean_dcache_area_pou(kaddr, size) - * - * Ensure that any D-cache lines for the interval [kaddr, kaddr+size) - * are cleaned to the PoU. - * - * - kaddr - kernel address - * - size - size in question - */ -ENTRY(__clean_dcache_area_pou) - dcache_by_line_op cvau, ish, x0, x1, x2, x3 - ret -ENDPROC(__clean_dcache_area_pou) - -/* * __inval_cache_range(start, end) * - start - start address of region * - end - end address of region diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index 7275628ba59f..e87f53ff5f58 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -187,7 +187,7 @@ switch_mm_fastpath: static int asids_init(void) { - int fld = cpuid_feature_extract_field(read_cpuid(SYS_ID_AA64MMFR0_EL1), 4); + int fld = cpuid_feature_extract_field(read_cpuid(ID_AA64MMFR0_EL1), 4); switch (fld) { default: diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c index 22e4cb4d6f53..13bbc3be6f5a 100644 --- a/arch/arm64/mm/copypage.c +++ b/arch/arm64/mm/copypage.c @@ -24,9 +24,8 @@ void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) { - struct page *page = virt_to_page(kto); copy_page(kto, kfrom); - flush_dcache_page(page); + __flush_dcache_area(kto, PAGE_SIZE); } EXPORT_SYMBOL_GPL(__cpu_copy_user_page); diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 7109e27de235..e5389bc981ee 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -52,7 +52,7 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot, static struct gen_pool *atomic_pool; #define NO_KERNEL_MAPPING_DUMMY 0x2222 #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K -static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE; +static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE; static int __init early_coherent_pool(char *p) { @@ -1015,7 +1015,7 @@ static int __iommu_attach_notifier(struct notifier_block *nb, return 0; } -static int __init register_iommu_dma_ops_notifier(struct bus_type *bus) +static int register_iommu_dma_ops_notifier(struct bus_type *bus) { struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL); int ret; diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index 6be918478f85..5a22a119a74c 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -35,9 +35,7 @@ struct addr_marker { }; enum address_markers_idx { - MODULES_START_NR = 0, - MODULES_END_NR, - VMALLOC_START_NR, + VMALLOC_START_NR = 0, VMALLOC_END_NR, #ifdef CONFIG_SPARSEMEM_VMEMMAP VMEMMAP_START_NR, @@ -47,12 +45,12 @@ enum address_markers_idx { FIXADDR_END_NR, PCI_START_NR, PCI_END_NR, + MODULES_START_NR, + MODUELS_END_NR, KERNEL_SPACE_NR, }; static struct addr_marker address_markers[] = { - { MODULES_VADDR, "Modules start" }, - { MODULES_END, "Modules end" }, { VMALLOC_START, "vmalloc() Area" }, { VMALLOC_END, "vmalloc() End" }, #ifdef CONFIG_SPARSEMEM_VMEMMAP @@ -63,7 +61,9 @@ static struct addr_marker address_markers[] = { { FIXADDR_TOP, "Fixmap end" }, { PCI_IO_START, "PCI I/O start" }, { PCI_IO_END, "PCI I/O end" }, - { PAGE_OFFSET, "Linear Mapping" }, + { MODULES_VADDR, "Modules start" }, + { MODULES_END, "Modules end" }, + { PAGE_OFFSET, "Kernel Mapping" }, { -1, NULL }, }; @@ -90,11 +90,6 @@ struct prot_bits { static const struct prot_bits pte_bits[] = { { - .mask = PTE_VALID, - .val = PTE_VALID, - .set = " ", - .clear = "F", - }, { .mask = PTE_USER, .val = PTE_USER, .set = "USR", diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c index 81acd4706878..79444279ba8c 100644 --- a/arch/arm64/mm/extable.c +++ b/arch/arm64/mm/extable.c @@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs) fixup = search_exception_tables(instruction_pointer(regs)); if (fixup) - regs->pc = (unsigned long)&fixup->fixup + fixup->fixup; + regs->pc = fixup->fixup; return fixup != NULL; } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 69079e5bfc84..88ada16a1301 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -197,14 +197,6 @@ out: return fault; } -static inline int permission_fault(unsigned int esr) -{ - unsigned int ec = (esr & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT; - unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE; - - return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM); -} - static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) { @@ -238,13 +230,12 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, mm_flags |= FAULT_FLAG_WRITE; } - if (permission_fault(esr) && (addr < USER_DS)) { - if (get_fs() == KERNEL_DS) - die("Accessing user space memory with fs=KERNEL_DS", regs, esr); - - if (!search_exception_tables(regs->pc)) - die("Accessing user space memory outside uaccess.h routines", regs, esr); - } + /* + * PAN bit set implies the fault happened in kernel space, but not + * in the arch's user access functions. + */ + if (IS_ENABLED(CONFIG_ARM64_PAN) && (regs->pstate & PSR_PAN_BIT)) + goto no_context; /* * As per x86, we may deadlock here. However, since the kernel only @@ -576,16 +567,3 @@ void cpu_enable_pan(void *__unused) config_sctlr_el1(SCTLR_EL1_SPAN, 0); } #endif /* CONFIG_ARM64_PAN */ - -#ifdef CONFIG_ARM64_UAO -/* - * Kernel threads have fs=KERNEL_DS by default, and don't need to call - * set_fs(), devtmpfs in particular relies on this behaviour. - * We need to enable the feature at runtime (instead of adding it to - * PSR_MODE_EL1h) as the feature may not be implemented by the cpu. - */ -void cpu_enable_uao(void *__unused) -{ - asm(SET_PSTATE_UAO(1)); -} -#endif /* CONFIG_ARM64_UAO */ diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c index 61b0911aa475..07844184975b 100644 --- a/arch/arm64/mm/flush.c +++ b/arch/arm64/mm/flush.c @@ -34,24 +34,19 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, __flush_icache_all(); } -static void sync_icache_aliases(void *kaddr, unsigned long len) -{ - unsigned long addr = (unsigned long)kaddr; - - if (icache_is_aliasing()) { - __clean_dcache_area_pou(kaddr, len); - __flush_icache_all(); - } else { - flush_icache_range(addr, addr + len); - } -} - static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, unsigned long uaddr, void *kaddr, unsigned long len) { - if (vma->vm_flags & VM_EXEC) - sync_icache_aliases(kaddr, len); + if (vma->vm_flags & VM_EXEC) { + unsigned long addr = (unsigned long)kaddr; + if (icache_is_aliasing()) { + __flush_dcache_area(kaddr, len); + __flush_icache_all(); + } else { + flush_icache_range(addr, addr + len); + } + } } /* @@ -79,11 +74,13 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr) if (!page_mapping(page)) return; - if (!test_and_set_bit(PG_dcache_clean, &page->flags)) - sync_icache_aliases(page_address(page), - PAGE_SIZE << compound_order(page)); - else if (icache_is_aivivt()) + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) { + __flush_dcache_area(page_address(page), + PAGE_SIZE << compound_order(page)); __flush_icache_all(); + } else if (icache_is_aivivt()) { + __flush_icache_all(); + } } /* diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index da30529bb1f6..383b03ff38f8 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -41,273 +41,15 @@ int pud_huge(pud_t pud) #endif } -static int find_num_contig(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pte, size_t *pgsize) -{ - pgd_t *pgd = pgd_offset(mm, addr); - pud_t *pud; - pmd_t *pmd; - - *pgsize = PAGE_SIZE; - if (!pte_cont(pte)) - return 1; - if (!pgd_present(*pgd)) { - VM_BUG_ON(!pgd_present(*pgd)); - return 1; - } - pud = pud_offset(pgd, addr); - if (!pud_present(*pud)) { - VM_BUG_ON(!pud_present(*pud)); - return 1; - } - pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd)) { - VM_BUG_ON(!pmd_present(*pmd)); - return 1; - } - if ((pte_t *)pmd == ptep) { - *pgsize = PMD_SIZE; - return CONT_PMDS; - } - return CONT_PTES; -} - -void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pte) -{ - size_t pgsize; - int i; - int ncontig = find_num_contig(mm, addr, ptep, pte, &pgsize); - unsigned long pfn; - pgprot_t hugeprot; - - if (ncontig == 1) { - set_pte_at(mm, addr, ptep, pte); - return; - } - - pfn = pte_pfn(pte); - hugeprot = __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte)); - for (i = 0; i < ncontig; i++) { - pr_debug("%s: set pte %p to 0x%llx\n", __func__, ptep, - pte_val(pfn_pte(pfn, hugeprot))); - set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot)); - ptep++; - pfn += pgsize >> PAGE_SHIFT; - addr += pgsize; - } -} - -pte_t *huge_pte_alloc(struct mm_struct *mm, - unsigned long addr, unsigned long sz) -{ - pgd_t *pgd; - pud_t *pud; - pte_t *pte = NULL; - - pr_debug("%s: addr:0x%lx sz:0x%lx\n", __func__, addr, sz); - pgd = pgd_offset(mm, addr); - pud = pud_alloc(mm, pgd, addr); - if (!pud) - return NULL; - - if (sz == PUD_SIZE) { - pte = (pte_t *)pud; - } else if (sz == (PAGE_SIZE * CONT_PTES)) { - pmd_t *pmd = pmd_alloc(mm, pud, addr); - - WARN_ON(addr & (sz - 1)); - /* - * Note that if this code were ever ported to the - * 32-bit arm platform then it will cause trouble in - * the case where CONFIG_HIGHPTE is set, since there - * will be no pte_unmap() to correspond with this - * pte_alloc_map(). - */ - pte = pte_alloc_map(mm, NULL, pmd, addr); - } else if (sz == PMD_SIZE) { - if (IS_ENABLED(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) && - pud_none(*pud)) - pte = huge_pmd_share(mm, addr, pud); - else - pte = (pte_t *)pmd_alloc(mm, pud, addr); - } else if (sz == (PMD_SIZE * CONT_PMDS)) { - pmd_t *pmd; - - pmd = pmd_alloc(mm, pud, addr); - WARN_ON(addr & (sz - 1)); - return (pte_t *)pmd; - } - - pr_debug("%s: addr:0x%lx sz:0x%lx ret pte=%p/0x%llx\n", __func__, addr, - sz, pte, pte_val(*pte)); - return pte; -} - -pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd = NULL; - pte_t *pte = NULL; - - pgd = pgd_offset(mm, addr); - pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd); - if (!pgd_present(*pgd)) - return NULL; - pud = pud_offset(pgd, addr); - if (!pud_present(*pud)) - return NULL; - - if (pud_huge(*pud)) - return (pte_t *)pud; - pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd)) - return NULL; - - if (pte_cont(pmd_pte(*pmd))) { - pmd = pmd_offset( - pud, (addr & CONT_PMD_MASK)); - return (pte_t *)pmd; - } - if (pmd_huge(*pmd)) - return (pte_t *)pmd; - pte = pte_offset_kernel(pmd, addr); - if (pte_present(*pte) && pte_cont(*pte)) { - pte = pte_offset_kernel( - pmd, (addr & CONT_PTE_MASK)); - return pte; - } - return NULL; -} - -pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma, - struct page *page, int writable) -{ - size_t pagesize = huge_page_size(hstate_vma(vma)); - - if (pagesize == CONT_PTE_SIZE) { - entry = pte_mkcont(entry); - } else if (pagesize == CONT_PMD_SIZE) { - entry = pmd_pte(pmd_mkcont(pte_pmd(entry))); - } else if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) { - pr_warn("%s: unrecognized huge page size 0x%lx\n", - __func__, pagesize); - } - return entry; -} - -pte_t huge_ptep_get_and_clear(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - pte_t pte; - - if (pte_cont(*ptep)) { - int ncontig, i; - size_t pgsize; - pte_t *cpte; - bool is_dirty = false; - - cpte = huge_pte_offset(mm, addr); - ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize); - /* save the 1st pte to return */ - pte = ptep_get_and_clear(mm, addr, cpte); - for (i = 1; i < ncontig; ++i) { - /* - * If HW_AFDBM is enabled, then the HW could - * turn on the dirty bit for any of the page - * in the set, so check them all. - */ - ++cpte; - if (pte_dirty(ptep_get_and_clear(mm, addr, cpte))) - is_dirty = true; - } - if (is_dirty) - return pte_mkdirty(pte); - else - return pte; - } else { - return ptep_get_and_clear(mm, addr, ptep); - } -} - -int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, - pte_t pte, int dirty) -{ - pte_t *cpte; - - if (pte_cont(pte)) { - int ncontig, i, changed = 0; - size_t pgsize = 0; - unsigned long pfn = pte_pfn(pte); - /* Select all bits except the pfn */ - pgprot_t hugeprot = - __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ - pte_val(pte)); - - cpte = huge_pte_offset(vma->vm_mm, addr); - pfn = pte_pfn(*cpte); - ncontig = find_num_contig(vma->vm_mm, addr, cpte, - *cpte, &pgsize); - for (i = 0; i < ncontig; ++i, ++cpte) { - changed = ptep_set_access_flags(vma, addr, cpte, - pfn_pte(pfn, - hugeprot), - dirty); - pfn += pgsize >> PAGE_SHIFT; - } - return changed; - } else { - return ptep_set_access_flags(vma, addr, ptep, pte, dirty); - } -} - -void huge_ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - if (pte_cont(*ptep)) { - int ncontig, i; - pte_t *cpte; - size_t pgsize = 0; - - cpte = huge_pte_offset(mm, addr); - ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize); - for (i = 0; i < ncontig; ++i, ++cpte) - ptep_set_wrprotect(mm, addr, cpte); - } else { - ptep_set_wrprotect(mm, addr, ptep); - } -} - -void huge_ptep_clear_flush(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) -{ - if (pte_cont(*ptep)) { - int ncontig, i; - pte_t *cpte; - size_t pgsize = 0; - - cpte = huge_pte_offset(vma->vm_mm, addr); - ncontig = find_num_contig(vma->vm_mm, addr, cpte, - *cpte, &pgsize); - for (i = 0; i < ncontig; ++i, ++cpte) - ptep_clear_flush(vma, addr, cpte); - } else { - ptep_clear_flush(vma, addr, ptep); - } -} - static __init int setup_hugepagesz(char *opt) { unsigned long ps = memparse(opt, &opt); - if (ps == PMD_SIZE) { hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT); } else if (ps == PUD_SIZE) { hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT); } else { - pr_err("hugepagesz: Unsupported page size %lu K\n", ps >> 10); + pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20); return 0; } return 1; diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 0d5b0d0578b3..52406a2a39ad 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -35,10 +35,7 @@ #include <linux/efi.h> #include <linux/swiotlb.h> -#include <asm/boot.h> #include <asm/fixmap.h> -#include <asm/kasan.h> -#include <asm/kernel-pgtable.h> #include <asm/memory.h> #include <asm/sections.h> #include <asm/setup.h> @@ -48,13 +45,7 @@ #include "mm.h" -/* - * We need to be able to catch inadvertent references to memstart_addr - * that occur (potentially in generic code) before arm64_memblock_init() - * executes, which assigns it its actual value. So use a default value - * that cannot be mistaken for a real physical address. - */ -s64 memstart_addr __read_mostly = -1; +phys_addr_t memstart_addr __read_mostly = 0; phys_addr_t arm64_dma_phys_limit __read_mostly; #ifdef CONFIG_BLK_DEV_INITRD @@ -67,8 +58,8 @@ static int __init early_initrd(char *p) if (*endp == ',') { size = memparse(endp + 1, NULL); - initrd_start = start; - initrd_end = start + size; + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(start + size); } return 0; } @@ -80,7 +71,7 @@ early_param("initrd", early_initrd); * currently assumes that for memory starting above 4G, 32-bit devices will * use a DMA offset. */ -static phys_addr_t __init max_zone_dma_phys(void) +static phys_addr_t max_zone_dma_phys(void) { phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); return min(offset + (1ULL << 32), memblock_end_of_DRAM()); @@ -137,11 +128,11 @@ EXPORT_SYMBOL(pfn_valid); #endif #ifndef CONFIG_SPARSEMEM -static void __init arm64_memory_present(void) +static void arm64_memory_present(void) { } #else -static void __init arm64_memory_present(void) +static void arm64_memory_present(void) { struct memblock_region *reg; @@ -170,57 +161,7 @@ early_param("mem", early_mem); void __init arm64_memblock_init(void) { - const s64 linear_region_size = -(s64)PAGE_OFFSET; - - /* - * Ensure that the linear region takes up exactly half of the kernel - * virtual address space. This way, we can distinguish a linear address - * from a kernel/module/vmalloc address by testing a single bit. - */ - BUILD_BUG_ON(linear_region_size != BIT(VA_BITS - 1)); - - /* - * Select a suitable value for the base of physical memory. - */ - memstart_addr = round_down(memblock_start_of_DRAM(), - ARM64_MEMSTART_ALIGN); - - /* - * Remove the memory that we will not be able to cover with the - * linear mapping. Take care not to clip the kernel which may be - * high in memory. - */ - memblock_remove(max_t(u64, memstart_addr + linear_region_size, __pa(_end)), - ULLONG_MAX); - if (memblock_end_of_DRAM() > linear_region_size) - memblock_remove(0, memblock_end_of_DRAM() - linear_region_size); - - /* - * Apply the memory limit if it was set. Since the kernel may be loaded - * high up in memory, add back the kernel region that must be accessible - * via the linear mapping. - */ - if (memory_limit != (phys_addr_t)ULLONG_MAX) { - memblock_enforce_memory_limit(memory_limit); - memblock_add(__pa(_text), (u64)(_end - _text)); - } - - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - extern u16 memstart_offset_seed; - u64 range = linear_region_size - - (memblock_end_of_DRAM() - memblock_start_of_DRAM()); - - /* - * If the size of the linear region exceeds, by a sufficient - * margin, the size of the region that the available physical - * memory spans, randomize the linear region as well. - */ - if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) { - range = range / ARM64_MEMSTART_ALIGN + 1; - memstart_addr -= ARM64_MEMSTART_ALIGN * - ((range * memstart_offset_seed) >> 16); - } - } + memblock_enforce_memory_limit(memory_limit); /* * Register the kernel text, kernel data, initrd, and initial @@ -228,13 +169,8 @@ void __init arm64_memblock_init(void) */ memblock_reserve(__pa(_text), _end - _text); #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) { - memblock_reserve(initrd_start, initrd_end - initrd_start); - - /* the generic initrd code expects virtual addresses */ - initrd_start = __phys_to_virt(initrd_start); - initrd_end = __phys_to_virt(initrd_end); - } + if (initrd_start) + memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start); #endif early_init_fdt_scan_reserved_mem(); @@ -368,36 +304,35 @@ void __init mem_init(void) #ifdef CONFIG_KASAN " kasan : 0x%16lx - 0x%16lx (%6ld GB)\n" #endif - " modules : 0x%16lx - 0x%16lx (%6ld MB)\n" " vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n" - " .init : 0x%p" " - 0x%p" " (%6ld KB)\n" - " .text : 0x%p" " - 0x%p" " (%6ld KB)\n" - " .data : 0x%p" " - 0x%p" " (%6ld KB)\n" #ifdef CONFIG_SPARSEMEM_VMEMMAP " vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n" " 0x%16lx - 0x%16lx (%6ld MB actual)\n" #endif " fixed : 0x%16lx - 0x%16lx (%6ld KB)\n" " PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n" - " memory : 0x%16lx - 0x%16lx (%6ld MB)\n", + " modules : 0x%16lx - 0x%16lx (%6ld MB)\n" + " memory : 0x%16lx - 0x%16lx (%6ld MB)\n" + " .init : 0x%p" " - 0x%p" " (%6ld KB)\n" + " .text : 0x%p" " - 0x%p" " (%6ld KB)\n" + " .data : 0x%p" " - 0x%p" " (%6ld KB)\n", #ifdef CONFIG_KASAN MLG(KASAN_SHADOW_START, KASAN_SHADOW_END), #endif - MLM(MODULES_VADDR, MODULES_END), MLG(VMALLOC_START, VMALLOC_END), - MLK_ROUNDUP(__init_begin, __init_end), - MLK_ROUNDUP(_text, _etext), - MLK_ROUNDUP(_sdata, _edata), #ifdef CONFIG_SPARSEMEM_VMEMMAP MLG(VMEMMAP_START, VMEMMAP_START + VMEMMAP_SIZE), - MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()), + MLM((unsigned long)virt_to_page(PAGE_OFFSET), (unsigned long)virt_to_page(high_memory)), #endif MLK(FIXADDR_START, FIXADDR_TOP), MLM(PCI_IO_START, PCI_IO_END), - MLM(__phys_to_virt(memblock_start_of_DRAM()), - (unsigned long)high_memory)); + MLM(MODULES_VADDR, MODULES_END), + MLM(PAGE_OFFSET, (unsigned long)high_memory), + MLK_ROUNDUP(__init_begin, __init_end), + MLK_ROUNDUP(_text, _etext), + MLK_ROUNDUP(_sdata, _edata)); #undef MLK #undef MLM @@ -430,8 +365,9 @@ static inline void poison_init_mem(void *s, size_t count) void free_initmem(void) { - free_initmem_default(0); fixup_init(); + free_initmem_default(0); + free_alternatives_memory(); } #ifdef CONFIG_BLK_DEV_INITRD @@ -465,27 +401,3 @@ void set_kernel_text_ro(void) set_memory_ro(start, (end - start) >> PAGE_SHIFT); } #endif -/* - * Dump out memory limit information on panic. - */ -static int dump_mem_limit(struct notifier_block *self, unsigned long v, void *p) -{ - if (memory_limit != (phys_addr_t)ULLONG_MAX) { - pr_emerg("Memory Limit: %llu MB\n", memory_limit >> 20); - } else { - pr_emerg("Memory Limit: none\n"); - } - return 0; -} - -static struct notifier_block mem_limit_notifier = { - .notifier_call = dump_mem_limit, -}; - -static int __init register_mem_limit_dumper(void) -{ - atomic_notifier_chain_register(&panic_notifier_list, - &mem_limit_notifier); - return 0; -} -__initcall(register_mem_limit_dumper); diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c index 757009daa9ed..cf038c7d9fa9 100644 --- a/arch/arm64/mm/kasan_init.c +++ b/arch/arm64/mm/kasan_init.c @@ -16,12 +16,9 @@ #include <linux/memblock.h> #include <linux/start_kernel.h> -#include <asm/mmu_context.h> -#include <asm/kernel-pgtable.h> #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> -#include <asm/sections.h> #include <asm/tlbflush.h> static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE); @@ -35,7 +32,7 @@ static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr, if (pmd_none(*pmd)) pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte); - pte = pte_offset_kimg(pmd, addr); + pte = pte_offset_kernel(pmd, addr); do { next = addr + PAGE_SIZE; set_pte(pte, pfn_pte(virt_to_pfn(kasan_zero_page), @@ -53,7 +50,7 @@ static void __init kasan_early_pmd_populate(pud_t *pud, if (pud_none(*pud)) pud_populate(&init_mm, pud, kasan_zero_pmd); - pmd = pmd_offset_kimg(pud, addr); + pmd = pmd_offset(pud, addr); do { next = pmd_addr_end(addr, end); kasan_early_pte_populate(pmd, addr, next); @@ -70,7 +67,7 @@ static void __init kasan_early_pud_populate(pgd_t *pgd, if (pgd_none(*pgd)) pgd_populate(&init_mm, pgd, kasan_zero_pud); - pud = pud_offset_kimg(pgd, addr); + pud = pud_offset(pgd, addr); do { next = pud_addr_end(addr, end); kasan_early_pmd_populate(pud, addr, next); @@ -99,21 +96,6 @@ asmlinkage void __init kasan_early_init(void) kasan_map_early_shadow(); } -/* - * Copy the current shadow region into a new pgdir. - */ -void __init kasan_copy_shadow(pgd_t *pgdir) -{ - pgd_t *pgd, *pgd_new, *pgd_end; - - pgd = pgd_offset_k(KASAN_SHADOW_START); - pgd_end = pgd_offset_k(KASAN_SHADOW_END); - pgd_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START); - do { - set_pgd(pgd_new, *pgd); - } while (pgd++, pgd_new++, pgd != pgd_end); -} - static void __init clear_pgds(unsigned long start, unsigned long end) { @@ -126,18 +108,18 @@ static void __init clear_pgds(unsigned long start, set_pgd(pgd_offset_k(start), __pgd(0)); } +static void __init cpu_set_ttbr1(unsigned long ttbr1) +{ + asm( + " msr ttbr1_el1, %0\n" + " isb" + : + : "r" (ttbr1)); +} + void __init kasan_init(void) { - u64 kimg_shadow_start, kimg_shadow_end; - u64 mod_shadow_start, mod_shadow_end; struct memblock_region *reg; - int i; - - kimg_shadow_start = (u64)kasan_mem_to_shadow(_text); - kimg_shadow_end = (u64)kasan_mem_to_shadow(_end); - - mod_shadow_start = (u64)kasan_mem_to_shadow((void *)MODULES_VADDR); - mod_shadow_end = (u64)kasan_mem_to_shadow((void *)MODULES_END); /* * We are going to perform proper setup of shadow memory. @@ -147,33 +129,13 @@ void __init kasan_init(void) * setup will be finished. */ memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir)); - dsb(ishst); - cpu_replace_ttbr1(tmp_pg_dir); + cpu_set_ttbr1(__pa(tmp_pg_dir)); + flush_tlb_all(); clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); - vmemmap_populate(kimg_shadow_start, kimg_shadow_end, - pfn_to_nid(virt_to_pfn(_text))); - - /* - * vmemmap_populate() has populated the shadow region that covers the - * kernel image with SWAPPER_BLOCK_SIZE mappings, so we have to round - * the start and end addresses to SWAPPER_BLOCK_SIZE as well, to prevent - * kasan_populate_zero_shadow() from replacing the page table entries - * (PMD or PTE) at the edges of the shadow region for the kernel - * image. - */ - kimg_shadow_start = round_down(kimg_shadow_start, SWAPPER_BLOCK_SIZE); - kimg_shadow_end = round_up(kimg_shadow_end, SWAPPER_BLOCK_SIZE); - kasan_populate_zero_shadow((void *)KASAN_SHADOW_START, - (void *)mod_shadow_start); - kasan_populate_zero_shadow((void *)kimg_shadow_end, - kasan_mem_to_shadow((void *)PAGE_OFFSET)); - - if (kimg_shadow_start > mod_shadow_end) - kasan_populate_zero_shadow((void *)mod_shadow_end, - (void *)kimg_shadow_start); + kasan_mem_to_shadow((void *)MODULES_VADDR)); for_each_memblock(memory, reg) { void *start = (void *)__phys_to_virt(reg->base); @@ -193,16 +155,9 @@ void __init kasan_init(void) pfn_to_nid(virt_to_pfn(start))); } - /* - * KAsan may reuse the contents of kasan_zero_pte directly, so we - * should make sure that it maps the zero page read-only. - */ - for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(&kasan_zero_pte[i], - pfn_pte(virt_to_pfn(kasan_zero_page), PAGE_KERNEL_RO)); - memset(kasan_zero_page, 0, PAGE_SIZE); - cpu_replace_ttbr1(swapper_pg_dir); + cpu_set_ttbr1(__pa(swapper_pg_dir)); + flush_tlb_all(); /* At this point kasan is fully initialized. Enable error messages */ init_task.kasan_depth = 0; diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 62096a7e047a..e82aabb3c5e2 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -32,10 +32,8 @@ #include <linux/dma-contiguous.h> #include <linux/cma.h> -#include <asm/barrier.h> #include <asm/cputype.h> #include <asm/fixmap.h> -#include <asm/kasan.h> #include <asm/kernel-pgtable.h> #include <asm/sections.h> #include <asm/setup.h> @@ -48,21 +46,14 @@ u64 idmap_t0sz = TCR_T0SZ(VA_BITS); -u64 kimage_voffset __read_mostly; -EXPORT_SYMBOL(kimage_voffset); - /* * Empty_zero_page is a special page that is used for zero-initialized data * and COW. */ -unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss; +struct page *empty_zero_page; EXPORT_SYMBOL(empty_zero_page); -static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; -static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused; -static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused; - -static bool dma_overlap(phys_addr_t start, phys_addr_t end); +static bool __init dma_overlap(phys_addr_t start, phys_addr_t end); pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) @@ -75,30 +66,16 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, } EXPORT_SYMBOL(phys_mem_access_prot); -static phys_addr_t __init early_pgtable_alloc(void) +static void __init *early_alloc(unsigned long sz) { phys_addr_t phys; void *ptr; - phys = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + phys = memblock_alloc(sz, sz); BUG_ON(!phys); - - /* - * The FIX_{PGD,PUD,PMD} slots may be in active use, but the FIX_PTE - * slot will be free, so we can (ab)use the FIX_PTE slot to initialise - * any level of table. - */ - ptr = pte_set_fixmap(phys); - - memset(ptr, 0, PAGE_SIZE); - - /* - * Implicit barriers also ensure the zeroed page is visible to the page - * table walker - */ - pte_clear_fixmap(); - - return phys; + ptr = __va(phys); + memset(ptr, 0, sz); + return ptr; } /* @@ -122,30 +99,24 @@ static void split_pmd(pmd_t *pmd, pte_t *pte) static void alloc_init_pte(pmd_t *pmd, unsigned long addr, unsigned long end, unsigned long pfn, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(void)) + void *(*alloc)(unsigned long size)) { pte_t *pte; if (pmd_none(*pmd) || pmd_sect(*pmd)) { - phys_addr_t pte_phys; - BUG_ON(!pgtable_alloc); - pte_phys = pgtable_alloc(); - pte = pte_set_fixmap(pte_phys); + pte = alloc(PTRS_PER_PTE * sizeof(pte_t)); if (pmd_sect(*pmd)) split_pmd(pmd, pte); - __pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE); + __pmd_populate(pmd, __pa(pte), PMD_TYPE_TABLE); flush_tlb_all(); - pte_clear_fixmap(); } BUG_ON(pmd_bad(*pmd)); - pte = pte_set_fixmap_offset(pmd, addr); + pte = pte_offset_kernel(pmd, addr); do { set_pte(pte, pfn_pte(pfn, prot)); pfn++; } while (pte++, addr += PAGE_SIZE, addr != end); - - pte_clear_fixmap(); } static void split_pud(pud_t *old_pud, pmd_t *pmd) @@ -160,29 +131,10 @@ static void split_pud(pud_t *old_pud, pmd_t *pmd) } while (pmd++, i++, i < PTRS_PER_PMD); } -#ifdef CONFIG_DEBUG_PAGEALLOC -static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void)) -{ - - /* - * If debug_page_alloc is enabled we must map the linear map - * using pages. However, other mappings created by - * create_mapping_noalloc must use sections in some cases. Allow - * sections to be used in those cases, where no pgtable_alloc - * function is provided. - */ - return !pgtable_alloc || !debug_pagealloc_enabled(); -} -#else -static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void)) -{ - return true; -} -#endif - -static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end, +static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(void)) + void *(*alloc)(unsigned long size), bool pages) { pmd_t *pmd; unsigned long next; @@ -191,10 +143,7 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end, * Check for initial section mappings in the pgd/pud and remove them. */ if (pud_none(*pud) || pud_sect(*pud)) { - phys_addr_t pmd_phys; - BUG_ON(!pgtable_alloc); - pmd_phys = pgtable_alloc(); - pmd = pmd_set_fixmap(pmd_phys); + pmd = alloc(PTRS_PER_PMD * sizeof(pmd_t)); if (pud_sect(*pud)) { /* * need to have the 1G of mappings continue to be @@ -202,21 +151,19 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end, */ split_pud(pud, pmd); } - __pud_populate(pud, pmd_phys, PUD_TYPE_TABLE); + pud_populate(mm, pud, pmd); flush_tlb_all(); - pmd_clear_fixmap(); } BUG_ON(pud_bad(*pud)); - pmd = pmd_set_fixmap_offset(pud, addr); + pmd = pmd_offset(pud, addr); do { next = pmd_addr_end(addr, end); /* try section mapping first */ - if (((addr | next | phys) & ~SECTION_MASK) == 0 && - block_mappings_allowed(pgtable_alloc) && - !dma_overlap(phys, phys + next - addr)) { + if (!pages && ((addr | next | phys) & ~SECTION_MASK) == 0) { pmd_t old_pmd =*pmd; - pmd_set_huge(pmd, phys, prot); + set_pmd(pmd, __pmd(phys | + pgprot_val(mk_sect_prot(prot)))); /* * Check for previous table entries created during * boot (__create_page_tables) and flush them. @@ -224,19 +171,17 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end, if (!pmd_none(old_pmd)) { flush_tlb_all(); if (pmd_table(old_pmd)) { - phys_addr_t table = pmd_page_paddr(old_pmd); + phys_addr_t table = __pa(pte_offset_map(&old_pmd, 0)); if (!WARN_ON_ONCE(slab_is_available())) memblock_free(table, PAGE_SIZE); } } } else { alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), - prot, pgtable_alloc); + prot, alloc); } phys += next - addr; } while (pmd++, addr = next, addr != end); - - pmd_clear_fixmap(); } static inline bool use_1G_block(unsigned long addr, unsigned long next, @@ -251,22 +196,21 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next, return true; } -static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, +static void alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(void)) + void *(*alloc)(unsigned long size), bool force_pages) { pud_t *pud; unsigned long next; if (pgd_none(*pgd)) { - phys_addr_t pud_phys; - BUG_ON(!pgtable_alloc); - pud_phys = pgtable_alloc(); - __pgd_populate(pgd, pud_phys, PUD_TYPE_TABLE); + pud = alloc(PTRS_PER_PUD * sizeof(pud_t)); + pgd_populate(mm, pgd, pud); } BUG_ON(pgd_bad(*pgd)); - pud = pud_set_fixmap_offset(pgd, addr); + pud = pud_offset(pgd, addr); do { next = pud_addr_end(addr, end); @@ -274,10 +218,12 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, * For 4K granule only, attempt to put down a 1GB block */ if (use_1G_block(addr, next, phys) && - block_mappings_allowed(pgtable_alloc) && - !dma_overlap(phys, phys + next - addr)) { + !force_pages && + !dma_overlap(phys, phys + next - addr) && + !IS_ENABLED(CONFIG_FORCE_PAGES)) { pud_t old_pud = *pud; - pud_set_huge(pud, phys, prot); + set_pud(pud, __pud(phys | + pgprot_val(mk_sect_prot(prot)))); /* * If we have an old value for a pud, it will @@ -289,274 +235,359 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, if (!pud_none(old_pud)) { flush_tlb_all(); if (pud_table(old_pud)) { - phys_addr_t table = pud_page_paddr(old_pud); + phys_addr_t table = __pa(pmd_offset(&old_pud, 0)); if (!WARN_ON_ONCE(slab_is_available())) memblock_free(table, PAGE_SIZE); } } } else { - alloc_init_pmd(pud, addr, next, phys, prot, - pgtable_alloc); + alloc_init_pmd(mm, pud, addr, next, phys, prot, alloc, force_pages); } phys += next - addr; } while (pud++, addr = next, addr != end); - - pud_clear_fixmap(); } /* * Create the page directory entries and any necessary page tables for the * mapping specified by 'md'. */ -static void init_pgd(pgd_t *pgd, phys_addr_t phys, unsigned long virt, +static void __create_mapping(struct mm_struct *mm, pgd_t *pgd, + phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(void)) + void *(*alloc)(unsigned long size), bool force_pages) { unsigned long addr, length, end, next; - /* - * If the virtual and physical address don't have the same offset - * within a page, we cannot map the region as the caller expects. - */ - if (WARN_ON((phys ^ virt) & ~PAGE_MASK)) - return; - - phys &= PAGE_MASK; addr = virt & PAGE_MASK; length = PAGE_ALIGN(size + (virt & ~PAGE_MASK)); end = addr + length; do { next = pgd_addr_end(addr, end); - alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc); + alloc_init_pud(mm, pgd, addr, next, phys, prot, alloc, force_pages); phys += next - addr; } while (pgd++, addr = next, addr != end); } -static phys_addr_t late_pgtable_alloc(void) +static void *late_alloc(unsigned long size) { - void *ptr = (void *)__get_free_page(PGALLOC_GFP); - BUG_ON(!ptr); - - /* Ensure the zeroed page is visible to the page table walker */ - dsb(ishst); - return __pa(ptr); -} + void *ptr; -static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, - unsigned long virt, phys_addr_t size, - pgprot_t prot, - phys_addr_t (*alloc)(void)) -{ - init_pgd(pgd_offset_raw(pgdir, virt), phys, virt, size, prot, alloc); + BUG_ON(size > PAGE_SIZE); + ptr = (void *)__get_free_page(PGALLOC_GFP); + BUG_ON(!ptr); + return ptr; } -/* - * This function can only be used to modify existing table entries, - * without allocating new levels of table. Note that this permits the - * creation of new section or page entries. - */ -static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt, - phys_addr_t size, pgprot_t prot) +static void __init create_mapping(phys_addr_t phys, unsigned long virt, + phys_addr_t size, pgprot_t prot, bool force_pages) { if (virt < VMALLOC_START) { pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", &phys, virt); return; } - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, - NULL); + __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt, + size, prot, early_alloc, force_pages); } void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot) { - __create_pgd_mapping(mm->pgd, phys, virt, size, prot, - late_pgtable_alloc); + __create_mapping(mm, pgd_offset(mm, virt), phys, virt, size, prot, + late_alloc, false); } -static void create_mapping_late(phys_addr_t phys, unsigned long virt, - phys_addr_t size, pgprot_t prot) +static inline pmd_t *pmd_off_k(unsigned long virt) { - if (virt < VMALLOC_START) { - pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", - &phys, virt); - return; - } - - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, - late_pgtable_alloc); + return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt); } -static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end) +void __init remap_as_pages(unsigned long start, unsigned long size) { - unsigned long kernel_start = __pa(_stext); - unsigned long kernel_end = __pa(_etext); + unsigned long addr; + unsigned long end = start + size; /* - * Take care not to create a writable alias for the - * read-only text and rodata sections of the kernel image. + * Make start and end PMD_SIZE aligned, observing memory + * boundaries */ + if (memblock_is_memory(start & PMD_MASK)) + start = start & PMD_MASK; + if (memblock_is_memory(ALIGN(end, PMD_SIZE))) + end = ALIGN(end, PMD_SIZE); - /* No overlap with the kernel text */ - if (end < kernel_start || start >= kernel_end) { - __create_pgd_mapping(pgd, start, __phys_to_virt(start), - end - start, PAGE_KERNEL, - early_pgtable_alloc); - return; - } + size = end - start; /* - * This block overlaps the kernel text mapping. - * Map the portion(s) which don't overlap. + * Clear previous low-memory mapping */ - if (start < kernel_start) - __create_pgd_mapping(pgd, start, - __phys_to_virt(start), - kernel_start - start, PAGE_KERNEL, - early_pgtable_alloc); - if (kernel_end < end) - __create_pgd_mapping(pgd, kernel_end, - __phys_to_virt(kernel_end), - end - kernel_end, PAGE_KERNEL, - early_pgtable_alloc); + for (addr = __phys_to_virt(start); addr < __phys_to_virt(end); + addr += PMD_SIZE) { + pmd_t *pmd; + pmd = pmd_off_k(addr); + if (pmd_bad(*pmd) || pmd_sect(*pmd)) + pmd_clear(pmd); + } - /* - * Map the linear alias of the [_stext, _etext) interval as - * read-only/non-executable. This makes the contents of the - * region accessible to subsystems such as hibernate, but - * protects it from inadvertent modification or execution. - */ - __create_pgd_mapping(pgd, kernel_start, __phys_to_virt(kernel_start), - kernel_end - kernel_start, PAGE_KERNEL_RO, - early_pgtable_alloc); + create_mapping(start, __phys_to_virt(start), size, PAGE_KERNEL, true); } -static void __init map_mem(pgd_t *pgd) +struct dma_contig_early_reserve { + phys_addr_t base; + unsigned long size; +}; + +static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS] __initdata; + +static int dma_mmu_remap_num __initdata; + +void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { - struct memblock_region *reg; + dma_mmu_remap[dma_mmu_remap_num].base = base; + dma_mmu_remap[dma_mmu_remap_num].size = size; + dma_mmu_remap_num++; +} - /* map all the memory banks */ - for_each_memblock(memory, reg) { - phys_addr_t start = reg->base; - phys_addr_t end = start + reg->size; +static bool __init dma_overlap(phys_addr_t start, phys_addr_t end) +{ + int i; - if (start >= end) - break; + for (i = 0; i < dma_mmu_remap_num; i++) { + phys_addr_t dma_base = dma_mmu_remap[i].base; + phys_addr_t dma_end = dma_mmu_remap[i].base + + dma_mmu_remap[i].size; - __map_memblock(pgd, start, end); + if ((dma_base < end) && (dma_end > start)) + return true; } + return false; } -void mark_rodata_ro(void) +static void __init dma_contiguous_remap(void) { - if (!IS_ENABLED(CONFIG_DEBUG_RODATA)) + int i; + for (i = 0; i < dma_mmu_remap_num; i++) + remap_as_pages(dma_mmu_remap[i].base, + dma_mmu_remap[i].size); +} + +static void create_mapping_late(phys_addr_t phys, unsigned long virt, + phys_addr_t size, pgprot_t prot) +{ + if (virt < VMALLOC_START) { + pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", + &phys, virt); return; + } - create_mapping_late(__pa(_stext), (unsigned long)_stext, - (unsigned long)_etext - (unsigned long)_stext, - PAGE_KERNEL_ROX); + return __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), + phys, virt, size, prot, late_alloc, + IS_ENABLED(CONFIG_FORCE_PAGES)); } -void fixup_init(void) +#ifdef CONFIG_DEBUG_RODATA +static void __init __map_memblock(phys_addr_t start, phys_addr_t end) { /* - * Unmap the __init region but leave the VM area in place. This - * prevents the region from being reused for kernel modules, which - * is not supported by kallsyms. + * Set up the executable regions using the existing section mappings + * for now. This will get more fine grained later once all memory + * is mapped */ - unmap_kernel_range((u64)__init_begin, (u64)(__init_end - __init_begin)); + unsigned long kernel_x_start = round_down(__pa(_stext), SWAPPER_BLOCK_SIZE); + unsigned long kernel_x_end = round_up(__pa(__init_end), SWAPPER_BLOCK_SIZE); + + if (end < kernel_x_start) { + create_mapping(start, __phys_to_virt(start), + end - start, PAGE_KERNEL, false); + } else if (start >= kernel_x_end) { + create_mapping(start, __phys_to_virt(start), + end - start, PAGE_KERNEL, false); + } else { + if (start < kernel_x_start) + create_mapping(start, __phys_to_virt(start), + kernel_x_start - start, + PAGE_KERNEL, false); + create_mapping(kernel_x_start, + __phys_to_virt(kernel_x_start), + kernel_x_end - kernel_x_start, + PAGE_KERNEL_EXEC, false); + if (kernel_x_end < end) + create_mapping(kernel_x_end, + __phys_to_virt(kernel_x_end), + end - kernel_x_end, + PAGE_KERNEL, false); + } } +#else +static void __init __map_memblock(phys_addr_t start, phys_addr_t end) +{ + create_mapping(start, __phys_to_virt(start), end - start, + PAGE_KERNEL_EXEC, false); +} +#endif -static void __init map_kernel_chunk(pgd_t *pgd, void *va_start, void *va_end, - pgprot_t prot, struct vm_struct *vma) +static void __init map_mem(void) { - phys_addr_t pa_start = __pa(va_start); - unsigned long size = va_end - va_start; + struct memblock_region *reg; + phys_addr_t limit; - BUG_ON(!PAGE_ALIGNED(pa_start)); - BUG_ON(!PAGE_ALIGNED(size)); + /* + * Temporarily limit the memblock range. We need to do this as + * create_mapping requires puds, pmds and ptes to be allocated from + * memory addressable from the initial direct kernel mapping. + * + * The initial direct kernel mapping, located at swapper_pg_dir, gives + * us PUD_SIZE (with SECTION maps) or PMD_SIZE (without SECTION maps, + * memory starting from PHYS_OFFSET (which must be aligned to 2MB as + * per Documentation/arm64/booting.txt). + */ + limit = PHYS_OFFSET + SWAPPER_INIT_MAP_SIZE; + memblock_set_current_limit(limit); + + /* map all the memory banks */ + for_each_memblock(memory, reg) { + phys_addr_t start = reg->base; + phys_addr_t end = start + reg->size; - __create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot, - early_pgtable_alloc); + if (start >= end) + break; - vma->addr = va_start; - vma->phys_addr = pa_start; - vma->size = size; - vma->flags = VM_MAP; - vma->caller = __builtin_return_address(0); + if (ARM64_SWAPPER_USES_SECTION_MAPS) { + /* + * For the first memory bank align the start address and + * current memblock limit to prevent create_mapping() from + * allocating pte page tables from unmapped memory. With + * the section maps, if the first block doesn't end on section + * size boundary, create_mapping() will try to allocate a pte + * page, which may be returned from an unmapped area. + * When section maps are not used, the pte page table for the + * current limit is already present in swapper_pg_dir. + */ + if (start < limit) + start = ALIGN(start, SECTION_SIZE); + if (end < limit) { + limit = end & SECTION_MASK; + memblock_set_current_limit(limit); + } + } + __map_memblock(start, end); + } - vm_area_add_early(vma); + /* Limit no longer required. */ + memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE); } - -/* - * Create fine-grained mappings for the kernel. - */ -static void __init map_kernel(pgd_t *pgd) +#ifdef CONFIG_FORCE_PAGES +static noinline void __init split_and_set_pmd(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long pfn) { - static struct vm_struct vmlinux_text, vmlinux_init, vmlinux_data; + pte_t *pte, *start_pte; - map_kernel_chunk(pgd, _stext, _etext, PAGE_KERNEL_EXEC, &vmlinux_text); - map_kernel_chunk(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC, - &vmlinux_init); - map_kernel_chunk(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data); + start_pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t)); + pte = start_pte; - if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) { - /* - * The fixmap falls in a separate pgd to the kernel, and doesn't - * live in the carveout for the swapper_pg_dir. We can simply - * re-use the existing dir for the fixmap. - */ - set_pgd(pgd_offset_raw(pgd, FIXADDR_START), - *pgd_offset_k(FIXADDR_START)); - } else if (CONFIG_PGTABLE_LEVELS > 3) { - /* - * The fixmap shares its top level pgd entry with the kernel - * mapping. This can really only occur when we are running - * with 16k/4 levels, so we can simply reuse the pud level - * entry instead. - */ - BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); - set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START), - __pud(__pa(bm_pmd) | PUD_TYPE_TABLE)); - pud_clear_fixmap(); - } else { - BUG(); - } + do { + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); - kasan_copy_shadow(pgd); + set_pmd(pmd, __pmd((__pa(start_pte)) | PMD_TYPE_TABLE)); } -struct dma_contig_early_reserve { - phys_addr_t base; - unsigned long size; -}; +static noinline void __init remap_pages(void) +{ + struct memblock_region *reg; -static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS]; + for_each_memblock(memory, reg) { + phys_addr_t phys_pgd = reg->base; + phys_addr_t phys_end = reg->base + reg->size; + unsigned long addr_pgd = (unsigned long)__va(phys_pgd); + unsigned long end = (unsigned long)__va(phys_end); + pmd_t *pmd = NULL; + pud_t *pud = NULL; + pgd_t *pgd = NULL; + unsigned long next_pud, next_pmd, next_pgd; + unsigned long addr_pmd, addr_pud; + phys_addr_t phys_pud, phys_pmd; + + if (phys_pgd >= phys_end) + break; -static int dma_mmu_remap_num; + pgd = pgd_offset(&init_mm, addr_pgd); + do { + next_pgd = pgd_addr_end(addr_pgd, end); + pud = pud_offset(pgd, addr_pgd); + addr_pud = addr_pgd; + phys_pud = phys_pgd; + do { + next_pud = pud_addr_end(addr_pud, next_pgd); + pmd = pmd_offset(pud, addr_pud); + addr_pmd = addr_pud; + phys_pmd = phys_pud; + do { + next_pmd = pmd_addr_end(addr_pmd, + next_pud); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + split_and_set_pmd(pmd, addr_pmd, + next_pmd, __phys_to_pfn(phys_pmd)); + pmd++; + phys_pmd += next_pmd - addr_pmd; + } while (addr_pmd = next_pmd, + addr_pmd < next_pud); + phys_pud += next_pud - addr_pud; + } while (pud++, addr_pud = next_pud, + addr_pud < next_pgd); + phys_pgd += next_pgd - addr_pgd; + } while (pgd++, addr_pgd = next_pgd, addr_pgd < end); + } +} -void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) +#else +static void __init remap_pages(void) { - dma_mmu_remap[dma_mmu_remap_num].base = base; - dma_mmu_remap[dma_mmu_remap_num].size = size; - dma_mmu_remap_num++; + } +#endif -static bool dma_overlap(phys_addr_t start, phys_addr_t end) +static void __init fixup_executable(void) { - int i; +#ifdef CONFIG_DEBUG_RODATA + /* now that we are actually fully mapped, make the start/end more fine grained */ + if (!IS_ALIGNED((unsigned long)_stext, SWAPPER_BLOCK_SIZE)) { + unsigned long aligned_start = round_down(__pa(_stext), + SWAPPER_BLOCK_SIZE); - for (i = 0; i < dma_mmu_remap_num; i++) { - phys_addr_t dma_base = dma_mmu_remap[i].base; - phys_addr_t dma_end = dma_mmu_remap[i].base + - dma_mmu_remap[i].size; + create_mapping(aligned_start, __phys_to_virt(aligned_start), + __pa(_stext) - aligned_start, + PAGE_KERNEL, false); + } - if ((dma_base < end) && (dma_end > start)) - return true; + if (!IS_ALIGNED((unsigned long)__init_end, SWAPPER_BLOCK_SIZE)) { + unsigned long aligned_end = round_up(__pa(__init_end), + SWAPPER_BLOCK_SIZE); + create_mapping(__pa(__init_end), (unsigned long)__init_end, + aligned_end - __pa(__init_end), + PAGE_KERNEL, false); } - return false; +#endif +} + +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void) +{ + create_mapping_late(__pa(_stext), (unsigned long)_stext, + (unsigned long)_etext - (unsigned long)_stext, + PAGE_KERNEL_ROX); + +} +#endif + +void fixup_init(void) +{ + create_mapping_late(__pa(__init_begin), (unsigned long)__init_begin, + (unsigned long)__init_end - (unsigned long)__init_begin, + PAGE_KERNEL); } /* @@ -565,35 +596,39 @@ static bool dma_overlap(phys_addr_t start, phys_addr_t end) */ void __init paging_init(void) { - phys_addr_t pgd_phys = early_pgtable_alloc(); - pgd_t *pgd = pgd_set_fixmap(pgd_phys); + void *zero_page; - map_kernel(pgd); - map_mem(pgd); + map_mem(); + fixup_executable(); + dma_contiguous_remap(); + remap_pages(); /* - * We want to reuse the original swapper_pg_dir so we don't have to - * communicate the new address to non-coherent secondaries in - * secondary_entry, and so cpu_switch_mm can generate the address with - * adrp+add rather than a load from some global variable. - * - * To do this we need to go via a temporary pgd. + * Finally flush the caches and tlb to ensure that we're in a + * consistent state. */ - cpu_replace_ttbr1(__va(pgd_phys)); - memcpy(swapper_pg_dir, pgd, PAGE_SIZE); - cpu_replace_ttbr1(swapper_pg_dir); + flush_tlb_all(); + + /* allocate the zero page. */ + zero_page = early_alloc(PAGE_SIZE); - pgd_clear_fixmap(); - memblock_free(pgd_phys, PAGE_SIZE); + bootmem_init(); + + empty_zero_page = virt_to_page(zero_page); + + /* Ensure the zero page is visible to the page table walker */ + dsb(ishst); /* - * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd - * allocated with it. + * TTBR0 is only used for the identity mapping at this stage. Make it + * point to zero page to avoid speculatively fetching new entries. */ - memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE, - SWAPPER_DIR_SIZE - PAGE_SIZE); - - bootmem_init(); + cpu_set_reserved_ttbr0(); + local_flush_tlb_all(); + cpu_set_default_tcr_t0sz(); + flush_tlb_all(); + set_kernel_text_ro(); + flush_tlb_all(); } /* @@ -680,13 +715,21 @@ void vmemmap_free(unsigned long start, unsigned long end) } #endif /* CONFIG_SPARSEMEM_VMEMMAP */ +static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; +#if CONFIG_PGTABLE_LEVELS > 2 +static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss; +#endif +#if CONFIG_PGTABLE_LEVELS > 3 +static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss; +#endif + static inline pud_t * fixmap_pud(unsigned long addr) { pgd_t *pgd = pgd_offset_k(addr); BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd)); - return pud_offset_kimg(pgd, addr); + return pud_offset(pgd, addr); } static inline pmd_t * fixmap_pmd(unsigned long addr) @@ -695,12 +738,16 @@ static inline pmd_t * fixmap_pmd(unsigned long addr) BUG_ON(pud_none(*pud) || pud_bad(*pud)); - return pmd_offset_kimg(pud, addr); + return pmd_offset(pud, addr); } static inline pte_t * fixmap_pte(unsigned long addr) { - return &bm_pte[pte_index(addr)]; + pmd_t *pmd = fixmap_pmd(addr); + + BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd)); + + return pte_offset_kernel(pmd, addr); } void __init early_fixmap_init(void) @@ -711,26 +758,15 @@ void __init early_fixmap_init(void) unsigned long addr = FIXADDR_START; pgd = pgd_offset_k(addr); - if (CONFIG_PGTABLE_LEVELS > 3 && - !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa(bm_pud))) { - /* - * We only end up here if the kernel mapping and the fixmap - * share the top level pgd entry, which should only happen on - * 16k/4 levels configurations. - */ - BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); - pud = pud_offset_kimg(pgd, addr); - } else { - pgd_populate(&init_mm, pgd, bm_pud); - pud = fixmap_pud(addr); - } + pgd_populate(&init_mm, pgd, bm_pud); + pud = pud_offset(pgd, addr); pud_populate(&init_mm, pud, bm_pmd); - pmd = fixmap_pmd(addr); + pmd = pmd_offset(pud, addr); pmd_populate_kernel(&init_mm, pmd, bm_pte); /* * The boot-ioremap range spans multiple pmds, for which - * we are not prepared: + * we are not preparted: */ BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT) != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT)); @@ -769,10 +805,11 @@ void __set_fixmap(enum fixed_addresses idx, } } -void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot) +void *__init fixmap_remap_fdt(phys_addr_t dt_phys) { const u64 dt_virt_base = __fix_to_virt(FIX_FDT); - int offset; + pgprot_t prot = PAGE_KERNEL_RO; + int size, offset; void *dt_virt; /* @@ -789,7 +826,7 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot) /* * Make sure that the FDT region can be mapped without the need to * allocate additional translation table pages, so that it is safe - * to call create_mapping_noalloc() this early. + * to call create_mapping() this early. * * On 64k pages, the FDT will be mapped using PTEs, so we need to * be in the same PMD as the rest of the fixmap. @@ -805,73 +842,21 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot) dt_virt = (void *)dt_virt_base + offset; /* map the first chunk so we can read the size from the header */ - create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), - dt_virt_base, SWAPPER_BLOCK_SIZE, prot); + create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base, + SWAPPER_BLOCK_SIZE, prot, false); if (fdt_check_header(dt_virt) != 0) return NULL; - *size = fdt_totalsize(dt_virt); - if (*size > MAX_FDT_SIZE) + size = fdt_totalsize(dt_virt); + if (size > MAX_FDT_SIZE) return NULL; - if (offset + *size > SWAPPER_BLOCK_SIZE) - create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base, - round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot); - - return dt_virt; -} - -void *__init fixmap_remap_fdt(phys_addr_t dt_phys) -{ - void *dt_virt; - int size; - - dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO); - if (!dt_virt) - return NULL; + if (offset + size > SWAPPER_BLOCK_SIZE) + create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base, + round_up(offset + size, SWAPPER_BLOCK_SIZE), prot, false); memblock_reserve(dt_phys, size); - return dt_virt; -} - -int __init arch_ioremap_pud_supported(void) -{ - /* only 4k granule supports level 1 block mappings */ - return IS_ENABLED(CONFIG_ARM64_4K_PAGES); -} - -int __init arch_ioremap_pmd_supported(void) -{ - return 1; -} - -int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) -{ - BUG_ON(phys & ~PUD_MASK); - set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot)))); - return 1; -} - -int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) -{ - BUG_ON(phys & ~PMD_MASK); - set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot)))); - return 1; -} -int pud_clear_huge(pud_t *pud) -{ - if (!pud_sect(*pud)) - return 0; - pud_clear(pud); - return 1; -} - -int pmd_clear_huge(pmd_t *pmd) -{ - if (!pmd_sect(*pmd)) - return 0; - pmd_clear(pmd); - return 1; + return dt_virt; } diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 4754762bde49..0f35e8ba0f33 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -14,7 +14,6 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/sched.h> -#include <linux/vmalloc.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -37,32 +36,14 @@ static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr, return 0; } -/* - * This function assumes that the range is mapped with PAGE_SIZE pages. - */ -static int __change_memory_common(unsigned long start, unsigned long size, - pgprot_t set_mask, pgprot_t clear_mask) -{ - struct page_change_data data; - int ret; - - data.set_mask = set_mask; - data.clear_mask = clear_mask; - - ret = apply_to_page_range(&init_mm, start, size, change_page_range, - &data); - - flush_tlb_kernel_range(start, start + size); - return ret; -} - static int change_memory_common(unsigned long addr, int numpages, pgprot_t set_mask, pgprot_t clear_mask) { unsigned long start = addr; unsigned long size = PAGE_SIZE*numpages; unsigned long end = start + size; - struct vm_struct *area; + int ret; + struct page_change_data data; if (!PAGE_ALIGNED(addr)) { start &= PAGE_MASK; @@ -77,29 +58,18 @@ static int change_memory_common(unsigned long addr, int numpages, if (end < MODULES_VADDR || end >= MODULES_END) return -EINVAL; } - /* - * Kernel VA mappings are always live, and splitting live section - * mappings into page mappings may cause TLB conflicts. This means - * we have to ensure that changing the permission bits of the range - * we are operating on does not result in such splitting. - * - * Let's restrict ourselves to mappings created by vmalloc (or vmap). - * Those are guaranteed to consist entirely of page mappings, and - * splitting is never needed. - * - * So check whether the [addr, addr + size) interval is entirely - * covered by precisely one VM area that has the VM_ALLOC flag set. - */ - area = find_vm_area((void *)addr); - if (!area || - end > (unsigned long)area->addr + area->size || - !(area->flags & VM_ALLOC)) - return -EINVAL; if (!numpages) return 0; - return __change_memory_common(start, size, set_mask, clear_mask); + data.set_mask = set_mask; + data.clear_mask = clear_mask; + + ret = apply_to_page_range(&init_mm, start, size, change_page_range, + &data); + + flush_tlb_kernel_range(start, end); + return ret; } int set_memory_ro(unsigned long addr, int numpages) @@ -131,19 +101,3 @@ int set_memory_x(unsigned long addr, int numpages) __pgprot(PTE_PXN)); } EXPORT_SYMBOL_GPL(set_memory_x); - -#ifdef CONFIG_DEBUG_PAGEALLOC -void __kernel_map_pages(struct page *page, int numpages, int enable) -{ - unsigned long addr = (unsigned long) page_address(page); - - if (enable) - __change_memory_common(addr, PAGE_SIZE * numpages, - __pgprot(PTE_VALID), - __pgprot(0)); - else - __change_memory_common(addr, PAGE_SIZE * numpages, - __pgprot(0), - __pgprot(PTE_VALID)); -} -#endif diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c index ae11d4e03d0e..cb3ba1b812e7 100644 --- a/arch/arm64/mm/pgd.c +++ b/arch/arm64/mm/pgd.c @@ -46,14 +46,14 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd) kmem_cache_free(pgd_cache, pgd); } -void __init pgd_cache_init(void) +static int __init pgd_cache_init(void) { - if (PGD_SIZE == PAGE_SIZE) - return; - /* * Naturally aligned pgds required by the architecture. */ - pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE, - SLAB_PANIC, NULL); + if (PGD_SIZE != PAGE_SIZE) + pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE, + SLAB_PANIC, NULL); + return 0; } +core_initcall(pgd_cache_init); diff --git a/arch/arm64/mm/proc-macros.S b/arch/arm64/mm/proc-macros.S index 984edcda1850..d69dffffaa89 100644 --- a/arch/arm64/mm/proc-macros.S +++ b/arch/arm64/mm/proc-macros.S @@ -74,25 +74,3 @@ msr pmuserenr_el0, xzr // Disable PMU access from EL0 9000: .endm - -/* - * Macro to perform a data cache maintenance for the interval - * [kaddr, kaddr + size) - * - * op: operation passed to dc instruction - * domain: domain used in dsb instruciton - * kaddr: starting virtual address of the region - * size: size of the region - * Corrupts: kaddr, size, tmp1, tmp2 - */ - .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2 - dcache_line_size \tmp1, \tmp2 - add \size, \kaddr, \size - sub \tmp2, \tmp1, #1 - bic \kaddr, \kaddr, \tmp2 -9998: dc \op, \kaddr - add \kaddr, \kaddr, \tmp1 - cmp \kaddr, \size - b.lo 9998b - dsb \domain - .endm diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index dc22de0ce413..cd8853e11f2a 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -186,33 +186,7 @@ ENTRY(cpu_do_switch_mm) ret ENDPROC(cpu_do_switch_mm) - .pushsection ".idmap.text", "ax" -/* - * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd) - * - * This is the low-level counterpart to cpu_replace_ttbr1, and should not be - * called by anything else. It can only be executed from a TTBR0 mapping. - */ -ENTRY(idmap_cpu_replace_ttbr1) - mrs x2, daif - msr daifset, #0xf - - adrp x1, empty_zero_page - msr ttbr1_el1, x1 - isb - - tlbi vmalle1 - dsb nsh - isb - - msr ttbr1_el1, x0 - isb - - msr daif, x2 - - ret -ENDPROC(idmap_cpu_replace_ttbr1) - .popsection + .section ".text.init", #alloc, #execinstr /* * __cpu_setup diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index d2256fa97ea0..729f89163bc3 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -11,7 +11,6 @@ config PARISC select RTC_DRV_GENERIC select INIT_ALL_POSSIBLE select BUG - select BUILDTIME_EXTABLE_SORT select HAVE_PERF_EVENTS select GENERIC_ATOMIC64 if !64BIT select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h index 60e6f07b7e32..b3069fd83468 100644 --- a/arch/parisc/include/asm/assembly.h +++ b/arch/parisc/include/asm/assembly.h @@ -523,7 +523,7 @@ */ #define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr) \ .section __ex_table,"aw" ! \ - .word (fault_addr - .), (except_addr - .) ! \ + ASM_ULONG_INSN fault_addr, except_addr ! \ .previous diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 6f893d29f1b2..1960b87c1c8b 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -60,15 +60,14 @@ static inline long access_ok(int type, const void __user * addr, * use a 32bit (unsigned int) address here. */ -#define ARCH_HAS_RELATIVE_EXTABLE struct exception_table_entry { - int insn; /* relative address of insn that is allowed to fault. */ - int fixup; /* relative address of fixup routine */ + unsigned long insn; /* address of insn that is allowed to fault. */ + unsigned long fixup; /* fixup routine */ }; #define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ ".section __ex_table,\"aw\"\n" \ - ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ + ASM_WORD_INSN #fault_addr ", " #except_addr "\n\t" \ ".previous\n" /* diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 16dbe81c97c9..f9064449908a 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -140,6 +140,12 @@ int fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *fix; + /* If we only stored 32bit addresses in the exception table we can drop + * out if we faulted on a 64bit address. */ + if ((sizeof(regs->iaoq[0]) > sizeof(fix->insn)) + && (regs->iaoq[0] >> 32)) + return 0; + fix = search_exception_tables(regs->iaoq[0]); if (fix) { struct exception_data *d; @@ -149,8 +155,7 @@ int fixup_exception(struct pt_regs *regs) d->fault_space = regs->isr; d->fault_addr = regs->ior; - regs->iaoq[0] = (unsigned long)&fix->fixup + fix->fixup; - regs->iaoq[0] &= ~3; + regs->iaoq[0] = ((fix->fixup) & ~3); /* * NOTE: In some cases the faulting instruction * may be in the delay slot of a branch. We diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h index 4afe66aa1400..e4396a7d0f7c 100644 --- a/arch/powerpc/include/asm/word-at-a-time.h +++ b/arch/powerpc/include/asm/word-at-a-time.h @@ -82,7 +82,7 @@ static inline unsigned long create_zero_mask(unsigned long bits) "andc %1,%1,%2\n\t" "popcntd %0,%1" : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask) - : "b" (bits)); + : "r" (bits)); return leading_zero_bits; } diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h index 2734c005da21..43686043e297 100644 --- a/arch/powerpc/include/uapi/asm/cputable.h +++ b/arch/powerpc/include/uapi/asm/cputable.h @@ -31,7 +31,6 @@ #define PPC_FEATURE_PSERIES_PERFMON_COMPAT \ 0x00000040 -/* Reserved - do not use 0x00000004 */ #define PPC_FEATURE_TRUE_LE 0x00000002 #define PPC_FEATURE_PPC_LE 0x00000001 diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 646bf4d222c1..ef2ad2d682da 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -569,6 +569,24 @@ static void tm_reclaim_thread(struct thread_struct *thr, if (!MSR_TM_SUSPENDED(mfmsr())) return; + /* + * Use the current MSR TM suspended bit to track if we have + * checkpointed state outstanding. + * On signal delivery, we'd normally reclaim the checkpointed + * state to obtain stack pointer (see:get_tm_stackpointer()). + * This will then directly return to userspace without going + * through __switch_to(). However, if the stack frame is bad, + * we need to exit this thread which calls __switch_to() which + * will again attempt to reclaim the already saved tm state. + * Hence we need to check that we've not already reclaimed + * this state. + * We do this using the current MSR, rather tracking it in + * some specific thread_struct bit, as it has the additional + * benifit of checking for a potential TM bad thing exception. + */ + if (!MSR_TM_SUSPENDED(mfmsr())) + return; + tm_reclaim(thr, thr->regs->msr, cause); /* Having done the reclaim, we now have the checkpointed diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index a15fe1d4e84a..7030b035905d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -148,25 +148,23 @@ static struct ibm_pa_feature { unsigned long cpu_features; /* CPU_FTR_xxx bit */ unsigned long mmu_features; /* MMU_FTR_xxx bit */ unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ - unsigned int cpu_user_ftrs2; /* PPC_FEATURE2_xxx bit */ unsigned char pabyte; /* byte number in ibm,pa-features */ unsigned char pabit; /* bit number (big-endian) */ unsigned char invert; /* if 1, pa bit set => clear feature */ } ibm_pa_features[] __initdata = { - {0, 0, PPC_FEATURE_HAS_MMU, 0, 0, 0, 0}, - {0, 0, PPC_FEATURE_HAS_FPU, 0, 0, 1, 0}, - {CPU_FTR_CTRL, 0, 0, 0, 0, 3, 0}, - {CPU_FTR_NOEXECUTE, 0, 0, 0, 0, 6, 0}, - {CPU_FTR_NODSISRALIGN, 0, 0, 0, 1, 1, 1}, - {0, MMU_FTR_CI_LARGE_PAGE, 0, 0, 1, 2, 0}, - {CPU_FTR_REAL_LE, 0, PPC_FEATURE_TRUE_LE, 0, 5, 0, 0}, + {0, 0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, + {0, 0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, + {CPU_FTR_CTRL, 0, 0, 0, 3, 0}, + {CPU_FTR_NOEXECUTE, 0, 0, 0, 6, 0}, + {CPU_FTR_NODSISRALIGN, 0, 0, 1, 1, 1}, + {0, MMU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, + {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, /* - * If the kernel doesn't support TM (ie CONFIG_PPC_TRANSACTIONAL_MEM=n), - * we don't want to turn on TM here, so we use the *_COMP versions - * which are 0 if the kernel doesn't support TM. + * If the kernel doesn't support TM (ie. CONFIG_PPC_TRANSACTIONAL_MEM=n), + * we don't want to turn on CPU_FTR_TM here, so we use CPU_FTR_TM_COMP + * which is 0 if the kernel doesn't support TM. */ - {CPU_FTR_TM_COMP, 0, 0, - PPC_FEATURE2_HTM_COMP|PPC_FEATURE2_HTM_NOSC_COMP, 22, 0, 0}, + {CPU_FTR_TM_COMP, 0, 0, 22, 0, 0}, }; static void __init scan_features(unsigned long node, const unsigned char *ftrs, @@ -197,12 +195,10 @@ static void __init scan_features(unsigned long node, const unsigned char *ftrs, if (bit ^ fp->invert) { cur_cpu_spec->cpu_features |= fp->cpu_features; cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; - cur_cpu_spec->cpu_user_features2 |= fp->cpu_user_ftrs2; cur_cpu_spec->mmu_features |= fp->mmu_features; } else { cur_cpu_spec->cpu_features &= ~fp->cpu_features; cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; - cur_cpu_spec->cpu_user_features2 &= ~fp->cpu_user_ftrs2; cur_cpu_spec->mmu_features &= ~fp->mmu_features; } } diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 081b2ad99d73..d29ad9545b41 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -11,7 +11,7 @@ typedef struct { spinlock_t list_lock; struct list_head pgtable_list; struct list_head gmap_list; - unsigned long asce; + unsigned long asce_bits; unsigned long asce_limit; unsigned long vdso_base; /* The mmu context allocates 4K page tables. */ diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 22877c9440ea..e485817f7b1a 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -26,28 +26,12 @@ static inline int init_new_context(struct task_struct *tsk, mm->context.has_pgste = 0; mm->context.use_skey = 0; #endif - switch (mm->context.asce_limit) { - case 1UL << 42: - /* - * forked 3-level task, fall through to set new asce with new - * mm->pgd - */ - case 0: + if (mm->context.asce_limit == 0) { /* context created by exec, set asce limit to 4TB */ + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | _ASCE_TYPE_REGION3; mm->context.asce_limit = STACK_TOP_MAX; - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_REGION3; - break; - case 1UL << 53: - /* forked 4-level task, set new asce with new mm->pgd */ - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_REGION2; - break; - case 1UL << 31: - /* forked 2-level compat task, set new asce with new mm->pgd */ - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; - /* pgd_alloc() did not increase mm->nr_pmds */ + } else if (mm->context.asce_limit == (1UL << 31)) { mm_inc_nr_pmds(mm); } crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); @@ -58,7 +42,7 @@ static inline int init_new_context(struct task_struct *tsk, static inline void set_user_asce(struct mm_struct *mm) { - S390_lowcore.user_asce = mm->context.asce; + S390_lowcore.user_asce = mm->context.asce_bits | __pa(mm->pgd); if (current->thread.mm_segment.ar4) __ctl_load(S390_lowcore.user_asce, 7, 7); set_cpu_flag(CIF_ASCE); @@ -87,7 +71,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, { int cpu = smp_processor_id(); - S390_lowcore.user_asce = next->context.asce; + S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd); if (prev == next) return; if (MACHINE_HAS_TLB_LC) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 6dafabb6ae1a..2b2ced9dc00a 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -45,8 +45,7 @@ struct zpci_fmb { u64 rpcit_ops; u64 dma_rbytes; u64 dma_wbytes; - u64 pad[2]; -} __packed __aligned(128); +} __packed __aligned(64); enum zpci_state { ZPCI_FN_STATE_RESERVED, diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 5991cdcb5b40..d7cc79fb6191 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -56,8 +56,8 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) return _REGION2_ENTRY_EMPTY; } -int crst_table_upgrade(struct mm_struct *); -void crst_table_downgrade(struct mm_struct *); +int crst_table_upgrade(struct mm_struct *, unsigned long limit); +void crst_table_downgrade(struct mm_struct *, unsigned long limit); static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) { diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index c1ea67db8404..b16c3d0a1b9f 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -163,7 +163,7 @@ extern __vector128 init_task_fpu_regs[__NUM_VXRS]; regs->psw.mask = PSW_USER_BITS | PSW_MASK_BA; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ regs->gprs[15] = new_stackp; \ - crst_table_downgrade(current->mm); \ + crst_table_downgrade(current->mm, 1UL << 31); \ execve_tail(); \ } while (0) diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index a2e6ef32e054..ca148f7c3eaa 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -110,7 +110,8 @@ static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce) static inline void __tlb_flush_kernel(void) { if (MACHINE_HAS_IDTE) - __tlb_flush_idte(init_mm.context.asce); + __tlb_flush_idte((unsigned long) init_mm.pgd | + init_mm.context.asce_bits); else __tlb_flush_global(); } @@ -132,7 +133,8 @@ static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce) static inline void __tlb_flush_kernel(void) { if (MACHINE_HAS_TLB_LC) - __tlb_flush_idte_local(init_mm.context.asce); + __tlb_flush_idte_local((unsigned long) init_mm.pgd | + init_mm.context.asce_bits); else __tlb_flush_local(); } @@ -146,7 +148,8 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) * only ran on the local cpu. */ if (MACHINE_HAS_IDTE && list_empty(&mm->context.gmap_list)) - __tlb_flush_asce(mm, mm->context.asce); + __tlb_flush_asce(mm, (unsigned long) mm->pgd | + mm->context.asce_bits); else __tlb_flush_full(mm); } diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index feff9caf89b5..c722400c7697 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -89,8 +89,7 @@ void __init paging_init(void) asce_bits = _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; pgd_type = _REGION3_ENTRY_EMPTY; } - init_mm.context.asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits; - S390_lowcore.kernel_asce = init_mm.context.asce; + S390_lowcore.kernel_asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits; clear_table((unsigned long *) init_mm.pgd, pgd_type, sizeof(unsigned long)*2048); vmem_map_init(); diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index f2b6b1d9c804..ea01477b4aa6 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -174,7 +174,7 @@ int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) if (!(flags & MAP_FIXED)) addr = 0; if ((addr + len) >= TASK_SIZE) - return crst_table_upgrade(current->mm); + return crst_table_upgrade(current->mm, 1UL << 53); return 0; } @@ -191,7 +191,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr, return area; if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) { /* Upgrade the page table to 4 levels and retry. */ - rc = crst_table_upgrade(mm); + rc = crst_table_upgrade(mm, 1UL << 53); if (rc) return (unsigned long) rc; area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); @@ -213,7 +213,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, return area; if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) { /* Upgrade the page table to 4 levels and retry. */ - rc = crst_table_upgrade(mm); + rc = crst_table_upgrade(mm, 1UL << 53); if (rc) return (unsigned long) rc; area = arch_get_unmapped_area_topdown(filp, addr, len, diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 471a370a527b..54ef3bc01b43 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -49,52 +49,81 @@ static void __crst_table_upgrade(void *arg) __tlb_flush_local(); } -int crst_table_upgrade(struct mm_struct *mm) +int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) { unsigned long *table, *pgd; + unsigned long entry; + int flush; - /* upgrade should only happen from 3 to 4 levels */ - BUG_ON(mm->context.asce_limit != (1UL << 42)); - + BUG_ON(limit > (1UL << 53)); + flush = 0; +repeat: table = crst_table_alloc(mm); if (!table) return -ENOMEM; - spin_lock_bh(&mm->page_table_lock); - pgd = (unsigned long *) mm->pgd; - crst_table_init(table, _REGION2_ENTRY_EMPTY); - pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd); - mm->pgd = (pgd_t *) table; - mm->context.asce_limit = 1UL << 53; - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_REGION2; - mm->task_size = mm->context.asce_limit; + if (mm->context.asce_limit < limit) { + pgd = (unsigned long *) mm->pgd; + if (mm->context.asce_limit <= (1UL << 31)) { + entry = _REGION3_ENTRY_EMPTY; + mm->context.asce_limit = 1UL << 42; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_REGION3; + } else { + entry = _REGION2_ENTRY_EMPTY; + mm->context.asce_limit = 1UL << 53; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_REGION2; + } + crst_table_init(table, entry); + pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd); + mm->pgd = (pgd_t *) table; + mm->task_size = mm->context.asce_limit; + table = NULL; + flush = 1; + } spin_unlock_bh(&mm->page_table_lock); - - on_each_cpu(__crst_table_upgrade, mm, 0); + if (table) + crst_table_free(mm, table); + if (mm->context.asce_limit < limit) + goto repeat; + if (flush) + on_each_cpu(__crst_table_upgrade, mm, 0); return 0; } -void crst_table_downgrade(struct mm_struct *mm) +void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) { pgd_t *pgd; - /* downgrade should only happen from 3 to 2 levels (compat only) */ - BUG_ON(mm->context.asce_limit != (1UL << 42)); - if (current->active_mm == mm) { clear_user_asce(); __tlb_flush_mm(mm); } - - pgd = mm->pgd; - mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN); - mm->context.asce_limit = 1UL << 31; - mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; - mm->task_size = mm->context.asce_limit; - crst_table_free(mm, (unsigned long *) pgd); - + while (mm->context.asce_limit > limit) { + pgd = mm->pgd; + switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { + case _REGION_ENTRY_TYPE_R2: + mm->context.asce_limit = 1UL << 42; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_REGION3; + break; + case _REGION_ENTRY_TYPE_R3: + mm->context.asce_limit = 1UL << 31; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_SEGMENT; + break; + default: + BUG(); + } + mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN); + mm->task_size = mm->context.asce_limit; + crst_table_free(mm, (unsigned long *) pgd); + } if (current->active_mm == mm) set_user_asce(mm); } diff --git a/arch/x86/crypto/sha-mb/sha1_mb.c b/arch/x86/crypto/sha-mb/sha1_mb.c index 8381c09d2870..a841e9765bd6 100644 --- a/arch/x86/crypto/sha-mb/sha1_mb.c +++ b/arch/x86/crypto/sha-mb/sha1_mb.c @@ -453,10 +453,10 @@ static int sha_complete_job(struct mcryptd_hash_request_ctx *rctx, req = cast_mcryptd_ctx_to_req(req_ctx); if (irqs_disabled()) - req_ctx->complete(&req->base, ret); + rctx->complete(&req->base, ret); else { local_bh_disable(); - req_ctx->complete(&req->base, ret); + rctx->complete(&req->base, ret); local_bh_enable(); } } diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 08b1f2f6ea50..0010c78c4998 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -25,8 +25,6 @@ #define EFI32_LOADER_SIGNATURE "EL32" #define EFI64_LOADER_SIGNATURE "EL64" -#define MAX_CMDLINE_ADDRESS UINT_MAX - #ifdef CONFIG_X86_32 diff --git a/arch/x86/include/asm/hugetlb.h b/arch/x86/include/asm/hugetlb.h index e6a8613fbfb0..f8a29d2c97b0 100644 --- a/arch/x86/include/asm/hugetlb.h +++ b/arch/x86/include/asm/hugetlb.h @@ -4,7 +4,6 @@ #include <asm/page.h> #include <asm-generic/hugetlb.h> -#define hugepages_supported() cpu_has_pse static inline int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index df6b4eeac0bd..7af2505f20c2 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -254,8 +254,7 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) struct irq_desc *desc; int cpu, vector; - if (!data->cfg.vector) - return; + BUG_ON(!data->cfg.vector); vector = data->cfg.vector; for_each_cpu_and(cpu, data->domain, cpu_online_mask) diff --git a/arch/x86/kernel/cpu/mcheck/mce-genpool.c b/arch/x86/kernel/cpu/mcheck/mce-genpool.c index 2658e2af74ec..0a850100c594 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-genpool.c +++ b/arch/x86/kernel/cpu/mcheck/mce-genpool.c @@ -29,7 +29,7 @@ static char gen_pool_buf[MCE_POOLSZ]; void mce_gen_pool_process(void) { struct llist_node *head; - struct mce_evt_llist *node, *tmp; + struct mce_evt_llist *node; struct mce *mce; head = llist_del_all(&mce_event_llist); @@ -37,7 +37,7 @@ void mce_gen_pool_process(void) return; head = llist_reverse_order(head); - llist_for_each_entry_safe(node, tmp, head, llnode) { + llist_for_each_entry(node, head, llnode) { mce = &node->mce; atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce); gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node)); diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 05538582a809..2c5aaf8c2e2f 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -385,9 +385,6 @@ static void intel_thermal_interrupt(void) { __u64 msr_val; - if (static_cpu_has(X86_FEATURE_HWP)) - wrmsrl_safe(MSR_HWP_STATUS, 0); - rdmsrl(MSR_IA32_THERM_STATUS, msr_val); /* Check for violation of core thermal thresholds*/ diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c index 5da924bbf0a0..b285d4e8c68e 100644 --- a/arch/x86/kernel/sysfb_efi.c +++ b/arch/x86/kernel/sysfb_efi.c @@ -106,24 +106,14 @@ static int __init efifb_set_system(const struct dmi_system_id *id) continue; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { resource_size_t start, end; - unsigned long flags; - - flags = pci_resource_flags(dev, i); - if (!(flags & IORESOURCE_MEM)) - continue; - - if (flags & IORESOURCE_UNSET) - continue; - - if (pci_resource_len(dev, i) == 0) - continue; start = pci_resource_start(dev, i); + if (start == 0) + break; end = pci_resource_end(dev, i); if (screen_info.lfb_base >= start && screen_info.lfb_base < end) { found_bar = 1; - break; } } } diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 6aa0f4d9eea6..92ae6acac8a7 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -92,7 +92,7 @@ unsigned long try_msr_calibrate_tsc(void) if (freq_desc_tables[cpu_index].msr_plat) { rdmsr(MSR_PLATFORM_INFO, lo, hi); - ratio = (lo >> 8) & 0xff; + ratio = (lo >> 8) & 0x1f; } else { rdmsr(MSR_IA32_PERF_STATUS, lo, hi); ratio = (hi >> 8) & 0x1f; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 605cea75eb0d..7eb4ebd3ebea 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -697,6 +697,7 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) if ((xcr0 & XFEATURE_MASK_AVX512) != XFEATURE_MASK_AVX512) return 1; } + kvm_put_guest_xcr0(vcpu); vcpu->arch.xcr0 = xcr0; if ((xcr0 ^ old_xcr0) & XFEATURE_MASK_EXTEND) @@ -6494,6 +6495,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) kvm_x86_ops->prepare_guest_switch(vcpu); if (vcpu->fpu_active) kvm_load_guest_fpu(vcpu); + kvm_load_guest_xcr0(vcpu); + vcpu->mode = IN_GUEST_MODE; srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); @@ -6516,8 +6519,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto cancel_injection; } - kvm_load_guest_xcr0(vcpu); - if (req_immediate_exit) smp_send_reschedule(vcpu->cpu); @@ -6567,8 +6568,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) vcpu->mode = OUTSIDE_GUEST_MODE; smp_wmb(); - kvm_put_guest_xcr0(vcpu); - /* Interrupt is enabled by handle_external_intr() */ kvm_x86_ops->handle_external_intr(vcpu); @@ -7216,6 +7215,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) * and assume host would use all available bits. * Guest xcr0 would be loaded later. */ + kvm_put_guest_xcr0(vcpu); vcpu->guest_fpu_loaded = 1; __kernel_fpu_begin(); __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state); @@ -7224,6 +7224,8 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) { + kvm_put_guest_xcr0(vcpu); + if (!vcpu->guest_fpu_loaded) { vcpu->fpu_counter = 0; return; diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index ddb2244b06a1..637ab34ed632 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c @@ -33,7 +33,7 @@ struct kmmio_fault_page { struct list_head list; struct kmmio_fault_page *release_next; - unsigned long addr; /* the requested address */ + unsigned long page; /* location of the fault page */ pteval_t old_presence; /* page presence prior to arming */ bool armed; @@ -70,16 +70,9 @@ unsigned int kmmio_count; static struct list_head kmmio_page_table[KMMIO_PAGE_TABLE_SIZE]; static LIST_HEAD(kmmio_probes); -static struct list_head *kmmio_page_list(unsigned long addr) +static struct list_head *kmmio_page_list(unsigned long page) { - unsigned int l; - pte_t *pte = lookup_address(addr, &l); - - if (!pte) - return NULL; - addr &= page_level_mask(l); - - return &kmmio_page_table[hash_long(addr, KMMIO_PAGE_HASH_BITS)]; + return &kmmio_page_table[hash_long(page, KMMIO_PAGE_HASH_BITS)]; } /* Accessed per-cpu */ @@ -105,19 +98,15 @@ static struct kmmio_probe *get_kmmio_probe(unsigned long addr) } /* You must be holding RCU read lock. */ -static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long addr) +static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page) { struct list_head *head; struct kmmio_fault_page *f; - unsigned int l; - pte_t *pte = lookup_address(addr, &l); - if (!pte) - return NULL; - addr &= page_level_mask(l); - head = kmmio_page_list(addr); + page &= PAGE_MASK; + head = kmmio_page_list(page); list_for_each_entry_rcu(f, head, list) { - if (f->addr == addr) + if (f->page == page) return f; } return NULL; @@ -148,10 +137,10 @@ static void clear_pte_presence(pte_t *pte, bool clear, pteval_t *old) static int clear_page_presence(struct kmmio_fault_page *f, bool clear) { unsigned int level; - pte_t *pte = lookup_address(f->addr, &level); + pte_t *pte = lookup_address(f->page, &level); if (!pte) { - pr_err("no pte for addr 0x%08lx\n", f->addr); + pr_err("no pte for page 0x%08lx\n", f->page); return -1; } @@ -167,7 +156,7 @@ static int clear_page_presence(struct kmmio_fault_page *f, bool clear) return -1; } - __flush_tlb_one(f->addr); + __flush_tlb_one(f->page); return 0; } @@ -187,12 +176,12 @@ static int arm_kmmio_fault_page(struct kmmio_fault_page *f) int ret; WARN_ONCE(f->armed, KERN_ERR pr_fmt("kmmio page already armed.\n")); if (f->armed) { - pr_warning("double-arm: addr 0x%08lx, ref %d, old %d\n", - f->addr, f->count, !!f->old_presence); + pr_warning("double-arm: page 0x%08lx, ref %d, old %d\n", + f->page, f->count, !!f->old_presence); } ret = clear_page_presence(f, true); - WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming at 0x%08lx failed.\n"), - f->addr); + WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming 0x%08lx failed.\n"), + f->page); f->armed = true; return ret; } @@ -202,7 +191,7 @@ static void disarm_kmmio_fault_page(struct kmmio_fault_page *f) { int ret = clear_page_presence(f, false); WARN_ONCE(ret < 0, - KERN_ERR "kmmio disarming at 0x%08lx failed.\n", f->addr); + KERN_ERR "kmmio disarming 0x%08lx failed.\n", f->page); f->armed = false; } @@ -226,12 +215,6 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr) struct kmmio_context *ctx; struct kmmio_fault_page *faultpage; int ret = 0; /* default to fault not handled */ - unsigned long page_base = addr; - unsigned int l; - pte_t *pte = lookup_address(addr, &l); - if (!pte) - return -EINVAL; - page_base &= page_level_mask(l); /* * Preemption is now disabled to prevent process switch during @@ -244,7 +227,7 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr) preempt_disable(); rcu_read_lock(); - faultpage = get_kmmio_fault_page(page_base); + faultpage = get_kmmio_fault_page(addr); if (!faultpage) { /* * Either this page fault is not caused by kmmio, or @@ -256,7 +239,7 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr) ctx = &get_cpu_var(kmmio_ctx); if (ctx->active) { - if (page_base == ctx->addr) { + if (addr == ctx->addr) { /* * A second fault on the same page means some other * condition needs handling by do_page_fault(), the @@ -284,9 +267,9 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr) ctx->active++; ctx->fpage = faultpage; - ctx->probe = get_kmmio_probe(page_base); + ctx->probe = get_kmmio_probe(addr); ctx->saved_flags = (regs->flags & (X86_EFLAGS_TF | X86_EFLAGS_IF)); - ctx->addr = page_base; + ctx->addr = addr; if (ctx->probe && ctx->probe->pre_handler) ctx->probe->pre_handler(ctx->probe, regs, addr); @@ -371,11 +354,12 @@ out: } /* You must be holding kmmio_lock. */ -static int add_kmmio_fault_page(unsigned long addr) +static int add_kmmio_fault_page(unsigned long page) { struct kmmio_fault_page *f; - f = get_kmmio_fault_page(addr); + page &= PAGE_MASK; + f = get_kmmio_fault_page(page); if (f) { if (!f->count) arm_kmmio_fault_page(f); @@ -388,25 +372,26 @@ static int add_kmmio_fault_page(unsigned long addr) return -1; f->count = 1; - f->addr = addr; + f->page = page; if (arm_kmmio_fault_page(f)) { kfree(f); return -1; } - list_add_rcu(&f->list, kmmio_page_list(f->addr)); + list_add_rcu(&f->list, kmmio_page_list(f->page)); return 0; } /* You must be holding kmmio_lock. */ -static void release_kmmio_fault_page(unsigned long addr, +static void release_kmmio_fault_page(unsigned long page, struct kmmio_fault_page **release_list) { struct kmmio_fault_page *f; - f = get_kmmio_fault_page(addr); + page &= PAGE_MASK; + f = get_kmmio_fault_page(page); if (!f) return; @@ -435,27 +420,18 @@ int register_kmmio_probe(struct kmmio_probe *p) int ret = 0; unsigned long size = 0; const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK); - unsigned int l; - pte_t *pte; spin_lock_irqsave(&kmmio_lock, flags); if (get_kmmio_probe(p->addr)) { ret = -EEXIST; goto out; } - - pte = lookup_address(p->addr, &l); - if (!pte) { - ret = -EINVAL; - goto out; - } - kmmio_count++; list_add_rcu(&p->list, &kmmio_probes); while (size < size_lim) { if (add_kmmio_fault_page(p->addr + size)) pr_err("Unable to set page fault.\n"); - size += page_level_size(l); + size += PAGE_SIZE; } out: spin_unlock_irqrestore(&kmmio_lock, flags); @@ -530,17 +506,11 @@ void unregister_kmmio_probe(struct kmmio_probe *p) const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK); struct kmmio_fault_page *release_list = NULL; struct kmmio_delayed_release *drelease; - unsigned int l; - pte_t *pte; - - pte = lookup_address(p->addr, &l); - if (!pte) - return; spin_lock_irqsave(&kmmio_lock, flags); while (size < size_lim) { release_kmmio_fault_page(p->addr + size, &release_list); - size += page_level_size(l); + size += PAGE_SIZE; } list_del_rcu(&p->list); kmmio_count--; diff --git a/block/partition-generic.c b/block/partition-generic.c index 91327dbfbb1d..ae95e963c5bb 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -360,20 +360,15 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, goto out_del; } - err = hd_ref_init(p); - if (err) { - if (flags & ADDPART_FLAG_WHOLEDISK) - goto out_remove_file; - goto out_del; - } - /* everything is up and running, commence */ rcu_assign_pointer(ptbl->part[partno], p); /* suppress uevent if the disk suppresses it */ if (!dev_get_uevent_suppress(ddev)) kobject_uevent(&pdev->kobj, KOBJ_ADD); - return p; + + if (!hd_ref_init(p)) + return p; out_free_info: free_part_info(p); @@ -382,8 +377,6 @@ out_free_stats: out_free: kfree(p); return ERR_PTR(err); -out_remove_file: - device_remove_file(pdev, &dev_attr_whole_disk); out_del: kobject_put(p->holder_dir); device_del(pdev); diff --git a/crypto/ahash.c b/crypto/ahash.c index dac1c24e9c3e..d19b52324cf5 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -69,9 +69,8 @@ static int hash_walk_new_entry(struct crypto_hash_walk *walk) struct scatterlist *sg; sg = walk->sg; + walk->pg = sg_page(sg); walk->offset = sg->offset; - walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); - walk->offset = offset_in_page(walk->offset); walk->entrylen = sg->length; if (walk->entrylen > walk->total) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index d4944318ca1f..ae8c57fd8bc7 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1849,7 +1849,6 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, static int do_test_rsa(struct crypto_akcipher *tfm, struct akcipher_testvec *vecs) { - char *xbuf[XBUFSIZE]; struct akcipher_request *req; void *outbuf_enc = NULL; void *outbuf_dec = NULL; @@ -1858,12 +1857,9 @@ static int do_test_rsa(struct crypto_akcipher *tfm, int err = -ENOMEM; struct scatterlist src, dst, src_tab[2]; - if (testmgr_alloc_buf(xbuf)) - return err; - req = akcipher_request_alloc(tfm, GFP_KERNEL); if (!req) - goto free_xbuf; + return err; init_completion(&result.completion); @@ -1881,14 +1877,9 @@ static int do_test_rsa(struct crypto_akcipher *tfm, if (!outbuf_enc) goto free_req; - if (WARN_ON(vecs->m_size > PAGE_SIZE)) - goto free_all; - - memcpy(xbuf[0], vecs->m, vecs->m_size); - sg_init_table(src_tab, 2); - sg_set_buf(&src_tab[0], xbuf[0], 8); - sg_set_buf(&src_tab[1], xbuf[0] + 8, vecs->m_size - 8); + sg_set_buf(&src_tab[0], vecs->m, 8); + sg_set_buf(&src_tab[1], vecs->m + 8, vecs->m_size - 8); sg_init_one(&dst, outbuf_enc, out_len_max); akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size, out_len_max); @@ -1907,7 +1898,7 @@ static int do_test_rsa(struct crypto_akcipher *tfm, goto free_all; } /* verify that encrypted message is equal to expected */ - if (memcmp(vecs->c, outbuf_enc, vecs->c_size)) { + if (memcmp(vecs->c, sg_virt(req->dst), vecs->c_size)) { pr_err("alg: rsa: encrypt test failed. Invalid output\n"); err = -EINVAL; goto free_all; @@ -1922,13 +1913,7 @@ static int do_test_rsa(struct crypto_akcipher *tfm, err = -ENOMEM; goto free_all; } - - if (WARN_ON(vecs->c_size > PAGE_SIZE)) - goto free_all; - - memcpy(xbuf[0], vecs->c, vecs->c_size); - - sg_init_one(&src, xbuf[0], vecs->c_size); + sg_init_one(&src, vecs->c, vecs->c_size); sg_init_one(&dst, outbuf_dec, out_len_max); init_completion(&result.completion); akcipher_request_set_crypt(req, &src, &dst, vecs->c_size, out_len_max); @@ -1955,8 +1940,6 @@ free_all: kfree(outbuf_enc); free_req: akcipher_request_free(req); -free_xbuf: - testmgr_free_buf(xbuf); return err; } diff --git a/drivers/Makefile b/drivers/Makefile index 1761f8f2cda7..eb67aadf2ee0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ obj-$(CONFIG_NUBUS) += nubus/ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ +obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SCSI) += scsi/ obj-y += nvme/ obj-$(CONFIG_ATA) += ata/ @@ -126,7 +127,6 @@ obj-$(CONFIG_SWITCH) += switch/ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ -obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ obj-$(CONFIG_ARCH_SHMOBILE) += sh/ ifndef CONFIG_ARCH_USES_GETTIMEOFFSET diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 9f77943653fb..6979186dbd4b 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -491,58 +491,6 @@ static void acpi_processor_remove(struct acpi_device *device) } #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -#ifdef CONFIG_X86 -static bool acpi_hwp_native_thermal_lvt_set; -static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, - u32 lvl, - void *context, - void **rv) -{ - u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; - u32 capbuf[2]; - struct acpi_osc_context osc_context = { - .uuid_str = sb_uuid_str, - .rev = 1, - .cap.length = 8, - .cap.pointer = capbuf, - }; - - if (acpi_hwp_native_thermal_lvt_set) - return AE_CTRL_TERMINATE; - - capbuf[0] = 0x0000; - capbuf[1] = 0x1000; /* set bit 12 */ - - if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) { - if (osc_context.ret.pointer && osc_context.ret.length > 1) { - u32 *capbuf_ret = osc_context.ret.pointer; - - if (capbuf_ret[1] & 0x1000) { - acpi_handle_info(handle, - "_OSC native thermal LVT Acked\n"); - acpi_hwp_native_thermal_lvt_set = true; - } - } - kfree(osc_context.ret.pointer); - } - - return AE_OK; -} - -void __init acpi_early_processor_osc(void) -{ - if (boot_cpu_has(X86_FEATURE_HWP)) { - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - acpi_hwp_native_thermal_lvt_osc, - NULL, NULL, NULL); - acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, - acpi_hwp_native_thermal_lvt_osc, - NULL, NULL); - } -} -#endif - /* * The following ACPI IDs are known to be suitable for representing as * processor devices. diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 28c50c6b5f45..bc32f3194afe 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -417,9 +417,6 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, obj_desc->method.mutex->mutex. original_sync_level = obj_desc->method.mutex->mutex.sync_level; - - obj_desc->method.mutex->mutex.thread_id = - acpi_os_get_thread_id(); } } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ca4f28432d87..a212cefae524 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1004,9 +1004,6 @@ static int __init acpi_bus_init(void) goto error1; } - /* Set capability bits for _OSC under processor scope */ - acpi_early_processor_osc(); - /* * _OSC method may exist in module level code, * so it must be run after ACPI_FULL_INITIALIZATION diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 0f3f41c13b38..11d87bf67e73 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -130,12 +130,6 @@ void acpi_early_processor_set_pdc(void); static inline void acpi_early_processor_set_pdc(void) {} #endif -#ifdef CONFIG_X86 -void acpi_early_processor_osc(void); -#else -static inline void acpi_early_processor_osc(void) {} -#endif - /* -------------------------------------------------------------------------- Embedded Controller -------------------------------------------------------------------------- */ diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 639adb1f8abd..04975b851c23 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -51,9 +51,6 @@ static int ahci_probe(struct platform_device *pdev) if (rc) return rc; - of_property_read_u32(dev->of_node, - "ports-implemented", &hpriv->force_port_map); - if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index e916bff6cee8..e2c6d9e0c5ac 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -739,9 +739,9 @@ static int xgene_ahci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n", __func__); version = XGENE_AHCI_V1; - } else if (info->valid & ACPI_VALID_CID) { - version = XGENE_AHCI_V2; } + if (info->valid & ACPI_VALID_CID) + version = XGENE_AHCI_V2; } } #endif diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 9628fa131757..998c6a85ad89 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -467,7 +467,6 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", port_map, hpriv->force_port_map); port_map = hpriv->force_port_map; - hpriv->saved_port_map = port_map; } if (hpriv->mask_port_map) { diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a48824deabc5..65f50eccd49b 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1381,7 +1381,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, mutex_lock(&genpd->lock); - if (!list_empty(&subdomain->master_links) || subdomain->device_count) { + if (!list_empty(&subdomain->slave_links) || subdomain->device_count) { pr_warn("%s: unable to remove subdomain %s\n", genpd->name, subdomain->name); ret = -EBUSY; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 80cf8add46ff..423f4ca7d712 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -488,12 +488,6 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); iov_iter_bvec(&iter, ITER_BVEC | rw, bvec, bio_segments(bio), blk_rq_bytes(cmd->rq)); - /* - * This bio may be started from the middle of the 'bvec' - * because of bio splitting, so offset from the bvec must - * be passed to iov iterator - */ - iter.iov_offset = bio->bi_iter.bi_bvec_done; cmd->iocb.ki_pos = pos; cmd->iocb.ki_filp = file; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 8f1ce6d57a08..93b3f99b6865 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -618,8 +618,8 @@ static void nbd_request_handler(struct request_queue *q) req, req->cmd_type); if (unlikely(!nbd->sock)) { - dev_err_ratelimited(disk_to_dev(nbd->disk), - "Attempted send on closed socket\n"); + dev_err(disk_to_dev(nbd->disk), + "Attempted send on closed socket\n"); req->errors++; nbd_end_request(nbd, req); spin_lock_irq(q->queue_lock); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 78a39f736c64..562b5a4ca7b7 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -126,7 +126,7 @@ */ #include <linux/types.h> -static int verbose = 0; +static bool verbose = 0; static int major = PD_MAJOR; static char *name = PD_NAME; static int cluster = 64; @@ -161,7 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; static DEFINE_MUTEX(pd_mutex); static DEFINE_SPINLOCK(pd_lock); -module_param(verbose, int, 0); +module_param(verbose, bool, 0); module_param(major, int, 0); module_param(name, charp, 0); module_param(cluster, int, 0); diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 216a94fed5b4..1740d75e8a32 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -117,7 +117,7 @@ */ -static int verbose = 0; +static bool verbose = 0; static int major = PT_MAJOR; static char *name = PT_NAME; static int disable = 0; @@ -152,7 +152,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include <asm/uaccess.h> -module_param(verbose, int, 0); +module_param(verbose, bool, 0); module_param(major, int, 0); module_param(name, charp, 0); module_param_array(drive0, int, NULL, 0); diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 1827fc4d15c1..e98d15eaa799 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -150,7 +150,7 @@ static int __init weim_parse_dt(struct platform_device *pdev, return ret; } - for_each_available_child_of_node(pdev->dev.of_node, child) { + for_each_child_of_node(pdev->dev.of_node, child) { if (!child->name) continue; diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index 0a6d8bb7b21f..fea1b74aacae 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -475,7 +475,7 @@ static void diag_glink_open_work_fn(struct work_struct *work) struct glink_open_config open_cfg; void *handle = NULL; - if (!glink_info) + if (!glink_info || glink_info->hdl) return; memset(&open_cfg, 0, sizeof(struct glink_open_config)); @@ -499,11 +499,12 @@ static void diag_glink_close_work_fn(struct work_struct *work) struct diag_glink_info *glink_info = container_of(work, struct diag_glink_info, close_work); - if (!glink_info->inited) + if (!glink_info || !glink_info->inited || !glink_info->hdl) return; glink_close(glink_info->hdl); atomic_set(&glink_info->opened, 0); + glink_info->hdl = NULL; diagfwd_channel_close(glink_info->fwd_ctxt); } @@ -586,6 +587,7 @@ static void __diag_glink_init(struct diag_glink_info *glink_info) { char wq_name[DIAG_GLINK_NAME_SZ + 12]; struct glink_link_info link_info; + void *link_state_handle = NULL; if (!glink_info) return; @@ -606,23 +608,25 @@ static void __diag_glink_init(struct diag_glink_info *glink_info) INIT_WORK(&(glink_info->read_work), diag_glink_read_work_fn); link_info.glink_link_state_notif_cb = diag_glink_notify_cb; link_info.transport = NULL; - strlcpy((char *)link_info.edge, glink_info->edge, - sizeof(link_info.edge)); - glink_info->hdl = glink_register_link_state_cb(&link_info, + link_info.edge = glink_info->edge; + glink_info->link_state_handle = NULL; + link_state_handle = glink_register_link_state_cb(&link_info, (void *)glink_info); - if (IS_ERR_OR_NULL(glink_info->hdl)) { + if (IS_ERR_OR_NULL(link_state_handle)) { pr_err("diag: In %s, unable to register for glink channel %s\n", __func__, glink_info->name); destroy_workqueue(glink_info->wq); return; } + glink_info->link_state_handle = link_state_handle; glink_info->fwd_ctxt = NULL; atomic_set(&glink_info->tx_intent_ready, 0); atomic_set(&glink_info->opened, 0); atomic_set(&glink_info->diag_state, 0); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s initialized fwd_ctxt: %pK hdl: %pK\n", - glink_info->name, glink_info->fwd_ctxt, glink_info->hdl); + glink_info->name, glink_info->fwd_ctxt, + glink_info->link_state_handle); } void diag_glink_invalidate(void *ctxt, struct diagfwd_info *fwd_ctxt) diff --git a/drivers/char/diag/diagfwd_glink.h b/drivers/char/diag/diagfwd_glink.h index 3f00a7ed60a8..bad4629b5ab8 100644 --- a/drivers/char/diag/diagfwd_glink.h +++ b/drivers/char/diag/diagfwd_glink.h @@ -25,6 +25,7 @@ struct diag_glink_info { uint32_t fifo_size; atomic_t tx_intent_ready; void *hdl; + void *link_state_handle; char edge[DIAG_GLINK_NAME_SZ]; char name[DIAG_GLINK_NAME_SZ]; struct mutex lock; diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index b8ed216faaf6..f7b1e98f22b0 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -404,8 +404,11 @@ static void mhi_read_done_work_fn(struct work_struct *work) * buffers here and do not forward them to the mux layer. */ if ((atomic_read(&(mhi_info->read_ch.opened)))) { - diag_remote_dev_read_done(mhi_info->dev_id, buf, + err = diag_remote_dev_read_done(mhi_info->dev_id, buf, result.bytes_xferd); + if (err) + mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, + buf, result.bytes_xferd); } else { mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, result.bytes_xferd); diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index bbf206e3da0d..3ace102a2a0a 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -422,12 +422,6 @@ const struct clk_ops clk_divider_ops = { }; EXPORT_SYMBOL_GPL(clk_divider_ops); -const struct clk_ops clk_divider_ro_ops = { - .recalc_rate = clk_divider_recalc_rate, - .round_rate = clk_divider_round_rate, -}; -EXPORT_SYMBOL_GPL(clk_divider_ro_ops); - static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -451,10 +445,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); init.name = name; - if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) - init.ops = &clk_divider_ro_ops; - else - init.ops = &clk_divider_ops; + init.ops = &clk_divider_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c index d920d410b51d..c83ae1367abc 100644 --- a/drivers/clk/meson/clkc.c +++ b/drivers/clk/meson/clkc.c @@ -198,7 +198,7 @@ meson_clk_register_fixed_rate(const struct clk_conf *clk_conf, } void __init meson_clk_register_clks(const struct clk_conf *clk_confs, - unsigned int nr_confs, + size_t nr_confs, void __iomem *clk_base) { unsigned int i; diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig index d94678e9e4fc..650a23ea1ead 100644 --- a/drivers/clk/msm/Kconfig +++ b/drivers/clk/msm/Kconfig @@ -2,6 +2,7 @@ config COMMON_CLK_MSM tristate "Support for MSM clock controllers" depends on OF depends on ARCH_QCOM + select RATIONAL help This support clock controller used by MSM devices which support global, mmss and gpu clock controller. diff --git a/drivers/clk/msm/clock-gcc-cobalt.c b/drivers/clk/msm/clock-gcc-cobalt.c index 2049a0bf7dd2..e469c61cc3db 100644 --- a/drivers/clk/msm/clock-gcc-cobalt.c +++ b/drivers/clk/msm/clock-gcc-cobalt.c @@ -32,6 +32,7 @@ #include <dt-bindings/clock/msm-clocks-hwio-cobalt.h> #include "vdd-level-cobalt.h" +#include "reset.h" static void __iomem *virt_base; static void __iomem *virt_dbgbase; @@ -2695,6 +2696,23 @@ static struct clk_lookup msm_clocks_gcc_cobalt[] = { CLK_LIST(gcc_qspi_ref_clk), }; +static const struct msm_reset_map gcc_cobalt_resets[] = { + [QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [QUSB2PHY_SEC_BCR] = { 0x12004 }, + [BLSP1_BCR] = { 0x17000 }, + [BLSP2_BCR] = { 0x25000 }, + [BOOT_ROM_BCR] = { 0x38000 }, + [PRNG_BCR] = { 0x34000 }, + [UFS_BCR] = { 0x75000 }, + [USB_30_BCR] = { 0x0f000 }, + [USB3_PHY_BCR] = { 0x50020 }, + [USB3PHY_PHY_BCR] = { 0x50024 }, + [PCIE_0_PHY_BCR] = { 0x6c01c }, + [PCIE_PHY_BCR] = { 0x6f000 }, + [PCIE_PHY_NOCSR_COM_PHY_BCR] = { 0x6f00C }, + [PCIE_PHY_COM_BCR] = { 0x6f014 }, +}; + static void msm_gcc_cobalt_v1_fixup(void) { gcc_ufs_rx_symbol_1_clk.c.ops = &clk_ops_dummy; @@ -2800,6 +2818,10 @@ static int msm_gcc_cobalt_probe(struct platform_device *pdev) clk_set_flags(&gcc_gpu_bimc_gfx_clk.c, CLKFLAG_RETAIN_MEM); + /* Register block resets */ + msm_reset_controller_register(pdev, gcc_cobalt_resets, + ARRAY_SIZE(gcc_cobalt_resets), virt_base); + dev_info(&pdev->dev, "Registered GCC clocks\n"); return 0; } diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c index bbb9af961235..fbd83a02aa02 100644 --- a/drivers/clk/msm/clock-mmss-cobalt.c +++ b/drivers/clk/msm/clock-mmss-cobalt.c @@ -30,6 +30,7 @@ #include <dt-bindings/clock/msm-clocks-hwio-cobalt.h> #include "vdd-level-cobalt.h" +#include "reset.h" static void __iomem *virt_base; @@ -2637,6 +2638,10 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = { CLK_LIST(mmss_debug_mux), }; +static const struct msm_reset_map mmss_cobalt_resets[] = { + [CAMSS_MICRO_BCR] = { 0x3490 }, +}; + static void msm_mmsscc_hamster_fixup(void) { mmpll3_pll.c.rate = 1066000000; @@ -2838,6 +2843,10 @@ int msm_mmsscc_cobalt_probe(struct platform_device *pdev) if (rc) return rc; + /* Register block resets */ + msm_reset_controller_register(pdev, mmss_cobalt_resets, + ARRAY_SIZE(mmss_cobalt_resets), virt_base); + dev_info(&pdev->dev, "Registered MMSS clocks.\n"); return 0; } diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index 9d605503520f..78dde263d487 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -48,6 +48,7 @@ enum clk_osm_bases { OSM_BASE, PLL_BASE, + EFUSE_BASE, NUM_BASES, }; @@ -208,6 +209,11 @@ enum clk_osm_trace_packet_id { #define PLL_DD_D0_USER_CTL_LO 0x17916208 #define PLL_DD_D1_USER_CTL_LO 0x17816208 +#define PWRCL_EFUSE_SHIFT 0 +#define PWRCL_EFUSE_MASK 0 +#define PERFCL_EFUSE_SHIFT 29 +#define PERFCL_EFUSE_MASK 0x7 + static void __iomem *virt_base; #define lmh_lite_clk_src_source_val 1 @@ -913,6 +919,35 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } + /* efuse speed bin fuses are optional */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pwrcl_efuse"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in pwrcl_efuse base\n"); + return -ENOMEM; + } + pwrcl_clk.pbases[EFUSE_BASE] = pbase; + pwrcl_clk.vbases[EFUSE_BASE] = vbase; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "perfcl_efuse"); + if (res) { + pbase = (unsigned long)res->start; + vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!vbase) { + dev_err(&pdev->dev, "Unable to map in perfcl_efuse base\n"); + return -ENOMEM; + } + perfcl_clk.pbases[EFUSE_BASE] = pbase; + perfcl_clk.vbases[EFUSE_BASE] = vbase; + } + vdd_pwrcl = devm_regulator_get(&pdev->dev, "vdd-pwrcl"); if (IS_ERR(vdd_pwrcl)) { rc = PTR_ERR(vdd_pwrcl); @@ -2441,9 +2476,11 @@ static unsigned long osm_clk_init_rate = 200000000; static int cpu_clock_osm_driver_probe(struct platform_device *pdev) { - char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; - char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; int rc, cpu; + int speedbin = 0, pvs_ver = 0; + u32 pte_efuse; + char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; + char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; struct cpu_cycle_counter_cb cb = { .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter, }; @@ -2462,6 +2499,18 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } + if (pwrcl_clk.vbases[EFUSE_BASE]) { + /* Multiple speed-bins are supported */ + pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]); + speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) & + PWRCL_EFUSE_MASK); + snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr), + "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver); + } + + dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n", + speedbin, pvs_ver); + rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr); if (rc) { @@ -2470,6 +2519,18 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } + if (perfcl_clk.vbases[EFUSE_BASE]) { + /* Multiple speed-bins are supported */ + pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]); + speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) & + PERFCL_EFUSE_MASK); + snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr), + "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver); + } + + dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n", + speedbin, pvs_ver); + rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr); if (rc) { dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n", diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c index 558da89555af..13aabbb3acbe 100644 --- a/drivers/clk/nxp/clk-lpc18xx-ccu.c +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -222,7 +222,7 @@ static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *bran div->width = 1; div_hw = &div->hw; - div_ops = &clk_divider_ro_ops; + div_ops = &clk_divider_ops; } branch->gate.reg = branch->offset + reg_base; diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 76310e249fb2..0987c8e7f807 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -125,15 +125,62 @@ static int clk_branch_enable(struct clk_hw *hw) return clk_branch_toggle(hw, true, clk_branch_check_halt); } +static int clk_cbcr_set_flags(struct regmap *regmap, unsigned int reg, + unsigned long flags) +{ + u32 cbcr_val; + + regmap_read(regmap, reg, &cbcr_val); + + switch (flags) { + case CLKFLAG_PERIPH_OFF_SET: + cbcr_val |= BIT(12); + break; + case CLKFLAG_PERIPH_OFF_CLEAR: + cbcr_val &= ~BIT(12); + break; + case CLKFLAG_RETAIN_PERIPH: + cbcr_val |= BIT(13); + break; + case CLKFLAG_NORETAIN_PERIPH: + cbcr_val &= ~BIT(13); + break; + case CLKFLAG_RETAIN_MEM: + cbcr_val |= BIT(14); + break; + case CLKFLAG_NORETAIN_MEM: + cbcr_val &= ~BIT(14); + break; + default: + return -EINVAL; + } + + regmap_write(regmap, reg, cbcr_val); + + /* Make sure power is enabled/disabled before returning. */ + mb(); + udelay(1); + + return 0; +} + static void clk_branch_disable(struct clk_hw *hw) { clk_branch_toggle(hw, false, clk_branch_check_halt); } +static int clk_branch_set_flags(struct clk_hw *hw, unsigned flags) +{ + struct clk_branch *br = to_clk_branch(hw); + + return clk_cbcr_set_flags(br->clkr.regmap, br->halt_reg, flags); +} + const struct clk_ops clk_branch_ops = { .enable = clk_branch_enable, .disable = clk_branch_disable, .is_enabled = clk_is_enabled_regmap, + .set_flags = clk_branch_set_flags, }; EXPORT_SYMBOL_GPL(clk_branch_ops); @@ -151,6 +198,7 @@ const struct clk_ops clk_branch2_ops = { .enable = clk_branch2_enable, .disable = clk_branch2_disable, .is_enabled = clk_is_enabled_regmap, + .set_flags = clk_branch_set_flags, }; EXPORT_SYMBOL_GPL(clk_branch2_ops); diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 915c54f9351f..331f58d651e5 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -73,4 +73,13 @@ extern const struct clk_ops clk_branch_simple_ops; #define to_clk_gate2(_hw) \ container_of(to_clk_regmap(_hw), struct clk_gate2, clkr) +enum branch_mem_flags { + CLKFLAG_RETAIN_PERIPH, + CLKFLAG_NORETAIN_PERIPH, + CLKFLAG_RETAIN_MEM, + CLKFLAG_NORETAIN_MEM, + CLKFLAG_PERIPH_OFF_SET, + CLKFLAG_PERIPH_OFF_CLEAR, +}; + #endif diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c index 3205fbc6b8ba..e06a829e508c 100644 --- a/drivers/clk/qcom/clk-dummy.c +++ b/drivers/clk/qcom/clk-dummy.c @@ -15,14 +15,18 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/reset-controller.h> struct clk_dummy { struct clk_hw hw; + struct reset_controller_dev reset; unsigned long rrate; }; #define to_clk_dummy(_hw) container_of(_hw, struct clk_dummy, hw) +#define RESET_MAX 100 + static int dummy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -51,22 +55,48 @@ static unsigned long dummy_clk_recalc_rate(struct clk_hw *hw, return dummy->rrate; } +static int dummy_clk_set_flags(struct clk_hw *hw, unsigned flags) +{ + return 0; +} + struct clk_ops clk_dummy_ops = { .set_rate = dummy_clk_set_rate, .round_rate = dummy_clk_round_rate, .recalc_rate = dummy_clk_recalc_rate, + .set_flags = dummy_clk_set_flags, }; EXPORT_SYMBOL_GPL(clk_dummy_ops); +static int dummy_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static int dummy_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static struct reset_control_ops dummy_reset_ops = { + .assert = dummy_reset_assert, + .deassert = dummy_reset_deassert, +}; + /** * clk_register_dummy - register dummy clock with the * clock framework * @dev: device that is registering this clock * @name: name of this clock * @flags: framework-specific flags + * @node: device node */ static struct clk *clk_register_dummy(struct device *dev, const char *name, - unsigned long flags) + unsigned long flags, struct device_node *node) { struct clk_dummy *dummy; struct clk *clk; @@ -85,8 +115,20 @@ static struct clk *clk_register_dummy(struct device *dev, const char *name, /* register the clock */ clk = clk_register(dev, &dummy->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { kfree(dummy); + return clk; + } + + dummy->reset.of_node = node; + dummy->reset.ops = &dummy_reset_ops; + dummy->reset.nr_resets = RESET_MAX; + + if (reset_controller_register(&dummy->reset)) + pr_err("Failed to register reset controller for %s\n", name); + else + pr_info("Successfully registered a dummy reset controller for %s\n", + name); return clk; } @@ -101,10 +143,15 @@ static void of_dummy_clk_setup(struct device_node *node) of_property_read_string(node, "clock-output-names", &clk_name); - clk = clk_register_dummy(NULL, clk_name, 0); + clk = clk_register_dummy(NULL, clk_name, 0, node); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); + else { + pr_err("Failed to register dummy clock controller for %s\n", + clk_name); + return; + } - pr_info("%s: Dummy clock registered\n", clk_name); + pr_info("Successfully registered dummy clock for %s\n", clk_name); } CLK_OF_DECLARE(dummy_clk, "qcom,dummycc", of_dummy_clk_setup); diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index 8b9c388bc43c..6c899fb5b856 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -2722,7 +2722,7 @@ static struct clk_rcg ce3_src = { }, .freq_tbl = clk_tbl_ce3, .clkr = { - .enable_reg = 0x36c0, + .enable_reg = 0x2c08, .enable_mask = BIT(7), .hw.init = &(struct clk_init_data){ .name = "ce3_src", @@ -2738,7 +2738,7 @@ static struct clk_branch ce3_core_clk = { .halt_reg = 0x2fdc, .halt_bit = 5, .clkr = { - .enable_reg = 0x36cc, + .enable_reg = 0x36c4, .enable_mask = BIT(4), .hw.init = &(struct clk_init_data){ .name = "ce3_core_clk", diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 9b6c8188efac..be6c7fd8315d 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -70,7 +70,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, if (gate_offset >= 0) { gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) - goto err_gate; + return ERR_PTR(-ENOMEM); gate->flags = gate_flags; gate->reg = base + gate_offset; @@ -82,7 +82,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, if (div_width > 0) { div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) - goto err_div; + return ERR_PTR(-ENOMEM); div->flags = div_flags; div->reg = base + muxdiv_offset; @@ -90,9 +90,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, div->width = div_width; div->lock = lock; div->table = div_table; - div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) - ? &clk_divider_ro_ops - : &clk_divider_ops; + div_ops = &clk_divider_ops; } clk = clk_register_composite(NULL, name, parent_names, num_parents, @@ -102,11 +100,6 @@ static struct clk *rockchip_clk_register_branch(const char *name, flags); return clk; -err_div: - kfree(gate); -err_gate: - kfree(mux); - return ERR_PTR(-ENOMEM); } static struct clk *rockchip_clk_register_frac_branch(const char *name, diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index 897c36c1754a..a1cdef6b0f90 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -92,7 +92,6 @@ static void __init clk_sp810_of_setup(struct device_node *node) int num = ARRAY_SIZE(parent_names); char name[12]; struct clk_init_data init; - static int instance; int i; bool deprecated; @@ -119,7 +118,7 @@ static void __init clk_sp810_of_setup(struct device_node *node) deprecated = !of_find_property(node, "assigned-clock-parents", NULL); for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { - snprintf(name, sizeof(name), "sp810_%d_%d", instance, i); + snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); sp810->timerclken[i].sp810 = sp810; sp810->timerclken[i].channel = i; @@ -140,6 +139,5 @@ static void __init clk_sp810_of_setup(struct device_node *node) } of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810); - instance++; } CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f53b02a6bc05..98fb8821382d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -667,11 +667,6 @@ static int core_get_max_pstate(void) if (err) goto skip_tar; - /* For level 1 and 2, bits[23:16] contain the ratio */ - if (tdp_ctrl) - tdp_ratio >>= 16; - - tdp_ratio &= 0xff; /* ratios are only 8 bits long */ if (tdp_ratio - 1 == tar) { max_pstate = tar; pr_debug("max_pstate=TAC %x\n", max_pstate); diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index e342565e8715..545069d5fdfb 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -50,7 +50,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev, * call the CPU ops suspend protocol with idle index as a * parameter. */ - ret = arm_cpuidle_suspend(idx); + arm_cpuidle_suspend(idx); cpu_pm_exit(); } diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c index 60fc0fa26fd3..3d9acc53d247 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c @@ -225,9 +225,6 @@ static int ccp_aes_cmac_export(struct ahash_request *req, void *out) struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req); struct ccp_aes_cmac_exp_ctx state; - /* Don't let anything leak to 'out' */ - memset(&state, 0, sizeof(state)); - state.null_msg = rctx->null_msg; memcpy(state.iv, rctx->iv, sizeof(state.iv)); state.buf_count = rctx->buf_count; diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c index ab9945f2cb7a..8ef06fad8b14 100644 --- a/drivers/crypto/ccp/ccp-crypto-sha.c +++ b/drivers/crypto/ccp/ccp-crypto-sha.c @@ -212,9 +212,6 @@ static int ccp_sha_export(struct ahash_request *req, void *out) struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); struct ccp_sha_exp_ctx state; - /* Don't let anything leak to 'out' */ - memset(&state, 0, sizeof(state)); - state.type = rctx->type; state.msg_bits = rctx->msg_bits; state.first = rctx->first; diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index b9178d0a3093..3f76bd495bcb 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -145,8 +145,6 @@ int adf_enable_aer(struct adf_accel_dev *accel_dev, struct pci_driver *adf); void adf_disable_aer(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); -int adf_init_pf_wq(void); -void adf_exit_pf_wq(void); int adf_init_admin_comms(struct adf_accel_dev *accel_dev); void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); int adf_send_admin_init(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index e7480f373532..473d36d91644 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -469,17 +469,12 @@ static int __init adf_register_ctl_device_driver(void) if (adf_init_aer()) goto err_aer; - if (adf_init_pf_wq()) - goto err_pf_wq; - if (qat_crypto_register()) goto err_crypto_register; return 0; err_crypto_register: - adf_exit_pf_wq(); -err_pf_wq: adf_exit_aer(); err_aer: adf_chr_drv_destroy(); @@ -492,7 +487,6 @@ static void __exit adf_unregister_ctl_device_driver(void) { adf_chr_drv_destroy(); adf_exit_aer(); - adf_exit_pf_wq(); qat_crypto_unregister(); adf_clean_vf_map(false); mutex_destroy(&adf_ctl_lock); diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c index 38a0415e767d..1117a8b58280 100644 --- a/drivers/crypto/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -119,6 +119,11 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) int i; u32 reg; + /* Workqueue for PF2VF responses */ + pf2vf_resp_wq = create_workqueue("qat_pf2vf_resp_wq"); + if (!pf2vf_resp_wq) + return -ENOMEM; + for (i = 0, vf_info = accel_dev->pf.vf_info; i < totalvfs; i++, vf_info++) { /* This ptr will be populated when VFs will be created */ @@ -211,6 +216,11 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) kfree(accel_dev->pf.vf_info); accel_dev->pf.vf_info = NULL; + + if (pf2vf_resp_wq) { + destroy_workqueue(pf2vf_resp_wq); + pf2vf_resp_wq = NULL; + } } EXPORT_SYMBOL_GPL(adf_disable_sriov); @@ -294,19 +304,3 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs) return numvfs; } EXPORT_SYMBOL_GPL(adf_sriov_configure); - -int __init adf_init_pf_wq(void) -{ - /* Workqueue for PF2VF responses */ - pf2vf_resp_wq = create_workqueue("qat_pf2vf_resp_wq"); - - return !pf2vf_resp_wq ? -ENOMEM : 0; -} - -void adf_exit_pf_wq(void) -{ - if (pf2vf_resp_wq) { - destroy_workqueue(pf2vf_resp_wq); - pf2vf_resp_wq = NULL; - } -} diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index a04fea4d0063..b6f9f42e2985 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -63,14 +63,6 @@ static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr, ptr->eptr = upper_32_bits(dma_addr); } -static void copy_talitos_ptr(struct talitos_ptr *dst_ptr, - struct talitos_ptr *src_ptr, bool is_sec1) -{ - dst_ptr->ptr = src_ptr->ptr; - if (!is_sec1) - dst_ptr->eptr = src_ptr->eptr; -} - static void to_talitos_ptr_len(struct talitos_ptr *ptr, unsigned int len, bool is_sec1) { @@ -1091,20 +1083,21 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ?: 1, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + /* hmac data */ desc->ptr[1].len = cpu_to_be16(areq->assoclen); if (sg_count > 1 && (ret = sg_to_link_tbl_offset(areq->src, sg_count, 0, areq->assoclen, &edesc->link_tbl[tbl_off])) > 1) { + tbl_off += ret; + to_talitos_ptr(&desc->ptr[1], edesc->dma_link_tbl + tbl_off * sizeof(struct talitos_ptr), 0); desc->ptr[1].j_extent = DESC_PTR_LNKTBL_JUMP; dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); - - tbl_off += ret; } else { to_talitos_ptr(&desc->ptr[1], sg_dma_address(areq->src), 0); desc->ptr[1].j_extent = 0; @@ -1133,13 +1126,11 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) sg_link_tbl_len += authsize; - if (sg_count == 1) { - to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src) + - areq->assoclen, 0); - } else if ((ret = sg_to_link_tbl_offset(areq->src, sg_count, - areq->assoclen, sg_link_tbl_len, - &edesc->link_tbl[tbl_off])) > - 1) { + if (sg_count > 1 && + (ret = sg_to_link_tbl_offset(areq->src, sg_count, areq->assoclen, + sg_link_tbl_len, + &edesc->link_tbl[tbl_off])) > 1) { + tbl_off += ret; desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl + tbl_off * @@ -1147,10 +1138,8 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); - tbl_off += ret; - } else { - copy_talitos_ptr(&desc->ptr[4], &edesc->link_tbl[tbl_off], 0); - } + } else + to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src), 0); /* cipher out */ desc->ptr[5].len = cpu_to_be16(cryptlen); @@ -1162,13 +1151,11 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->icv_ool = false; - if (sg_count == 1) { - to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst) + - areq->assoclen, 0); - } else if ((sg_count = - sg_to_link_tbl_offset(areq->dst, sg_count, + if (sg_count > 1 && + (sg_count = sg_to_link_tbl_offset(areq->dst, sg_count, areq->assoclen, cryptlen, - &edesc->link_tbl[tbl_off])) > 1) { + &edesc->link_tbl[tbl_off])) > + 1) { struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl + @@ -1191,9 +1178,8 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->dma_len, DMA_BIDIRECTIONAL); edesc->icv_ool = true; - } else { - copy_talitos_ptr(&desc->ptr[5], &edesc->link_tbl[tbl_off], 0); - } + } else + to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst), 0); /* iv out */ map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, @@ -2533,11 +2519,21 @@ struct talitos_crypto_alg { struct talitos_alg_template algt; }; -static int talitos_init_common(struct talitos_ctx *ctx, - struct talitos_crypto_alg *talitos_alg) +static int talitos_cra_init(struct crypto_tfm *tfm) { + struct crypto_alg *alg = tfm->__crt_alg; + struct talitos_crypto_alg *talitos_alg; + struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); struct talitos_private *priv; + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH) + talitos_alg = container_of(__crypto_ahash_alg(alg), + struct talitos_crypto_alg, + algt.alg.hash); + else + talitos_alg = container_of(alg, struct talitos_crypto_alg, + algt.alg.crypto); + /* update context with ptr to dev */ ctx->dev = talitos_alg->dev; @@ -2555,33 +2551,10 @@ static int talitos_init_common(struct talitos_ctx *ctx, return 0; } -static int talitos_cra_init(struct crypto_tfm *tfm) -{ - struct crypto_alg *alg = tfm->__crt_alg; - struct talitos_crypto_alg *talitos_alg; - struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); - - if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH) - talitos_alg = container_of(__crypto_ahash_alg(alg), - struct talitos_crypto_alg, - algt.alg.hash); - else - talitos_alg = container_of(alg, struct talitos_crypto_alg, - algt.alg.crypto); - - return talitos_init_common(ctx, talitos_alg); -} - static int talitos_cra_init_aead(struct crypto_aead *tfm) { - struct aead_alg *alg = crypto_aead_alg(tfm); - struct talitos_crypto_alg *talitos_alg; - struct talitos_ctx *ctx = crypto_aead_ctx(tfm); - - talitos_alg = container_of(alg, struct talitos_crypto_alg, - algt.alg.aead); - - return talitos_init_common(ctx, talitos_alg); + talitos_cra_init(crypto_aead_tfm(tfm)); + return 0; } static int talitos_cra_init_ahash(struct crypto_tfm *tfm) diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index e0f75b0022fc..b997e79e3d73 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -67,8 +67,6 @@ struct hwmon_node { unsigned long hyst_en; unsigned long above_low_power; unsigned long prev_req; - unsigned long up_wake_mbps; - unsigned long down_wake_mbps; unsigned int wake; unsigned int down_cnt; ktime_t prev_ts; @@ -191,7 +189,7 @@ static unsigned int mbps_to_bytes(unsigned long mbps, unsigned int ms) return mbps; } -static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) +static int __bw_hwmon_sw_sample_end(struct bw_hwmon *hwmon) { struct devfreq *df; struct hwmon_node *node; @@ -220,9 +218,9 @@ static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) * bandwidth usage and do the bandwidth calculation based on just * this micro sample. */ - if (mbps > node->up_wake_mbps) { + if (mbps > node->hw->up_wake_mbps) { wake = UP_WAKE; - } else if (mbps < node->down_wake_mbps) { + } else if (mbps < node->hw->down_wake_mbps) { if (node->down_cnt) node->down_cnt--; if (node->down_cnt <= 0) @@ -241,6 +239,50 @@ static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) return wake; } +static int __bw_hwmon_hw_sample_end(struct bw_hwmon *hwmon) +{ + struct devfreq *df; + struct hwmon_node *node; + unsigned long bytes, mbps; + int wake = 0; + + df = hwmon->df; + node = df->data; + + /* + * If this read is in response to an IRQ, the HW monitor should + * return the measurement in the micro sample that triggered the IRQ. + * Otherwise, it should return the maximum measured value in any + * micro sample since the last time we called get_bytes_and_clear() + */ + bytes = hwmon->get_bytes_and_clear(hwmon); + mbps = bytes_to_mbps(bytes, node->sample_ms * USEC_PER_MSEC); + node->max_mbps = mbps; + + if (mbps > node->hw->up_wake_mbps) + wake = UP_WAKE; + else if (mbps < node->hw->down_wake_mbps) + wake = DOWN_WAKE; + + node->wake = wake; + node->sampled = true; + + trace_bw_hwmon_meas(dev_name(df->dev.parent), + mbps, + node->sample_ms * USEC_PER_MSEC, + wake); + + return 1; +} + +static int __bw_hwmon_sample_end(struct bw_hwmon *hwmon) +{ + if (hwmon->set_hw_events) + return __bw_hwmon_hw_sample_end(hwmon); + else + return __bw_hwmon_sw_sample_end(hwmon); +} + int bw_hwmon_sample_end(struct bw_hwmon *hwmon) { unsigned long flags; @@ -275,12 +317,14 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, struct bw_hwmon *hw = node->hw; unsigned int new_bw, io_percent; ktime_t ts; - unsigned int ms; + unsigned int ms = 0; spin_lock_irqsave(&irq_lock, flags); - ts = ktime_get(); - ms = ktime_to_ms(ktime_sub(ts, node->prev_ts)); + if (!hw->set_hw_events) { + ts = ktime_get(); + ms = ktime_to_ms(ktime_sub(ts, node->prev_ts)); + } if (!node->sampled || ms >= node->sample_ms) __bw_hwmon_sample_end(node->hw); node->sampled = false; @@ -388,9 +432,10 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, /* Stretch the short sample window size, if the traffic is too low */ if (meas_mbps < MIN_MBPS) { - node->up_wake_mbps = (max(MIN_MBPS, req_mbps) + hw->up_wake_mbps = (max(MIN_MBPS, req_mbps) * (100 + node->up_thres)) / 100; - node->down_wake_mbps = 0; + hw->down_wake_mbps = 0; + hw->undo_over_req_mbps = 0; thres = mbps_to_bytes(max(MIN_MBPS, req_mbps / 2), node->sample_ms); } else { @@ -401,13 +446,22 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, * reduce the vote based on the measured mbps being less than * the previous measurement that caused the "over request". */ - node->up_wake_mbps = (req_mbps * (100 + node->up_thres)) / 100; - node->down_wake_mbps = (meas_mbps * node->down_thres) / 100; + hw->up_wake_mbps = (req_mbps * (100 + node->up_thres)) / 100; + hw->down_wake_mbps = (meas_mbps * node->down_thres) / 100; + if (node->wake == UP_WAKE) + hw->undo_over_req_mbps = min(req_mbps, meas_mbps_zone); + else + hw->undo_over_req_mbps = 0; thres = mbps_to_bytes(meas_mbps, node->sample_ms); } - node->down_cnt = node->down_count; - node->bytes = hw->set_thres(hw, thres); + if (hw->set_hw_events) { + hw->down_cnt = node->down_count; + hw->set_hw_events(hw, node->sample_ms); + } else { + node->down_cnt = node->down_count; + node->bytes = hw->set_thres(hw, thres); + } node->wake = 0; node->prev_req = req_mbps; @@ -432,8 +486,8 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, trace_bw_hwmon_update(dev_name(node->hw->df->dev.parent), new_bw, *freq, - node->up_wake_mbps, - node->down_wake_mbps); + hw->up_wake_mbps, + hw->down_wake_mbps); return req_mbps; } @@ -503,6 +557,9 @@ static int start_monitor(struct devfreq *df, bool init) node->resume_freq = 0; node->resume_ab = 0; mbps = (df->previous_freq * node->io_percent) / 100; + hw->up_wake_mbps = mbps; + hw->down_wake_mbps = MIN_MBPS; + hw->undo_over_req_mbps = 0; ret = hw->start_hwmon(hw, mbps); } else { ret = hw->resume_hwmon(hw); diff --git a/drivers/devfreq/governor_bw_hwmon.h b/drivers/devfreq/governor_bw_hwmon.h index 59bf48ac5af7..7578399cfb88 100644 --- a/drivers/devfreq/governor_bw_hwmon.h +++ b/drivers/devfreq/governor_bw_hwmon.h @@ -48,6 +48,8 @@ struct bw_hwmon { int (*suspend_hwmon)(struct bw_hwmon *hw); int (*resume_hwmon)(struct bw_hwmon *hw); unsigned long (*set_thres)(struct bw_hwmon *hw, unsigned long bytes); + unsigned long (*set_hw_events)(struct bw_hwmon *hw, + unsigned int sample_ms); unsigned long (*get_bytes_and_clear)(struct bw_hwmon *hw); int (*set_throttle_adj)(struct bw_hwmon *hw, uint adj); u32 (*get_throttle_adj)(struct bw_hwmon *hw); @@ -55,6 +57,11 @@ struct bw_hwmon { struct device_node *of_node; struct devfreq_governor *gov; + unsigned long up_wake_mbps; + unsigned long undo_over_req_mbps; + unsigned long down_wake_mbps; + unsigned int down_cnt; + struct devfreq *df; }; diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index c66133b5e852..4f099ea29f83 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -130,14 +130,26 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) static void dwc_initialize(struct dw_dma_chan *dwc) { struct dw_dma *dw = to_dw_dma(dwc->chan.device); + struct dw_dma_slave *dws = dwc->chan.private; u32 cfghi = DWC_CFGH_FIFO_MODE; u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); if (dwc->initialized == true) return; - cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); - cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); + if (dws) { + /* + * We need controller-specific data to set up slave + * transfers. + */ + BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); + + cfghi |= DWC_CFGH_DST_PER(dws->dst_id); + cfghi |= DWC_CFGH_SRC_PER(dws->src_id); + } else { + cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); + cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); + } channel_writel(dwc, CFG_LO, cfglo); channel_writel(dwc, CFG_HI, cfghi); @@ -924,7 +936,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param) struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma_slave *dws = param; - if (dws->dma_dev != chan->device->dev) + if (!dws || dws->dma_dev != chan->device->dev) return false; /* We have to copy data since dws can be temporary storage */ @@ -1148,14 +1160,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) * doesn't mean what you think it means), and status writeback. */ - /* - * We need controller-specific data to set up slave transfers. - */ - if (chan->private && !dw_dma_filter(chan, chan->private)) { - dev_warn(chan2dev(chan), "Wrong controller-specific data\n"); - return -EINVAL; - } - /* Enable controller here if needed */ if (!dw->in_use) dw_dma_on(dw); @@ -1217,14 +1221,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); list_splice_init(&dwc->free_list, &list); dwc->descs_allocated = 0; - - /* Clear custom channel configuration */ - dwc->src_id = 0; - dwc->dst_id = 0; - - dwc->src_master = 0; - dwc->dst_master = 0; - dwc->initialized = false; /* Disable interrupts */ diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index efc02b98e6ba..823ad728aecf 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -135,7 +135,7 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) sr = hsu_chan_readl(hsuc, HSU_CH_SR); spin_unlock_irqrestore(&hsuc->vchan.lock, flags); - return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); + return sr; } irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h index 26da2865b025..f06579c6d548 100644 --- a/drivers/dma/hsu/hsu.h +++ b/drivers/dma/hsu/hsu.h @@ -41,9 +41,6 @@ #define HSU_CH_SR_DESCTO(x) BIT(8 + (x)) #define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8)) #define HSU_CH_SR_CHE BIT(15) -#define HSU_CH_SR_DESCE(x) BIT(16 + (x)) -#define HSU_CH_SR_DESCE_ANY (BIT(19) | BIT(18) | BIT(17) | BIT(16)) -#define HSU_CH_SR_CDESC_ANY (BIT(31) | BIT(30)) /* Bits in HSU_CH_CR */ #define HSU_CH_CR_CHA BIT(0) diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 55f5d33f6dc7..a59061e4221a 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -122,7 +122,6 @@ struct pxad_chan { struct pxad_device { struct dma_device slave; int nr_chans; - int nr_requestors; void __iomem *base; struct pxad_phy *phys; spinlock_t phy_lock; /* Phy association */ @@ -474,7 +473,7 @@ static void pxad_free_phy(struct pxad_chan *chan) return; /* clear the channel mapping in DRCMR */ - if (chan->drcmr <= pdev->nr_requestors) { + if (chan->drcmr <= DRCMR_CHLNUM) { reg = pxad_drcmr(chan->drcmr); writel_relaxed(0, chan->phy->base + reg); } @@ -510,7 +509,6 @@ static bool is_running_chan_misaligned(struct pxad_chan *chan) static void phy_enable(struct pxad_phy *phy, bool misaligned) { - struct pxad_device *pdev; u32 reg, dalgn; if (!phy->vchan) @@ -520,8 +518,7 @@ static void phy_enable(struct pxad_phy *phy, bool misaligned) "%s(); phy=%p(%d) misaligned=%d\n", __func__, phy, phy->idx, misaligned); - pdev = to_pxad_dev(phy->vchan->vc.chan.device); - if (phy->vchan->drcmr <= pdev->nr_requestors) { + if (phy->vchan->drcmr <= DRCMR_CHLNUM) { reg = pxad_drcmr(phy->vchan->drcmr); writel_relaxed(DRCMR_MAPVLD | phy->idx, phy->base + reg); } @@ -917,7 +914,6 @@ static void pxad_get_config(struct pxad_chan *chan, { u32 maxburst = 0, dev_addr = 0; enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED; - struct pxad_device *pdev = to_pxad_dev(chan->vc.chan.device); *dcmd = 0; if (dir == DMA_DEV_TO_MEM) { @@ -926,7 +922,7 @@ static void pxad_get_config(struct pxad_chan *chan, dev_addr = chan->cfg.src_addr; *dev_src = dev_addr; *dcmd |= PXA_DCMD_INCTRGADDR; - if (chan->drcmr <= pdev->nr_requestors) + if (chan->drcmr <= DRCMR_CHLNUM) *dcmd |= PXA_DCMD_FLOWSRC; } if (dir == DMA_MEM_TO_DEV) { @@ -935,7 +931,7 @@ static void pxad_get_config(struct pxad_chan *chan, dev_addr = chan->cfg.dst_addr; *dev_dst = dev_addr; *dcmd |= PXA_DCMD_INCSRCADDR; - if (chan->drcmr <= pdev->nr_requestors) + if (chan->drcmr <= DRCMR_CHLNUM) *dcmd |= PXA_DCMD_FLOWTRG; } if (dir == DMA_MEM_TO_MEM) @@ -1345,15 +1341,13 @@ static struct dma_chan *pxad_dma_xlate(struct of_phandle_args *dma_spec, static int pxad_init_dmadev(struct platform_device *op, struct pxad_device *pdev, - unsigned int nr_phy_chans, - unsigned int nr_requestors) + unsigned int nr_phy_chans) { int ret; unsigned int i; struct pxad_chan *c; pdev->nr_chans = nr_phy_chans; - pdev->nr_requestors = nr_requestors; INIT_LIST_HEAD(&pdev->slave.channels); pdev->slave.device_alloc_chan_resources = pxad_alloc_chan_resources; pdev->slave.device_free_chan_resources = pxad_free_chan_resources; @@ -1388,7 +1382,7 @@ static int pxad_probe(struct platform_device *op) const struct of_device_id *of_id; struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev); struct resource *iores; - int ret, dma_channels = 0, nb_requestors = 0; + int ret, dma_channels = 0; const enum dma_slave_buswidth widths = DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -1405,23 +1399,13 @@ static int pxad_probe(struct platform_device *op) return PTR_ERR(pdev->base); of_id = of_match_device(pxad_dt_ids, &op->dev); - if (of_id) { + if (of_id) of_property_read_u32(op->dev.of_node, "#dma-channels", &dma_channels); - ret = of_property_read_u32(op->dev.of_node, "#dma-requests", - &nb_requestors); - if (ret) { - dev_warn(pdev->slave.dev, - "#dma-requests set to default 32 as missing in OF: %d", - ret); - nb_requestors = 32; - }; - } else if (pdata && pdata->dma_channels) { + else if (pdata && pdata->dma_channels) dma_channels = pdata->dma_channels; - nb_requestors = pdata->nb_requestors; - } else { + else dma_channels = 32; /* default 32 channel */ - } dma_cap_set(DMA_SLAVE, pdev->slave.cap_mask); dma_cap_set(DMA_MEMCPY, pdev->slave.cap_mask); @@ -1438,7 +1422,7 @@ static int pxad_probe(struct platform_device *op) pdev->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; pdev->slave.dev = &op->dev; - ret = pxad_init_dmadev(op, pdev, dma_channels, nb_requestors); + ret = pxad_init_dmadev(op, pdev, dma_channels); if (ret) { dev_err(pdev->slave.dev, "unable to register\n"); return ret; @@ -1457,8 +1441,7 @@ static int pxad_probe(struct platform_device *op) platform_set_drvdata(op, pdev); pxad_init_debugfs(pdev); - dev_info(pdev->slave.dev, "initialized %d channels on %d requestors\n", - dma_channels, nb_requestors); + dev_info(pdev->slave.dev, "initialized %d channels\n", dma_channels); return 0; } diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 792bdae2b91d..01087a38da22 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1866,7 +1866,7 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val, i7_dev = get_i7core_dev(mce->socketid); if (!i7_dev) - return NOTIFY_DONE; + return NOTIFY_BAD; mci = i7_dev->mci; pvt = mci->pvt_info; diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 37649221f81c..cbee3179ec08 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1396,7 +1396,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, } ch_way = TAD_CH(reg) + 1; - sck_way = TAD_SOCK(reg); + sck_way = 1 << TAD_SOCK(reg); if (ch_way == 3) idx = addr >> 6; @@ -1435,7 +1435,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, switch(ch_way) { case 2: case 4: - sck_xch = (1 << sck_way) * (ch_way >> 1); + sck_xch = 1 << sck_way * (ch_way >> 1); break; default: sprintf(msg, "Invalid mirror set. Can't decode addr"); @@ -1471,7 +1471,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ch_addr = addr - offset; ch_addr >>= (6 + shiftup); - ch_addr /= sck_xch; + ch_addr /= ch_way * sck_way; ch_addr <<= (6 + shiftup); ch_addr |= addr & ((1 << (6 + shiftup)) - 1); @@ -2254,7 +2254,7 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, mci = get_mci_for_node_id(mce->socketid); if (!mci) - return NOTIFY_DONE; + return NOTIFY_BAD; pvt = mci->pvt_info; /* diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index b6cb30d207be..9f9ea334399c 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -803,7 +803,7 @@ static int max77843_muic_probe(struct platform_device *pdev) /* Clear IRQ bits before request IRQs */ ret = regmap_bulk_read(max77843->regmap_muic, MAX77843_MUIC_REG_INT1, info->status, - MAX77843_MUIC_STATUS_NUM); + MAX77843_MUIC_IRQ_NUM); if (ret) { dev_err(&pdev->dev, "Failed to Clear IRQ bits\n"); goto err_muic_irq; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 3b52677f459a..027ca212179f 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -180,7 +180,6 @@ static int generic_ops_register(void) { generic_ops.get_variable = efi.get_variable; generic_ops.set_variable = efi.set_variable; - generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking; generic_ops.get_next_variable = efi.get_next_variable; generic_ops.query_variable_store = efi_query_variable_store; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index d775e2bfc017..b2a172d93a08 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -8,7 +8,7 @@ cflags-$(CONFIG_X86_32) := -march=i386 cflags-$(CONFIG_X86_64) := -mcmodel=small cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ -fPIC -fno-strict-aliasing -mno-red-zone \ - -mno-mmx -mno-sse + -mno-mmx -mno-sse -DDISABLE_BRANCH_PROFILING cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ @@ -16,7 +16,7 @@ cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt -KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ +KBUILD_CFLAGS := $(cflags-y) \ $(call cc-option,-ffreestanding) \ $(call cc-option,-fno-stack-protector) @@ -35,8 +35,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ $(patsubst %.c,lib-%.o,$(arm-deps)) -lib-$(CONFIG_ARM) += arm32-stub.o -lib-$(CONFIG_ARM64) += arm64-stub.o random.o +lib-$(CONFIG_ARM64) += arm64-stub.o CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index d5aa1d16154f..950c87f5d279 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -18,8 +18,6 @@ #include "efistub.h" -bool __nokaslr; - static int efi_secureboot_enabled(efi_system_table_t *sys_table_arg) { static efi_guid_t const var_guid = EFI_GLOBAL_VARIABLE_GUID; @@ -209,6 +207,14 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, pr_efi_err(sys_table, "Failed to find DRAM base\n"); goto fail; } + status = handle_kernel_image(sys_table, image_addr, &image_size, + &reserve_addr, + &reserve_size, + dram_base, image); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to relocate kernel\n"); + goto fail; + } /* * Get the command line from EFI, using the LOADED_IMAGE @@ -218,28 +224,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size); if (!cmdline_ptr) { pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n"); - goto fail; - } - - /* check whether 'nokaslr' was passed on the command line */ - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - static const u8 default_cmdline[] = CONFIG_CMDLINE; - const u8 *str, *cmdline = cmdline_ptr; - - if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) - cmdline = default_cmdline; - str = strstr(cmdline, "nokaslr"); - if (str == cmdline || (str > cmdline && *(str - 1) == ' ')) - __nokaslr = true; - } - - status = handle_kernel_image(sys_table, image_addr, &image_size, - &reserve_addr, - &reserve_size, - dram_base, image); - if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Failed to relocate kernel\n"); - goto fail_free_cmdline; + goto fail_free_image; } status = efi_parse_options(cmdline_ptr); @@ -259,7 +244,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (status != EFI_SUCCESS) { pr_efi_err(sys_table, "Failed to load device tree!\n"); - goto fail_free_image; + goto fail_free_cmdline; } } @@ -301,11 +286,12 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, efi_free(sys_table, initrd_size, initrd_addr); efi_free(sys_table, fdt_size, fdt_addr); +fail_free_cmdline: + efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr); + fail_free_image: efi_free(sys_table, image_size, *image_addr); efi_free(sys_table, reserve_size, reserve_addr); -fail_free_cmdline: - efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr); fail: return EFI_ERROR; } diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index e0e6b74fef8f..78dfbd34b6bf 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -13,10 +13,6 @@ #include <asm/efi.h> #include <asm/sections.h> -#include "efistub.h" - -extern bool __nokaslr; - efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, unsigned long *image_addr, unsigned long *image_size, @@ -27,52 +23,26 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, { efi_status_t status; unsigned long kernel_size, kernel_memsize = 0; + unsigned long nr_pages; void *old_image_addr = (void *)*image_addr; unsigned long preferred_offset; - u64 phys_seed = 0; - - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - if (!__nokaslr) { - status = efi_get_random_bytes(sys_table_arg, - sizeof(phys_seed), - (u8 *)&phys_seed); - if (status == EFI_NOT_FOUND) { - pr_efi(sys_table_arg, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n"); - } else if (status != EFI_SUCCESS) { - pr_efi_err(sys_table_arg, "efi_get_random_bytes() failed\n"); - return status; - } - } else { - pr_efi(sys_table_arg, "KASLR disabled on kernel command line\n"); - } - } /* * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond * a 2 MB aligned base, which itself may be lower than dram_base, as * long as the resulting offset equals or exceeds it. */ - preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET; + preferred_offset = round_down(dram_base, SZ_2M) + TEXT_OFFSET; if (preferred_offset < dram_base) - preferred_offset += MIN_KIMG_ALIGN; + preferred_offset += SZ_2M; + /* Relocate the image, if required. */ kernel_size = _edata - _text; - kernel_memsize = kernel_size + (_end - _edata); - - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) { - /* - * If KASLR is enabled, and we have some randomness available, - * locate the kernel at a randomized offset in physical memory. - */ - *reserve_size = kernel_memsize + TEXT_OFFSET; - status = efi_random_alloc(sys_table_arg, *reserve_size, - MIN_KIMG_ALIGN, reserve_addr, - phys_seed); + if (*image_addr != preferred_offset) { + kernel_memsize = kernel_size + (_end - _edata); - *image_addr = *reserve_addr + TEXT_OFFSET; - } else { /* - * Else, try a straight allocation at the preferred offset. + * First, try a straight allocation at the preferred offset. * This will work around the issue where, if dram_base == 0x0, * efi_low_alloc() refuses to allocate at 0x0 (to prevent the * address of the allocation to be mistaken for a FAIL return @@ -82,31 +52,27 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, * Mustang), we can still place the kernel at the address * 'dram_base + TEXT_OFFSET'. */ - if (*image_addr == preferred_offset) - return EFI_SUCCESS; - *image_addr = *reserve_addr = preferred_offset; - *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN); - + nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / + EFI_PAGE_SIZE; status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, - EFI_LOADER_DATA, - *reserve_size / EFI_PAGE_SIZE, + EFI_LOADER_DATA, nr_pages, (efi_physical_addr_t *)reserve_addr); - } - - if (status != EFI_SUCCESS) { - *reserve_size = kernel_memsize + TEXT_OFFSET; - status = efi_low_alloc(sys_table_arg, *reserve_size, - MIN_KIMG_ALIGN, reserve_addr); - if (status != EFI_SUCCESS) { - pr_efi_err(sys_table_arg, "Failed to relocate kernel\n"); - *reserve_size = 0; - return status; + kernel_memsize += TEXT_OFFSET; + status = efi_low_alloc(sys_table_arg, kernel_memsize, + SZ_2M, reserve_addr); + + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, "Failed to relocate kernel\n"); + return status; + } + *image_addr = *reserve_addr + TEXT_OFFSET; } - *image_addr = *reserve_addr + TEXT_OFFSET; + memcpy((void *)*image_addr, old_image_addr, kernel_size); + *reserve_size = kernel_memsize; } - memcpy((void *)*image_addr, old_image_addr, kernel_size); + return EFI_SUCCESS; } diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 29ed2f9b218c..f07d4a67fa76 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -649,10 +649,6 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n) return dst; } -#ifndef MAX_CMDLINE_ADDRESS -#define MAX_CMDLINE_ADDRESS ULONG_MAX -#endif - /* * Convert the unicode UEFI command line to ASCII to pass to kernel. * Size of memory allocated return in *cmd_line_len. @@ -688,8 +684,7 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, options_bytes++; /* NUL termination */ - status = efi_high_alloc(sys_table_arg, options_bytes, 0, - &cmdline_addr, MAX_CMDLINE_ADDRESS); + status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr); if (status != EFI_SUCCESS) return NULL; diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 5ed3d3f38166..6b6548fda089 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -43,11 +43,4 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, efi_memory_desc_t *runtime_map, int *count); -efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table, - unsigned long size, u8 *out); - -efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, - unsigned long *addr, unsigned long random_seed); - #endif diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index b1c22cf18f7d..b62e2f5dcab3 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -147,20 +147,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, if (status) goto fdt_set_fail; - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - efi_status_t efi_status; - - efi_status = efi_get_random_bytes(sys_table, sizeof(fdt_val64), - (u8 *)&fdt_val64); - if (efi_status == EFI_SUCCESS) { - status = fdt_setprop(fdt, node, "kaslr-seed", - &fdt_val64, sizeof(fdt_val64)); - if (status) - goto fdt_set_fail; - } else if (efi_status != EFI_NOT_FOUND) { - return efi_status; - } - } return EFI_SUCCESS; fdt_set_fail: diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c deleted file mode 100644 index 53f6d3fe6d86..000000000000 --- a/drivers/firmware/efi/libstub/random.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2016 Linaro Ltd; <ard.biesheuvel@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/efi.h> -#include <asm/efi.h> - -#include "efistub.h" - -struct efi_rng_protocol { - efi_status_t (*get_info)(struct efi_rng_protocol *, - unsigned long *, efi_guid_t *); - efi_status_t (*get_rng)(struct efi_rng_protocol *, - efi_guid_t *, unsigned long, u8 *out); -}; - -efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg, - unsigned long size, u8 *out) -{ - efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; - efi_status_t status; - struct efi_rng_protocol *rng; - - status = efi_call_early(locate_protocol, &rng_proto, NULL, - (void **)&rng); - if (status != EFI_SUCCESS) - return status; - - return rng->get_rng(rng, NULL, size, out); -} - -/* - * Return the number of slots covered by this entry, i.e., the number of - * addresses it covers that are suitably aligned and supply enough room - * for the allocation. - */ -static unsigned long get_entry_num_slots(efi_memory_desc_t *md, - unsigned long size, - unsigned long align) -{ - u64 start, end; - - if (md->type != EFI_CONVENTIONAL_MEMORY) - return 0; - - start = round_up(md->phys_addr, align); - end = round_down(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - size, - align); - - if (start > end) - return 0; - - return (end - start + 1) / align; -} - -/* - * The UEFI memory descriptors have a virtual address field that is only used - * when installing the virtual mapping using SetVirtualAddressMap(). Since it - * is unused here, we can reuse it to keep track of each descriptor's slot - * count. - */ -#define MD_NUM_SLOTS(md) ((md)->virt_addr) - -efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, - unsigned long align, - unsigned long *addr, - unsigned long random_seed) -{ - unsigned long map_size, desc_size, total_slots = 0, target_slot; - efi_status_t status; - efi_memory_desc_t *memory_map; - int map_offset; - - status = efi_get_memory_map(sys_table_arg, &memory_map, &map_size, - &desc_size, NULL, NULL); - if (status != EFI_SUCCESS) - return status; - - if (align < EFI_ALLOC_ALIGN) - align = EFI_ALLOC_ALIGN; - - /* count the suitable slots in each memory map entry */ - for (map_offset = 0; map_offset < map_size; map_offset += desc_size) { - efi_memory_desc_t *md = (void *)memory_map + map_offset; - unsigned long slots; - - slots = get_entry_num_slots(md, size, align); - MD_NUM_SLOTS(md) = slots; - total_slots += slots; - } - - /* find a random number between 0 and total_slots */ - target_slot = (total_slots * (u16)random_seed) >> 16; - - /* - * target_slot is now a value in the range [0, total_slots), and so - * it corresponds with exactly one of the suitable slots we recorded - * when iterating over the memory map the first time around. - * - * So iterate over the memory map again, subtracting the number of - * slots of each entry at each iteration, until we have found the entry - * that covers our chosen slot. Use the residual value of target_slot - * to calculate the randomly chosen address, and allocate it directly - * using EFI_ALLOCATE_ADDRESS. - */ - for (map_offset = 0; map_offset < map_size; map_offset += desc_size) { - efi_memory_desc_t *md = (void *)memory_map + map_offset; - efi_physical_addr_t target; - unsigned long pages; - - if (target_slot >= MD_NUM_SLOTS(md)) { - target_slot -= MD_NUM_SLOTS(md); - continue; - } - - target = round_up(md->phys_addr, align) + target_slot * align; - pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; - - status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, - EFI_LOADER_DATA, pages, &target); - if (status == EFI_SUCCESS) - *addr = target; - break; - } - - efi_call_early(free_pool, memory_map); - - return status; -} diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 6f182fd91a6d..7f2ea21c730d 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -202,44 +202,29 @@ static const struct variable_validate variable_validate[] = { { NULL_GUID, "", NULL }, }; -/* - * Check if @var_name matches the pattern given in @match_name. - * - * @var_name: an array of @len non-NUL characters. - * @match_name: a NUL-terminated pattern string, optionally ending in "*". A - * final "*" character matches any trailing characters @var_name, - * including the case when there are none left in @var_name. - * @match: on output, the number of non-wildcard characters in @match_name - * that @var_name matches, regardless of the return value. - * @return: whether @var_name fully matches @match_name. - */ static bool variable_matches(const char *var_name, size_t len, const char *match_name, int *match) { for (*match = 0; ; (*match)++) { char c = match_name[*match]; + char u = var_name[*match]; - switch (c) { - case '*': - /* Wildcard in @match_name means we've matched. */ + /* Wildcard in the matching name means we've matched */ + if (c == '*') return true; - case '\0': - /* @match_name has ended. Has @var_name too? */ - return (*match == len); + /* Case sensitive match */ + if (!c && *match == len) + return true; - default: - /* - * We've reached a non-wildcard char in @match_name. - * Continue only if there's an identical character in - * @var_name. - */ - if (*match < len && c == var_name[*match]) - continue; + if (c != u) return false; - } + + if (!c) + return true; } + return true; } bool diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 053fc2f465df..bb1099c549df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1673,7 +1673,6 @@ struct amdgpu_uvd { struct amdgpu_bo *vcpu_bo; void *cpu_addr; uint64_t gpu_addr; - unsigned fw_version; atomic_t handles[AMDGPU_MAX_UVD_HANDLES]; struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES]; struct delayed_work idle_work; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 5a8fbadbd27b..8ac49812a716 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -63,6 +63,10 @@ bool amdgpu_has_atpx(void) { return amdgpu_atpx_priv.atpx_detected; } +bool amdgpu_has_atpx_dgpu_power_cntl(void) { + return amdgpu_atpx_priv.atpx.functions.power_cntl; +} + /** * amdgpu_atpx_call - call an ATPX method * @@ -142,10 +146,6 @@ static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mas */ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx) { - /* make sure required functions are enabled */ - /* dGPU power control is required */ - atpx->functions.power_cntl = true; - if (atpx->functions.px_params) { union acpi_object *info; struct atpx_px_params output; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c961fe093e12..9d88023df836 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -61,6 +61,12 @@ static const char *amdgpu_asic_name[] = { "LAST", }; +#if defined(CONFIG_VGA_SWITCHEROO) +bool amdgpu_has_atpx_dgpu_power_cntl(void); +#else +static inline bool amdgpu_has_atpx_dgpu_power_cntl(void) { return false; } +#endif + bool amdgpu_device_is_px(struct drm_device *dev) { struct amdgpu_device *adev = dev->dev_private; @@ -1469,7 +1475,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (amdgpu_runtime_pm == 1) runtime = true; - if (amdgpu_device_is_px(ddev)) + if (amdgpu_device_is_px(ddev) && amdgpu_has_atpx_dgpu_power_cntl()) runtime = true; vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime); if (runtime) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 4488e82f87b0..e23843f4d877 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -303,7 +303,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file fw_info.feature = adev->vce.fb_version; break; case AMDGPU_INFO_FW_UVD: - fw_info.ver = adev->uvd.fw_version; + fw_info.ver = 0; fw_info.feature = 0; break; case AMDGPU_INFO_FW_GMC: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 89df7871653d..064ebb347074 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -52,7 +52,7 @@ struct amdgpu_hpd; #define AMDGPU_MAX_HPD_PINS 6 #define AMDGPU_MAX_CRTCS 6 -#define AMDGPU_MAX_AFMT_BLOCKS 9 +#define AMDGPU_MAX_AFMT_BLOCKS 7 enum amdgpu_rmx_type { RMX_OFF, @@ -308,8 +308,8 @@ struct amdgpu_mode_info { struct atom_context *atom_context; struct card_info *atom_card_info; bool mode_config_initialized; - struct amdgpu_crtc *crtcs[AMDGPU_MAX_CRTCS]; - struct amdgpu_afmt *afmt[AMDGPU_MAX_AFMT_BLOCKS]; + struct amdgpu_crtc *crtcs[6]; + struct amdgpu_afmt *afmt[7]; /* DVI-I properties */ struct drm_property *coherent_mode_property; /* DAC enable load detect */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 73628c7599e7..b8fbbd7699e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -540,7 +540,6 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, if (!metadata_size) { if (bo->metadata_size) { kfree(bo->metadata); - bo->metadata = NULL; bo->metadata_size = 0; } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 3b35ad83867c..53f987aeeacf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -156,9 +156,6 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", version_major, version_minor, family_id); - adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) | - (family_id << 8)); - bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) + AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE; r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true, @@ -276,8 +273,6 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) memcpy(adev->uvd.cpu_addr, (adev->uvd.fw->data) + offset, (adev->uvd.fw->size) - offset); - cancel_delayed_work_sync(&adev->uvd.idle_work); - size = amdgpu_bo_size(adev->uvd.vcpu_bo); size -= le32_to_cpu(hdr->ucode_size_bytes); ptr = adev->uvd.cpu_addr; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index bb0da76051a1..a745eeeb5d82 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -220,7 +220,6 @@ int amdgpu_vce_suspend(struct amdgpu_device *adev) if (i == AMDGPU_MAX_VCE_HANDLES) return 0; - cancel_delayed_work_sync(&adev->vce.idle_work); /* TODO: suspending running encoding sessions isn't supported */ return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index 1cd6de575305..1e0bba29e167 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -298,10 +298,6 @@ bool amdgpu_atombios_encoder_mode_fixup(struct drm_encoder *encoder, && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; - /* vertical FP must be at least 1 */ - if (mode->crtc_vsync_start == mode->crtc_vdisplay) - adjusted_mode->crtc_vsync_start++; - /* get the native mode for scaling */ if (amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) amdgpu_panel_mode_fixup(encoder, adjusted_mode); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 946300764609..aa491540ba85 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -3628,7 +3628,7 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vm_id, uint64_t pd_addr) { int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX); - uint32_t seq = ring->fence_drv.sync_seq[ring->idx]; + uint32_t seq = ring->fence_drv.sync_seq; uint64_t addr = ring->fence_drv.gpu_addr; amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c index d5e19b5fbbfb..c34c393e9aea 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c @@ -513,7 +513,7 @@ static int dbgdev_wave_control_set_registers( union SQ_CMD_BITS *in_reg_sq_cmd, union GRBM_GFX_INDEX_BITS *in_reg_gfx_index) { - int status = 0; + int status; union SQ_CMD_BITS reg_sq_cmd; union GRBM_GFX_INDEX_BITS reg_gfx_index; struct HsaDbgWaveMsgAMDGen2 *pMsg; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index d268bf18a662..39d7e2e15c11 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1665,19 +1665,13 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb; int len, ret, port_num; - port = drm_dp_get_validated_port_ref(mgr, port); - if (!port) - return -EINVAL; - port_num = port->port_num; mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); if (!mstb) { mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num); - if (!mstb) { - drm_dp_put_port(port); + if (!mstb) return -EINVAL; - } } txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); @@ -1703,7 +1697,6 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, kfree(txmsg); fail_put: drm_dp_put_mst_branch_device(mstb); - drm_dp_put_port(port); return ret; } @@ -1786,11 +1779,6 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) req_payload.start_slot = cur_slots; if (mgr->proposed_vcpis[i]) { port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi); - port = drm_dp_get_validated_port_ref(mgr, port); - if (!port) { - mutex_unlock(&mgr->payload_lock); - return -EINVAL; - } req_payload.num_slots = mgr->proposed_vcpis[i]->num_slots; } else { port = NULL; @@ -1816,9 +1804,6 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) mgr->payloads[i].payload_state = req_payload.payload_state; } cur_slots += req_payload.num_slots; - - if (port) - drm_dp_put_port(port); } for (i = 0; i < mgr->max_payloads; i++) { @@ -2124,8 +2109,6 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) if (mgr->mst_primary) { int sret; - u8 guid[16]; - sret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE); if (sret != DP_RECEIVER_CAP_SIZE) { DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); @@ -2140,16 +2123,6 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) ret = -1; goto out_unlock; } - - /* Some hubs forget their guids after they resume */ - sret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16); - if (sret != 16) { - DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); - ret = -1; - goto out_unlock; - } - drm_dp_check_mstb_guid(mgr->mst_primary, guid); - ret = 0; } else ret = -1; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7e461dca564c..bc7b8faba84d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2838,14 +2838,7 @@ enum skl_disp_power_wells { #define GEN6_RP_STATE_CAP (MCHBAR_MIRROR_BASE_SNB + 0x5998) #define BXT_RP_STATE_CAP 0x138170 -/* - * Make these a multiple of magic 25 to avoid SNB (eg. Dell XPS - * 8300) freezing up around GPU hangs. Looks as if even - * scheduling/timer interrupts start misbehaving if the RPS - * EI/thresholds are "bad", leading to a very sluggish or even - * frozen machine. - */ -#define INTERVAL_1_28_US(us) roundup(((us) * 100) >> 7, 25) +#define INTERVAL_1_28_US(us) (((us) * 100) >> 7) #define INTERVAL_1_33_US(us) (((us) * 3) >> 2) #define INTERVAL_0_833_US(us) (((us) * 6) / 5) #define GT_INTERVAL_FROM_US(dev_priv, us) (IS_GEN9(dev_priv) ? \ diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 97d1ed20418b..6a2c76e367a5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -248,14 +248,8 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder, pipe_config->has_pch_encoder = true; /* LPT FDI RX only supports 8bpc. */ - if (HAS_PCH_LPT(dev)) { - if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { - DRM_DEBUG_KMS("LPT only supports 24bpp\n"); - return false; - } - + if (HAS_PCH_LPT(dev)) pipe_config->pipe_bpp = 24; - } /* FDI must always be 2.7 GHz */ if (HAS_DDI(dev)) { diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index fc28c512ece3..9e530a739354 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -180,8 +180,7 @@ struct stepping_info { static const struct stepping_info skl_stepping_info[] = { {'A', '0'}, {'B', '0'}, {'C', '0'}, {'D', '0'}, {'E', '0'}, {'F', '0'}, - {'G', '0'}, {'H', '0'}, {'I', '0'}, - {'J', '0'}, {'K', '0'} + {'G', '0'}, {'H', '0'}, {'I', '0'} }; static struct stepping_info bxt_stepping_info[] = { diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3c6b07683bd9..7e6158b889da 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -464,17 +464,9 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, } else if (IS_BROADWELL(dev)) { ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; - - if (dev_priv->edp_low_vswing) { - ddi_translations_edp = bdw_ddi_translations_edp; - n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp); - } else { - ddi_translations_edp = bdw_ddi_translations_dp; - n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_dp); - } - + ddi_translations_edp = bdw_ddi_translations_edp; ddi_translations_hdmi = bdw_ddi_translations_hdmi; - + n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp); n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp); n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); hdmi_default_entry = 7; @@ -3196,6 +3188,12 @@ void intel_ddi_get_config(struct intel_encoder *encoder, intel_ddi_clock_get(encoder, pipe_config); } +static void intel_ddi_destroy(struct drm_encoder *encoder) +{ + /* HDMI has nothing special to destroy, so we can go with this. */ + intel_dp_encoder_destroy(encoder); +} + static bool intel_ddi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { @@ -3214,8 +3212,7 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder, } static const struct drm_encoder_funcs intel_ddi_funcs = { - .reset = intel_dp_encoder_reset, - .destroy = intel_dp_encoder_destroy, + .destroy = intel_ddi_destroy, }; static struct intel_connector * @@ -3287,7 +3284,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->post_disable = intel_ddi_post_disable; intel_encoder->get_hw_state = intel_ddi_get_hw_state; intel_encoder->get_config = intel_ddi_get_config; - intel_encoder->suspend = intel_dp_encoder_suspend; intel_dig_port->port = port; intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index afa81691163d..f859a5b87ed4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4447,7 +4447,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state) intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX, - &state->scaler_state.scaler_id, BIT(DRM_ROTATE_0), + &state->scaler_state.scaler_id, DRM_ROTATE_0, state->pipe_src_w, state->pipe_src_h, adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e55a82a99e7f..78b8ec84d576 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5035,7 +5035,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) kfree(intel_dig_port); } -void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) +static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); @@ -5077,7 +5077,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) edp_panel_vdd_schedule_off(intel_dp); } -void intel_dp_encoder_reset(struct drm_encoder *encoder) +static void intel_dp_encoder_reset(struct drm_encoder *encoder) { struct intel_dp *intel_dp; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 06bd9257acdc..0639275fc471 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -477,8 +477,6 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; - intel_connector->unregister(intel_connector); - /* need to nuke the connector */ drm_modeset_lock_all(dev); if (connector->state->crtc) { @@ -492,7 +490,11 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, WARN(ret, "Disabling mst crtc failed with %i\n", ret); } + drm_modeset_unlock_all(dev); + intel_connector->unregister(intel_connector); + + drm_modeset_lock_all(dev); intel_connector_remove_from_fbdev(intel_connector); drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f34a219ec5c4..0d00f07b7163 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1204,8 +1204,6 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp, void intel_dp_start_link_train(struct intel_dp *intel_dp); void intel_dp_stop_link_train(struct intel_dp *intel_dp); void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); -void intel_dp_encoder_reset(struct drm_encoder *encoder); -void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); void intel_dp_encoder_destroy(struct drm_encoder *encoder); int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc); bool intel_dp_compute_config(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 4b8ed9f2dabc..e6c035b0fc1c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1388,16 +1388,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) hdmi_to_dig_port(intel_hdmi)); } - if (!live_status) { - DRM_DEBUG_KMS("HDMI live status down\n"); - /* - * Live status register is not reliable on all intel platforms. - * So consider live_status only for certain platforms, for - * others, read EDID to determine presence of sink. - */ - if (INTEL_INFO(dev_priv)->gen < 7 || IS_IVYBRIDGE(dev_priv)) - live_status = true; - } + if (!live_status) + DRM_DEBUG_KMS("Live status not up!"); intel_hdmi_unset_edid(connector); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7058f75c7b42..d69547a65dbb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -776,11 +776,11 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) if (unlikely(total_bytes > remain_usable)) { /* * The base request will fit but the reserved space - * falls off the end. So don't need an immediate wrap - * and only need to effectively wait for the reserved - * size space from the start of ringbuffer. + * falls off the end. So only need to to wait for the + * reserved size after flushing out the remainder. */ wait_bytes = remain_actual + ringbuf->reserved_size; + need_wrap = true; } else if (total_bytes > ringbuf->space) { /* No wrapping required, just waiting. */ wait_bytes = total_bytes; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0a68d2ec89dc..f091ad12d694 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6620,12 +6620,6 @@ static void broadwell_init_clock_gating(struct drm_device *dev) misccpctl = I915_READ(GEN7_MISCCPCTL); I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); I915_WRITE(GEN8_L3SQCREG1, BDW_WA_L3SQCREG1_DEFAULT); - /* - * Wait at least 100 clocks before re-enabling clock gating. See - * the definition of L3SQCREG1 in BSpec. - */ - POSTING_READ(GEN8_L3SQCREG1); - udelay(1); I915_WRITE(GEN7_MISCCPCTL, misccpctl); /* diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9d48443bca2e..f6b2a814e629 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1922,17 +1922,6 @@ i915_dispatch_execbuffer(struct drm_i915_gem_request *req, return 0; } -static void cleanup_phys_status_page(struct intel_engine_cs *ring) -{ - struct drm_i915_private *dev_priv = to_i915(ring->dev); - - if (!dev_priv->status_page_dmah) - return; - - drm_pci_free(ring->dev, dev_priv->status_page_dmah); - ring->status_page.page_addr = NULL; -} - static void cleanup_status_page(struct intel_engine_cs *ring) { struct drm_i915_gem_object *obj; @@ -1949,9 +1938,9 @@ static void cleanup_status_page(struct intel_engine_cs *ring) static int init_status_page(struct intel_engine_cs *ring) { - struct drm_i915_gem_object *obj = ring->status_page.obj; + struct drm_i915_gem_object *obj; - if (obj == NULL) { + if ((obj = ring->status_page.obj) == NULL) { unsigned flags; int ret; @@ -2145,7 +2134,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto error; } else { - WARN_ON(ring->id != RCS); + BUG_ON(ring->id != RCS); ret = init_phys_status_page(ring); if (ret) goto error; @@ -2190,12 +2179,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) if (ring->cleanup) ring->cleanup(ring); - if (I915_NEED_GFX_HWS(ring->dev)) { - cleanup_status_page(ring); - } else { - WARN_ON(ring->id != RCS); - cleanup_phys_status_page(ring); - } + cleanup_status_page(ring); i915_cmd_parser_fini_ring(ring); i915_gem_batch_pool_fini(&ring->batch_pool); @@ -2357,11 +2341,11 @@ static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) if (unlikely(total_bytes > remain_usable)) { /* * The base request will fit but the reserved space - * falls off the end. So don't need an immediate wrap - * and only need to effectively wait for the reserved - * size space from the start of ringbuffer. + * falls off the end. So only need to to wait for the + * reserved size after flushing out the remainder. */ wait_bytes = remain_actual + ringbuf->reserved_size; + need_wrap = true; } else if (total_bytes > ringbuf->space) { /* No wrapping required, just waiting. */ wait_bytes = total_bytes; diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index cc91ae832ffb..43cba129a0c0 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1132,11 +1132,7 @@ static void intel_uncore_fw_domains_init(struct drm_device *dev) } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->uncore.funcs.force_wake_get = fw_domains_get_with_thread_status; - if (IS_HASWELL(dev)) - dev_priv->uncore.funcs.force_wake_put = - fw_domains_put_with_fifo; - else - dev_priv->uncore.funcs.force_wake_put = fw_domains_put; + dev_priv->uncore.funcs.force_wake_put = fw_domains_put; fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER, FORCEWAKE_MT, FORCEWAKE_ACK_HSW); } else if (IS_IVYBRIDGE(dev)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index 89da47234016..3216e157a8a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -131,7 +131,7 @@ nvkm_ramht_del(struct nvkm_ramht **pramht) struct nvkm_ramht *ramht = *pramht; if (ramht) { nvkm_gpuobj_del(&ramht->gpuobj); - vfree(*pramht); + kfree(*pramht); *pramht = NULL; } } @@ -143,8 +143,8 @@ nvkm_ramht_new(struct nvkm_device *device, u32 size, u32 align, struct nvkm_ramht *ramht; int ret, i; - if (!(ramht = *pramht = vzalloc(sizeof(*ramht) + - (size >> 3) * sizeof(*ramht->data)))) + if (!(ramht = *pramht = kzalloc(sizeof(*ramht) + (size >> 3) * + sizeof(*ramht->data), GFP_KERNEL))) return -ENOMEM; ramht->device = device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 36655a74c538..9f5dfc85147a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1717,8 +1717,6 @@ gf100_gr_init(struct gf100_gr *gr) gf100_gr_mmio(gr, gr->func->mmio); - nvkm_mask(device, TPC_UNIT(0, 0, 0x05c), 0x00000001, 0x00000001); - memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 5edebf495c07..183aea1abebc 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -375,15 +375,10 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, qxl_bo_kunmap(user_bo); - qcrtc->cur_x += qcrtc->hot_spot_x - hot_x; - qcrtc->cur_y += qcrtc->hot_spot_y - hot_y; - qcrtc->hot_spot_x = hot_x; - qcrtc->hot_spot_y = hot_y; - cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); cmd->type = QXL_CURSOR_SET; - cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x; - cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y; + cmd->u.set.position.x = qcrtc->cur_x; + cmd->u.set.position.y = qcrtc->cur_y; cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0); @@ -446,8 +441,8 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc, cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); cmd->type = QXL_CURSOR_MOVE; - cmd->u.position.x = qcrtc->cur_x + qcrtc->hot_spot_x; - cmd->u.position.y = qcrtc->cur_y + qcrtc->hot_spot_y; + cmd->u.position.x = qcrtc->cur_x; + cmd->u.position.y = qcrtc->cur_y; qxl_release_unmap(qdev, release, &cmd->release_info); qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 3ab90179e9ab..01a86948eb8c 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -135,8 +135,6 @@ struct qxl_crtc { int index; int cur_x; int cur_y; - int hot_spot_x; - int hot_spot_y; }; struct qxl_output { diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 79bab6fd76bb..dac78ad24b31 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1739,7 +1739,6 @@ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; @@ -1749,10 +1748,6 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) test_radeon_crtc = to_radeon_crtc(test_crtc); if (test_radeon_crtc->encoder && ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { - /* PPLL2 is exclusive to UNIPHYA on DCE61 */ - if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && - test_radeon_crtc->pll_id == ATOM_PPLL2) - continue; /* for DP use the same PLL for all */ if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) return test_radeon_crtc->pll_id; @@ -1774,7 +1769,6 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; u32 adjusted_clock, test_adjusted_clock; @@ -1790,10 +1784,6 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) test_radeon_crtc = to_radeon_crtc(test_crtc); if (test_radeon_crtc->encoder && !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { - /* PPLL2 is exclusive to UNIPHYA on DCE61 */ - if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && - test_radeon_crtc->pll_id == ATOM_PPLL2) - continue; /* check if we are already driving this connector with another crtc */ if (test_radeon_crtc->connector == radeon_crtc->connector) { /* if we are, return that pll */ diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 0b04b9282f56..adf74f4366bb 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -310,10 +310,6 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; - /* vertical FP must be at least 1 */ - if (mode->crtc_vsync_start == mode->crtc_vdisplay) - adjusted_mode->crtc_vsync_start++; - /* get the native mode for scaling */ if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { radeon_panel_mode_fixup(encoder, adjusted_mode); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 32491355a1d4..2ad462896896 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2608,152 +2608,10 @@ static void evergreen_agp_enable(struct radeon_device *rdev) WREG32(VM_CONTEXT1_CNTL, 0); } -static const unsigned ni_dig_offsets[] = -{ - NI_DIG0_REGISTER_OFFSET, - NI_DIG1_REGISTER_OFFSET, - NI_DIG2_REGISTER_OFFSET, - NI_DIG3_REGISTER_OFFSET, - NI_DIG4_REGISTER_OFFSET, - NI_DIG5_REGISTER_OFFSET -}; - -static const unsigned ni_tx_offsets[] = -{ - NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1, - NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1, - NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1, - NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1, - NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1, - NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1 -}; - -static const unsigned evergreen_dp_offsets[] = -{ - EVERGREEN_DP0_REGISTER_OFFSET, - EVERGREEN_DP1_REGISTER_OFFSET, - EVERGREEN_DP2_REGISTER_OFFSET, - EVERGREEN_DP3_REGISTER_OFFSET, - EVERGREEN_DP4_REGISTER_OFFSET, - EVERGREEN_DP5_REGISTER_OFFSET -}; - - -/* - * Assumption is that EVERGREEN_CRTC_MASTER_EN enable for requested crtc - * We go from crtc to connector and it is not relible since it - * should be an opposite direction .If crtc is enable then - * find the dig_fe which selects this crtc and insure that it enable. - * if such dig_fe is found then find dig_be which selects found dig_be and - * insure that it enable and in DP_SST mode. - * if UNIPHY_PLL_CONTROL1.enable then we should disconnect timing - * from dp symbols clocks . - */ -static bool evergreen_is_dp_sst_stream_enabled(struct radeon_device *rdev, - unsigned crtc_id, unsigned *ret_dig_fe) -{ - unsigned i; - unsigned dig_fe; - unsigned dig_be; - unsigned dig_en_be; - unsigned uniphy_pll; - unsigned digs_fe_selected; - unsigned dig_be_mode; - unsigned dig_fe_mask; - bool is_enabled = false; - bool found_crtc = false; - - /* loop through all running dig_fe to find selected crtc */ - for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) { - dig_fe = RREG32(NI_DIG_FE_CNTL + ni_dig_offsets[i]); - if (dig_fe & NI_DIG_FE_CNTL_SYMCLK_FE_ON && - crtc_id == NI_DIG_FE_CNTL_SOURCE_SELECT(dig_fe)) { - /* found running pipe */ - found_crtc = true; - dig_fe_mask = 1 << i; - dig_fe = i; - break; - } - } - - if (found_crtc) { - /* loop through all running dig_be to find selected dig_fe */ - for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) { - dig_be = RREG32(NI_DIG_BE_CNTL + ni_dig_offsets[i]); - /* if dig_fe_selected by dig_be? */ - digs_fe_selected = NI_DIG_BE_CNTL_FE_SOURCE_SELECT(dig_be); - dig_be_mode = NI_DIG_FE_CNTL_MODE(dig_be); - if (dig_fe_mask & digs_fe_selected && - /* if dig_be in sst mode? */ - dig_be_mode == NI_DIG_BE_DPSST) { - dig_en_be = RREG32(NI_DIG_BE_EN_CNTL + - ni_dig_offsets[i]); - uniphy_pll = RREG32(NI_DCIO_UNIPHY0_PLL_CONTROL1 + - ni_tx_offsets[i]); - /* dig_be enable and tx is running */ - if (dig_en_be & NI_DIG_BE_EN_CNTL_ENABLE && - dig_en_be & NI_DIG_BE_EN_CNTL_SYMBCLK_ON && - uniphy_pll & NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE) { - is_enabled = true; - *ret_dig_fe = dig_fe; - break; - } - } - } - } - - return is_enabled; -} - -/* - * Blank dig when in dp sst mode - * Dig ignores crtc timing - */ -static void evergreen_blank_dp_output(struct radeon_device *rdev, - unsigned dig_fe) -{ - unsigned stream_ctrl; - unsigned fifo_ctrl; - unsigned counter = 0; - - if (dig_fe >= ARRAY_SIZE(evergreen_dp_offsets)) { - DRM_ERROR("invalid dig_fe %d\n", dig_fe); - return; - } - - stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL + - evergreen_dp_offsets[dig_fe]); - if (!(stream_ctrl & EVERGREEN_DP_VID_STREAM_CNTL_ENABLE)) { - DRM_ERROR("dig %d , should be enable\n", dig_fe); - return; - } - - stream_ctrl &=~EVERGREEN_DP_VID_STREAM_CNTL_ENABLE; - WREG32(EVERGREEN_DP_VID_STREAM_CNTL + - evergreen_dp_offsets[dig_fe], stream_ctrl); - - stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL + - evergreen_dp_offsets[dig_fe]); - while (counter < 32 && stream_ctrl & EVERGREEN_DP_VID_STREAM_STATUS) { - msleep(1); - counter++; - stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL + - evergreen_dp_offsets[dig_fe]); - } - if (counter >= 32 ) - DRM_ERROR("counter exceeds %d\n", counter); - - fifo_ctrl = RREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe]); - fifo_ctrl |= EVERGREEN_DP_STEER_FIFO_RESET; - WREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe], fifo_ctrl); - -} - void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) { u32 crtc_enabled, tmp, frame_count, blackout; int i, j; - unsigned dig_fe; if (!ASIC_IS_NODCE(rdev)) { save->vga_render_control = RREG32(VGA_RENDER_CONTROL); @@ -2793,17 +2651,7 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav break; udelay(1); } - /*we should disable dig if it drives dp sst*/ - /*but we are in radeon_device_init and the topology is unknown*/ - /*and it is available after radeon_modeset_init*/ - /*the following method radeon_atom_encoder_dpms_dig*/ - /*does the job if we initialize it properly*/ - /*for now we do it this manually*/ - /**/ - if (ASIC_IS_DCE5(rdev) && - evergreen_is_dp_sst_stream_enabled(rdev, i ,&dig_fe)) - evergreen_blank_dp_output(rdev, dig_fe); - /*we could remove 6 lines below*/ + /* XXX this is a hack to avoid strange behavior with EFI on certain systems */ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index b436badf9efa..aa939dfed3a3 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -250,43 +250,8 @@ /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */ #define EVERGREEN_HDMI_BASE 0x7030 -/*DIG block*/ -#define NI_DIG0_REGISTER_OFFSET (0x7000 - 0x7000) -#define NI_DIG1_REGISTER_OFFSET (0x7C00 - 0x7000) -#define NI_DIG2_REGISTER_OFFSET (0x10800 - 0x7000) -#define NI_DIG3_REGISTER_OFFSET (0x11400 - 0x7000) -#define NI_DIG4_REGISTER_OFFSET (0x12000 - 0x7000) -#define NI_DIG5_REGISTER_OFFSET (0x12C00 - 0x7000) - - -#define NI_DIG_FE_CNTL 0x7000 -# define NI_DIG_FE_CNTL_SOURCE_SELECT(x) ((x) & 0x3) -# define NI_DIG_FE_CNTL_SYMCLK_FE_ON (1<<24) - - -#define NI_DIG_BE_CNTL 0x7140 -# define NI_DIG_BE_CNTL_FE_SOURCE_SELECT(x) (((x) >> 8 ) & 0x3F) -# define NI_DIG_FE_CNTL_MODE(x) (((x) >> 16) & 0x7 ) - -#define NI_DIG_BE_EN_CNTL 0x7144 -# define NI_DIG_BE_EN_CNTL_ENABLE (1 << 0) -# define NI_DIG_BE_EN_CNTL_SYMBCLK_ON (1 << 8) -# define NI_DIG_BE_DPSST 0 /* Display Port block */ -#define EVERGREEN_DP0_REGISTER_OFFSET (0x730C - 0x730C) -#define EVERGREEN_DP1_REGISTER_OFFSET (0x7F0C - 0x730C) -#define EVERGREEN_DP2_REGISTER_OFFSET (0x10B0C - 0x730C) -#define EVERGREEN_DP3_REGISTER_OFFSET (0x1170C - 0x730C) -#define EVERGREEN_DP4_REGISTER_OFFSET (0x1230C - 0x730C) -#define EVERGREEN_DP5_REGISTER_OFFSET (0x12F0C - 0x730C) - - -#define EVERGREEN_DP_VID_STREAM_CNTL 0x730C -# define EVERGREEN_DP_VID_STREAM_CNTL_ENABLE (1 << 0) -# define EVERGREEN_DP_VID_STREAM_STATUS (1 <<16) -#define EVERGREEN_DP_STEER_FIFO 0x7310 -# define EVERGREEN_DP_STEER_FIFO_RESET (1 << 0) #define EVERGREEN_DP_SEC_CNTL 0x7280 # define EVERGREEN_DP_SEC_STREAM_ENABLE (1 << 0) # define EVERGREEN_DP_SEC_ASP_ENABLE (1 << 4) @@ -301,15 +266,4 @@ # define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x) (((x) & 0xf) << 24) # define EVERGREEN_DP_SEC_SS_EN (1 << 28) -/*DCIO_UNIPHY block*/ -#define NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1 (0x6600 -0x6600) -#define NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1 (0x6640 -0x6600) -#define NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1 (0x6680 - 0x6600) -#define NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1 (0x66C0 - 0x6600) -#define NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1 (0x6700 - 0x6600) -#define NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1 (0x6740 - 0x6600) - -#define NI_DCIO_UNIPHY0_PLL_CONTROL1 0x6618 -# define NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE (1 << 0) - #endif diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index c4b4f298a283..9bc408c9f9f6 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -62,6 +62,10 @@ bool radeon_has_atpx(void) { return radeon_atpx_priv.atpx_detected; } +bool radeon_has_atpx_dgpu_power_cntl(void) { + return radeon_atpx_priv.atpx.functions.power_cntl; +} + /** * radeon_atpx_call - call an ATPX method * @@ -141,10 +145,6 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas */ static int radeon_atpx_validate(struct radeon_atpx *atpx) { - /* make sure required functions are enabled */ - /* dGPU power control is required */ - atpx->functions.power_cntl = true; - if (atpx->functions.px_params) { union acpi_object *info; struct atpx_px_params output; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 9cfc1c3e1965..340f3f549f29 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1996,12 +1996,10 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.dither_property, RADEON_FMT_DITHER_DISABLE); - if (radeon_audio != 0) { + if (radeon_audio != 0) drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); - radeon_connector->audio = RADEON_AUDIO_AUTO; - } if (ASIC_IS_DCE5(rdev)) drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.output_csc_property, @@ -2126,7 +2124,6 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); - radeon_connector->audio = RADEON_AUDIO_AUTO; } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; @@ -2182,7 +2179,6 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); - radeon_connector->audio = RADEON_AUDIO_AUTO; } if (ASIC_IS_DCE5(rdev)) drm_object_attach_property(&radeon_connector->base.base, @@ -2235,7 +2231,6 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); - radeon_connector->audio = RADEON_AUDIO_AUTO; } if (ASIC_IS_DCE5(rdev)) drm_object_attach_property(&radeon_connector->base.base, diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index c566993a2ec3..f78f111e68de 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -103,6 +103,12 @@ static const char radeon_family_name[][16] = { "LAST", }; +#if defined(CONFIG_VGA_SWITCHEROO) +bool radeon_has_atpx_dgpu_power_cntl(void); +#else +static inline bool radeon_has_atpx_dgpu_power_cntl(void) { return false; } +#endif + #define RADEON_PX_QUIRK_DISABLE_PX (1 << 0) #define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1) @@ -1433,7 +1439,7 @@ int radeon_device_init(struct radeon_device *rdev, * ignore it */ vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); - if (rdev->flags & RADEON_IS_PX) + if ((rdev->flags & RADEON_IS_PX) && radeon_has_atpx_dgpu_power_cntl()) runtime = true; vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); if (runtime) diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c index db64e0062689..3b0c229d7dcd 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_auxch.c +++ b/drivers/gpu/drm/radeon/radeon_dp_auxch.c @@ -105,7 +105,7 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg tmp &= AUX_HPD_SEL(0x7); tmp |= AUX_HPD_SEL(chan->rec.hpd); - tmp |= AUX_EN | AUX_LS_READ_EN | AUX_HPD_DISCON(0x1); + tmp |= AUX_EN | AUX_LS_READ_EN; WREG32(AUX_CONTROL + aux_offset[instance], tmp); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index f342aad79cc6..e06ac546a90f 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -235,8 +235,6 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) { struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo); - if (radeon_ttm_tt_has_userptr(bo->ttm)) - return -EPERM; return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); } diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index caa73de584a5..7285adb27099 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2931,7 +2931,6 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = { { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 }, { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 }, { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 }, - { PCI_VENDOR_ID_ATI, 0x6810, 0x1682, 0x9275, 0, 120000 }, { 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 0585fd2031dd..a0e28f3a278d 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1068,6 +1068,7 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) goto err_register; } + pdev->dev.of_node = of_node; pdev->dev.parent = dev; ret = platform_device_add_data(pdev, ®->pdata, @@ -1078,12 +1079,6 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) platform_device_put(pdev); goto err_register; } - - /* - * Set of_node only after calling platform_device_add. Otherwise - * the platform:imx-ipuv3-crtc modalias won't be used. - */ - pdev->dev.of_node = of_node; } return 0; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 18fdd400ac7a..362493118670 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1193,7 +1193,8 @@ static int adreno_init(struct kgsl_device *device) if (!adreno_is_a3xx(adreno_dev)) { int r = kgsl_allocate_global(device, - &adreno_dev->cmdbatch_profile_buffer, PAGE_SIZE, 0, 0); + &adreno_dev->cmdbatch_profile_buffer, PAGE_SIZE, + 0, 0, "alwayson"); adreno_dev->cmdbatch_profile_index = 0; @@ -1279,7 +1280,7 @@ static void _setup_throttling_counters(struct adreno_device *adreno_dev) static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev) { - int i; + int i, adj; uint32_t th[ADRENO_GPMU_THROTTLE_COUNTERS]; struct adreno_busy_data *busy = &adreno_dev->busy_data; @@ -1300,8 +1301,14 @@ static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev) adreno_dev->gpmu_throttle_counters[i], &busy->throttle_cycles[i]); } - i = th[CRC_MORE50PCT] - th[IDLE_10PCT]; - return th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (i < 0 ? 0 : i) * 3; + adj = th[CRC_MORE50PCT] - th[IDLE_10PCT]; + adj = th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (adj < 0 ? 0 : adj) * 3; + + trace_kgsl_clock_throttling( + th[IDLE_10PCT], th[CRC_50PCT], + th[CRC_MORE50PCT], th[CRC_LESS50PCT], + adj); + return adj; } static void _update_threshold_count(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 2accbe5c5764..97e71464c2df 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -174,7 +174,7 @@ static int _a3xx_pwron_fixup(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &adreno_dev->pwron_fixup, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, 0, "pwron_fixup"); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index b15d23cfbe0a..7a691667e59f 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -1360,7 +1360,7 @@ static int _a4xx_pwron_fixup(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &adreno_dev->pwron_fixup, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, 0, "pwron_fixup"); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 3252bfb764f2..583de85678fc 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -244,7 +244,8 @@ static int a5xx_critical_packet_construct(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, + 0, "crit_pkts"); if (ret) return ret; @@ -258,19 +259,19 @@ static int a5xx_critical_packet_construct(struct adreno_device *adreno_dev) ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts_refbuf1, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "crit_pkts_refbuf1"); if (ret) return ret; ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts_refbuf2, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "crit_pkts_refbuf2"); if (ret) return ret; ret = kgsl_allocate_global(&adreno_dev->dev, &crit_pkts_refbuf3, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "crit_pkts_refbuf3"); if (ret) return ret; @@ -2366,7 +2367,7 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, } ret = kgsl_allocate_global(device, ucode, fw->size - 4, - KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_MEMFLAGS_GPUREADONLY, 0, "ucode"); if (ret) goto done; diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index c1463b824c67..ffd7acbbe1f9 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -490,7 +490,8 @@ static int a5xx_preemption_ringbuffer_init(struct adreno_device *adreno_dev, int ret; ret = kgsl_allocate_global(device, &rb->preemption_desc, - A5XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED); + A5XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED, + "preemption_desc"); if (ret) return ret; @@ -525,7 +526,8 @@ static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) /* Allocate mem for storing preemption smmu record */ return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED); + KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED, + "smmu_info"); } #else static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) @@ -555,7 +557,8 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) /* Allocate mem for storing preemption counters */ ret = kgsl_allocate_global(device, &preempt->counters, adreno_dev->num_ringbuffers * - A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0); + A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, + "preemption_counters"); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index 04d82844a5e9..aeffeab2f6dc 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c @@ -1033,11 +1033,11 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev) /* The script buffers needs 2 extra qwords on the end */ if (kgsl_allocate_global(device, &capturescript, script_size + 16, KGSL_MEMFLAGS_GPUREADONLY, - KGSL_MEMDESC_PRIVILEGED)) + KGSL_MEMDESC_PRIVILEGED, "capturescript")) return; if (kgsl_allocate_global(device, ®isters, data_size, 0, - KGSL_MEMDESC_PRIVILEGED)) { + KGSL_MEMDESC_PRIVILEGED, "capturescript_regs")) { kgsl_free_global(KGSL_DEVICE(adreno_dev), &capturescript); return; } diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 9cbcd06d7658..680827e5b848 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -138,7 +138,7 @@ static void sync_event_print(struct seq_file *s, break; } case KGSL_CMD_SYNCPOINT_TYPE_FENCE: - seq_printf(s, "sync: [%p] %s", sync_event->handle, + seq_printf(s, "sync: [%pK] %s", sync_event->handle, (sync_event->handle && sync_event->handle->fence) ? sync_event->handle->fence->name : "NULL"); break; diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c index c4fab8a5528a..d8af520b2fe6 100644 --- a/drivers/gpu/msm/adreno_profile.c +++ b/drivers/gpu/msm/adreno_profile.c @@ -1071,7 +1071,8 @@ void adreno_profile_init(struct adreno_device *adreno_dev) /* allocate shared_buffer, which includes pre_ib and post_ib */ profile->shared_size = ADRENO_PROFILE_SHARED_BUF_SIZE_DWORDS; ret = kgsl_allocate_global(device, &profile->shared_buffer, - profile->shared_size * sizeof(unsigned int), 0, 0); + profile->shared_size * sizeof(unsigned int), + 0, 0, "profile"); if (ret) { profile->shared_size = 0; diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 5ffb0b2513f3..07ef09034d7c 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -250,12 +250,12 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, * switch pagetable */ ret = kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &rb->pagetable_desc, - PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED); + PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED, "pagetable_desc"); if (ret) return ret; - return kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &rb->buffer_desc, - KGSL_RB_SIZE, KGSL_MEMFLAGS_GPUREADONLY, 0); + KGSL_RB_SIZE, KGSL_MEMFLAGS_GPUREADONLY, + 0, "ringbuffer"); } int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 24005a1fda72..f9eb080d903b 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4457,9 +4457,8 @@ int kgsl_device_platform_probe(struct kgsl_device *device) disable_irq(device->pwrctrl.interrupt_num); KGSL_DRV_INFO(device, - "dev_id %d regs phys 0x%08lx size 0x%08x virt %p\n", - device->id, device->reg_phys, device->reg_len, - device->reg_virt); + "dev_id %d regs phys 0x%08lx size 0x%08x\n", + device->id, device->reg_phys, device->reg_len); rwlock_init(&device->context_lock); @@ -4475,13 +4474,13 @@ int kgsl_device_platform_probe(struct kgsl_device *device) goto error_close_mmu; status = kgsl_allocate_global(device, &device->memstore, - KGSL_MEMSTORE_SIZE, 0, KGSL_MEMDESC_CONTIG); + KGSL_MEMSTORE_SIZE, 0, KGSL_MEMDESC_CONTIG, "memstore"); if (status != 0) goto error_close_mmu; status = kgsl_allocate_global(device, &device->scratch, - PAGE_SIZE, 0, 0); + PAGE_SIZE, 0, 0, "scratch"); if (status != 0) goto error_free_memstore; diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c index 2e90f78a303c..8e783f8ce017 100644 --- a/drivers/gpu/msm/kgsl_cffdump.c +++ b/drivers/gpu/msm/kgsl_cffdump.c @@ -513,10 +513,6 @@ EXPORT_SYMBOL(kgsl_cffdump_waitirq); static int subbuf_start_handler(struct rchan_buf *buf, void *subbuf, void *prev_subbuf, size_t prev_padding) { - pr_debug("kgsl: cffdump: subbuf_start_handler(subbuf=%p, prev_subbuf" - "=%p, prev_padding=%08zx)\n", subbuf, prev_subbuf, - prev_padding); - if (relay_buf_full(buf)) { if (!suspended) { suspended = 1; @@ -573,9 +569,6 @@ static struct rchan *create_channel(unsigned subbuf_size, unsigned n_subbufs) { struct rchan *chan; - pr_info("kgsl: cffdump: relay: create_channel: subbuf_size %u, " - "n_subbufs %u, dir 0x%p\n", subbuf_size, n_subbufs, dir); - chan = relay_open("cpu", dir, subbuf_size, n_subbufs, &relay_callbacks, NULL); if (!chan) { diff --git a/drivers/gpu/msm/kgsl_cmdbatch.c b/drivers/gpu/msm/kgsl_cmdbatch.c index ceca8b1e1522..6272410ce544 100644 --- a/drivers/gpu/msm/kgsl_cmdbatch.c +++ b/drivers/gpu/msm/kgsl_cmdbatch.c @@ -80,7 +80,7 @@ void kgsl_dump_syncpoints(struct kgsl_device *device, } case KGSL_CMD_SYNCPOINT_TYPE_FENCE: if (event->handle) - dev_err(device->dev, " fence: [%p] %s\n", + dev_err(device->dev, " fence: [%pK] %s\n", event->handle->fence, event->handle->name); else diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index df9eb9ebd779..2f293e4da398 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -280,6 +280,29 @@ static const struct file_operations process_sparse_mem_fops = { .release = process_mem_release, }; +static int globals_print(struct seq_file *s, void *unused) +{ + kgsl_print_global_pt_entries(s); + return 0; +} + +static int globals_open(struct inode *inode, struct file *file) +{ + return single_open(file, globals_print, NULL); +} + +static int globals_release(struct inode *inode, struct file *file) +{ + return single_release(inode, file); +} + +static const struct file_operations global_fops = { + .open = globals_open, + .read = seq_read, + .llseek = seq_lseek, + .release = globals_release, +}; + /** * kgsl_process_init_debugfs() - Initialize debugfs for a process * @private: Pointer to process private structure created for the process @@ -336,6 +359,9 @@ void kgsl_core_debugfs_init(void) kgsl_debugfs_dir = debugfs_create_dir("kgsl", NULL); + debugfs_create_file("globals", 0444, kgsl_debugfs_dir, NULL, + &global_fops); + debug_dir = debugfs_create_dir("debug", kgsl_debugfs_dir); debugfs_create_file("strict_memory", 0644, debug_dir, NULL, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 166bb68e64a1..71b6086423d6 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -38,6 +38,10 @@ #define _IOMMU_PRIV(_mmu) (&((_mmu)->priv.iommu)) +#define ADDR_IN_GLOBAL(_a) \ + (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \ + ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE))) + static struct kgsl_mmu_pt_ops iommu_pt_ops; static bool need_iommu_sync; @@ -92,19 +96,41 @@ static struct kmem_cache *addr_entry_cache; #define GLOBAL_PT_ENTRIES 32 -static struct kgsl_memdesc *global_pt_entries[GLOBAL_PT_ENTRIES]; +struct global_pt_entry { + struct kgsl_memdesc *memdesc; + char name[32]; +}; + +static struct global_pt_entry global_pt_entries[GLOBAL_PT_ENTRIES]; static struct kgsl_memdesc *kgsl_global_secure_pt_entry; static int global_pt_count; uint64_t global_pt_alloc; static struct kgsl_memdesc gpu_qdss_desc; +void kgsl_print_global_pt_entries(struct seq_file *s) +{ + int i; + + for (i = 0; i < global_pt_count; i++) { + struct kgsl_memdesc *memdesc = global_pt_entries[i].memdesc; + + if (memdesc == NULL) + continue; + + seq_printf(s, "0x%16.16llX-0x%16.16llX %16llu %s\n", + memdesc->gpuaddr, memdesc->gpuaddr + memdesc->size - 1, + memdesc->size, global_pt_entries[i].name); + } +} + static void kgsl_iommu_unmap_globals(struct kgsl_pagetable *pagetable) { unsigned int i; for (i = 0; i < global_pt_count; i++) { - if (global_pt_entries[i] != NULL) - kgsl_mmu_unmap(pagetable, global_pt_entries[i]); + if (global_pt_entries[i].memdesc != NULL) + kgsl_mmu_unmap(pagetable, + global_pt_entries[i].memdesc); } } @@ -113,8 +139,9 @@ static void kgsl_iommu_map_globals(struct kgsl_pagetable *pagetable) unsigned int i; for (i = 0; i < global_pt_count; i++) { - if (global_pt_entries[i] != NULL) { - int ret = kgsl_mmu_map(pagetable, global_pt_entries[i]); + if (global_pt_entries[i].memdesc != NULL) { + int ret = kgsl_mmu_map(pagetable, + global_pt_entries[i].memdesc); BUG_ON(ret); } @@ -152,17 +179,17 @@ static void kgsl_iommu_remove_global(struct kgsl_mmu *mmu, return; for (i = 0; i < global_pt_count; i++) { - if (global_pt_entries[i] == memdesc) { + if (global_pt_entries[i].memdesc == memdesc) { memdesc->gpuaddr = 0; memdesc->priv &= ~KGSL_MEMDESC_GLOBAL; - global_pt_entries[i] = NULL; + global_pt_entries[i].memdesc = NULL; return; } } } static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, - struct kgsl_memdesc *memdesc) + struct kgsl_memdesc *memdesc, const char *name) { if (memdesc->gpuaddr != 0) return; @@ -174,7 +201,10 @@ static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, memdesc->priv |= KGSL_MEMDESC_GLOBAL; global_pt_alloc += memdesc->size; - global_pt_entries[global_pt_count++] = memdesc; + global_pt_entries[global_pt_count].memdesc = memdesc; + strlcpy(global_pt_entries[global_pt_count].name, name, + sizeof(global_pt_entries[global_pt_count].name)); + global_pt_count++; } void kgsl_add_global_secure_entry(struct kgsl_device *device, @@ -220,7 +250,7 @@ static void kgsl_setup_qdss_desc(struct kgsl_device *device) return; } - kgsl_mmu_add_global(device, &gpu_qdss_desc); + kgsl_mmu_add_global(device, &gpu_qdss_desc, "gpu-qdss"); } static inline void kgsl_cleanup_qdss_desc(struct kgsl_mmu *mmu) @@ -493,8 +523,62 @@ struct _mem_entry { unsigned int priv; int pending_free; pid_t pid; + char name[32]; }; +static void _get_global_entries(uint64_t faultaddr, + struct _mem_entry *prev, + struct _mem_entry *next) +{ + int i; + uint64_t prevaddr = 0; + struct global_pt_entry *p = NULL; + + uint64_t nextaddr = (uint64_t) -1; + struct global_pt_entry *n = NULL; + + for (i = 0; i < global_pt_count; i++) { + uint64_t addr; + + if (global_pt_entries[i].memdesc == NULL) + continue; + + addr = global_pt_entries[i].memdesc->gpuaddr; + if ((addr < faultaddr) && (addr > prevaddr)) { + prevaddr = addr; + p = &global_pt_entries[i]; + } + + if ((addr > faultaddr) && (addr < nextaddr)) { + nextaddr = addr; + n = &global_pt_entries[i]; + } + } + + if (p != NULL) { + prev->gpuaddr = p->memdesc->gpuaddr; + prev->size = p->memdesc->size; + prev->flags = p->memdesc->flags; + prev->priv = p->memdesc->priv; + prev->pid = 0; + strlcpy(prev->name, p->name, sizeof(prev->name)); + } + + if (n != NULL) { + next->gpuaddr = n->memdesc->gpuaddr; + next->size = n->memdesc->size; + next->flags = n->memdesc->flags; + next->priv = n->memdesc->priv; + next->pid = 0; + strlcpy(next->name, n->name, sizeof(next->name)); + } +} + +void __kgsl_get_memory_usage(struct _mem_entry *entry) +{ + kgsl_get_memory_usage(entry->name, sizeof(entry->name), entry->flags); +} + static void _get_entries(struct kgsl_process_private *private, uint64_t faultaddr, struct _mem_entry *prev, struct _mem_entry *next) @@ -529,6 +613,7 @@ static void _get_entries(struct kgsl_process_private *private, prev->priv = p->memdesc.priv; prev->pending_free = p->pending_free; prev->pid = private->pid; + __kgsl_get_memory_usage(prev); } if (n != NULL) { @@ -538,6 +623,7 @@ static void _get_entries(struct kgsl_process_private *private, next->priv = n->memdesc.priv; next->pending_free = n->pending_free; next->pid = private->pid; + __kgsl_get_memory_usage(next); } } @@ -553,7 +639,9 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, /* Set the maximum possible size as an initial value */ nextentry->gpuaddr = (uint64_t) -1; - if (context) { + if (ADDR_IN_GLOBAL(faultaddr)) { + _get_global_entries(faultaddr, preventry, nextentry); + } else if (context) { private = context->proc_priv; spin_lock(&private->mem_lock); _get_entries(private, faultaddr, preventry, nextentry); @@ -563,18 +651,13 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, static void _print_entry(struct kgsl_device *device, struct _mem_entry *entry) { - char name[32]; - memset(name, 0, sizeof(name)); - - kgsl_get_memory_usage(name, sizeof(name) - 1, entry->flags); - KGSL_LOG_DUMP(device, "[%016llX - %016llX] %s %s (pid = %d) (%s)\n", entry->gpuaddr, entry->gpuaddr + entry->size, entry->priv & KGSL_MEMDESC_GUARD_PAGE ? "(+guard)" : "", entry->pending_free ? "(pending free)" : "", - entry->pid, name); + entry->pid, entry->name); } static void _check_if_freed(struct kgsl_iommu_context *ctx, @@ -1395,7 +1478,7 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) } } - kgsl_iommu_add_global(mmu, &iommu->setstate); + kgsl_iommu_add_global(mmu, &iommu->setstate, "setstate"); kgsl_setup_qdss_desc(device); done: @@ -2220,10 +2303,6 @@ static uint64_t kgsl_iommu_find_svm_region(struct kgsl_pagetable *pagetable, return addr; } -#define ADDR_IN_GLOBAL(_a) \ - (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \ - ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE))) - static int kgsl_iommu_set_svm_region(struct kgsl_pagetable *pagetable, uint64_t gpuaddr, uint64_t size) { diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 10f6b8049d36..4371c9a1b87e 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -543,12 +543,12 @@ void kgsl_mmu_remove_global(struct kgsl_device *device, EXPORT_SYMBOL(kgsl_mmu_remove_global); void kgsl_mmu_add_global(struct kgsl_device *device, - struct kgsl_memdesc *memdesc) + struct kgsl_memdesc *memdesc, const char *name) { struct kgsl_mmu *mmu = &device->mmu; if (MMU_OP_VALID(mmu, mmu_add_global)) - mmu->mmu_ops->mmu_add_global(mmu, memdesc); + mmu->mmu_ops->mmu_add_global(mmu, memdesc, name); } EXPORT_SYMBOL(kgsl_mmu_add_global); @@ -620,7 +620,7 @@ static struct kgsl_mmu_pt_ops nommu_pt_ops = { }; static void nommu_add_global(struct kgsl_mmu *mmu, - struct kgsl_memdesc *memdesc) + struct kgsl_memdesc *memdesc, const char *name) { memdesc->gpuaddr = (uint64_t) sg_phys(memdesc->sgt->sgl); } diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 53645cc1741c..acbc0e784cf2 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -75,7 +75,7 @@ struct kgsl_mmu_ops { (struct kgsl_mmu *mmu); int (*mmu_init_pt)(struct kgsl_mmu *mmu, struct kgsl_pagetable *); void (*mmu_add_global)(struct kgsl_mmu *mmu, - struct kgsl_memdesc *memdesc); + struct kgsl_memdesc *memdesc, const char *name); void (*mmu_remove_global)(struct kgsl_mmu *mmu, struct kgsl_memdesc *memdesc); struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu, @@ -174,6 +174,7 @@ struct kgsl_pagetable *kgsl_mmu_getpagetable_ptbase(struct kgsl_mmu *, void kgsl_add_global_secure_entry(struct kgsl_device *device, struct kgsl_memdesc *memdesc); +void kgsl_print_global_pt_entries(struct seq_file *s); void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable); int kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable, @@ -198,7 +199,7 @@ int kgsl_mmu_find_region(struct kgsl_pagetable *pagetable, uint64_t *gpuaddr, uint64_t size, unsigned int align); void kgsl_mmu_add_global(struct kgsl_device *device, - struct kgsl_memdesc *memdesc); + struct kgsl_memdesc *memdesc, const char *name); void kgsl_mmu_remove_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc); diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 565ae4c39fdd..9e6817c76df8 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -279,7 +279,7 @@ kgsl_memdesc_footprint(const struct kgsl_memdesc *memdesc) */ static inline int kgsl_allocate_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc, uint64_t size, uint64_t flags, - unsigned int priv) + unsigned int priv, const char *name) { int ret; @@ -297,7 +297,7 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, } if (ret == 0) - kgsl_mmu_add_global(device, memdesc); + kgsl_mmu_add_global(device, memdesc, name); return ret; } diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index f9d3ede718ab..dd004f9588e9 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -1042,9 +1042,6 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work) goto done; snapshot->mempool = vmalloc(size); - if (snapshot->mempool != NULL) - KGSL_CORE_ERR("snapshot: mempool address %p, size %zx\n", - snapshot->mempool, size); ptr = snapshot->mempool; snapshot->mempool_size = 0; diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index 1b51eb591036..4ef9f80177d6 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -1192,6 +1192,41 @@ TRACE_EVENT(sparse_unbind, ); +TRACE_EVENT(kgsl_clock_throttling, + TP_PROTO( + int idle_10pct, + int crc_50pct, + int crc_more50pct, + int crc_less50pct, + int adj + ), + TP_ARGS( + idle_10pct, + crc_50pct, + crc_more50pct, + crc_less50pct, + adj + ), + TP_STRUCT__entry( + __field(int, idle_10pct) + __field(int, crc_50pct) + __field(int, crc_more50pct) + __field(int, crc_less50pct) + __field(int, adj) + ), + TP_fast_assign( + __entry->idle_10pct = idle_10pct; + __entry->crc_50pct = crc_50pct; + __entry->crc_more50pct = crc_more50pct; + __entry->crc_less50pct = crc_less50pct; + __entry->adj = adj; + ), + TP_printk("idle_10=%d crc_50=%d crc_more50=%d crc_less50=%d adj=%d", + __entry->idle_10pct, __entry->crc_50pct, __entry->crc_more50pct, + __entry->crc_less50pct, __entry->adj + ) +); + #endif /* _KGSL_TRACE_H */ /* This part must be outside protection */ diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 909ab0176ef2..8b78a7f1f779 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -255,7 +255,6 @@ #define USB_DEVICE_ID_CORSAIR_K90 0x1b02 #define USB_VENDOR_ID_CREATIVELABS 0x041e -#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 #define USB_VENDOR_ID_CVTOUCH 0x1ff7 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index dc8e6adf95a4..7dd0953cd70f 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -70,7 +70,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, - { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL }, diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 5c02d7bbc7f2..3c0f47ac8e53 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -3449,10 +3449,6 @@ static const struct wacom_features wacom_features_0x33E = { "Wacom Intuos PT M 2", 21600, 13500, 2047, 63, INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x343 = - { "Wacom DTK1651", 34616, 19559, 1023, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC }; @@ -3618,7 +3614,6 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x33C) }, { USB_DEVICE_WACOM(0x33D) }, { USB_DEVICE_WACOM(0x33E) }, - { USB_DEVICE_WACOM(0x343) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 26fbfba23c94..a234d61802ce 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -22,6 +22,7 @@ #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/pm_runtime.h> #include <linux/clk.h> #include <linux/bitmap.h> #include <linux/of.h> @@ -135,7 +136,6 @@ struct stm_drvdata { struct device *dev; struct coresight_device *csdev; struct miscdevice miscdev; - struct clk *clk; spinlock_t spinlock; struct channel_space chs; bool enable; @@ -270,8 +270,8 @@ static int stm_enable(struct coresight_device *csdev) int ret; unsigned long flags; - ret = clk_prepare_enable(drvdata->clk); - if (ret) + ret = pm_runtime_get_sync(drvdata->dev); + if (ret < 0) return ret; spin_lock_irqsave(&drvdata->spinlock, flags); @@ -349,7 +349,7 @@ static void stm_disable(struct coresight_device *csdev) /* Wait for 100ms so that pending data has been written to HW */ msleep(100); - clk_disable_unprepare(drvdata->clk); + pm_runtime_put(drvdata->dev); dev_info(drvdata->dev, "STM tracing disabled\n"); } @@ -360,7 +360,7 @@ static int stm_trace_id(struct coresight_device *csdev) unsigned long flags; int trace_id = -1; - if (clk_prepare_enable(drvdata->clk)) + if (pm_runtime_get_sync(drvdata->dev) < 0) goto out; spin_lock_irqsave(&drvdata->spinlock, flags); @@ -370,7 +370,7 @@ static int stm_trace_id(struct coresight_device *csdev) CS_LOCK(drvdata->base); spin_unlock_irqrestore(&drvdata->spinlock, flags); - clk_disable_unprepare(drvdata->clk); + pm_runtime_put(drvdata->dev); out: return trace_id; } @@ -806,19 +806,14 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock); - drvdata->clk = adev->pclk; - ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE); - if (ret) - return ret; - - ret = clk_prepare_enable(drvdata->clk); + ret = clk_set_rate(adev->pclk, CORESIGHT_CLK_RATE_TRACE); if (ret) return ret; if (!coresight_authstatus_enabled(drvdata->base)) goto err1; - clk_disable_unprepare(drvdata->clk); + pm_runtime_put(&adev->dev); bitmap_fill(drvdata->entities, OST_ENTITY_MAX); @@ -856,7 +851,7 @@ err: coresight_unregister(drvdata->csdev); return ret; err1: - clk_disable_unprepare(drvdata->clk); + pm_runtime_put(&adev->dev); return -EPERM; } diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig index e7a348807f0c..83e9f591a54b 100644 --- a/drivers/hwtracing/stm/Kconfig +++ b/drivers/hwtracing/stm/Kconfig @@ -1,7 +1,6 @@ config STM tristate "System Trace Module devices" select CONFIGFS_FS - select SRCU help A System Trace Module (STM) is a device exporting data in System Trace Protocol (STP) format as defined by MIPI STP standards. diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b167ab25310a..714bdc837769 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -116,8 +116,8 @@ struct cpm_i2c { cbd_t __iomem *rbase; u_char *txbuf[CPM_MAXBD]; u_char *rxbuf[CPM_MAXBD]; - dma_addr_t txdma[CPM_MAXBD]; - dma_addr_t rxdma[CPM_MAXBD]; + u32 txdma[CPM_MAXBD]; + u32 rxdma[CPM_MAXBD]; }; static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index f54ece8fce78..b29c7500461a 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -671,9 +671,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, return -EIO; } - ret = clk_enable(i2c->clk); - if (ret) - return ret; + clk_prepare_enable(i2c->clk); for (i = 0; i < num; i++, msgs++) { stop = (i == num - 1); @@ -697,7 +695,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, } out: - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); return ret; } @@ -749,9 +747,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev) return -ENOENT; } - ret = clk_prepare_enable(i2c->clk); - if (ret) - return ret; + clk_prepare_enable(i2c->clk); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->regs = devm_ioremap_resource(&pdev->dev, mem); @@ -803,10 +799,6 @@ static int exynos5_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - clk_disable(i2c->clk); - - return 0; - err_clk: clk_disable_unprepare(i2c->clk); return ret; @@ -818,8 +810,6 @@ static int exynos5_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); - clk_unprepare(i2c->clk); - return 0; } @@ -831,8 +821,6 @@ static int exynos5_i2c_suspend_noirq(struct device *dev) i2c->suspended = 1; - clk_unprepare(i2c->clk); - return 0; } @@ -842,9 +830,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev) struct exynos5_i2c *i2c = platform_get_drvdata(pdev); int ret = 0; - ret = clk_prepare_enable(i2c->clk); - if (ret) - return ret; + clk_prepare_enable(i2c->clk); ret = exynos5_hsi2c_clock_setup(i2c); if (ret) { @@ -853,7 +839,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev) } exynos5_i2c_init(i2c); - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); i2c->suspended = 0; return 0; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 8a0e2c809fb2..90135f496aaf 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -318,6 +318,18 @@ config QCOM_RRADC To compile this driver as a module, choose M here: the module will be called qcom-rradc. +config QCOM_TADC + tristate "Qualcomm Technologies Inc. TADC driver" + depends on MFD_I2C_PMIC + help + Say yes here to support the Qualcomm Technologies Inc. telemetry ADC. + The TADC provides battery temperature, skin temperature, + die temperature, battery voltage, battery current, input voltage, + input current, and OTG current. + + The driver can also be built as a module. If so, the module will be + called qcom-tadc. + config ROCKCHIP_SARADC tristate "Rockchip SARADC driver" depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 59cac58d769e..9124e49a5f65 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_QCOM_RRADC) += qcom-rradc.o +obj-$(CONFIG_QCOM_TADC) += qcom-tadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o diff --git a/drivers/iio/adc/qcom-tadc.c b/drivers/iio/adc/qcom-tadc.c new file mode 100644 index 000000000000..3cc2694f9a03 --- /dev/null +++ b/drivers/iio/adc/qcom-tadc.c @@ -0,0 +1,742 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define TADC_REVISION1_REG 0x00 +#define TADC_REVISION2_REG 0x01 +#define TADC_REVISION3_REG 0x02 +#define TADC_REVISION4_REG 0x03 +#define TADC_PERPH_TYPE_REG 0x04 +#define TADC_PERPH_SUBTYPE_REG 0x05 + +/* TADC register definitions */ +#define TADC_SW_CH_CONV_REG(chip) (chip->tadc_base + 0x06) +#define TADC_MBG_ERR_REG(chip) (chip->tadc_base + 0x07) +#define TADC_EN_CTL_REG(chip) (chip->tadc_base + 0x46) +#define TADC_CONV_REQ_REG(chip) (chip->tadc_base + 0x51) +#define TADC_HWTRIG_CONV_CH_EN_REG(chip) (chip->tadc_base + 0x52) +#define TADC_HW_SETTLE_DELAY_REG(chip) (chip->tadc_base + 0x53) +#define TADC_LONG_HW_SETTLE_DLY_EN_REG(chip) (chip->tadc_base + 0x54) +#define TADC_LONG_HW_SETTLE_DLY_REG(chip) (chip->tadc_base + 0x55) +#define TADC_ADC_BUF_CH_REG(chip) (chip->tadc_base + 0x56) +#define TADC_ADC_AAF_CH_REG(chip) (chip->tadc_base + 0x57) +#define TADC_ADC_DATA_RDBK_REG(chip) (chip->tadc_base + 0x58) +#define TADC_CH1_ADC_LO_REG(chip) (chip->tadc_base + 0x60) +#define TADC_CH1_ADC_HI_REG(chip) (chip->tadc_base + 0x61) +#define TADC_CH2_ADC_LO_REG(chip) (chip->tadc_base + 0x62) +#define TADC_CH2_ADC_HI_REG(chip) (chip->tadc_base + 0x63) +#define TADC_CH3_ADC_LO_REG(chip) (chip->tadc_base + 0x64) +#define TADC_CH3_ADC_HI_REG(chip) (chip->tadc_base + 0x65) +#define TADC_CH4_ADC_LO_REG(chip) (chip->tadc_base + 0x66) +#define TADC_CH4_ADC_HI_REG(chip) (chip->tadc_base + 0x67) +#define TADC_CH5_ADC_LO_REG(chip) (chip->tadc_base + 0x68) +#define TADC_CH5_ADC_HI_REG(chip) (chip->tadc_base + 0x69) +#define TADC_CH6_ADC_LO_REG(chip) (chip->tadc_base + 0x70) +#define TADC_CH6_ADC_HI_REG(chip) (chip->tadc_base + 0x71) +#define TADC_CH7_ADC_LO_REG(chip) (chip->tadc_base + 0x72) +#define TADC_CH7_ADC_HI_REG(chip) (chip->tadc_base + 0x73) +#define TADC_CH8_ADC_LO_REG(chip) (chip->tadc_base + 0x74) +#define TADC_CH8_ADC_HI_REG(chip) (chip->tadc_base + 0x75) + +/* TADC_CMP register definitions */ +#define TADC_CMP_THR1_CMP_REG(chip) (chip->tadc_cmp_base + 0x51) +#define TADC_CMP_THR1_CH1_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x52) +#define TADC_CMP_THR1_CH1_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x53) +#define TADC_CMP_THR1_CH2_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x54) +#define TADC_CMP_THR1_CH2_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x55) +#define TADC_CMP_THR1_CH3_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x56) +#define TADC_CMP_THR1_CH3_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x57) +#define TADC_CMP_THR2_CMP_REG(chip) (chip->tadc_cmp_base + 0x67) +#define TADC_CMP_THR2_CH1_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x68) +#define TADC_CMP_THR2_CH1_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x69) +#define TADC_CMP_THR2_CH2_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x6A) +#define TADC_CMP_THR2_CH2_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x6B) +#define TADC_CMP_THR2_CH3_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x6C) +#define TADC_CMP_THR2_CH3_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x6D) +#define TADC_CMP_THR3_CMP_REG(chip) (chip->tadc_cmp_base + 0x7D) +#define TADC_CMP_THR3_CH1_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x7E) +#define TADC_CMP_THR3_CH1_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x7F) +#define TADC_CMP_THR3_CH2_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x80) +#define TADC_CMP_THR3_CH2_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x81) +#define TADC_CMP_THR3_CH3_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x82) +#define TADC_CMP_THR3_CH3_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x83) +#define TADC_CMP_THR4_CMP_REG(chip) (chip->tadc_cmp_base + 0x93) +#define TADC_CMP_THR4_CH1_CMP_LO_REG(chip) (chip->tadc_cmp_base + 0x94) +#define TADC_CMP_THR4_CH1_CMP_HI_REG(chip) (chip->tadc_cmp_base + 0x95) +#define TADC_CMP_THR1_CH1_HYST_REG(chip) (chip->tadc_cmp_base + 0xB0) +#define TADC_CMP_THR2_CH1_HYST_REG(chip) (chip->tadc_cmp_base + 0xB1) +#define TADC_CMP_THR3_CH1_HYST_REG(chip) (chip->tadc_cmp_base + 0xB2) +#define TADC_CMP_THR4_CH1_HYST_REG(chip) (chip->tadc_cmp_base + 0xB3) + +/* 10 bits of resolution */ +#define TADC_RESOLUTION 1024 +/* number of hardware channels */ +#define TADC_NUM_CH 8 + +enum tadc_chan_id { + TADC_THERM1 = 0, + TADC_THERM2, + TADC_DIE_TEMP, + TADC_BATT_I, + TADC_BATT_V, + TADC_INPUT_I, + TADC_INPUT_V, + TADC_OTG_I, + /* virtual channels */ + TADC_BATT_P, + TADC_INPUT_P, + TADC_THERM1_THR1, + TADC_THERM2_THR1, + TADC_DIE_TEMP_THR1, +}; + +#define TADC_CHAN(_name, _type, _channel, _info_mask) \ +{ \ + .type = _type, \ + .channel = _channel, \ + .info_mask_separate = _info_mask, \ + .extend_name = _name, \ +} + +#define TADC_THERM_CHAN(_name, _channel) \ +TADC_CHAN(_name, IIO_TEMP, _channel, \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED)) + +#define TADC_TEMP_CHAN(_name, _channel) \ +TADC_CHAN(_name, IIO_TEMP, _channel, \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET)) + +#define TADC_CURRENT_CHAN(_name, _channel) \ +TADC_CHAN(_name, IIO_CURRENT, _channel, \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_SCALE)) + + +#define TADC_VOLTAGE_CHAN(_name, _channel) \ +TADC_CHAN(_name, IIO_VOLTAGE, _channel, \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_SCALE)) + +#define TADC_POWER_CHAN(_name, _channel) \ +TADC_CHAN(_name, IIO_POWER, _channel, \ + BIT(IIO_CHAN_INFO_PROCESSED)) + +static const struct iio_chan_spec tadc_iio_chans[] = { + [TADC_THERM1] = TADC_THERM_CHAN( + "batt", TADC_THERM1), + [TADC_THERM2] = TADC_THERM_CHAN( + "skin", TADC_THERM2), + [TADC_DIE_TEMP] = TADC_TEMP_CHAN( + "die", TADC_DIE_TEMP), + [TADC_BATT_I] = TADC_CURRENT_CHAN( + "batt", TADC_BATT_I), + [TADC_BATT_V] = TADC_VOLTAGE_CHAN( + "batt", TADC_BATT_V), + [TADC_INPUT_I] = TADC_CURRENT_CHAN( + "input", TADC_INPUT_I), + [TADC_INPUT_V] = TADC_VOLTAGE_CHAN( + "input", TADC_INPUT_V), + [TADC_OTG_I] = TADC_CURRENT_CHAN( + "otg", TADC_OTG_I), + [TADC_BATT_P] = TADC_POWER_CHAN( + "batt", TADC_BATT_P), + [TADC_INPUT_P] = TADC_POWER_CHAN( + "input", TADC_INPUT_P), + [TADC_THERM1_THR1] = TADC_THERM_CHAN( + "batt_hot", TADC_THERM1_THR1), + [TADC_THERM2_THR1] = TADC_THERM_CHAN( + "skin_hot", TADC_THERM2_THR1), + [TADC_DIE_TEMP_THR1] = TADC_THERM_CHAN( + "die_hot", TADC_DIE_TEMP_THR1), +}; + +struct tadc_chan_data { + s32 scale; + s32 offset; + u32 rbias; + const struct tadc_pt *table; + size_t tablesize; +}; + +struct tadc_chip { + struct device *dev; + struct regmap *regmap; + u32 tadc_base; + u32 tadc_cmp_base; + struct tadc_chan_data chans[TADC_NUM_CH]; + struct completion eoc_complete; +}; + +struct tadc_pt { + s32 x; + s32 y; +}; + +/* + * Thermistor tables are generated by the B-parameter equation which is a + * simplifed version of the Steinhart-Hart equation. + * + * (1 / T) = (1 / T0) + (1 / B) * ln(R / R0) + * + * Where R0 is the resistance at temperature T0, and T0 is typically room + * temperature (25C). + */ +static const struct tadc_pt tadc_therm_3450b_68k[] = { + { 4151, 120000 }, + { 4648, 115000 }, + { 5220, 110000 }, + { 5880, 105000 }, + { 6644, 100000 }, + { 7533, 95000 }, + { 8571, 90000 }, + { 9786, 85000 }, + { 11216, 80000 }, + { 12906, 75000 }, + { 14910, 70000 }, + { 17300, 65000 }, + { 20163, 60000 }, + { 23609, 55000 }, + { 27780, 50000 }, + { 32855, 45000 }, + { 39065, 40000 }, + { 46712, 35000 }, + { 56185, 30000 }, + { 68000, 25000 }, + { 82837, 20000 }, + { 101604, 15000 }, + { 125525, 10000 }, + { 156261, 5000 }, + { 196090, 0 }, + { 248163, -5000 }, + { 316887, -10000 }, + { 408493, -15000 }, + { 531889, -20000 }, + { 699966, -25000 }, + { 931618, -30000 }, + { 1254910, -35000 }, + { 1712127, -40000 }, +}; + +static int tadc_read(struct tadc_chip *chip, u16 reg, u8 *val, + size_t val_count) +{ + int rc = 0; + + rc = regmap_bulk_read(chip->regmap, reg, val, val_count); + if (rc < 0) + pr_err("Couldn't read %04x rc=%d\n", reg, rc); + + return rc; +} + +static int tadc_write(struct tadc_chip *chip, u16 reg, u8 data) +{ + int rc = 0; + + rc = regmap_write(chip->regmap, reg, data); + if (rc < 0) + pr_err("Couldn't write %02x to %04x rc=%d\n", + data, reg, rc); + + return rc; +} + +static int tadc_lerp(const struct tadc_pt *pts, size_t tablesize, s32 input, + s32 *output) +{ + int i; + s64 temp; + + if (pts == NULL) { + pr_err("Table is NULL\n"); + return -EINVAL; + } + + if (tablesize < 1) { + pr_err("Table has no entries\n"); + return -ENOENT; + } + + if (tablesize == 1) { + *output = pts[0].y; + return 0; + } + + if (pts[0].x > pts[1].x) { + pr_err("Table is not in acending order\n"); + return -EINVAL; + } + + if (input <= pts[0].x) { + *output = pts[0].y; + return 0; + } + + if (input >= pts[tablesize - 1].x) { + *output = pts[tablesize - 1].y; + return 0; + } + + for (i = 1; i < tablesize; i++) + if (input <= pts[i].x) + break; + + temp = (s64)(pts[i].y - pts[i - 1].y) * (s64)(input - pts[i - 1].x); + temp = div_s64(temp, pts[i].x - pts[i - 1].x); + *output = temp + pts[i - 1].y; + return 0; +} + +/* + * Process the result of a thermistor reading. + * + * The voltage input to the ADC is a result of a voltage divider circuit. + * Vout = (Rtherm / (Rbias + Rtherm)) * Vbias + * + * The ADC value is based on the output voltage of the voltage divider, and the + * bias voltage. + * ADC = (Vin * 1024) / Vbias + * + * Combine these equations and solve for Rtherm + * Rtherm = (ADC * Rbias) / (1024 - ADC) + */ +static int tadc_process_therm(const struct tadc_chan_data *chan_data, + s16 adc, s32 *result) +{ + s64 rtherm; + + rtherm = (s64)adc * (s64)chan_data->rbias; + rtherm = div_s64(rtherm, TADC_RESOLUTION - adc); + return tadc_lerp(chan_data->table, chan_data->tablesize, rtherm, + result); +} + +static int tadc_read_channel(struct tadc_chip *chip, u16 address, int *adc) +{ + u8 val[2]; + int rc; + + rc = tadc_read(chip, address, val, ARRAY_SIZE(val)); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read channel rc=%d\n", rc); + return rc; + } + + *adc = (s16)(val[0] | val[1] << BITS_PER_BYTE); + return 0; +} + +#define CONVERSION_TIMEOUT_MS 100 +static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc) +{ + unsigned long timeout, timeleft; + u8 val[TADC_NUM_CH * 2]; + int rc, i; + + rc = tadc_read(chip, TADC_MBG_ERR_REG(chip), val, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read mbg error status rc=%d\n", + rc); + return rc; + } + + if (val[0] != 0) { + tadc_write(chip, TADC_EN_CTL_REG(chip), 0); + tadc_write(chip, TADC_EN_CTL_REG(chip), 0x80); + } + + rc = tadc_write(chip, TADC_CONV_REQ_REG(chip), channels); + if (rc < 0) { + dev_err(chip->dev, "Couldn't write conversion request rc=%d\n", + rc); + return rc; + } + + timeout = msecs_to_jiffies(CONVERSION_TIMEOUT_MS); + timeleft = wait_for_completion_timeout(&chip->eoc_complete, timeout); + + if (timeleft == 0) { + rc = tadc_read(chip, TADC_SW_CH_CONV_REG(chip), val, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read conversion status rc=%d\n", + rc); + return rc; + } + + if (val[0] != channels) { + dev_err(chip->dev, "Conversion timed out\n"); + return -ETIMEDOUT; + } + } + + rc = tadc_read(chip, TADC_CH1_ADC_LO_REG(chip), val, ARRAY_SIZE(val)); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read adc channels rc=%d\n", + rc); + return rc; + } + + for (i = 0; i < TADC_NUM_CH; i++) + adc[i] = val[i * 2] | val[i * 2 + 1] << BITS_PER_BYTE; + + return jiffies_to_msecs(timeout - timeleft); +} + +static int tadc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct tadc_chip *chip = iio_priv(indio_dev); + const struct tadc_chan_data *chan_data = &chip->chans[chan->channel]; + int rc = 0, offset = 0, scale, scale2, scale_type; + s16 adc[TADC_NUM_CH]; + + switch (chan->channel) { + case TADC_THERM1_THR1: + chan_data = &chip->chans[TADC_THERM1]; + break; + case TADC_THERM2_THR1: + chan_data = &chip->chans[TADC_THERM2]; + break; + case TADC_DIE_TEMP_THR1: + chan_data = &chip->chans[TADC_DIE_TEMP]; + break; + default: + break; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->channel) { + case TADC_THERM1_THR1: + rc = tadc_read_channel(chip, + TADC_CMP_THR1_CH1_CMP_LO_REG(chip), val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read THERM1 threshold rc=%d\n", + rc); + return rc; + } + break; + case TADC_THERM2_THR1: + rc = tadc_read_channel(chip, + TADC_CMP_THR1_CH2_CMP_LO_REG(chip), val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read THERM2 threshold rc=%d\n", + rc); + return rc; + } + break; + case TADC_DIE_TEMP_THR1: + rc = tadc_read_channel(chip, + TADC_CMP_THR1_CH3_CMP_LO_REG(chip), val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read DIE_TEMP threshold rc=%d\n", + rc); + return rc; + } + break; + default: + rc = tadc_do_conversion(chip, BIT(chan->channel), adc); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read channel %d\n", + chan->channel); + return rc; + } + *val = adc[chan->channel]; + break; + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_PROCESSED: + switch (chan->channel) { + case TADC_THERM1: + case TADC_THERM2: + case TADC_THERM1_THR1: + case TADC_THERM2_THR1: + rc = tadc_read_raw(indio_dev, chan, val, NULL, + IIO_CHAN_INFO_RAW); + if (rc < 0) + return rc; + + rc = tadc_process_therm(chan_data, *val, val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't process 0x%04x from channel %d rc=%d\n", + *val, chan->channel, rc); + return rc; + } + break; + case TADC_BATT_P: + rc = tadc_do_conversion(chip, + BIT(TADC_BATT_I) | BIT(TADC_BATT_V), adc); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read battery current and voltage channels\n"); + return rc; + } + + *val = adc[TADC_BATT_I] * adc[TADC_BATT_V]; + break; + case TADC_INPUT_P: + rc = tadc_do_conversion(chip, + BIT(TADC_INPUT_I) | BIT(TADC_INPUT_V), adc); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read input current and voltage channels\n"); + return rc; + } + + *val = adc[TADC_INPUT_I] * adc[TADC_INPUT_V]; + break; + default: + rc = tadc_read_raw(indio_dev, chan, val, NULL, + IIO_CHAN_INFO_RAW); + if (rc < 0) + return rc; + + /* offset is optional */ + rc = tadc_read_raw(indio_dev, chan, &offset, NULL, + IIO_CHAN_INFO_OFFSET); + if (rc < 0) + return rc; + + scale_type = tadc_read_raw(indio_dev, chan, + &scale, &scale2, IIO_CHAN_INFO_SCALE); + switch (scale_type) { + case IIO_VAL_INT: + *val = *val * scale + offset; + break; + case IIO_VAL_FRACTIONAL: + *val = div_s64((s64)*val * scale + offset, + scale2); + break; + default: + return -EINVAL; + } + break; + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->channel) { + case TADC_DIE_TEMP: + case TADC_DIE_TEMP_THR1: + *val = chan_data->scale; + return IIO_VAL_INT; + case TADC_BATT_I: + case TADC_BATT_V: + case TADC_INPUT_I: + case TADC_INPUT_V: + case TADC_OTG_I: + *val = chan_data->scale; + *val2 = TADC_RESOLUTION; + return IIO_VAL_FRACTIONAL; + } + return -EINVAL; + case IIO_CHAN_INFO_OFFSET: + *val = chan_data->offset; + return IIO_VAL_INT; + } + return -EINVAL; +} + +static irqreturn_t handle_eoc(int irq, void *dev_id) +{ + struct tadc_chip *chip = dev_id; + + complete(&chip->eoc_complete); + return IRQ_HANDLED; +} + +static int tadc_set_therm_table(struct tadc_chan_data *chan_data, u32 beta, + u32 rtherm) +{ + if (beta == 3450 && rtherm == 68000) { + chan_data->table = tadc_therm_3450b_68k; + chan_data->tablesize = ARRAY_SIZE(tadc_therm_3450b_68k); + return 0; + } + + return -ENOENT; +} + +static int tadc_parse_dt(struct tadc_chip *chip) +{ + struct device_node *child, *node; + struct tadc_chan_data *chan_data; + u32 chan_id, rtherm, beta; + int rc = 0; + + node = chip->dev->of_node; + for_each_available_child_of_node(node, child) { + rc = of_property_read_u32(child, "reg", &chan_id); + if (rc < 0) { + dev_err(chip->dev, "Couldn't find channel for %s rc=%d", + child->name, rc); + return rc; + } + + if (chan_id > TADC_NUM_CH - 1) { + dev_err(chip->dev, "Channel %d is out of range [0, %d]\n", + chan_id, TADC_NUM_CH - 1); + return -EINVAL; + } + + chan_data = &chip->chans[chan_id]; + switch (chan_id) { + case TADC_THERM1: + case TADC_THERM2: + rc = of_property_read_u32(child, + "qcom,rbias", &chan_data->rbias); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read qcom,rbias rc=%d\n", + rc); + return rc; + } + + rc = of_property_read_u32(child, + "qcom,beta-coefficient", &beta); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read qcom,beta-coefficient rc=%d\n", + rc); + return rc; + } + + rc = of_property_read_u32(child, + "qcom,rtherm-at-25degc", &rtherm); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read qcom,rtherm-at-25degc rc=%d\n", + rc); + return rc; + } + + rc = tadc_set_therm_table(chan_data, beta, rtherm); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set therm table rc=%d\n", + rc); + return rc; + } + break; + default: + rc = of_property_read_s32(child, "qcom,scale", + &chan_data->scale); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read scale rc=%d\n", + rc); + return rc; + } + + of_property_read_s32(child, "qcom,offset", + &chan_data->offset); + break; + } + } + + return rc; +} + +static const struct iio_info tadc_info = { + .read_raw = &tadc_read_raw, + .driver_module = THIS_MODULE, +}; + +static int tadc_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct iio_dev *indio_dev; + struct tadc_chip *chip; + int rc = 0, irq; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + chip->dev = &pdev->dev; + init_completion(&chip->eoc_complete); + + rc = of_property_read_u32(node, "reg", &chip->tadc_base); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read base address rc=%d\n", rc); + return rc; + } + chip->tadc_cmp_base = chip->tadc_base + 0x100; + + chip->regmap = dev_get_regmap(chip->dev->parent, NULL); + if (!chip->regmap) { + pr_err("Couldn't get regmap\n"); + return -ENODEV; + } + + rc = tadc_parse_dt(chip); + if (rc < 0) { + pr_err("Couldn't parse device tree rc=%d\n", rc); + return rc; + } + + irq = of_irq_get_byname(node, "eoc"); + if (irq < 0) { + pr_err("Couldn't get eoc irq rc=%d\n", irq); + return irq; + } + + rc = devm_request_threaded_irq(chip->dev, irq, NULL, handle_eoc, + IRQF_ONESHOT, "eoc", chip); + if (rc < 0) { + pr_err("Couldn't request irq %d rc=%d\n", irq, rc); + return rc; + } + + indio_dev->dev.parent = chip->dev; + indio_dev->name = pdev->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &tadc_info; + indio_dev->channels = tadc_iio_chans; + indio_dev->num_channels = ARRAY_SIZE(tadc_iio_chans); + + rc = devm_iio_device_register(chip->dev, indio_dev); + if (rc < 0) + dev_err(chip->dev, "Couldn't register IIO device rc=%d\n", rc); + + return rc; +} + +static int tadc_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id tadc_match_table[] = { + { .compatible = "qcom,tadc" }, + { } +}; +MODULE_DEVICE_TABLE(of, tadc_match_table); + +static struct platform_driver tadc_driver = { + .driver = { + .name = "qcom-tadc", + .of_match_table = tadc_match_table, + }, + .probe = tadc_probe, + .remove = tadc_remove, +}; +module_platform_driver(tadc_driver); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. TADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index f2a7f72f7aa6..b13936dacc78 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -462,8 +462,6 @@ static int ak8975_setup_irq(struct ak8975_data *data) int rc; int irq; - init_waitqueue_head(&data->data_ready_queue); - clear_bit(0, &data->flags); if (client->irq) irq = client->irq; else @@ -479,6 +477,8 @@ static int ak8975_setup_irq(struct ak8975_data *data) return rc; } + init_waitqueue_head(&data->data_ready_queue); + clear_bit(0, &data->flags); data->eoc_irq = irq; return rc; @@ -732,7 +732,7 @@ static int ak8975_probe(struct i2c_client *client, int eoc_gpio; int err; const char *name = NULL; - enum asahi_compass_chipset chipset = AK_MAX_TYPE; + enum asahi_compass_chipset chipset; /* Grab and set up the supplied GPIO. */ if (client->dev.platform_data) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 564adf3116e8..6b4e8a008bc0 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -48,7 +48,6 @@ #include <asm/uaccess.h> -#include <rdma/ib.h> #include <rdma/ib_cm.h> #include <rdma/ib_user_cm.h> #include <rdma/ib_marshall.h> @@ -1104,9 +1103,6 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, struct ib_ucm_cmd_hdr hdr; ssize_t result; - if (WARN_ON_ONCE(!ib_safe_file_access(filp))) - return -EACCES; - if (len < sizeof(hdr)) return -EINVAL; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 886f61ea6cc7..8b5a934e1133 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1574,9 +1574,6 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf, struct rdma_ucm_cmd_hdr hdr; ssize_t ret; - if (WARN_ON_ONCE(!ib_safe_file_access(filp))) - return -EACCES; - if (len < sizeof(hdr)) return -EINVAL; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 24f3ca2c4ad7..e3ef28861be6 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -48,8 +48,6 @@ #include <asm/uaccess.h> -#include <rdma/ib.h> - #include "uverbs.h" MODULE_AUTHOR("Roland Dreier"); @@ -684,9 +682,6 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, int srcu_key; ssize_t ret; - if (WARN_ON_ONCE(!ib_safe_file_access(filp))) - return -EACCES; - if (count < sizeof hdr) return -EINVAL; diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index bc147582bed9..de9cd6901752 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -162,7 +162,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, T4_BAR2_QTYPE_INGRESS, &cq->bar2_qid, user ? &cq->bar2_pa : NULL); - if (user && !cq->bar2_pa) { + if (user && !cq->bar2_va) { pr_warn(MOD "%s: cqid %u not in BAR2 range.\n", pci_name(rdev->lldi.pdev), cq->cqid); ret = -EINVAL; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 53aa7515f542..aa515afee724 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -185,10 +185,6 @@ void __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid, if (pbar2_pa) *pbar2_pa = (rdev->bar2_pa + bar2_qoffset) & PAGE_MASK; - - if (is_t4(rdev->lldi.adapter_type)) - return NULL; - return rdev->bar2_kva + bar2_qoffset; } @@ -274,7 +270,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, /* * User mode must have bar2 access. */ - if (user && (!wq->sq.bar2_pa || !wq->rq.bar2_pa)) { + if (user && (!wq->sq.bar2_va || !wq->rq.bar2_va)) { pr_warn(MOD "%s: sqid %u or rqid %u not in BAR2 range.\n", pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid); goto free_dma; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index fd17443aeacd..c4e091528390 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -273,7 +273,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, sizeof(struct mlx5_wqe_ctrl_seg)) / sizeof(struct mlx5_wqe_data_seg); props->max_sge = min(max_rq_sg, max_sq_sg); - props->max_sge_rd = MLX5_MAX_SGE_RD; + props->max_sge_rd = props->max_sge; props->max_cq = 1 << MLX5_CAP_GEN(mdev, log_max_cq); props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_cq_sz)) - 1; props->max_mr = 1 << MLX5_CAP_GEN(mdev, log_max_mkey); @@ -405,8 +405,8 @@ static int mlx5_query_hca_port(struct ib_device *ibdev, u8 port, struct mlx5_ib_dev *dev = to_mdev(ibdev); struct mlx5_core_dev *mdev = dev->mdev; struct mlx5_hca_vport_context *rep; - u16 max_mtu; - u16 oper_mtu; + int max_mtu; + int oper_mtu; int err; u8 ib_link_width_oper; u8 vl_hw_cap; diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 24f4a782e0f4..e449e394963f 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -45,8 +45,6 @@ #include <linux/export.h> #include <linux/uio.h> -#include <rdma/ib.h> - #include "qib.h" #include "qib_common.h" #include "qib_user_sdma.h" @@ -2069,9 +2067,6 @@ static ssize_t qib_write(struct file *fp, const char __user *data, ssize_t ret = 0; void *dest; - if (WARN_ON_ONCE(!ib_safe_file_access(fp))) - return -EACCES; - if (count < sizeof(cmd.type)) { ret = -EINVAL; goto bail; diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index 8d6326d7e7be..a806ba3818f7 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -255,14 +255,12 @@ static int max8997_haptic_probe(struct platform_device *pdev) struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); const struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); - const struct max8997_haptic_platform_data *haptic_pdata = NULL; + const struct max8997_haptic_platform_data *haptic_pdata = + pdata->haptic_pdata; struct max8997_haptic *chip; struct input_dev *input_dev; int error; - if (pdata) - haptic_pdata = pdata->haptic_pdata; - if (!haptic_pdata) { dev_err(&pdev->dev, "no haptic platform data\n"); return -EINVAL; diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 67aab86048ad..3f02e0e03d12 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -353,8 +353,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay)) kpd_delay = 15625; - /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */ - if (kpd_delay > USEC_PER_SEC * 2 || kpd_delay < USEC_PER_SEC / 64) { + if (kpd_delay > 62500 || kpd_delay == 0) { dev_err(&pdev->dev, "invalid power key trigger delay\n"); return -EINVAL; } @@ -386,8 +385,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) pwr->name = "pmic8xxx_pwrkey"; pwr->phys = "pmic8xxx_pwrkey/input0"; - delay = (kpd_delay << 6) / USEC_PER_SEC; - delay = ilog2(delay); + delay = (kpd_delay << 10) / USEC_PER_SEC; + delay = 1 + ilog2(delay); err = regmap_read(regmap, PON_CNTL_1, &pon_cntl); if (err < 0) { diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 7c18249d6c8e..3a7f3a4a4396 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -858,14 +858,6 @@ static int gtco_probe(struct usb_interface *usbinterface, goto err_free_buf; } - /* Sanity check that a device has an endpoint */ - if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) { - dev_err(&usbinterface->dev, - "Invalid number of endpoints\n"); - error = -EINVAL; - goto err_free_urb; - } - /* * The endpoint is always altsetting 0, we know this since we know * this device only has one interrupt endpoint @@ -887,7 +879,7 @@ static int gtco_probe(struct usb_interface *usbinterface, * HID report descriptor */ if (usb_get_extra_descriptor(usbinterface->cur_altsetting, - HID_DEVICE_TYPE, &hid_desc) != 0) { + HID_DEVICE_TYPE, &hid_desc) != 0){ dev_err(&usbinterface->dev, "Can't retrieve exta USB descriptor to get hid report descriptor length\n"); error = -EIO; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 7c4a7c7c16e7..bc5126a08ecb 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1119,6 +1119,15 @@ config TOUCHSCREEN_FT5X06_PSENSOR If unsure, say N. +config TOUCHSCREEN_FT5X06_GESTURE + tristate "FocalTech gesture feature support" + depends on TOUCHSCREEN_FT5X06 + help + Say Y here if you want to support ft5x06's gesture + feature. + + If unsure, say N. + config TOUCHSCREEN_MSTAR21XX tristate "Mstar touchscreens" depends on I2C diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index beb86c9dea11..17bce3d18d2f 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -29,8 +29,13 @@ #include <linux/regulator/consumer.h> #include <linux/firmware.h> #include <linux/debugfs.h> -#include <linux/sensors.h> #include <linux/input/ft5x06_ts.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> + #if defined(CONFIG_FB) #include <linux/notifier.h> @@ -74,18 +79,26 @@ #define FT_REG_FW_MIN_VER 0xB2 #define FT_REG_FW_SUB_MIN_VER 0xB3 -/* psensor register address*/ -#define FT_REG_PSENSOR_ENABLE 0xB0 -#define FT_REG_PSENSOR_STATUS 0x01 - -/* psensor register bits*/ -#define FT_PSENSOR_ENABLE_MASK 0x01 -#define FT_PSENSOR_STATUS_NEAR 0xC0 -#define FT_PSENSOR_STATUS_FAR 0xE0 -#define FT_PSENSOR_FAR_TO_NEAR 0 -#define FT_PSENSOR_NEAR_TO_FAR 1 -#define FT_PSENSOR_ORIGINAL_STATE_FAR 1 -#define FT_PSENSOR_WAKEUP_TIMEOUT 100 +/* gesture register address*/ +#define FT_REG_GESTURE_ENABLE 0xD0 +#define FT_REG_GESTURE_OUTPUT 0xD3 + +/* gesture register bits*/ +#define FT_GESTURE_DOUBLECLICK_COORD_X 100 +#define FT_GESTURE_DOUBLECLICK_COORD_Y 100 +#define FT_GESTURE_WAKEUP_TIMEOUT 500 +#define FT_GESTURE_DEFAULT_TRACKING_ID 0x0A +#define FT_GESTURE_DOUBLECLICK_ID 0x24 +#define FT_GESTURE_POINTER_NUM_MAX 128 +#define FT_GESTURE_POINTER_SIZEOF 4 +#define FT_GESTURE_ID_FLAG_SIZE 1 +#define FT_GESTURE_POINTER_NUM_FLAG_SIZE 1 +/* 6 bytes are taken to mark which gesture is supported in firmware */ +#define FT_GESTURE_SET_FLAG_SIZE 6 +#define I2C_TRANSFER_MAX_BYTE 255 +#define FT_GESTURE_DATA_HEADER (FT_GESTURE_ID_FLAG_SIZE + \ + FT_GESTURE_POINTER_NUM_FLAG_SIZE + \ + FT_GESTURE_SET_FLAG_SIZE) /* power register bits*/ #define FT_PMODE_ACTIVE 0x00 @@ -135,6 +148,9 @@ #define FT_FW_FILE_MAJ_VER_FT6X36(x) ((x)->data[0x10a]) #define FT_FW_FILE_VENDOR_ID_FT6X36(x) ((x)->data[0x108]) +#define FT_SYSFS_TS_INFO "ts_info" + + /** * Application data verification will be run before upgrade flow. * Firmware image stores some flags with negative and positive value @@ -221,7 +237,7 @@ struct ft5x06_ts_data { struct i2c_client *client; struct input_dev *input_dev; const struct ft5x06_ts_platform_data *pdata; - struct ft5x06_psensor_platform_data *psensor_pdata; + struct ft5x06_gesture_platform_data *gesture_pdata; struct regulator *vdd; struct regulator *vcc_i2c; char fw_name[FT_FW_NAME_MAX_LEN]; @@ -235,7 +251,9 @@ struct ft5x06_ts_data { u32 tch_data_len; u8 fw_ver[3]; u8 fw_vendor_id; + struct kobject ts_info_kobj; #if defined(CONFIG_FB) + struct work_struct fb_notify_work; struct notifier_block fb_notif; #elif defined(CONFIG_HAS_EARLYSUSPEND) struct early_suspend early_suspend; @@ -246,27 +264,12 @@ struct ft5x06_ts_data { struct pinctrl_state *pinctrl_state_release; }; -static struct sensors_classdev __maybe_unused sensors_proximity_cdev = { - .name = "ft5x06-proximity", - .vendor = "FocalTech", - .version = 1, - .handle = SENSORS_PROXIMITY_HANDLE, - .type = SENSOR_TYPE_PROXIMITY, - .max_range = "5.0", - .resolution = "5.0", - .sensor_power = "0.1", - .min_delay = 0, - .fifo_reserved_event_count = 0, - .fifo_max_event_count = 0, - .enabled = 0, - .delay_msec = 200, - .sensors_enable = NULL, - .sensors_poll_delay = NULL, -}; +static int ft5x06_ts_start(struct device *dev); +static int ft5x06_ts_stop(struct device *dev); -static inline bool ft5x06_psensor_support_enabled(void) +static inline bool ft5x06_gesture_support_enabled(void) { - return config_enabled(CONFIG_TOUCHSCREEN_FT5X06_PSENSOR); + return config_enabled(CONFIG_TOUCHSCREEN_FT5X06_GESTURE); } static int ft5x06_i2c_read(struct i2c_client *client, char *writebuf, @@ -344,79 +347,196 @@ static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val) return ft5x06_i2c_read(client, &addr, 1, val, 1); } -#ifdef CONFIG_TOUCHSCREEN_FT5X06_PSENSOR -static void ft5x06_psensor_enable(struct ft5x06_ts_data *data, int enable) +#ifdef CONFIG_TOUCHSCREEN_FT5X06_GESTURE +static ssize_t ft5x06_gesture_enable_to_set_show(struct device *dev, + struct device_attribute *attr, char *buf) { - u8 state; - int ret = -1; + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + data->gesture_pdata->gesture_enable_to_set); +} + +static ssize_t ft5x06_gesture_enable_to_set_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + + if (data->suspended) + return -EINVAL; - if (data->client == NULL) - return; + ret = kstrtoul(buf, 16, &value); + if (ret < 0) { + dev_err(dev, "%s:kstrtoul failed, ret=0x%x\n", + __func__, ret); + return ret; + } - ft5x0x_read_reg(data->client, FT_REG_PSENSOR_ENABLE, &state); - if (enable) - state |= FT_PSENSOR_ENABLE_MASK; + if (value == 1) + data->gesture_pdata->gesture_enable_to_set = 1; else - state &= ~FT_PSENSOR_ENABLE_MASK; + data->gesture_pdata->gesture_enable_to_set = 0; + return size; +} - ret = ft5x0x_write_reg(data->client, FT_REG_PSENSOR_ENABLE, state); - if (ret < 0) +static DEVICE_ATTR(enable, 0664, + ft5x06_gesture_enable_to_set_show, + ft5x06_gesture_enable_to_set_store); + +static int ft5x06_entry_pocket(struct device *dev) +{ + return ft5x06_ts_stop(dev); +} + +static int ft5x06_leave_pocket(struct device *dev) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + int err; + + ft5x06_ts_start(dev); + ft5x0x_write_reg(data->client, FT_REG_GESTURE_ENABLE, 1); + err = enable_irq_wake(data->client->irq); + if (err) dev_err(&data->client->dev, - "write psensor switch command failed\n"); + "%s: set_irq_wake failed\n", __func__); + data->suspended = true; + + return err; } -static int ft5x06_psensor_enable_set(struct sensors_classdev *sensors_cdev, - unsigned int enable) +static ssize_t gesture_in_pocket_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct ft5x06_psensor_platform_data *psensor_pdata = - container_of(sensors_cdev, - struct ft5x06_psensor_platform_data, ps_cdev); - struct ft5x06_ts_data *data = psensor_pdata->data; - struct input_dev *input_dev = data->psensor_pdata->input_psensor_dev; - - mutex_lock(&input_dev->mutex); - ft5x06_psensor_enable(data, enable); - psensor_pdata->tp_psensor_data = FT_PSENSOR_ORIGINAL_STATE_FAR; - if (enable) - psensor_pdata->tp_psensor_opened = 1; - else - psensor_pdata->tp_psensor_opened = 0; - mutex_unlock(&input_dev->mutex); - return enable; + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + data->gesture_pdata->in_pocket); } -static int ft5x06_read_tp_psensor_data(struct ft5x06_ts_data *data) +static ssize_t gesture_in_pocket_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) { - u8 psensor_status; - char tmp; - int ret = 0; - - ft5x0x_read_reg(data->client, - FT_REG_PSENSOR_STATUS, &psensor_status); - - tmp = data->psensor_pdata->tp_psensor_data; - if (psensor_status == FT_PSENSOR_STATUS_NEAR) - data->psensor_pdata->tp_psensor_data = - FT_PSENSOR_FAR_TO_NEAR; - else if (psensor_status == FT_PSENSOR_STATUS_FAR) - data->psensor_pdata->tp_psensor_data = - FT_PSENSOR_NEAR_TO_FAR; - - if (tmp != data->psensor_pdata->tp_psensor_data) { - dev_info(&data->client->dev, - "%s sensor data changed\n", __func__); - ret = 1; + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + + ret = kstrtoul(buf, 16, &value); + if (ret < 0) { + dev_err(dev, "%s:kstrtoul failed, ret=0x%x\n", + __func__, ret); + return ret; } - return ret; + + if (value == 1 && data->gesture_pdata->in_pocket == 0) { + data->gesture_pdata->in_pocket = 1; + ft5x06_entry_pocket(dev); + } else if (value == 0 && data->gesture_pdata->in_pocket == 1) { + ft5x06_leave_pocket(dev); + data->gesture_pdata->in_pocket = 0; + } + return size; } -#else -static int ft5x06_psensor_enable_set(struct sensors_classdev *sensors_cdev, - unsigned int enable) + +static DEVICE_ATTR(pocket, 0664, + gesture_in_pocket_mode_show, + gesture_in_pocket_mode_store); + +static int ft5x06_report_gesture_doubleclick(struct input_dev *ip_dev) { - return enable; + int i; + + for (i = 0; i < 2; i++) { + input_mt_slot(ip_dev, FT_GESTURE_DEFAULT_TRACKING_ID); + input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1); + input_report_abs(ip_dev, ABS_MT_POSITION_X, + FT_GESTURE_DOUBLECLICK_COORD_X); + input_report_abs(ip_dev, ABS_MT_POSITION_Y, + FT_GESTURE_DOUBLECLICK_COORD_Y); + input_mt_report_pointer_emulation(ip_dev, false); + input_sync(ip_dev); + input_mt_slot(ip_dev, FT_GESTURE_DEFAULT_TRACKING_ID); + input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0); + input_mt_report_pointer_emulation(ip_dev, false); + input_sync(ip_dev); + } + return 0; +} + +static int ft5x06_report_gesture(struct i2c_client *i2c_client, + struct input_dev *ip_dev) +{ + int i, temp, gesture_data_size; + int gesture_coord_x, gesture_coord_y; + int ret = -1; + short pointnum = 0; + unsigned char buf[FT_GESTURE_POINTER_NUM_MAX * + FT_GESTURE_POINTER_SIZEOF + FT_GESTURE_DATA_HEADER]; + + buf[0] = FT_REG_GESTURE_OUTPUT; + ret = ft5x06_i2c_read(i2c_client, buf, 1, + buf, FT_GESTURE_DATA_HEADER); + if (ret < 0) { + dev_err(&i2c_client->dev, "%s read touchdata failed.\n", + __func__); + return ret; + } + + /* FW support doubleclick */ + if (buf[0] == FT_GESTURE_DOUBLECLICK_ID) { + ft5x06_report_gesture_doubleclick(ip_dev); + return 0; + } + + pointnum = (short)(buf[1]) & 0xff; + gesture_data_size = pointnum * FT_GESTURE_POINTER_SIZEOF + + FT_GESTURE_DATA_HEADER; + buf[0] = FT_REG_GESTURE_OUTPUT; + temp = gesture_data_size / I2C_TRANSFER_MAX_BYTE; + for (i = 0; i < temp; i++) + ret = ft5x06_i2c_read(i2c_client, buf, ((i == 0) ? 1 : 0), + buf + I2C_TRANSFER_MAX_BYTE * i, I2C_TRANSFER_MAX_BYTE); + ret = ft5x06_i2c_read(i2c_client, buf, ((temp == 0) ? 1 : 0), + buf + I2C_TRANSFER_MAX_BYTE * temp, + gesture_data_size - I2C_TRANSFER_MAX_BYTE * temp); + if (ret < 0) { + dev_err(&i2c_client->dev, "%s read touchdata failed.\n", + __func__); + return ret; + } + + for (i = 0; i < pointnum; i++) { + gesture_coord_x = (((s16) buf[FT_GESTURE_DATA_HEADER + + (FT_GESTURE_POINTER_SIZEOF * i)]) & 0x0F) << 8 | + (((s16) buf[FT_GESTURE_DATA_HEADER + 1 + + (FT_GESTURE_POINTER_SIZEOF * i)]) & 0xFF); + gesture_coord_y = (((s16) buf[FT_GESTURE_DATA_HEADER + 2 + + (FT_GESTURE_POINTER_SIZEOF * i)]) & 0x0F) << 8 | + (((s16) buf[FT_GESTURE_DATA_HEADER + 3 + + (FT_GESTURE_POINTER_SIZEOF * i)]) & 0xFF); + input_mt_slot(ip_dev, FT_GESTURE_DEFAULT_TRACKING_ID); + input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1); + input_report_abs(ip_dev, ABS_MT_POSITION_X, gesture_coord_x); + input_report_abs(ip_dev, ABS_MT_POSITION_Y, gesture_coord_y); + input_mt_report_pointer_emulation(ip_dev, false); + input_sync(ip_dev); + } + input_mt_slot(ip_dev, FT_GESTURE_DEFAULT_TRACKING_ID); + input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0); + input_mt_report_pointer_emulation(ip_dev, false); + input_sync(ip_dev); + + return 0; } +#else +static DEVICE_ATTR(pocket, 0664, NULL, NULL); +static DEVICE_ATTR(enable, 0664, NULL, NULL); -static int ft5x06_read_tp_psensor_data(struct ft5x06_ts_data *data) +static int ft5x06_report_gesture(struct i2c_client *i2c_client, + struct input_dev *ip_dev) { return 0; } @@ -465,7 +585,7 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) struct input_dev *ip_dev; int rc, i; u32 id, x, y, status, num_touches; - u8 reg, *buf; + u8 reg, *buf, gesture_is_active; bool update_input = false; if (!data) { @@ -476,25 +596,18 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) ip_dev = data->input_dev; buf = data->tch_data; - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && - data->psensor_pdata->tp_psensor_opened) { - rc = ft5x06_read_tp_psensor_data(data); - if (rc) { - if (data->suspended) - pm_wakeup_event(&data->client->dev, - FT_PSENSOR_WAKEUP_TIMEOUT); - input_report_abs(data->psensor_pdata->input_psensor_dev, - ABS_DISTANCE, - data->psensor_pdata->tp_psensor_data); - input_sync(data->psensor_pdata->input_psensor_dev); - if (data->suspended) - return IRQ_HANDLED; - } - if (data->suspended) + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) { + ft5x0x_read_reg(data->client, FT_REG_GESTURE_ENABLE, + &gesture_is_active); + if (gesture_is_active) { + pm_wakeup_event(&(data->client->dev), + FT_GESTURE_WAKEUP_TIMEOUT); + ft5x06_report_gesture(data->client, ip_dev); return IRQ_HANDLED; + } } - /** + /* * Read touch data start from register FT_REG_DEV_MODE. * The touch x/y value start from FT_TOUCH_X_H/L_POS and * FT_TOUCH_Y_H/L_POS in buf. @@ -784,32 +897,77 @@ err_pinctrl_get: } #ifdef CONFIG_PM -static int ft5x06_ts_suspend(struct device *dev) +static int ft5x06_ts_start(struct device *dev) { struct ft5x06_ts_data *data = dev_get_drvdata(dev); - char txbuf[2], i; int err; - if (data->loading_fw) { - dev_info(dev, "Firmware loading in process...\n"); - return 0; + if (data->pdata->power_on) { + err = data->pdata->power_on(true); + if (err) { + dev_err(dev, "power on failed"); + return err; + } + } else { + err = ft5x06_power_on(data, true); + if (err) { + dev_err(dev, "power on failed"); + return err; + } } - if (data->suspended) { - dev_info(dev, "Already in suspend state\n"); - return 0; + if (data->ts_pinctrl) { + err = pinctrl_select_state(data->ts_pinctrl, + data->pinctrl_state_active); + if (err < 0) + dev_err(dev, "Cannot get active pinctrl state\n"); } - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && - device_may_wakeup(dev) && - data->psensor_pdata->tp_psensor_opened) { - err = enable_irq_wake(data->client->irq); + err = ft5x06_gpio_configure(data, true); + if (err < 0) { + dev_err(&data->client->dev, + "failed to put gpios in resue state\n"); + goto err_gpio_configuration; + } + + if (gpio_is_valid(data->pdata->reset_gpio)) { + gpio_set_value_cansleep(data->pdata->reset_gpio, 0); + msleep(data->pdata->hard_rst_dly); + gpio_set_value_cansleep(data->pdata->reset_gpio, 1); + } + + msleep(data->pdata->soft_rst_dly); + + enable_irq(data->client->irq); + data->suspended = false; + + return 0; + +err_gpio_configuration: + if (data->ts_pinctrl) { + err = pinctrl_select_state(data->ts_pinctrl, + data->pinctrl_state_suspend); + if (err < 0) + dev_err(dev, "Cannot get suspend pinctrl state\n"); + } + if (data->pdata->power_on) { + err = data->pdata->power_on(false); if (err) - dev_err(&data->client->dev, - "%s: set_irq_wake failed\n", __func__); - data->suspended = true; - return err; + dev_err(dev, "power off failed"); + } else { + err = ft5x06_power_on(data, false); + if (err) + dev_err(dev, "power off failed"); } + return err; +} + +static int ft5x06_ts_stop(struct device *dev) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + char txbuf[2]; + int i, err; + disable_irq(data->client->irq); /* release all touches */ @@ -884,87 +1042,79 @@ pwr_off_fail: return err; } -static int ft5x06_ts_resume(struct device *dev) +static int ft5x06_ts_suspend(struct device *dev) { struct ft5x06_ts_data *data = dev_get_drvdata(dev); int err; - if (!data->suspended) { - dev_dbg(dev, "Already in awake state\n"); + if (data->loading_fw) { + dev_info(dev, "Firmware loading in process...\n"); + return 0; + } + + if (data->suspended) { + dev_info(dev, "Already in suspend state\n"); return 0; } - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support && device_may_wakeup(dev) && - data->psensor_pdata->tp_psensor_opened) { - err = disable_irq_wake(data->client->irq); + data->gesture_pdata->gesture_enable_to_set) { + + ft5x0x_write_reg(data->client, FT_REG_GESTURE_ENABLE, 1); + err = enable_irq_wake(data->client->irq); if (err) dev_err(&data->client->dev, - "%s: disable_irq_wake failed\n", - __func__); - data->suspended = false; + "%s: set_irq_wake failed\n", __func__); + data->suspended = true; return err; } - if (data->pdata->power_on) { - err = data->pdata->power_on(true); - if (err) { - dev_err(dev, "power on failed"); - return err; - } - } else { - err = ft5x06_power_on(data, true); - if (err) { - dev_err(dev, "power on failed"); - return err; - } - } - - if (data->ts_pinctrl) { - err = pinctrl_select_state(data->ts_pinctrl, - data->pinctrl_state_active); - if (err < 0) - dev_err(dev, "Cannot get active pinctrl state\n"); - } + return ft5x06_ts_stop(dev); +} - err = ft5x06_gpio_configure(data, true); - if (err < 0) { - dev_err(&data->client->dev, - "failed to put gpios in resue state\n"); - goto err_gpio_configuration; - } +static int ft5x06_ts_resume(struct device *dev) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + int err; - if (gpio_is_valid(data->pdata->reset_gpio)) { - gpio_set_value_cansleep(data->pdata->reset_gpio, 0); - msleep(data->pdata->hard_rst_dly); - gpio_set_value_cansleep(data->pdata->reset_gpio, 1); + if (!data->suspended) { + dev_dbg(dev, "Already in awake state\n"); + return 0; } - msleep(data->pdata->soft_rst_dly); + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support && + device_may_wakeup(dev) && + !(data->gesture_pdata->in_pocket) && + data->gesture_pdata->gesture_enable_to_set) { - enable_irq(data->client->irq); + ft5x0x_write_reg(data->client, FT_REG_GESTURE_ENABLE, 0); + err = disable_irq_wake(data->client->irq); + if (err) + dev_err(dev, "%s: disable_irq_wake failed\n", + __func__); + data->suspended = false; + return err; + } - data->suspended = false; + err = ft5x06_ts_start(dev); + if (err < 0) + return err; - return 0; + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support && + device_may_wakeup(dev) && + data->gesture_pdata->in_pocket && + data->gesture_pdata->gesture_enable_to_set) { -err_gpio_configuration: - if (data->ts_pinctrl) { - err = pinctrl_select_state(data->ts_pinctrl, - data->pinctrl_state_suspend); - if (err < 0) - dev_err(dev, "Cannot get suspend pinctrl state\n"); - } - if (data->pdata->power_on) { - err = data->pdata->power_on(false); - if (err) - dev_err(dev, "power off failed"); - } else { - err = ft5x06_power_on(data, false); + ft5x0x_write_reg(data->client, FT_REG_GESTURE_ENABLE, 0); + err = disable_irq_wake(data->client->irq); if (err) - dev_err(dev, "power off failed"); + dev_err(dev, "%s: disable_irq_wake failed\n", + __func__); + data->suspended = false; + data->gesture_pdata->in_pocket = 0; } - return err; + return 0; } static const struct dev_pm_ops ft5x06_ts_pm_ops = { @@ -988,6 +1138,13 @@ static int ft5x06_ts_resume(struct device *dev) #endif #if defined(CONFIG_FB) +static void fb_notify_resume_work(struct work_struct *work) +{ + struct ft5x06_ts_data *ft5x06_data = + container_of(work, struct ft5x06_ts_data, fb_notify_work); + ft5x06_ts_resume(&ft5x06_data->client->dev); +} + static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { @@ -996,13 +1153,27 @@ static int fb_notifier_callback(struct notifier_block *self, struct ft5x06_ts_data *ft5x06_data = container_of(self, struct ft5x06_ts_data, fb_notif); - if (evdata && evdata->data && event == FB_EVENT_BLANK && - ft5x06_data && ft5x06_data->client) { + if (evdata && evdata->data && ft5x06_data && ft5x06_data->client) { blank = evdata->data; - if (*blank == FB_BLANK_UNBLANK) - ft5x06_ts_resume(&ft5x06_data->client->dev); - else if (*blank == FB_BLANK_POWERDOWN) - ft5x06_ts_suspend(&ft5x06_data->client->dev); + if (ft5x06_data->pdata->resume_in_workqueue) { + if (event == FB_EARLY_EVENT_BLANK && + *blank == FB_BLANK_UNBLANK) + schedule_work(&ft5x06_data->fb_notify_work); + else if (event == FB_EVENT_BLANK && + *blank == FB_BLANK_POWERDOWN) { + flush_work(&ft5x06_data->fb_notify_work); + ft5x06_ts_suspend(&ft5x06_data->client->dev); + } + } else { + if (event == FB_EVENT_BLANK) { + if (*blank == FB_BLANK_UNBLANK) + ft5x06_ts_resume( + &ft5x06_data->client->dev); + else if (*blank == FB_BLANK_POWERDOWN) + ft5x06_ts_suspend( + &ft5x06_data->client->dev); + } + } } return 0; @@ -1446,6 +1617,23 @@ static ssize_t ft5x06_fw_name_store(struct device *dev, static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store); + +static ssize_t ft5x06_ts_info_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct ft5x06_ts_data *data = container_of(kobj, + struct ft5x06_ts_data, ts_info_kobj); + return snprintf(buf, FT_INFO_MAX_LEN, + "vendor name = Focaltech\n" + "model = 0x%x\n" + "fw_verion = %d.%d.%d\n", + data->family_id, data->fw_ver[0], + data->fw_ver[1], data->fw_ver[2]); +} + +static struct kobj_attribute ts_info_attribute = __ATTR(ts_info, + 0664, ft5x06_ts_info_show, NULL); + static bool ft5x06_debug_addr_is_valid(int addr) { if (addr < 0 || addr > 0xFF) { @@ -1749,8 +1937,12 @@ static int ft5x06_parse_dt(struct device *dev, pdata->ignore_id_check = of_property_read_bool(np, "focaltech,ignore-id-check"); - pdata->psensor_support = of_property_read_bool(np, - "focaltech,psensor-support"); + pdata->gesture_support = of_property_read_bool(np, + "focaltech,gesture-support"); + + pdata->resume_in_workqueue = of_property_read_bool(np, + "focaltech,resume-in-workqueue"); + rc = of_property_read_u32(np, "focaltech,family-id", &temp_val); if (!rc) pdata->family_id = temp_val; @@ -1786,15 +1978,13 @@ static int ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ft5x06_ts_platform_data *pdata; - struct ft5x06_psensor_platform_data *psensor_pdata; + struct ft5x06_gesture_platform_data *gesture_pdata; struct ft5x06_ts_data *data; struct input_dev *input_dev; - struct input_dev *psensor_input_dev; struct dentry *temp; u8 reg_value; u8 reg_addr; int err, len; - if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, sizeof(struct ft5x06_ts_platform_data), GFP_KERNEL); @@ -1871,7 +2061,8 @@ static int ft5x06_ts_probe(struct i2c_client *client, err = input_register_device(input_dev); if (err) { dev_err(&client->dev, "Input device registration failed\n"); - goto free_inputdev; + input_free_device(input_dev); + return err; } if (pdata->power_init) { @@ -1946,6 +2137,10 @@ static int ft5x06_ts_probe(struct i2c_client *client, err = request_threaded_irq(client->irq, NULL, ft5x06_ts_interrupt, + /* + * the interrupt trigger mode will be set in Device Tree with property + * "interrupts", so here we just need to set the flag IRQF_ONESHOT + */ IRQF_ONESHOT, client->dev.driver->name, data); if (err) { @@ -1953,54 +2148,55 @@ static int ft5x06_ts_probe(struct i2c_client *client, goto free_gpio; } - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) { + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) { device_init_wakeup(&client->dev, 1); - psensor_pdata = devm_kzalloc(&client->dev, - sizeof(struct ft5x06_psensor_platform_data), + gesture_pdata = devm_kzalloc(&client->dev, + sizeof(struct ft5x06_gesture_platform_data), GFP_KERNEL); - if (!psensor_pdata) { + if (!gesture_pdata) { dev_err(&client->dev, "Failed to allocate memory\n"); - goto irq_free; + goto free_gesture_dev; } - data->psensor_pdata = psensor_pdata; - - psensor_input_dev = input_allocate_device(); - if (!psensor_input_dev) { - dev_err(&data->client->dev, - "Failed to allocate device\n"); - goto free_psensor_pdata; + data->gesture_pdata = gesture_pdata; + gesture_pdata->data = data; + + gesture_pdata->gesture_class = + class_create(THIS_MODULE, "gesture"); + if (IS_ERR(gesture_pdata->gesture_class)) { + err = PTR_ERR(gesture_pdata->gesture_class); + dev_err(&client->dev, "Failed to create class.\n"); + goto free_gesture_pdata; } - __set_bit(EV_ABS, psensor_input_dev->evbit); - input_set_abs_params(psensor_input_dev, - ABS_DISTANCE, 0, 1, 0, 0); - psensor_input_dev->name = "proximity"; - psensor_input_dev->id.bustype = BUS_I2C; - psensor_input_dev->dev.parent = &data->client->dev; - data->psensor_pdata->input_psensor_dev = psensor_input_dev; + gesture_pdata->dev = device_create(gesture_pdata->gesture_class, + NULL, 0, NULL, "gesture_ft5x06"); + if (IS_ERR(gesture_pdata->dev)) { + err = PTR_ERR(gesture_pdata->dev); + dev_err(&client->dev, "Failed to create device.\n"); + goto free_gesture_class; + } - err = input_register_device(psensor_input_dev); + dev_set_drvdata(gesture_pdata->dev, data); + err = device_create_file(gesture_pdata->dev, + &dev_attr_enable); if (err) { - dev_err(&data->client->dev, - "Unable to register device, err=%d\n", err); - goto free_psensor_input_dev; + dev_err(gesture_pdata->dev, + "sys file creation failed\n"); + goto free_gesture_dev; + } + err = device_create_file(gesture_pdata->dev, + &dev_attr_pocket); + if (err) { + dev_err(gesture_pdata->dev, + "sys file creation failed\n"); + goto free_enable_sys; } - - psensor_pdata->ps_cdev = sensors_proximity_cdev; - psensor_pdata->ps_cdev.sensors_enable = - ft5x06_psensor_enable_set; - psensor_pdata->data = data; - - err = sensors_classdev_register(&client->dev, - &psensor_pdata->ps_cdev); - if (err) - goto unregister_psensor_input_device; } err = device_create_file(&client->dev, &dev_attr_fw_name); if (err) { dev_err(&client->dev, "sys file creation failed\n"); - goto free_psensor_class_sysfs; + goto free_pocket_sys; } err = device_create_file(&client->dev, &dev_attr_update_fw); @@ -2074,6 +2270,20 @@ static int ft5x06_ts_probe(struct i2c_client *client, dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4); + /*creation touch panel info kobj*/ + data->ts_info_kobj = *(kobject_create_and_add(FT_SYSFS_TS_INFO, + kernel_kobj)); + if (!&(data->ts_info_kobj)) { + dev_err(&client->dev, "kob creation failed .\n"); + } else { + err = sysfs_create_file(&(data->ts_info_kobj), + &ts_info_attribute.attr); + if (err) { + kobject_put(&(data->ts_info_kobj)); + dev_err(&client->dev, "sysfs create fail .\n"); + } + } + ft5x06_update_fw_ver(data); ft5x06_update_fw_vendor_id(data); @@ -2084,6 +2294,7 @@ static int ft5x06_ts_probe(struct i2c_client *client, data->fw_ver[1], data->fw_ver[2]); #if defined(CONFIG_FB) + INIT_WORK(&data->fb_notify_work, fb_notify_resume_work); data->fb_notif.notifier_call = fb_notifier_callback; err = fb_register_client(&data->fb_notif); @@ -2098,7 +2309,6 @@ static int ft5x06_ts_probe(struct i2c_client *client, data->early_suspend.resume = ft5x06_ts_late_resume; register_early_suspend(&data->early_suspend); #endif - return 0; free_debug_dir: @@ -2109,24 +2319,24 @@ free_update_fw_sys: device_remove_file(&client->dev, &dev_attr_update_fw); free_fw_name_sys: device_remove_file(&client->dev, &dev_attr_fw_name); -free_psensor_class_sysfs: - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) - sensors_classdev_unregister(&psensor_pdata->ps_cdev); -unregister_psensor_input_device: - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) - input_unregister_device(data->psensor_pdata->input_psensor_dev); -free_psensor_input_dev: - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) - input_free_device(data->psensor_pdata->input_psensor_dev); -free_psensor_pdata: - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) { - devm_kfree(&client->dev, psensor_pdata); - data->psensor_pdata = NULL; - } -irq_free: - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) - device_init_wakeup(&client->dev, 0); - free_irq(client->irq, data); +free_pocket_sys: + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) + device_remove_file(&client->dev, &dev_attr_pocket); +free_enable_sys: + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) + device_remove_file(&client->dev, &dev_attr_enable); +free_gesture_dev: + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) + device_destroy(gesture_pdata->gesture_class, 0); +free_gesture_class: + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) + class_destroy(gesture_pdata->gesture_class); +free_gesture_pdata: + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) { + devm_kfree(&client->dev, gesture_pdata); + data->gesture_pdata = NULL; + } + free_gpio: if (gpio_is_valid(pdata->reset_gpio)) gpio_free(pdata->reset_gpio); @@ -2155,9 +2365,6 @@ pwr_deinit: ft5x06_power_init(data, false); unreg_inputdev: input_unregister_device(input_dev); -free_inputdev: - input_free_device(input_dev); - input_dev = NULL; return err; } @@ -2166,14 +2373,14 @@ static int ft5x06_ts_remove(struct i2c_client *client) struct ft5x06_ts_data *data = i2c_get_clientdata(client); int retval; - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support) { - + if (ft5x06_gesture_support_enabled() && data->pdata->gesture_support) { device_init_wakeup(&client->dev, 0); - sensors_classdev_unregister(&data->psensor_pdata->ps_cdev); - input_unregister_device(data->psensor_pdata->input_psensor_dev); - input_free_device(data->psensor_pdata->input_psensor_dev); - devm_kfree(&client->dev, data->psensor_pdata); - data->psensor_pdata = NULL; + device_remove_file(&client->dev, &dev_attr_pocket); + device_remove_file(&client->dev, &dev_attr_enable); + device_destroy(data->gesture_pdata->gesture_class, 0); + class_destroy(data->gesture_pdata->gesture_class); + devm_kfree(&client->dev, data->gesture_pdata); + data->gesture_pdata = NULL; } debugfs_remove_recursive(data->dir); @@ -2218,7 +2425,7 @@ static int ft5x06_ts_remove(struct i2c_client *client) ft5x06_power_init(data, false); input_unregister_device(data->input_dev); - + kobject_put(&(data->ts_info_kobj)); return 0; } diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c index a0303ec3c26e..eb4947536230 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c @@ -610,23 +610,23 @@ static struct synaptics_rmi4_exp_fn_data exp_data; static struct synaptics_dsx_button_map *vir_button_map; static struct device_attribute attrs[] = { - __ATTR(reset, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(reset, S_IWUSR | S_IWGRP, + NULL, synaptics_rmi4_f01_reset_store), __ATTR(productinfo, S_IRUGO, synaptics_rmi4_f01_productinfo_show, - synaptics_rmi4_store_error), + NULL), __ATTR(buildid, S_IRUGO, synaptics_rmi4_f01_buildid_show, - synaptics_rmi4_store_error), + NULL), __ATTR(flashprog, S_IRUGO, synaptics_rmi4_f01_flashprog_show, - synaptics_rmi4_store_error), + NULL), __ATTR(0dbutton, (S_IRUGO | S_IWUSR | S_IWGRP), synaptics_rmi4_0dbutton_show, synaptics_rmi4_0dbutton_store), - __ATTR(suspend, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(suspend, S_IWUSR | S_IWGRP, + NULL, synaptics_rmi4_suspend_store), __ATTR(wake_gesture, (S_IRUGO | S_IWUSR | S_IWGRP), synaptics_rmi4_wake_gesture_show, diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h index b860a553b334..6fa392473885 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h @@ -464,22 +464,6 @@ static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data) } #endif -static inline ssize_t synaptics_rmi4_show_error(struct device *dev, - struct device_attribute *attr, char *buf) -{ - dev_warn(dev, "%s Attempted to read from write-only attribute %s\n", - __func__, attr->attr.name); - return -EPERM; -} - -static inline ssize_t synaptics_rmi4_store_error(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - dev_warn(dev, "%s Attempted to write to read-only attribute %s\n", - __func__, attr->attr.name); - return -EPERM; -} - static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size, const unsigned char *src, unsigned int src_size, unsigned int count) diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c index 34201f3957c3..52bd5cfc37c8 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c @@ -661,50 +661,50 @@ static struct bin_attribute dev_attr_data = { }; static struct device_attribute attrs[] = { - __ATTR(dorecovery, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(dorecovery, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_do_recovery_store), - __ATTR(doreflash, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(doreflash, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_do_reflash_store), - __ATTR(writeconfig, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(writeconfig, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_write_config_store), - __ATTR(readconfig, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(readconfig, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_read_config_store), - __ATTR(configarea, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(configarea, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_config_area_store), - __ATTR(imagename, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(imagename, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_image_name_store), - __ATTR(imagesize, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(imagesize, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_image_size_store), __ATTR(blocksize, S_IRUGO, fwu_sysfs_block_size_show, - synaptics_rmi4_store_error), + NULL), __ATTR(fwblockcount, S_IRUGO, fwu_sysfs_firmware_block_count_show, - synaptics_rmi4_store_error), + NULL), __ATTR(configblockcount, S_IRUGO, fwu_sysfs_configuration_block_count_show, - synaptics_rmi4_store_error), + NULL), __ATTR(dispconfigblockcount, S_IRUGO, fwu_sysfs_disp_config_block_count_show, - synaptics_rmi4_store_error), + NULL), __ATTR(permconfigblockcount, S_IRUGO, fwu_sysfs_perm_config_block_count_show, - synaptics_rmi4_store_error), + NULL), __ATTR(blconfigblockcount, S_IRUGO, fwu_sysfs_bl_config_block_count_show, - synaptics_rmi4_store_error), + NULL), __ATTR(guestcodeblockcount, S_IRUGO, fwu_sysfs_guest_code_block_count_show, - synaptics_rmi4_store_error), - __ATTR(writeguestcode, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + NULL), + __ATTR(writeguestcode, S_IWUSR | S_IWGRP, + NULL, fwu_sysfs_write_guest_code_store), }; diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c index dcada834c6cb..de8656389cad 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c @@ -389,47 +389,47 @@ struct synaptics_rmi4_udg_handle { static struct device_attribute attrs[] = { __ATTR(engine_enable, S_IWUGO, - synaptics_rmi4_show_error, + NULL, udg_sysfs_engine_enable_store), __ATTR(detection_enable, S_IWUGO, - synaptics_rmi4_show_error, + NULL, udg_sysfs_detection_enable_store), __ATTR(detection_score, S_IRUGO, udg_sysfs_detection_score_show, - synaptics_rmi4_store_error), + NULL), __ATTR(detection_index, S_IRUGO, udg_sysfs_detection_index_show, - synaptics_rmi4_store_error), + NULL), __ATTR(registration_enable, S_IWUGO, - synaptics_rmi4_show_error, + NULL, udg_sysfs_registration_enable_store), __ATTR(registration_begin, S_IWUGO, - synaptics_rmi4_show_error, + NULL, udg_sysfs_registration_begin_store), __ATTR(registration_status, S_IRUGO, udg_sysfs_registration_status_show, - synaptics_rmi4_store_error), + NULL), __ATTR(template_size, S_IRUGO, udg_sysfs_template_size_show, - synaptics_rmi4_store_error), + NULL), __ATTR(template_max_index, S_IRUGO, udg_sysfs_template_max_index_show, - synaptics_rmi4_store_error), + NULL), __ATTR(template_detection, S_IRUGO, udg_sysfs_template_detection_show, - synaptics_rmi4_store_error), + NULL), __ATTR(template_index, S_IWUGO, - synaptics_rmi4_show_error, + NULL, udg_sysfs_template_index_store), __ATTR(template_valid, (S_IRUGO | S_IWUGO), udg_sysfs_template_valid_show, udg_sysfs_template_valid_store), __ATTR(template_clear, S_IWUGO, - synaptics_rmi4_show_error, + NULL, udg_sysfs_template_clear_store), __ATTR(trace_size, S_IRUGO, udg_sysfs_trace_size_show, - synaptics_rmi4_store_error), + NULL), }; static struct bin_attribute template_data = { diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c index 582e43666b17..111b26c7b759 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c @@ -126,20 +126,20 @@ static struct bin_attribute attr_data = { }; static struct device_attribute attrs[] = { - __ATTR(open, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(open, S_IWUSR | S_IWGRP, + NULL, rmidev_sysfs_open_store), - __ATTR(release, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(release, S_IWUSR | S_IWGRP, + NULL, rmidev_sysfs_release_store), __ATTR(attn_state, S_IRUGO, rmidev_sysfs_attn_state_show, - synaptics_rmi4_store_error), + NULL), __ATTR(pid, S_IRUGO | S_IRUGO | S_IWUSR | S_IWGRP, rmidev_sysfs_pid_show, rmidev_sysfs_pid_store), - __ATTR(term, S_IRUGO | S_IWUSR | S_IWGRP, - synaptics_rmi4_show_error, + __ATTR(term, S_IWUSR | S_IWGRP, + NULL, rmidev_sysfs_term_store), __ATTR(intr_mask, S_IRUGO, rmidev_sysfs_intr_mask_show, diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c index a401457c3e4a..d42b23e46d0a 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c @@ -198,23 +198,13 @@ static ssize_t concat(test_sysfs, _##propname##_show)(\ struct device *dev,\ struct device_attribute *attr,\ - char *buf);\ -\ -static struct device_attribute dev_attr_##propname =\ - __ATTR(propname, S_IRUGO,\ - concat(test_sysfs, _##propname##_show),\ - synaptics_rmi4_store_error); + char *buf); #define store_prototype(propname)\ static ssize_t concat(test_sysfs, _##propname##_store)(\ struct device *dev,\ struct device_attribute *attr,\ - const char *buf, size_t count);\ -\ -static struct device_attribute dev_attr_##propname =\ - __ATTR(propname, S_IWUGO,\ - synaptics_rmi4_show_error,\ - concat(test_sysfs, _##propname##_store)); + const char *buf, size_t count); #define show_store_prototype(propname)\ static ssize_t concat(test_sysfs, _##propname##_show)(\ diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c index 0916529e64e4..847dc4dd3049 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c @@ -113,10 +113,10 @@ static struct dcs_command resume_sequence[] = { static struct device_attribute attrs[] = { __ATTR(dcs_write, S_IWUGO, - synaptics_rmi4_show_error, + NULL, video_sysfs_dcs_write_store), __ATTR(param, S_IWUGO, - synaptics_rmi4_show_error, + NULL, video_sysfs_param_store), }; diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 7b3845aa5983..9bbadaaf6bc3 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -370,8 +370,8 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload) point.coord_x = point.coord_y = 0; } - point.state = payload[9 * i + 5] & 0x0f; - point.id = (payload[9 * i + 5] & 0xf0) >> 4; + point.state = payload[9 * i + 5] & 0x03; + point.id = (payload[9 * i + 5] & 0xfc) >> 2; /* determine touch major, minor and orientation */ point.area_major = max(payload[9 * i + 6], diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index b9319b76a8a1..fc836f523afa 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -91,7 +91,6 @@ struct iommu_dev_data { struct list_head dev_data_list; /* For global dev_data_list */ struct protection_domain *domain; /* Domain the device is bound to */ u16 devid; /* PCI Device ID */ - u16 alias; /* Alias Device ID */ bool iommu_v2; /* Device can make use of IOMMUv2 */ bool passthrough; /* Device is identity mapped */ struct { @@ -126,13 +125,6 @@ static struct protection_domain *to_pdomain(struct iommu_domain *dom) return container_of(dom, struct protection_domain, domain); } -static inline u16 get_device_id(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - - return PCI_DEVID(pdev->bus->number, pdev->devfn); -} - static struct iommu_dev_data *alloc_dev_data(u16 devid) { struct iommu_dev_data *dev_data; @@ -170,68 +162,6 @@ out_unlock: return dev_data; } -static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) -{ - *(u16 *)data = alias; - return 0; -} - -static u16 get_alias(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - u16 devid, ivrs_alias, pci_alias; - - devid = get_device_id(dev); - ivrs_alias = amd_iommu_alias_table[devid]; - pci_for_each_dma_alias(pdev, __last_alias, &pci_alias); - - if (ivrs_alias == pci_alias) - return ivrs_alias; - - /* - * DMA alias showdown - * - * The IVRS is fairly reliable in telling us about aliases, but it - * can't know about every screwy device. If we don't have an IVRS - * reported alias, use the PCI reported alias. In that case we may - * still need to initialize the rlookup and dev_table entries if the - * alias is to a non-existent device. - */ - if (ivrs_alias == devid) { - if (!amd_iommu_rlookup_table[pci_alias]) { - amd_iommu_rlookup_table[pci_alias] = - amd_iommu_rlookup_table[devid]; - memcpy(amd_iommu_dev_table[pci_alias].data, - amd_iommu_dev_table[devid].data, - sizeof(amd_iommu_dev_table[pci_alias].data)); - } - - return pci_alias; - } - - pr_info("AMD-Vi: Using IVRS reported alias %02x:%02x.%d " - "for device %s[%04x:%04x], kernel reported alias " - "%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias), - PCI_FUNC(ivrs_alias), dev_name(dev), pdev->vendor, pdev->device, - PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias), - PCI_FUNC(pci_alias)); - - /* - * If we don't have a PCI DMA alias and the IVRS alias is on the same - * bus, then the IVRS table may know about a quirk that we don't. - */ - if (pci_alias == devid && - PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) { - pdev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; - pdev->dma_alias_devfn = ivrs_alias & 0xff; - pr_info("AMD-Vi: Added PCI DMA alias %02x.%d for %s\n", - PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias), - dev_name(dev)); - } - - return ivrs_alias; -} - static struct iommu_dev_data *find_dev_data(u16 devid) { struct iommu_dev_data *dev_data; @@ -244,6 +174,13 @@ static struct iommu_dev_data *find_dev_data(u16 devid) return dev_data; } +static inline u16 get_device_id(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return PCI_DEVID(pdev->bus->number, pdev->devfn); +} + static struct iommu_dev_data *get_dev_data(struct device *dev) { return dev->archdata.iommu; @@ -371,8 +308,6 @@ static int iommu_init_device(struct device *dev) if (!dev_data) return -ENOMEM; - dev_data->alias = get_alias(dev); - if (pci_iommuv2_capable(pdev)) { struct amd_iommu *iommu; @@ -393,7 +328,7 @@ static void iommu_ignore_device(struct device *dev) u16 devid, alias; devid = get_device_id(dev); - alias = get_alias(dev); + alias = amd_iommu_alias_table[devid]; memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry)); memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry)); @@ -1082,7 +1017,7 @@ static int device_flush_dte(struct iommu_dev_data *dev_data) int ret; iommu = amd_iommu_rlookup_table[dev_data->devid]; - alias = dev_data->alias; + alias = amd_iommu_alias_table[dev_data->devid]; ret = iommu_flush_dte(iommu, dev_data->devid); if (!ret && alias != dev_data->devid) @@ -1956,7 +1891,7 @@ static void do_attach(struct iommu_dev_data *dev_data, bool ats; iommu = amd_iommu_rlookup_table[dev_data->devid]; - alias = dev_data->alias; + alias = amd_iommu_alias_table[dev_data->devid]; ats = dev_data->ats.enabled; /* Update data structures */ @@ -1990,7 +1925,7 @@ static void do_detach(struct iommu_dev_data *dev_data) return; iommu = amd_iommu_rlookup_table[dev_data->devid]; - alias = dev_data->alias; + alias = amd_iommu_alias_table[dev_data->devid]; /* decrease reference counters */ dev_data->domain->dev_iommu[iommu->index] -= 1; diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 58f2fe687a24..72d6182666cb 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -403,7 +403,7 @@ static int __finalise_sg(struct device *dev, struct scatterlist *sg, int nents, unsigned int s_length = sg_dma_len(s); unsigned int s_dma_len = s->length; - s->offset += s_offset; + s->offset = s_offset; s->length = s_length; sg_dma_address(s) = dma_addr + s_offset; dma_addr += s_dma_len; @@ -422,7 +422,7 @@ static void __invalidate_sg(struct scatterlist *sg, int nents) for_each_sg(sg, s, nents, i) { if (sg_dma_address(s) != DMA_ERROR_CODE) - s->offset += sg_dma_address(s); + s->offset = sg_dma_address(s); if (sg_dma_len(s)) s->length = sg_dma_len(s); sg_dma_address(s) = DMA_ERROR_CODE; diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 17304705f2cf..efe50845939d 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -183,7 +183,7 @@ static void __iomem * __init icoll_init_iobase(struct device_node *np) void __iomem *icoll_base; icoll_base = of_io_request_and_map(np, 0, np->name); - if (IS_ERR(icoll_base)) + if (!icoll_base) panic("%s: unable to map resource", np->full_name); return icoll_base; } diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 1254e98f6b57..4ef178078e5b 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -154,9 +154,9 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node, gc = irq_get_domain_generic_chip(domain, 0); gc->reg_base = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(gc->reg_base)) { + if (!gc->reg_base) { pr_err("unable to map resource\n"); - ret = PTR_ERR(gc->reg_base); + ret = -ENOMEM; goto fail_irqd_remove; } diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 3970cda10080..27f2ef300f8b 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -867,55 +867,39 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, return 0; } -static bool cmd_write_lock(struct dm_cache_metadata *cmd) -{ - down_write(&cmd->root_lock); - if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { - up_write(&cmd->root_lock); - return false; +#define WRITE_LOCK(cmd) \ + down_write(&cmd->root_lock); \ + if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ + up_write(&cmd->root_lock); \ + return -EINVAL; \ } - return true; -} - -#define WRITE_LOCK(cmd) \ - do { \ - if (!cmd_write_lock((cmd))) \ - return -EINVAL; \ - } while(0) -#define WRITE_LOCK_VOID(cmd) \ - do { \ - if (!cmd_write_lock((cmd))) \ - return; \ - } while(0) +#define WRITE_LOCK_VOID(cmd) \ + down_write(&cmd->root_lock); \ + if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ + up_write(&cmd->root_lock); \ + return; \ + } #define WRITE_UNLOCK(cmd) \ - up_write(&(cmd)->root_lock) + up_write(&cmd->root_lock) -static bool cmd_read_lock(struct dm_cache_metadata *cmd) -{ - down_read(&cmd->root_lock); - if (cmd->fail_io) { - up_read(&cmd->root_lock); - return false; +#define READ_LOCK(cmd) \ + down_read(&cmd->root_lock); \ + if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ + up_read(&cmd->root_lock); \ + return -EINVAL; \ } - return true; -} - -#define READ_LOCK(cmd) \ - do { \ - if (!cmd_read_lock((cmd))) \ - return -EINVAL; \ - } while(0) -#define READ_LOCK_VOID(cmd) \ - do { \ - if (!cmd_read_lock((cmd))) \ - return; \ - } while(0) +#define READ_LOCK_VOID(cmd) \ + down_read(&cmd->root_lock); \ + if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ + up_read(&cmd->root_lock); \ + return; \ + } #define READ_UNLOCK(cmd) \ - up_read(&(cmd)->root_lock) + up_read(&cmd->root_lock) int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) { diff --git a/drivers/md/md.c b/drivers/md/md.c index c57fdf847b47..b1e1f6b95782 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -293,8 +293,6 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio) * go away inside make_request */ sectors = bio_sectors(bio); - /* bio could be mergeable after passing to underlayer */ - bio->bi_rw &= ~REQ_NOMERGE; mddev->pers->make_request(mddev, bio); cpu = part_stat_lock(); diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig index 7f7cc8ee9be3..568f817e8614 100644 --- a/drivers/media/platform/msm/camera_v2/Kconfig +++ b/drivers/media/platform/msm/camera_v2/Kconfig @@ -1,5 +1,5 @@ config MSM_CAMERA_SENSOR - bool "Qualcomm MSM camera sensor support" + bool "QTI MSM camera sensor support" depends on MSMB_CAMERA select NEW_LEDS select LEDS_CLASS @@ -10,7 +10,7 @@ config MSM_CAMERA_SENSOR subdev APIs. config MSM_CPP - bool "Qualcomm MSM Camera Post Processing Engine support" + bool "QTI MSM Camera Post Processing Engine support" depends on MSMB_CAMERA ---help--- Enable support for Camera Post-processing Engine @@ -19,7 +19,7 @@ config MSM_CPP APIs. config MSM_CCI - bool "Qualcomm MSM Camera Control Interface support" + bool "QTI MSM Camera Control Interface support" depends on MSMB_CAMERA ---help--- Enable support for Camera Control Interface driver only @@ -29,7 +29,7 @@ config MSM_CCI GPIO and data frames. config MSM_CSI20_HEADER - bool "Qualcomm MSM CSI 2.0 Header" + bool "QTI MSM CSI 2.0 Header" depends on MSMB_CAMERA ---help--- Enable support for CSI drivers to include 2.0 @@ -39,7 +39,7 @@ config MSM_CSI20_HEADER 8930 and 8064 platforms. config MSM_CSI22_HEADER - bool "Qualcomm MSM CSI 2.2 Header" + bool "QTI MSM CSI 2.2 Header" depends on MSMB_CAMERA ---help--- Enable support for CSI drivers to include 2.2 @@ -49,7 +49,7 @@ config MSM_CSI22_HEADER platform. config MSM_CSI30_HEADER - bool "Qualcomm MSM CSI 3.0 Header" + bool "QTI MSM CSI 3.0 Header" depends on MSMB_CAMERA ---help--- Enable support for CSI drivers to include 3.0 @@ -59,7 +59,7 @@ config MSM_CSI30_HEADER 8064 platforms. config MSM_CSI31_HEADER - bool "Qualcomm MSM CSI 3.1 Header" + bool "QTI MSM CSI 3.1 Header" depends on MSMB_CAMERA ---help--- Enable support for CSI drivers to include 3.0 @@ -69,7 +69,7 @@ config MSM_CSI31_HEADER APQ8084 platform. config MSM_CSIPHY - bool "Qualcomm MSM Camera Serial Interface Physical receiver support" + bool "QTI MSM Camera Serial Interface Physical receiver support" depends on MSMB_CAMERA ---help--- Enable support for Camera Serial Interface @@ -78,7 +78,7 @@ config MSM_CSIPHY signalling. config MSM_CSID - bool "Qualcomm MSM Camera Serial Interface decoder support" + bool "QTI MSM Camera Serial Interface decoder support" depends on MSMB_CAMERA ---help--- Enable support for Camera Serial Interface decoder. @@ -87,7 +87,7 @@ config MSM_CSID and datatype. config MSM_EEPROM - bool "Qualcomm MSM Camera ROM Interface for Calibration support" + bool "QTI MSM Camera ROM Interface for Calibration support" depends on MSMB_CAMERA ---help--- Enable support for ROM Interface for Calibration @@ -96,7 +96,7 @@ config MSM_EEPROM Currently supports I2C, CCI and SPI protocol config MSM_ISPIF - bool "Qualcomm MSM Image Signal Processing interface support" + bool "QTI MSM Image Signal Processing interface support" depends on MSMB_CAMERA ---help--- Enable support for Image Signal Processing interface module. @@ -105,7 +105,7 @@ config MSM_ISPIF data interface in VFE. config MSM_ISPIF_V1 - bool "Qualcomm MSM Image Signal Processing interface support" + bool "QTI MSM Image Signal Processing interface support" depends on MSMB_CAMERA ---help--- Enable support for Image Signal Processing interface module. @@ -114,7 +114,7 @@ config MSM_ISPIF_V1 or raw data interface in VFE. config MSM_ISPIF_V2 - bool "Qualcomm MSM Image Signal Processing interface support" + bool "QTI MSM Image Signal Processing interface support" depends on MSMB_CAMERA ---help--- Enable support for Image Signal Processing interface module. @@ -204,7 +204,7 @@ config OV12830 2 lanes max fps is 18, 4 lanes max fps is 24. config MSM_V4L2_VIDEO_OVERLAY_DEVICE - tristate "Qualcomm MSM V4l2 video overlay device" + tristate "QTI MSM V4l2 video overlay device" ---help--- Enables support for the MSM V4L2 video overlay driver. This allows video rendering @@ -212,7 +212,7 @@ config MSM_V4L2_VIDEO_OVERLAY_DEVICE APIs, by using /dev/videoX device config MSMB_JPEG - tristate "Qualcomm MSM Jpeg Encoder Engine support" + tristate "QTI MSM Jpeg Encoder Engine support" depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226 || ARCH_APQ8084 || ARCH_MSM8916 || ARCH_QCOM) ---help--- Enable support for Jpeg Encoder/Decoder @@ -221,7 +221,7 @@ config MSMB_JPEG for the JPEG 1.0 encoder and decoder. config MSM_GEMINI - tristate "Qualcomm MSM Gemini JPEG engine support" + tristate "QTI MSM Gemini JPEG engine support" depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960) ---help--- Enables support for the Gemini JPEG encoder @@ -230,14 +230,26 @@ config MSM_GEMINI for JPEG encoding functionality. config MSM_FD - tristate "Qualcomm MSM FD face detection engine support" + tristate "QTI MSM FD face detection engine support" depends on MSMB_CAMERA ---help--- Enables support for the MSM FD face detection engine. config MSM_JPEGDMA - tristate "Qualcomm Technologies Inc. MSM Jpeg dma" + tristate "QTI MSM Jpeg dma" depends on MSMB_CAMERA select V4L2_MEM2MEM_DEV ---help--- Enable support for Jpeg dma engine. + +config MSM_SEC_CCI_TA_NAME + string "Name of TA to handle Secure CCI transactions" + depends on MSM_CCI + default "seccamdemo64" + +config MSM_SEC_CCI_DEBUG + bool "QTI MSM Secure CCI Relay Debug" + depends on MSM_CCI + ---help--- + Enables simulation of secure camera for Secure CCI Realy + debugging. diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index d3f6fa3fa52d..4200215705d0 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -463,7 +463,8 @@ static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr, static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, - uint32_t bufq_handle, struct msm_isp_buffer **buf_info) + uint32_t bufq_handle, uint32_t buf_index, + struct msm_isp_buffer **buf_info) { int rc = -1; unsigned long flags; @@ -513,8 +514,12 @@ static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, } break; case MSM_ISP_BUFFER_SRC_HAL: - vb2_v4l2_buf = buf_mgr->vb2_ops->get_buf( - bufq->session_id, bufq->stream_id); + if (buf_index == MSM_ISP_INVALID_BUF_INDEX) + vb2_v4l2_buf = buf_mgr->vb2_ops->get_buf( + bufq->session_id, bufq->stream_id); + else + vb2_v4l2_buf = buf_mgr->vb2_ops->get_buf_by_idx( + bufq->session_id, bufq->stream_id, buf_index); if (vb2_v4l2_buf) { if (vb2_v4l2_buf->vb2_buf.index < bufq->num_bufs) { *buf_info = &bufq->bufs[vb2_v4l2_buf @@ -649,95 +654,35 @@ static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr, return rc; } -static int msm_isp_update_put_buf_cnt_unsafe( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit) +static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id) { - int rc = -1; + unsigned long flags; struct msm_isp_bufq *bufq = NULL; struct msm_isp_buffer *buf_info = NULL; - uint8_t *put_buf_mask = NULL; bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); if (!bufq) { pr_err("Invalid bufq\n"); - return rc; - } - - put_buf_mask = &bufq->put_buf_mask[pingpong_bit]; - - if (buf_index >= 0) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EFAULT; - } - if (buf_info->state != MSM_ISP_BUFFER_STATE_DEQUEUED) { - pr_err( - "%s: Invalid state, bufq_handle %x stream id %x, state %d\n", - __func__, bufq_handle, - bufq->stream_id, buf_info->state); - return -EFAULT; - } - if (buf_info->pingpong_bit != pingpong_bit) { - pr_err("%s: Pingpong bit mismatch\n", __func__); - return -EFAULT; - } - } - - if (bufq->buf_type != ISP_SHARE_BUF || - (*put_buf_mask == 0)) { - if (buf_info) - buf_info->frame_id = frame_id; - } - - if (bufq->buf_type == ISP_SHARE_BUF && - ((*put_buf_mask & (1 << id)) == 0)) { - *put_buf_mask |= (1 << id); - if (*put_buf_mask != ISP_SHARE_BUF_MASK) { - rc = *put_buf_mask; - return 1; - } - *put_buf_mask = 0; - rc = 0; - } else if (bufq->buf_type == ISP_SHARE_BUF && - (*put_buf_mask & (1 << id)) != 0) { - return -ENOTEMPTY; + return -EINVAL; } - if (buf_info && - MSM_ISP_BUFFER_SRC_NATIVE == BUF_SRC(bufq->stream_id)) { - buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; - buf_info->tv = tv; - } - return 0; -} - -static int msm_isp_update_put_buf_cnt(struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit) -{ - int rc = -1; - struct msm_isp_bufq *bufq = NULL; - unsigned long flags; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return -EINVAL; } spin_lock_irqsave(&bufq->bufq_lock, flags); - rc = msm_isp_update_put_buf_cnt_unsafe(buf_mgr, id, bufq_handle, - buf_index, tv, frame_id, pingpong_bit); - if (-ENOTEMPTY == rc) { - pr_err("%s: Error! Uncleared put_buf_mask for pingpong(%d) from vfe %d bufq 0x%x buf_idx %d\n", - __func__, pingpong_bit, id, bufq_handle, buf_index); - rc = -EFAULT; + + buf_info->frame_id = frame_id; + if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_NATIVE) { + buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; + buf_info->tv = tv; } spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; + return 0; } static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr, @@ -795,11 +740,11 @@ done: return rc; } -static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, +static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type, struct timeval *tv, uint32_t frame_id) { - int rc = 0, i; + int i; struct msm_isp_bufq *bufq = NULL; struct msm_isp_buffer *buf_info = NULL; unsigned long flags; @@ -817,43 +762,27 @@ static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, pr_err("%s: buf not found\n", __func__); continue; } - if (flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED && - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { + switch (flush_type) { + case MSM_ISP_BUFFER_FLUSH_DIVERTED: + if (buf_info->state != + MSM_ISP_BUFFER_STATE_DIVERTED) + continue; buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; msm_isp_put_buf_unsafe(buf_mgr, - bufq_handle, buf_info->buf_idx); - } else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL) { - if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - CDBG("%s: no need to queue Diverted buffer\n", - __func__); - } else if (buf_info->state == - MSM_ISP_BUFFER_STATE_DEQUEUED) { - rc = msm_isp_update_put_buf_cnt_unsafe(buf_mgr, - id, bufq_handle, buf_info->buf_idx, tv, - frame_id, buf_info->pingpong_bit); - if (-ENOTEMPTY == rc) { - rc = 0; - continue; - } - - if (rc == 0) { - buf_info->buf_debug.put_state[ - buf_info->buf_debug. - put_state_last] - = MSM_ISP_BUFFER_STATE_FLUSH; - buf_info->buf_debug.put_state_last ^= 1; - buf_info->state = - MSM_ISP_BUFFER_STATE_PREPARED; - rc = msm_isp_put_buf_unsafe(buf_mgr, - bufq_handle, buf_info->buf_idx); - if (rc == -EFAULT) { - spin_unlock_irqrestore( - &bufq->bufq_lock, - flags); - return rc; - } - } - } + bufq_handle, buf_info->buf_idx); + break; + case MSM_ISP_BUFFER_FLUSH_ALL: + if (buf_info->state == + MSM_ISP_BUFFER_STATE_DIVERTED) + continue; + if (buf_info->state != + MSM_ISP_BUFFER_STATE_DEQUEUED) + continue; + msm_isp_put_buf_unsafe(buf_mgr, + bufq_handle, buf_info->buf_idx); + break; + default: + WARN(1, "Invalid flush type %d\n", flush_type); } } @@ -1031,8 +960,6 @@ static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr, bufq->stream_id = buf_request->stream_id; bufq->num_bufs = buf_request->num_buf; bufq->buf_type = buf_request->buf_type; - for (i = 0; i < ISP_NUM_BUF_MASK; i++) - bufq->put_buf_mask[i] = 0; INIT_LIST_HEAD(&bufq->head); for (i = 0; i < buf_request->num_buf; i++) { @@ -1448,7 +1375,7 @@ static struct msm_isp_buf_ops isp_buf_ops = { .buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr, .buf_mgr_debug = msm_isp_buf_mgr_debug, .get_bufq = msm_isp_get_bufq, - .update_put_buf_cnt = msm_isp_update_put_buf_cnt, + .buf_divert = msm_isp_buf_divert, }; int msm_isp_create_isp_buf_mgr( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h index b22fb6a43145..43519ee74062 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.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 @@ -32,6 +32,8 @@ #define BUF_MGR_NUM_BUF_Q 28 #define MAX_IOMMU_CTX 2 +#define MSM_ISP_INVALID_BUF_INDEX 0xFFFFFFFF + struct msm_isp_buf_mgr; enum msm_isp_buffer_src_t { @@ -115,7 +117,6 @@ struct msm_isp_bufq { enum msm_isp_buf_type buf_type; struct msm_isp_buffer *bufs; spinlock_t bufq_lock; - uint8_t put_buf_mask[ISP_NUM_BUF_MASK]; /*Native buffer queue*/ struct list_head head; }; @@ -140,7 +141,8 @@ struct msm_isp_buf_ops { uint32_t bufq_handle, uint32_t *buf_src); int (*get_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, - uint32_t bufq_handle, struct msm_isp_buffer **buf_info); + uint32_t bufq_handle, uint32_t buf_index, + struct msm_isp_buffer **buf_info); int (*get_buf_by_index)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, uint32_t buf_index, @@ -154,7 +156,7 @@ struct msm_isp_buf_ops { int (*put_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, uint32_t buf_index); - int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, + int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type, struct timeval *tv, uint32_t frame_id); @@ -171,9 +173,9 @@ struct msm_isp_buf_ops { unsigned long fault_addr); struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle); - int (*update_put_buf_cnt)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit); + int (*buf_divert)(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id); }; struct msm_isp_buf_mgr { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index d3c2d77b0107..094996b2d60b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -498,7 +498,12 @@ static int vfe_probe(struct platform_device *pdev) vfe_parent_dev->common_sd->common_data = &vfe_common_data; memset(&vfe_common_data, 0, sizeof(vfe_common_data)); + mutex_init(&vfe_common_data.vfe_common_mutex); spin_lock_init(&vfe_common_data.common_dev_data_lock); + for (i = 0; i < (VFE_AXI_SRC_MAX * MAX_VFE); i++) + spin_lock_init(&(vfe_common_data.streams[i].lock)); + for (i = 0; i < (MSM_ISP_STATS_MAX * MAX_VFE); i++) + spin_lock_init(&(vfe_common_data.stats_streams[i].lock)); of_property_read_u32(pdev->dev.of_node, "num_child", &vfe_parent_dev->num_hw_sd); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 763b6a575326..3b6a2eecb4b6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -169,7 +169,7 @@ struct msm_vfe_axi_ops { int32_t (*cfg_io_format)(struct vfe_device *vfe_dev, enum msm_vfe_axi_stream_src stream_src, uint32_t io_format); - void (*cfg_framedrop)(void __iomem *vfe_base, + void (*cfg_framedrop)(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period); void (*clear_framedrop)(struct vfe_device *vfe_dev, @@ -207,7 +207,7 @@ struct msm_vfe_axi_ops { uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1); uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev); int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking); - int (*restart)(struct vfe_device *vfe_dev, uint32_t blocking, + void (*restart)(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif); void (*update_cgc_override)(struct vfe_device *vfe_dev, uint8_t wm_idx, uint8_t cgc_override); @@ -270,7 +270,7 @@ struct msm_vfe_stats_ops { void (*enable_module)(struct vfe_device *vfe_dev, uint32_t stats_mask, uint8_t enable); - void (*update_ping_pong_addr)(void __iomem *vfe_base, + void (*update_ping_pong_addr)(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr); @@ -373,12 +373,6 @@ enum msm_vfe_axi_state { UPDATING, }; -enum msm_vfe_axi_cfg_update_state { - NO_AXI_CFG_UPDATE, - APPLYING_UPDATE_RESUME, - UPDATE_REQUESTED, -}; - #define VFE_NO_DROP 0xFFFFFFFF #define VFE_DROP_EVERY_2FRAME 0x55555555 #define VFE_DROP_EVERY_4FRAME 0x11111111 @@ -394,9 +388,18 @@ enum msm_vfe_axi_stream_type { struct msm_vfe_frame_request_queue { struct list_head list; enum msm_vfe_buff_queue_id buff_queue_id; + uint32_t buf_index; uint8_t cmd_used; }; +enum msm_isp_comp_irq_types { + MSM_ISP_COMP_IRQ_REG_UPD = 0, + MSM_ISP_COMP_IRQ_EPOCH = 1, + MSM_ISP_COMP_IRQ_PING_BUFDONE = 2, + MSM_ISP_COMP_IRQ_PONG_BUFDONE = 3, + MSM_ISP_COMP_IRQ_MAX = 4 +}; + #define MSM_VFE_REQUESTQ_SIZE 8 struct msm_vfe_axi_stream { @@ -404,10 +407,10 @@ struct msm_vfe_axi_stream { enum msm_vfe_axi_state state; enum msm_vfe_axi_stream_src stream_src; uint8_t num_planes; - uint8_t wm[MAX_PLANES_PER_STREAM]; + uint8_t wm[MAX_VFE][MAX_PLANES_PER_STREAM]; uint32_t output_format;/*Planar/RAW/Misc*/ - struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; - uint8_t comp_mask_index; + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_VFE][MAX_PLANES_PER_STREAM]; + uint8_t comp_mask_index[MAX_VFE]; struct msm_isp_buffer *buf[2]; uint32_t session_id; uint32_t stream_id; @@ -419,7 +422,7 @@ struct msm_vfe_axi_stream { struct list_head request_q; struct msm_vfe_frame_request_queue request_queue_cmd[MSM_VFE_REQUESTQ_SIZE]; - uint32_t stream_handle; + uint32_t stream_handle[MAX_VFE]; uint8_t buf_divert; enum msm_vfe_axi_stream_type stream_type; uint32_t frame_based; @@ -432,16 +435,28 @@ struct msm_vfe_axi_stream { spinlock_t lock; /*Bandwidth calculation info*/ - uint32_t max_width; + uint32_t max_width[MAX_VFE]; /*Based on format plane size in Q2. e.g NV12 = 1.5*/ uint32_t format_factor; - uint32_t bandwidth; + uint32_t bandwidth[MAX_VFE]; uint32_t runtime_num_burst_capture; uint32_t runtime_output_format; enum msm_stream_memory_input_t memory_input; struct msm_isp_sw_framskip sw_skip; uint8_t sw_ping_pong_bit; + + struct vfe_device *vfe_dev[MAX_VFE]; + int num_isp; + struct completion active_comp; + struct completion inactive_comp; + uint32_t update_vfe_mask; + /* + * bits in this mask are set that correspond to vfe_id of + * the vfe on which this stream operates + */ + uint32_t vfe_mask; + uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; }; struct msm_vfe_axi_composite_info { @@ -450,17 +465,15 @@ struct msm_vfe_axi_composite_info { }; enum msm_vfe_camif_state { - CAMIF_STOPPED, CAMIF_ENABLE, CAMIF_DISABLE, - CAMIF_STOPPING, }; struct msm_vfe_src_info { uint32_t frame_id; uint32_t reg_update_frame_id; uint8_t active; - uint8_t pix_stream_count; + uint8_t stream_count; uint8_t raw_stream_count; enum msm_vfe_inputmux input_mux; uint32_t width; @@ -491,7 +504,6 @@ enum msm_wm_ub_cfg_type { struct msm_vfe_axi_shared_data { struct msm_vfe_axi_hardware_info *hw_info; - struct msm_vfe_axi_stream stream_info[VFE_AXI_SRC_MAX]; uint32_t free_wm[MAX_NUM_WM]; uint32_t wm_image_size[MAX_NUM_WM]; enum msm_wm_ub_cfg_type wm_ub_cfg_policy; @@ -503,14 +515,11 @@ struct msm_vfe_axi_shared_data { struct msm_vfe_axi_composite_info composite_info[MAX_NUM_COMPOSITE_MASK]; uint8_t num_used_composite_mask; - uint32_t stream_update[VFE_SRC_MAX]; atomic_t axi_cfg_update[VFE_SRC_MAX]; - enum msm_isp_camif_update_state pipeline_update; struct msm_vfe_src_info src_info[VFE_SRC_MAX]; uint16_t stream_handle_cnt; uint32_t event_mask; uint8_t enable_frameid_recovery; - enum msm_vfe_camif_state camif_state; }; struct msm_vfe_stats_hardware_info { @@ -522,7 +531,7 @@ struct msm_vfe_stats_hardware_info { }; enum msm_vfe_stats_state { - STATS_AVALIABLE, + STATS_AVAILABLE, STATS_INACTIVE, STATS_ACTIVE, STATS_START_PENDING, @@ -534,7 +543,7 @@ enum msm_vfe_stats_state { struct msm_vfe_stats_stream { uint32_t session_id; uint32_t stream_id; - uint32_t stream_handle; + uint32_t stream_handle[MAX_VFE]; uint32_t composite_flag; enum msm_isp_stats_type stats_type; enum msm_vfe_stats_state state; @@ -544,17 +553,27 @@ struct msm_vfe_stats_stream { uint32_t init_stats_frame_drop; struct msm_isp_sw_framskip sw_skip; - uint32_t buffer_offset; + uint32_t buffer_offset[MAX_VFE]; struct msm_isp_buffer *buf[2]; uint32_t bufq_handle; + + spinlock_t lock; + struct vfe_device *vfe_dev[MAX_VFE]; + int num_isp; + struct completion active_comp; + struct completion inactive_comp; + /* + * bits in this mask are set that correspond to vfe_id of + * the vfe on which this stream operates + */ + uint32_t vfe_mask; + uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; }; struct msm_vfe_stats_shared_data { - struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; uint8_t num_active_stream; atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; uint16_t stream_handle_cnt; - atomic_t stats_update; }; struct msm_vfe_tasklet_queue_cmd { @@ -653,7 +672,6 @@ struct dual_vfe_resource { struct msm_vfe_stats_shared_data *stats_data[MAX_VFE]; struct msm_vfe_axi_shared_data *axi_data[MAX_VFE]; uint32_t wm_reload_mask[MAX_VFE]; - uint32_t epoch_sync_mask; }; struct master_slave_resource_info { @@ -671,6 +689,9 @@ struct msm_vfe_common_dev_data { spinlock_t common_dev_data_lock; struct dual_vfe_resource *dual_vfe_res; struct master_slave_resource_info ms_resource; + struct msm_vfe_axi_stream streams[VFE_AXI_SRC_MAX * MAX_VFE]; + struct msm_vfe_stats_stream stats_streams[MSM_ISP_STATS_MAX * MAX_VFE]; + struct mutex vfe_common_mutex; }; struct msm_vfe_common_subdev { @@ -713,8 +734,6 @@ struct vfe_device { /* Sync variables*/ struct completion reset_complete; struct completion halt_complete; - struct completion stream_config_complete; - struct completion stats_config_complete; struct mutex realtime_mutex; struct mutex core_mutex; spinlock_t shared_data_lock; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 9481bede6417..8b5a3d8d508d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -412,10 +412,9 @@ static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, ISP_DBG("%s: SOF IRQ\n", __func__); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0, ts); msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); } } @@ -608,15 +607,14 @@ static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, if ((rdi_status & BIT(7)) && (!(irq_status0 & 0x20))) return; } - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); } for (i = VFE_RAW_0; i <= VFE_RAW_2; i++) { if (irq_status1 & BIT(26 + (i - VFE_RAW_0))) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); + msm_isp_axi_stream_update(vfe_dev, i, ts); msm_isp_update_framedrop_reg(vfe_dev, i); vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, @@ -693,8 +691,9 @@ static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + stream_info->comp_mask_index[vfe_idx]; uint32_t irq_mask; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); @@ -711,7 +710,9 @@ static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index[vfe_idx]; uint32_t irq_mask; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); @@ -727,8 +728,10 @@ static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t irq_mask; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(stream_info->wm[0] + 6); + irq_mask |= BIT(stream_info->wm[vfe_idx][0] + 6); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); } @@ -736,15 +739,19 @@ static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t irq_mask; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask &= ~BIT(stream_info->wm[0] + 6); + irq_mask &= ~BIT(stream_info->wm[vfe_idx][0] + 6); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); } -static void msm_vfe32_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; + if (stream_info->stream_src == PIX_ENCODER) { msm_camera_io_w(framedrop_period - 1, vfe_base + 0x504); msm_camera_io_w(framedrop_period - 1, vfe_base + 0x508); @@ -929,7 +936,7 @@ static void msm_vfe32_update_camif_state( VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data.src_info[ - VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + VFE_PIX_0].stream_count > 0) ? 1 : 0); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4); @@ -971,16 +978,17 @@ static void msm_vfe32_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); if (!stream_info->frame_based) { /*WR_IMAGE_SIZE*/ val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); @@ -988,9 +996,9 @@ static void msm_vfe32_axi_cfg_wm_reg( val = msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_stride) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1) << 4 | VFE32_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); } else { @@ -998,9 +1006,9 @@ static void msm_vfe32_axi_cfg_wm_reg( val = msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1) << 4 | VFE32_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); } @@ -1012,7 +1020,8 @@ static void msm_vfe32_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /*WR_IMAGE_SIZE*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); /*WR_BUFFER_CFG*/ @@ -1024,9 +1033,10 @@ static void msm_vfe32_axi_cfg_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + &stream_info->plane_cfg[vfe_idx][plane_idx]; + uint8_t wm = stream_info->wm[vfe_idx][plane_idx]; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; @@ -1080,7 +1090,8 @@ static void msm_vfe32_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm = stream_info->wm[vfe_idx][plane_idx]; uint32_t xbar_reg_cfg = 0; xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); @@ -1098,6 +1109,7 @@ static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev) uint32_t prop_size = 0; uint32_t wm_ub_size; uint64_t delta; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { if (axi_data->free_wm[i] > 0) { num_used_wms++; @@ -1243,9 +1255,11 @@ static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t irq_mask; irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13); + irq_mask |= BIT(STATS_IDX(stream_info->stream_handle[vfe_idx]) + 13); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); return; } @@ -1342,12 +1356,15 @@ static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10); } -static void msm_vfe32_stats_update_ping_pong_addr(void __iomem *vfe_base, +static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index d42ada769380..a2aa2983b056 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -599,7 +599,6 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, return; /* Shift status bits so that PIX REG UPDATE is 1st bit */ shift_irq = ((irq_status0 & 0xF0) >> 4); - for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { if (shift_irq & BIT(i)) { reg_updated |= BIT(i); @@ -607,15 +606,17 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, (uint32_t)BIT(i)); switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + if (vfe_dev->axi_data.src_info[i].stream_count + == 0 && + vfe_dev->axi_data.src_info[i]. + raw_stream_count == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); break; @@ -624,29 +625,22 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, i); + /* reg upd is also epoch for RDI */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -695,7 +689,9 @@ static void msm_vfe40_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x378); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x378); @@ -713,16 +709,18 @@ static void msm_vfe40_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { ISP_DBG("%s: SOF IRQ\n", __func__); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } @@ -791,8 +789,10 @@ static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -807,8 +807,11 @@ static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; - vfe_dev->irq0_mask &= ~BIT(27); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; + vfe_dev->irq0_mask &= ~BIT(27); comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -821,32 +824,38 @@ static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[vfe_idx][0] + 8)); + msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -static void msm_vfe40_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; uint32_t i, temp; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); temp = msm_camera_io_r(vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + vfe_base + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } msm_camera_io_w_mb(0x1, vfe_base + 0x378); @@ -856,9 +865,11 @@ static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); } static int32_t msm_vfe40_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1374,7 +1385,7 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1443,7 +1454,10 @@ static void msm_vfe40_axi_cfg_wm_reg( { uint32_t val; uint32_t burst_len, wm_bit_shift = VFE40_WM_BIT_SHIFT_8976_VERSION; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE40_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION || vfe_dev->vfe_hw_version == VFE40_8939_VERSION) { @@ -1468,18 +1482,18 @@ static void msm_vfe40_axi_cfg_wm_reg( val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /*WR_BUFFER_CFG*/ val = msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_stride) << 16 | - (stream_info->plane_cfg[ + (stream_info->plane_cfg[vfe_idx][ plane_idx].output_height - 1) << wm_bit_shift | burst_len; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); @@ -1487,9 +1501,9 @@ static void msm_vfe40_axi_cfg_wm_reg( msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); val = msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_width) << 16 | - (stream_info->plane_cfg[ + (stream_info->plane_cfg[vfe_idx][ plane_idx].output_height - 1) << 4 | burst_len; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); @@ -1507,7 +1521,10 @@ static void msm_vfe40_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE40_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /*WR_ADDR_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); /*WR_IMAGE_SIZE*/ @@ -1524,12 +1541,15 @@ static void msm_vfe40_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; + switch (stream_info->stream_src) { case PIX_ENCODER: case PIX_VIEWFINDER: { @@ -1584,9 +1604,12 @@ static void msm_vfe40_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); @@ -1714,6 +1737,7 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + struct msm_isp_timestamp ts; /* Keep only halt and restart mask */ msm_vfe40_config_irq(vfe_dev, (1 << 31), (1 << 8), @@ -1722,30 +1746,16 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24); + + msm_isp_get_timestamp(&ts); /* if any stream is waiting for update, signal complete */ for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { - /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); if (blocking) { init_completion(&vfe_dev->halt_complete); @@ -1764,7 +1774,7 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, return rc; } -static int msm_vfe40_axi_restart(struct vfe_device *vfe_dev, +static void msm_vfe40_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1786,8 +1796,6 @@ static int msm_vfe40_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } static uint32_t msm_vfe40_get_wm_mask( @@ -1903,27 +1911,37 @@ static void msm_vfe40_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe40_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 16), 0, - MSM_ISP_IRQ_ENABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 16), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe40_config_irq(vfe_dev, - (1 << (STATS_IDX(stream_info->stream_handle) + 16)), 0, - MSM_ISP_IRQ_DISABLE); + (1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 16)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe40_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE40_STATS_BASE(stats_idx); /*WR_ADDR_CFG*/ msm_camera_io_w(stream_info->framedrop_period << 2, vfe_dev->vfe_base + stats_base + 0x8); @@ -1939,9 +1957,14 @@ static void msm_vfe40_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE40_STATS_BASE(stats_idx); /*WR_ADDR_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); @@ -2095,11 +2118,16 @@ static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev, } static void msm_vfe40_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index 388656b9ca30..c77eff66ccca 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -437,15 +437,17 @@ static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, (uint32_t)BIT(i)); switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + if (vfe_dev->axi_data.src_info[i].stream_count + == 0 && + vfe_dev->axi_data.src_info[i]. + raw_stream_count == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); break; @@ -454,29 +456,22 @@ static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, i); + /* reg upd is epoch for rdi */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -498,17 +493,19 @@ static void msm_vfe44_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { ISP_DBG("%s: SOF IRQ\n", __func__); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update( + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } } @@ -550,7 +547,9 @@ static void msm_vfe44_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x378); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x378); @@ -628,8 +627,10 @@ static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -644,7 +645,10 @@ static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -657,31 +661,38 @@ static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -static void msm_vfe44_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe44_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; uint32_t i, temp; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); temp = msm_camera_io_r(vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + vfe_base + + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } } @@ -689,9 +700,11 @@ static void msm_vfe44_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); } static int32_t msm_vfe44_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1039,7 +1052,7 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1101,7 +1114,10 @@ static void msm_vfe44_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE44_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); if (!stream_info->frame_based) { msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); @@ -1109,28 +1125,30 @@ static void msm_vfe44_axi_cfg_wm_reg( val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /*WR_BUFFER_CFG*/ - val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1); val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); val = val << 2 | msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_stride) << 16 | VFE44_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); } else { msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); - val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1); val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); val = val << 2 | msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_width) << 16 | VFE44_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); @@ -1147,8 +1165,10 @@ static void msm_vfe44_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + wm_base = VFE44_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /*WR_ADDR_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); /*WR_IMAGE_SIZE*/ @@ -1164,12 +1184,15 @@ static void msm_vfe44_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; + switch (stream_info->stream_src) { case PIX_ENCODER: case PIX_VIEWFINDER: { @@ -1223,9 +1246,12 @@ static void msm_vfe44_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); @@ -1245,6 +1271,7 @@ static void msm_vfe44_cfg_axi_ub_equal_default( uint32_t prop_size = 0; uint32_t wm_ub_size; uint64_t delta; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { if (axi_data->free_wm[i] > 0) { num_used_wms++; @@ -1316,6 +1343,7 @@ static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + struct msm_isp_timestamp ts; /* Keep only halt and restart mask */ msm_vfe44_config_irq(vfe_dev, (1 << 31), (1 << 8), @@ -1349,34 +1377,20 @@ static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); } + msm_isp_get_timestamp(&ts); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); return rc; } -static int msm_vfe44_axi_restart(struct vfe_device *vfe_dev, +static void msm_vfe44_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1397,8 +1411,6 @@ static int msm_vfe44_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } static uint32_t msm_vfe44_get_wm_mask( @@ -1450,15 +1462,15 @@ static int msm_vfe44_stats_check_streams( struct msm_vfe_stats_stream *stream_info) { if (stream_info[STATS_IDX_BF].state == - STATS_AVALIABLE && + STATS_AVAILABLE && stream_info[STATS_IDX_BF_SCALE].state != - STATS_AVALIABLE) { + STATS_AVAILABLE) { pr_err("%s: does not support BF_SCALE while BF is disabled\n", __func__); return -EINVAL; } - if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && - stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && + if (stream_info[STATS_IDX_BF].state != STATS_AVAILABLE && + stream_info[STATS_IDX_BF_SCALE].state != STATS_AVAILABLE && stream_info[STATS_IDX_BF].composite_flag != stream_info[STATS_IDX_BF_SCALE].composite_flag) { pr_err("%s: Different composite flag for BF and BF_SCALE\n", @@ -1541,27 +1553,37 @@ static void msm_vfe44_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe44_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, - MSM_ISP_IRQ_ENABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe44_config_irq(vfe_dev, - (1 << (STATS_IDX(stream_info->stream_handle) + 15)), 0, - MSM_ISP_IRQ_DISABLE); + (1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe44_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE44_STATS_BASE(stats_idx); /* BF_SCALE does not have its own WR_ADDR_CFG, * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; * it's using the same from BF */ @@ -1582,9 +1604,14 @@ static void msm_vfe44_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE44_STATS_BASE(stats_idx); /* BF_SCALE does not have its own WR_ADDR_CFG, * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; * it's using the same from BF */ @@ -1742,12 +1769,16 @@ static void msm_vfe44_stats_update_cgc_override(struct vfe_device *vfe_dev, } static void msm_vfe44_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE44_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 40bb044fde47..6336892b1b4e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -376,46 +376,40 @@ static void msm_vfe46_process_reg_update(struct vfe_device *vfe_dev, switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + msm_isp_stats_stream_update(vfe_dev); + if (vfe_dev->axi_data.src_info[i].stream_count + == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, i); + reg_update(vfe_dev, i); break; case VFE_RAW_0: case VFE_RAW_1: case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, i); + /* reg upd is also epoch for rdi */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -437,14 +431,16 @@ static void msm_vfe46_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + stream_count == 0) { + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } @@ -488,7 +484,9 @@ static void msm_vfe46_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x3D8); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x3D8); @@ -567,8 +565,10 @@ static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -583,7 +583,10 @@ static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -596,31 +599,37 @@ static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe46_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -static void msm_vfe46_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe46_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { uint32_t i, temp; + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE46_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); temp = msm_camera_io_r(vfe_base + - VFE46_WM_BASE(stream_info->wm[i]) + 0xC); + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE46_WM_BASE(stream_info->wm[i]) + 0xC); + vfe_base + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } } @@ -628,10 +637,11 @@ static void msm_vfe46_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE46_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); } static int32_t msm_vfe46_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1114,7 +1124,7 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x3AC); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1178,7 +1188,10 @@ static void msm_vfe46_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE46_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE46_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0xC); val &= ~0x2; @@ -1190,17 +1203,18 @@ static void msm_vfe46_axi_cfg_wm_reg( val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+3)/4 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /* WR_BUFFER_CFG */ val = VFE46_BURST_LEN | - (stream_info->plane_cfg[plane_idx].output_height - 1) << + (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1) << 2 | ((msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_stride)+1)/2) << 16; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); } @@ -1215,7 +1229,10 @@ static void msm_vfe46_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE46_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE46_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /* WR_ADDR_CFG */ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); @@ -1232,12 +1249,15 @@ static void msm_vfe46_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; + switch (stream_info->stream_src) { case PIX_VIDEO: case PIX_ENCODER: @@ -1295,9 +1315,12 @@ static void msm_vfe46_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE46_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE46_XBAR_SHIFT(wm)); @@ -1407,6 +1430,7 @@ static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + struct msm_isp_timestamp ts; /* Keep only halt and restart mask */ msm_vfe46_config_irq(vfe_dev, (1 << 31), (1 << 8), @@ -1440,34 +1464,19 @@ static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x374); } + msm_isp_get_timestamp(&ts); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { - /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); return rc; } -static int msm_vfe46_axi_restart(struct vfe_device *vfe_dev, +static void msm_vfe46_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1488,8 +1497,6 @@ static int msm_vfe46_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } static uint32_t msm_vfe46_get_wm_mask( @@ -1541,15 +1548,15 @@ static int msm_vfe46_stats_check_streams( struct msm_vfe_stats_stream *stream_info) { if (stream_info[STATS_IDX_BF].state == - STATS_AVALIABLE && + STATS_AVAILABLE && stream_info[STATS_IDX_BF_SCALE].state != - STATS_AVALIABLE) { + STATS_AVAILABLE) { pr_err("%s: does not support BF_SCALE while BF is disabled\n", __func__); return -EINVAL; } - if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && - stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && + if (stream_info[STATS_IDX_BF].state != STATS_AVAILABLE && + stream_info[STATS_IDX_BF_SCALE].state != STATS_AVAILABLE && stream_info[STATS_IDX_BF].composite_flag != stream_info[STATS_IDX_BF_SCALE].composite_flag) { pr_err("%s: Different composite flag for BF and BF_SCALE\n", @@ -1632,26 +1639,37 @@ static void msm_vfe46_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe46_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, - MSM_ISP_IRQ_ENABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe46_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, - MSM_ISP_IRQ_DISABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe46_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE46_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE46_STATS_BASE(stats_idx); /* * BF_SCALE does not have its own WR_ADDR_CFG, @@ -1676,10 +1694,14 @@ static void msm_vfe46_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE46_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE46_STATS_BASE(stats_idx); /* * BF_SCALE does not have its own WR_ADDR_CFG, * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; @@ -1845,12 +1867,16 @@ static void msm_vfe46_stats_enable_module(struct vfe_device *vfe_dev, } static void msm_vfe46_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE46_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 290f100ffeba..b434161f5599 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -562,19 +562,20 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { if (shift_irq & BIT(i)) { reg_updated |= BIT(i); - ISP_DBG("%s REG_UPDATE IRQ %x\n", __func__, - (uint32_t)BIT(i)); + ISP_DBG("%s REG_UPDATE IRQ %x vfe %d\n", __func__, + (uint32_t)BIT(i), vfe_dev->pdev->id); switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + /* if 0 streams then force reg update */ + if (vfe_dev->axi_data.src_info + [i].stream_count == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); break; @@ -582,31 +583,23 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_1: case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); - msm_isp_save_framedrop_values(vfe_dev, i); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); + /* reg upd is also epoch for RDI */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -627,15 +620,17 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + stream_count == 0) { + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } @@ -679,7 +674,9 @@ void msm_vfe47_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x4AC); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x4AC); @@ -768,9 +765,10 @@ void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); comp_mask |= (axi_data->composite_info[comp_mask_index]. @@ -784,8 +782,10 @@ void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev, void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74); @@ -797,31 +797,37 @@ void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe47_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe47_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe47_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe47_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -void msm_vfe47_cfg_framedrop(void __iomem *vfe_base, +void msm_vfe47_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; uint32_t i, temp; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE47_WM_BASE(stream_info->wm[i]) + 0x24); + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x24); temp = msm_camera_io_r(vfe_base + - VFE47_WM_BASE(stream_info->wm[i]) + 0x14); + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x14); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE47_WM_BASE(stream_info->wm[i]) + 0x14); + vfe_base + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x14); } } @@ -829,10 +835,11 @@ void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE47_WM_BASE(stream_info->wm[i]) + 0x24); + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x24); } static int32_t msm_vfe47_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1395,7 +1402,7 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1404,7 +1411,6 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x478); /* configure EPOCH0 for 20 lines */ msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x4A0); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; /* testgen GO*/ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) msm_camera_io_w(1, vfe_dev->vfe_base + 0xC58); @@ -1427,7 +1433,6 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, poll_val, poll_val & 0x80000000, 1000, 2000000)) pr_err("%s: camif disable failed %x\n", __func__, poll_val); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; /* testgen OFF*/ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) msm_camera_io_w(1 << 1, vfe_dev->vfe_base + 0xC58); @@ -1469,8 +1474,10 @@ void msm_vfe47_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE47_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0x14); val &= ~0x2; if (stream_info->frame_based) @@ -1480,17 +1487,18 @@ void msm_vfe47_axi_cfg_wm_reg( /* WR_IMAGE_SIZE */ val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+3)/4 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x1C); /* WR_BUFFER_CFG */ val = VFE47_BURST_LEN | - (stream_info->plane_cfg[plane_idx].output_height - 1) << + (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1) << 2 | ((msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_stride)+1)/2) << 16; } msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); @@ -1504,8 +1512,10 @@ void msm_vfe47_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE47_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /* WR_ADDR_CFG */ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /* WR_IMAGE_SIZE */ @@ -1521,12 +1531,14 @@ void msm_vfe47_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; switch (stream_info->stream_src) { case PIX_VIDEO: case PIX_ENCODER: @@ -1585,9 +1597,11 @@ void msm_vfe47_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE47_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE47_XBAR_SHIFT(wm)); @@ -1707,6 +1721,7 @@ int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, int rc = 0; enum msm_vfe_input_src i; uint32_t val = 0; + struct msm_isp_timestamp ts; val = msm_camera_io_r(vfe_dev->vfe_vbif_base + VFE47_VBIF_CLK_OFFSET); val |= 0x1; @@ -1746,34 +1761,20 @@ int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x400); } + msm_isp_get_timestamp(&ts); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { - /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + /* if any stream is waiting for update, signal fake completes */ + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); return rc; } -int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, +void msm_vfe47_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1793,8 +1794,6 @@ int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } uint32_t msm_vfe47_get_wm_mask( @@ -1912,7 +1911,10 @@ void msm_vfe47_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - switch (STATS_IDX(stream_info->stream_handle)) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + + switch (STATS_IDX(stream_info->stream_handle[vfe_idx])) { case STATS_COMP_IDX_AEC_BG: msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_ENABLE); break; @@ -1943,7 +1945,7 @@ void msm_vfe47_stats_cfg_wm_irq_mask( break; default: pr_err("%s: Invalid stats idx %d\n", __func__, - STATS_IDX(stream_info->stream_handle)); + STATS_IDX(stream_info->stream_handle[vfe_idx])); } } @@ -1951,12 +1953,10 @@ void msm_vfe47_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - uint32_t irq_mask, irq_mask_1; - - irq_mask = vfe_dev->irq0_mask; - irq_mask_1 = vfe_dev->irq1_mask; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); - switch (STATS_IDX(stream_info->stream_handle)) { + switch (STATS_IDX(stream_info->stream_handle[vfe_idx])) { case STATS_COMP_IDX_AEC_BG: msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_DISABLE); break; @@ -1987,7 +1987,7 @@ void msm_vfe47_stats_clear_wm_irq_mask( break; default: pr_err("%s: Invalid stats idx %d\n", __func__, - STATS_IDX(stream_info->stream_handle)); + STATS_IDX(stream_info->stream_handle[vfe_idx])); } } @@ -1995,8 +1995,13 @@ void msm_vfe47_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE47_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE47_STATS_BASE(stats_idx); /* WR_ADDR_CFG */ msm_camera_io_w(stream_info->framedrop_period << 2, @@ -2013,9 +2018,14 @@ void msm_vfe47_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE47_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE47_STATS_BASE(stats_idx); /* WR_ADDR_CFG */ msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); @@ -2171,11 +2181,16 @@ void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, } void msm_vfe47_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h index 737f845c7272..8581373b3b71 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h @@ -56,7 +56,7 @@ void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); -void msm_vfe47_cfg_framedrop(void __iomem *vfe_base, +void msm_vfe47_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period); void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev, @@ -107,7 +107,7 @@ void msm_vfe47_update_ping_pong_addr( int32_t buf_size); int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking); -int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, +void msm_vfe47_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif); uint32_t msm_vfe47_get_wm_mask( uint32_t irq_status0, uint32_t irq_status1); @@ -141,7 +141,7 @@ bool msm_vfe47_is_module_cfg_lock_needed( void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, uint32_t stats_mask, uint8_t enable); void msm_vfe47_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr); uint32_t msm_vfe47_stats_get_wm_mask( uint32_t irq_status0, uint32_t irq_status1); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index ac2d508269a4..39a0845a886f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -22,9 +22,12 @@ static int msm_isp_update_dual_HW_ms_info_at_start( struct vfe_device *vfe_dev, enum msm_vfe_input_src stream_src); -static int msm_isp_update_dual_HW_axi( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); +static void msm_isp_reload_ping_pong_offset( + struct msm_vfe_axi_stream *stream_info); + +static void __msm_isp_axi_stream_update( + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts); #define DUAL_VFE_AND_VFE1(s, v) ((s->stream_src < RDI_INTF_0) && \ v->is_split && vfe_dev->pdev->id == ISP_VFE1) @@ -33,105 +36,151 @@ static int msm_isp_update_dual_HW_axi( ((s->stream_src >= RDI_INTF_0) && \ (stream_info->stream_src <= RDI_INTF_2))) -static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream( - struct dual_vfe_resource *dual_vfe_res, - int vfe_id, uint32_t index) -{ - struct msm_vfe_axi_shared_data *axi_data = - dual_vfe_res->axi_data[vfe_id]; - return &axi_data->stream_info[index]; -} - -static inline struct msm_vfe_axi_stream *msm_isp_get_controllable_stream( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - if (vfe_dev->is_split && stream_info->stream_src < RDI_INTF_0 && - stream_info->controllable_output) - return msm_isp_vfe_get_stream( - vfe_dev->common_data->dual_vfe_res, - ISP_VFE1, - HANDLE_TO_IDX( - stream_info->stream_handle)); - return stream_info; -} - -int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, +static int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, + struct msm_vfe_axi_stream *stream_info) { - uint32_t i = stream_cfg_cmd->stream_src; - - if (i >= VFE_AXI_SRC_MAX) { - pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, - stream_cfg_cmd->stream_src); - return -EINVAL; - } + uint32_t i; + int rc = 0; - if (axi_data->stream_info[i].state != AVAILABLE) { + if (stream_info->state != AVAILABLE) { pr_err("%s:%d invalid state %d expected %d for src %d\n", - __func__, __LINE__, axi_data->stream_info[i].state, + __func__, __LINE__, stream_info->state, AVAILABLE, i); return -EINVAL; } + if (stream_info->num_isp == 0) { + stream_info->session_id = stream_cfg_cmd->session_id; + stream_info->stream_id = stream_cfg_cmd->stream_id; + stream_info->buf_divert = stream_cfg_cmd->buf_divert; + stream_info->stream_src = stream_cfg_cmd->stream_src; + stream_info->controllable_output = + stream_cfg_cmd->controllable_output; + stream_info->activated_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + if (stream_cfg_cmd->controllable_output) + stream_cfg_cmd->frame_skip_pattern = SKIP_ALL; + INIT_LIST_HEAD(&stream_info->request_q); + } else { + /* check if the stream has been added for the vfe-device */ + if (stream_info->vfe_mask & (1 << vfe_dev->pdev->id)) { + pr_err("%s: stream %p/%x is already added for vfe dev %d vfe_mask %x\n", + __func__, stream_info, stream_info->stream_id, + vfe_dev->pdev->id, stream_info->vfe_mask); + return -EINVAL; + } + if (stream_info->session_id != stream_cfg_cmd->session_id) { + pr_err("%s: dual stream session id mismatch %d/%d\n", + __func__, stream_info->session_id, + stream_cfg_cmd->session_id); + rc = -EINVAL; + } + if (stream_info->stream_id != stream_cfg_cmd->stream_id) { + pr_err("%s: dual stream stream id mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_cfg_cmd->stream_id); + rc = -EINVAL; + } + if (stream_info->controllable_output != + stream_cfg_cmd->controllable_output) { + pr_err("%s: dual stream controllable_op mismatch %d/%d\n", + __func__, stream_info->controllable_output, + stream_cfg_cmd->controllable_output); + rc = -EINVAL; + } + if (stream_info->buf_divert != stream_cfg_cmd->buf_divert) { + pr_err("%s: dual stream buf_divert mismatch %d/%d\n", + __func__, stream_info->buf_divert, + stream_cfg_cmd->buf_divert); + rc = -EINVAL; + } + if (rc) + return rc; + } + stream_info->vfe_dev[stream_info->num_isp] = vfe_dev; + stream_info->num_isp++; + if ((axi_data->stream_handle_cnt << 8) == 0) axi_data->stream_handle_cnt++; stream_cfg_cmd->axi_stream_handle = - (++axi_data->stream_handle_cnt) << 8 | i; + (++axi_data->stream_handle_cnt) << 8 | stream_info->stream_src; ISP_DBG("%s: vfe %d handle %x\n", __func__, vfe_dev->pdev->id, stream_cfg_cmd->axi_stream_handle); - memset(&axi_data->stream_info[i], 0, - sizeof(struct msm_vfe_axi_stream)); - spin_lock_init(&axi_data->stream_info[i].lock); - axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id; - axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id; - axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert; - axi_data->stream_info[i].state = INACTIVE; - axi_data->stream_info[i].stream_handle = + stream_info->stream_handle[stream_info->num_isp - 1] = stream_cfg_cmd->axi_stream_handle; - axi_data->stream_info[i].controllable_output = - stream_cfg_cmd->controllable_output; - axi_data->stream_info[i].activated_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; - if (stream_cfg_cmd->controllable_output) - stream_cfg_cmd->frame_skip_pattern = SKIP_ALL; - INIT_LIST_HEAD(&axi_data->stream_info[i].request_q); + stream_info->vfe_mask |= (1 << vfe_dev->pdev->id); + + if (!vfe_dev->is_split || stream_cfg_cmd->stream_src >= RDI_INTF_0 || + stream_info->num_isp == MAX_VFE) { + stream_info->state = INACTIVE; + + for (i = 0; i < MSM_ISP_COMP_IRQ_MAX; i++) + stream_info->composite_irq[i] = 0; + } return 0; } -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx) +static void msm_isp_axi_destroy_stream( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - if (axi_data->stream_info[stream_idx].state != AVAILABLE) { - axi_data->stream_info[stream_idx].state = AVAILABLE; - axi_data->stream_info[stream_idx].stream_handle = 0; - } else { - pr_err("%s: stream does not exist\n", __func__); + int k; + int j; + int i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + /* + * For the index being removed, shift everything to it's right by 1 + * so that the index being removed becomes the last index + */ + for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) { + stream_info->vfe_dev[i] = stream_info->vfe_dev[k]; + stream_info->stream_handle[i] = stream_info->stream_handle[k]; + stream_info->bandwidth[i] = stream_info->bandwidth[k]; + stream_info->max_width[i] = stream_info->max_width[k]; + stream_info->comp_mask_index[i] = + stream_info->comp_mask_index[k]; + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->plane_cfg[i][j] = + stream_info->plane_cfg[k][j]; + stream_info->wm[i][j] = stream_info->wm[k][j]; + } + } + + stream_info->num_isp--; + stream_info->vfe_dev[stream_info->num_isp] = NULL; + stream_info->stream_handle[stream_info->num_isp] = 0; + stream_info->bandwidth[stream_info->num_isp] = 0; + stream_info->max_width[stream_info->num_isp] = 0; + stream_info->comp_mask_index[stream_info->num_isp] = -1; + stream_info->vfe_mask &= ~(1 << vfe_dev->pdev->id); + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->wm[stream_info->num_isp][j] = -1; + memset(&stream_info->plane_cfg[stream_info->num_isp][j], + 0, sizeof( + stream_info->plane_cfg[stream_info->num_isp][j])); + } + + if (stream_info->num_isp == 0) { + /* release the bufq */ + for (k = 0; k < VFE_BUF_QUEUE_MAX; k++) + stream_info->bufq_handle[k] = 0; + stream_info->vfe_mask = 0; + stream_info->state = AVAILABLE; } } -int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, +static int msm_isp_validate_axi_request(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) { int rc = -1, i; - struct msm_vfe_axi_stream *stream_info = NULL; - if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) - < VFE_AXI_SRC_MAX) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - } else { - pr_err("%s: Invalid axi_stream_handle\n", __func__); - return rc; - } - - if (!stream_info) { - pr_err("%s: Stream info is NULL\n", __func__); - return -EINVAL; - } + int vfe_idx; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; switch (stream_cfg_cmd->output_format) { case V4L2_PIX_FMT_YUYV: @@ -236,9 +285,13 @@ int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, return rc; } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) { - stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i]; - stream_info->max_width = max(stream_info->max_width, + stream_info->plane_cfg[vfe_idx][i] = + stream_cfg_cmd->plane_cfg[i]; + stream_info->max_width[vfe_idx] = + max(stream_info->max_width[vfe_idx], stream_cfg_cmd->plane_cfg[i].output_width); } @@ -250,10 +303,11 @@ int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, } static uint32_t msm_isp_axi_get_plane_size( - struct msm_vfe_axi_stream *stream_info, int plane_idx) + struct msm_vfe_axi_stream *stream_info, int vfe_idx, int plane_idx) { uint32_t size = 0; - struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg; + struct msm_vfe_axi_plane_cfg *plane_cfg = + stream_info->plane_cfg[vfe_idx]; switch (stream_info->output_format) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: @@ -355,37 +409,41 @@ static uint32_t msm_isp_axi_get_plane_size( return size; } -void msm_isp_axi_reserve_wm(struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_axi_reserve_wm(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; int i, j; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) { for (j = 0; j < axi_data->hw_info->num_wm; j++) { if (!axi_data->free_wm[j]) { axi_data->free_wm[j] = - stream_info->stream_handle; + stream_info->stream_handle[vfe_idx]; axi_data->wm_image_size[j] = msm_isp_axi_get_plane_size( - stream_info, i); + stream_info, vfe_idx, i); axi_data->num_used_wm++; break; } } ISP_DBG("%s vfe %d stream_handle %x wm %d\n", __func__, vfe_dev->pdev->id, - stream_info->stream_handle, j); - stream_info->wm[i] = j; + stream_info->stream_handle[vfe_idx], j); + stream_info->wm[vfe_idx][i] = j; } } -void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, +void msm_isp_axi_free_wm(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; int i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { - axi_data->free_wm[stream_info->wm[i]] = 0; + axi_data->free_wm[stream_info->wm[vfe_idx][i]] = 0; axi_data->num_used_wm--; } if (stream_info->stream_src <= IDEAL_RAW) @@ -394,88 +452,47 @@ void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, axi_data->num_rdi_stream++; } -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_axi_reserve_comp_mask( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { int i; uint8_t comp_mask = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) - comp_mask |= 1 << stream_info->wm[i]; + comp_mask |= 1 << stream_info->wm[vfe_idx][i]; for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { if (!axi_data->composite_info[i].stream_handle) { axi_data->composite_info[i].stream_handle = - stream_info->stream_handle; + stream_info->stream_handle[vfe_idx]; axi_data->composite_info[i]. stream_composite_mask = comp_mask; axi_data->num_used_composite_mask++; break; } } - stream_info->comp_mask_index = i; + stream_info->comp_mask_index[vfe_idx] = i; return; } -void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_axi_free_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - axi_data->composite_info[stream_info->comp_mask_index]. + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + axi_data->composite_info[stream_info->comp_mask_index[vfe_idx]]. stream_composite_mask = 0; - axi_data->composite_info[stream_info->comp_mask_index]. + axi_data->composite_info[stream_info->comp_mask_index[vfe_idx]]. stream_handle = 0; axi_data->num_used_composite_mask--; } -int msm_isp_axi_check_stream_state( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) -{ - int rc = 0, i; - unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - enum msm_vfe_axi_state valid_state = - (stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return -EINVAL; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state != valid_state) { - if ((stream_info->state == PAUSING || - stream_info->state == PAUSED || - stream_info->state == RESUME_PENDING || - stream_info->state == RESUMING || - stream_info->state == UPDATING) && - (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { - stream_info->state = ACTIVE; - } else { - pr_err("%s: Invalid stream state: %d\n", - __func__, stream_info->state); - spin_unlock_irqrestore( - &stream_info->lock, flags); - if (stream_cfg_cmd->cmd == START_STREAM) - rc = -EINVAL; - break; - } - } - spin_unlock_irqrestore(&stream_info->lock, flags); - } - return rc; -} - /** * msm_isp_cfg_framedrop_reg() - Program the period and pattern - * @vfe_dev: The device for which the period and pattern is programmed * @stream_info: The stream for which programming is done * * This function calculates the period and pattern to be configured @@ -484,15 +501,15 @@ int msm_isp_axi_check_stream_state( * * Returns void. */ -static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev, +static void msm_isp_cfg_framedrop_reg( struct msm_vfe_axi_stream *stream_info) { - struct msm_vfe_axi_stream *vfe0_stream_info = NULL; + struct vfe_device *vfe_dev = stream_info->vfe_dev[0]; uint32_t runtime_init_frame_drop; - uint32_t framedrop_pattern = 0; uint32_t framedrop_period = MSM_VFE_STREAM_STOP_PERIOD; enum msm_vfe_input_src frame_src = SRC_TO_INTF(stream_info->stream_src); + int i; if (vfe_dev->axi_data.src_info[frame_src].frame_id >= stream_info->init_frame_drop) @@ -507,127 +524,45 @@ static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev, if (MSM_VFE_STREAM_STOP_PERIOD != framedrop_period) framedrop_pattern = 0x1; - ISP_DBG("%s: stream %x framedrop pattern %x period %u\n", __func__, - stream_info->stream_handle, framedrop_pattern, - framedrop_period); - BUG_ON(0 == framedrop_period); - if (DUAL_VFE_AND_VFE1(stream_info, vfe_dev)) { - vfe0_stream_info = msm_isp_vfe_get_stream( - vfe_dev->common_data->dual_vfe_res, - ISP_VFE0, - HANDLE_TO_IDX( - stream_info->stream_handle)); + for (i = 0; i < stream_info->num_isp; i++) { + vfe_dev = stream_info->vfe_dev[i]; vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop( - vfe_dev->common_data->dual_vfe_res-> - vfe_base[ISP_VFE0], - vfe0_stream_info, framedrop_pattern, - framedrop_period); - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop( - vfe_dev->vfe_base, stream_info, - framedrop_pattern, - framedrop_period); + vfe_dev, stream_info, framedrop_pattern, + framedrop_period); + } - stream_info->requested_framedrop_period = - framedrop_period; - vfe0_stream_info->requested_framedrop_period = - framedrop_period; + ISP_DBG("%s: stream %x src %x framedrop pattern %x period %u\n", + __func__, + stream_info->stream_handle[0], stream_info->stream_src, + framedrop_pattern, framedrop_period); - } else if (RDI_OR_NOT_DUAL_VFE(vfe_dev, stream_info)) { - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop( - vfe_dev->vfe_base, stream_info, framedrop_pattern, - framedrop_period); - stream_info->requested_framedrop_period = framedrop_period; - } + stream_info->requested_framedrop_period = framedrop_period; } -/** - * msm_isp_check_epoch_status() - check the epock signal for framedrop - * - * @vfe_dev: The h/w on which the epoch signel is reveived - * @frame_src: The source of the epoch signal for this frame - * - * For dual vfe case and pixel stream, if both vfe's epoch signal is - * received, this function will return success. - * It will also return the vfe1 for further process - * For none dual VFE stream or none pixl source, this - * funciton will just return success. - * - * Returns 1 - epoch received is complete. - * 0 - epoch reveived is not complete. - */ -static int msm_isp_check_epoch_status(struct vfe_device **vfe_dev, - enum msm_vfe_input_src frame_src) +static int msm_isp_composite_irq(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + enum msm_isp_comp_irq_types irq) { - struct vfe_device *vfe_dev_cur = *vfe_dev; - struct vfe_device *vfe_dev_other = NULL; - uint32_t vfe_id_other = 0; - uint32_t vfe_id_cur = 0; - uint32_t epoch_mask = 0; - unsigned long flags; - int completed = 0; - - spin_lock_irqsave( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); - - if (vfe_dev_cur->is_split && - frame_src == VFE_PIX_0) { - if (vfe_dev_cur->pdev->id == ISP_VFE0) { - vfe_id_cur = ISP_VFE0; - vfe_id_other = ISP_VFE1; - } else { - vfe_id_cur = ISP_VFE1; - vfe_id_other = ISP_VFE0; - } - vfe_dev_other = vfe_dev_cur->common_data->dual_vfe_res-> - vfe_dev[vfe_id_other]; - - if (vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask & (1 << vfe_id_cur)) { - /* serious scheduling delay */ - pr_err("Missing epoch: vfe %d, epoch mask 0x%x\n", - vfe_dev_cur->pdev->id, - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask); - goto fatal; - } - - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask |= (1 << vfe_id_cur); - - epoch_mask = (1 << vfe_id_cur) | (1 << vfe_id_other); - if ((vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask & epoch_mask) == epoch_mask) { - - if (vfe_id_other == ISP_VFE0) - *vfe_dev = vfe_dev_cur; - else - *vfe_dev = vfe_dev_other; + /* interrupt recv on same vfe w/o recv on other vfe */ + if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) { + pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n", + __func__, irq, vfe_dev->pdev->id); + return -EINVAL; + } - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask &= ~epoch_mask; - completed = 1; - } - } else - completed = 1; + stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id); + if (stream_info->composite_irq[irq] != stream_info->vfe_mask) + return 1; - spin_unlock_irqrestore( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); + stream_info->composite_irq[irq] = 0; - return completed; -fatal: - spin_unlock_irqrestore( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); - /* new error event code will be added later */ - msm_isp_halt_send_error(vfe_dev_cur, ISP_EVENT_PING_PONG_MISMATCH); return 0; } - /** * msm_isp_update_framedrop_reg() - Update frame period pattern on h/w - * @vfe_dev: The h/w on which the perion pattern is updated. - * @frame_src: Input source. + * @stream_info: Stream for which update is to be performed * * If the period and pattern needs to be updated for a stream then it is * updated here. Updates happen if initial frame drop reaches 0 or burst @@ -635,47 +570,75 @@ fatal: * * Returns void */ -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) +static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info) +{ + if (stream_info->stream_type == BURST_STREAM) { + if (stream_info->runtime_num_burst_capture == 0 || + (stream_info->runtime_num_burst_capture == 1 && + stream_info->activated_framedrop_period == 1)) + stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + } + + if (stream_info->undelivered_request_cnt > 0) + stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + + /* + * re-configure the period pattern, only if it's not already + * set to what we want + */ + if (stream_info->current_framedrop_period != + stream_info->requested_framedrop_period) { + msm_isp_cfg_framedrop_reg(stream_info); + } +} + +void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, + enum msm_isp_comp_irq_types irq, + struct msm_isp_timestamp *ts) { int i; - struct msm_vfe_axi_shared_data *axi_data = NULL; struct msm_vfe_axi_stream *stream_info; unsigned long flags; - - if (msm_isp_check_epoch_status(&vfe_dev, frame_src) != 1) - return; - - axi_data = &vfe_dev->axi_data; + int ret; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); + if (SRC_TO_INTF(stream_info->stream_src) != frame_src) { continue; } - stream_info = &axi_data->stream_info[i]; - if (stream_info->state != ACTIVE) + if (stream_info->state == AVAILABLE || + stream_info->state == INACTIVE) continue; spin_lock_irqsave(&stream_info->lock, flags); - if (BURST_STREAM == stream_info->stream_type) { - if (0 == stream_info->runtime_num_burst_capture) - stream_info->current_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; + ret = msm_isp_composite_irq(vfe_dev, stream_info, irq); + if (ret) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (ret < 0) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return; + } + continue; } - if (stream_info->undelivered_request_cnt > 0) - stream_info->current_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; - - /* - * re-configure the period pattern, only if it's not already - * set to what we want - */ - if (stream_info->current_framedrop_period != - stream_info->requested_framedrop_period) { - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + switch (irq) { + case MSM_ISP_COMP_IRQ_REG_UPD: + stream_info->activated_framedrop_period = + stream_info->requested_framedrop_period; + __msm_isp_axi_stream_update(stream_info, ts); + break; + case MSM_ISP_COMP_IRQ_EPOCH: + if (stream_info->state == ACTIVE) + msm_isp_update_framedrop_reg(stream_info); + break; + default: + WARN(1, "Invalid irq %d\n", irq); } spin_unlock_irqrestore(&stream_info->lock, flags); } @@ -708,7 +671,7 @@ void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, stream_info->frame_skip_pattern); } - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + msm_isp_cfg_framedrop_reg(stream_info); ISP_DBG("%s: init frame drop: %d\n", __func__, stream_info->init_frame_drop); ISP_DBG("%s: num_burst_capture: %d\n", __func__, @@ -741,10 +704,9 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; } for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - struct msm_vfe_axi_stream *temp_stream_info; - - stream_info = &axi_data->stream_info[i]; - stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + stream_info = msm_isp_get_stream_common_data(vfe_dev, + i); + stream_idx = HANDLE_TO_IDX(stream_info->stream_handle[0]); /* * Process drop only if controllable ACTIVE PIX stream && @@ -761,10 +723,8 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, if (stream_info->controllable_output && !vfe_dev->reg_updated) { - temp_stream_info = - msm_isp_get_controllable_stream(vfe_dev, - stream_info); - if (temp_stream_info->undelivered_request_cnt) { + if (stream_info->undelivered_request_cnt) { + pr_err("Drop frame no reg update\n"); if (msm_isp_drop_frame(vfe_dev, stream_info, ts, sof_info)) { pr_err("drop frame failed\n"); @@ -991,7 +951,7 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, spin_unlock_irqrestore(&vfe_dev->common_data-> common_dev_data_lock, flags); } else { - if (frame_src == VFE_PIX_0) { + if (frame_src <= VFE_RAW_2) { msm_isp_check_for_output_error(vfe_dev, ts, &event_data.u.sof_info); } @@ -1010,7 +970,7 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, /** * msm_isp_calculate_framedrop() - Setup frame period and pattern - * @axi_data: Structure describing the h/w streams. + * @vfe_dev: vfe device. * @stream_cfg_cmd: User space input parameter for perion/pattern. * * Initialize the h/w stream framedrop period and pattern sent @@ -1018,16 +978,16 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, * * Returns 0 on success else error code. */ -int msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, +static int msm_isp_calculate_framedrop( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) { uint32_t framedrop_period = 0; struct msm_vfe_axi_stream *stream_info = NULL; if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < VFE_AXI_SRC_MAX) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); } else { pr_err("%s: Invalid stream handle", __func__); return -EINVAL; @@ -1059,26 +1019,36 @@ int msm_isp_calculate_framedrop( return 0; } -void msm_isp_calculate_bandwidth( - struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_calculate_bandwidth( struct msm_vfe_axi_stream *stream_info) { int bpp = 0; + struct msm_vfe_axi_shared_data *axi_data; + int i; + if (stream_info->stream_src < RDI_INTF_0) { - stream_info->bandwidth = - (axi_data->src_info[VFE_PIX_0].pixel_clock / - axi_data->src_info[VFE_PIX_0].width) * - stream_info->max_width; - stream_info->bandwidth = (unsigned long)stream_info->bandwidth * - stream_info->format_factor / ISP_Q2; + for (i = 0; i < stream_info->num_isp; i++) { + axi_data = &stream_info->vfe_dev[i]->axi_data; + stream_info->bandwidth[i] = + (axi_data->src_info[VFE_PIX_0].pixel_clock / + axi_data->src_info[VFE_PIX_0].width) * + stream_info->max_width[i]; + stream_info->bandwidth[i] = + (unsigned long)stream_info->bandwidth[i] * + stream_info->format_factor / ISP_Q2; + } } else { int rdi = SRC_TO_INTF(stream_info->stream_src); bpp = msm_isp_get_bit_per_pixel(stream_info->output_format); - if (rdi < VFE_SRC_MAX) - stream_info->bandwidth = + if (rdi < VFE_SRC_MAX) { + for (i = 0; i < stream_info->num_isp; i++) { + axi_data = &stream_info->vfe_dev[i]->axi_data; + stream_info->bandwidth[i] = (axi_data->src_info[rdi].pixel_clock / 8) * bpp; - else + } + } else { pr_err("%s: Invalid rdi interface\n", __func__); + } } } @@ -1133,37 +1103,40 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) uint32_t io_format = 0; struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg; struct msm_vfe_axi_stream *stream_info; + unsigned long flags; + + if (stream_cfg_cmd->stream_src >= VFE_AXI_SRC_MAX) { + pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, + stream_cfg_cmd->stream_src); + return -EINVAL; + } + stream_info = msm_isp_get_stream_common_data(vfe_dev, + stream_cfg_cmd->stream_src); + + spin_lock_irqsave(&stream_info->lock, flags); rc = msm_isp_axi_create_stream(vfe_dev, - &vfe_dev->axi_data, stream_cfg_cmd); + &vfe_dev->axi_data, stream_cfg_cmd, stream_info); if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: create stream failed\n", __func__); return rc; } rc = msm_isp_validate_axi_request( - &vfe_dev->axi_data, stream_cfg_cmd); + vfe_dev, stream_info, stream_cfg_cmd); if (rc) { + msm_isp_axi_destroy_stream(vfe_dev, stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: Request validation failed\n", __func__); - if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < - VFE_AXI_SRC_MAX) - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); return rc; } - stream_info = &vfe_dev->axi_data. - stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - if (!stream_info) { - pr_err("%s: can not find stream handle %x\n", __func__, - stream_cfg_cmd->axi_stream_handle); - return -EINVAL; - } stream_info->memory_input = stream_cfg_cmd->memory_input; vfe_dev->reg_update_requested &= ~(BIT(SRC_TO_INTF(stream_info->stream_src))); - msm_isp_axi_reserve_wm(vfe_dev, &vfe_dev->axi_data, stream_info); + msm_isp_axi_reserve_wm(vfe_dev, stream_info); if (stream_info->stream_src < RDI_INTF_0) { io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format; @@ -1183,16 +1156,67 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) goto done; } } - rc = msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); - if (rc) - goto done; + + if (!stream_info->controllable_output) { + /* + * check that the parameters passed from second vfe is same + * as first vfe, do this only for non controllable stream + * right now because user driver has bug where it sends + * mismatch info for controllable streams + */ + if (stream_info->num_isp > 1) { + if (stream_cfg_cmd->init_frame_drop != + stream_info->init_frame_drop) { + pr_err("%s: stream %d init drop mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_info->init_frame_drop, + stream_cfg_cmd->init_frame_drop); + rc = -EINVAL; + } + if (stream_cfg_cmd->frame_skip_pattern != + stream_info->frame_skip_pattern) { + pr_err("%s: stream %d skip pattern mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_info->frame_skip_pattern, + stream_cfg_cmd->frame_skip_pattern); + rc = -EINVAL; + } + if (stream_info->stream_type == CONTINUOUS_STREAM && + stream_cfg_cmd->burst_count > 0) { + pr_err("%s: stream %d stream type mismatch\n", + __func__, stream_info->stream_id); + rc = -EINVAL; + } + if (stream_info->stream_type == BURST_STREAM && + stream_info->num_burst_capture != + stream_cfg_cmd->burst_count) { + pr_err("%s: stream %d stream burst count mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_info->num_burst_capture, + stream_cfg_cmd->burst_count); + rc = -EINVAL; + } + } else { + rc = msm_isp_calculate_framedrop(vfe_dev, + stream_cfg_cmd); + } + if (rc) + goto done; + } else { + stream_info->stream_type = BURST_STREAM; + stream_info->num_burst_capture = 0; + stream_info->frame_skip_pattern = NO_SKIP; + stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop; + stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + } if (stream_cfg_cmd->vt_enable && !vfe_dev->vt_enable) { vfe_dev->vt_enable = stream_cfg_cmd->vt_enable; msm_isp_start_avtimer(); } + if (stream_info->num_planes > 1) - msm_isp_axi_reserve_comp_mask( - &vfe_dev->axi_data, stream_info); + msm_isp_axi_reserve_comp_mask(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { vfe_dev->hw_info->vfe_ops.axi_ops. @@ -1201,16 +1225,17 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) vfe_dev->hw_info->vfe_ops.axi_ops. cfg_wm_xbar_reg(vfe_dev, stream_info, i); } - /* initialize the WM ping pong with scratch buffer */ - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PONG_FLAG); - + if (stream_info->state == INACTIVE) { + /* initialize the WM ping pong with scratch buffer */ + msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); + } done: if (rc) { - msm_isp_axi_free_wm(&vfe_dev->axi_data, stream_info); - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); + msm_isp_axi_free_wm(vfe_dev, stream_info); + msm_isp_axi_destroy_stream(vfe_dev, stream_info); } + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; } @@ -1218,26 +1243,42 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, i; struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_stream_cfg_cmd stream_cfg; - + int vfe_idx; + unsigned long flags; if (HANDLE_TO_IDX(stream_release_cmd->stream_handle) >= VFE_AXI_SRC_MAX) { pr_err("%s: Invalid stream handle\n", __func__); return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_release_cmd->stream_handle)]; - if (stream_info->state == AVAILABLE) { - pr_err("%s: Stream already released\n", __func__); + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + + spin_lock_irqsave(&stream_info->lock, flags); + + vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info); + if (vfe_idx == -ENOTTY || + stream_release_cmd->stream_handle != + stream_info->stream_handle[vfe_idx]) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Invalid stream %p handle %x/%x vfe_idx %d vfe_dev %d num_isp %d\n", + __func__, stream_info, + stream_release_cmd->stream_handle, + vfe_idx != -ENOTTY ? + stream_info->stream_handle[vfe_idx] : 0, vfe_idx, + vfe_dev->pdev->id, stream_info->num_isp); return -EINVAL; - } else if (stream_info->state != INACTIVE) { + } + + if (stream_info->state != INACTIVE && stream_info->state != AVAILABLE) { stream_cfg.cmd = STOP_STREAM; stream_cfg.num_streams = 1; stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle; + spin_unlock_irqrestore(&stream_info->lock, flags); msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg); + spin_lock_irqsave(&stream_info->lock, flags); } for (i = 0; i < stream_info->num_planes; i++) { @@ -1249,33 +1290,75 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) } if (stream_info->num_planes > 1) - msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); + msm_isp_axi_free_comp_mask(vfe_dev, stream_info); vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); - msm_isp_axi_free_wm(axi_data, stream_info); + msm_isp_axi_free_wm(vfe_dev, stream_info); - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + msm_isp_axi_destroy_stream(vfe_dev, stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; } -static int msm_isp_axi_stream_enable_cfg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, int32_t dual_vfe_sync) +void msm_isp_release_all_axi_stream(struct vfe_device *vfe_dev) { - int i, vfe_id = 0, enable_wm = 0; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; + struct msm_vfe_axi_stream_release_cmd + stream_release_cmd[VFE_AXI_SRC_MAX]; + struct msm_vfe_axi_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_axi_stream *stream_info; + int i; + int vfe_idx; + int num_stream = 0; + unsigned long flags; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream_idx", __func__); - goto error; + stream_cfg_cmd.cmd = STOP_STREAM; + stream_cfg_cmd.num_streams = 0; + + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); + spin_lock_irqsave(&stream_info->lock, flags); + vfe_idx = msm_isp_get_vfe_idx_for_stream_user( + vfe_dev, stream_info); + if (-ENOTTY == vfe_idx) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_release_cmd[num_stream++].stream_handle = + stream_info->stream_handle[vfe_idx]; + if (stream_info->state == INACTIVE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_cfg_cmd.stream_handle[ + stream_cfg_cmd.num_streams] = + stream_info->stream_handle[vfe_idx]; + stream_cfg_cmd.num_streams++; + spin_unlock_irqrestore(&stream_info->lock, flags); } + if (stream_cfg_cmd.num_streams) + msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg_cmd); - if (stream_info->state == INACTIVE) - goto error; + for (i = 0; i < num_stream; i++) + msm_isp_release_axi_stream(vfe_dev, &stream_release_cmd[i]); +} + +static void msm_isp_axi_stream_enable_cfg( + struct msm_vfe_axi_stream *stream_info) +{ + int enable_wm = 0; + struct vfe_device *vfe_dev; + struct msm_vfe_axi_shared_data *axi_data; + uint32_t stream_idx = stream_info->stream_src; + int k; + int i; + + WARN_ON(stream_idx >= VFE_AXI_SRC_MAX); + + WARN_ON(stream_info->state != START_PENDING && + stream_info->state != RESUME_PENDING && + stream_info->state != STOP_PENDING && + stream_info->state != PAUSE_PENDING); if (stream_info->state == START_PENDING || stream_info->state == RESUME_PENDING) { @@ -1283,50 +1366,24 @@ static int msm_isp_axi_stream_enable_cfg( } else { enable_wm = 0; } - for (i = 0; i < stream_info->num_planes; i++) { - /* - * In case when sensor is streaming, use dual vfe sync mode - * to enable wm together and avoid split. - */ - if ((stream_info->stream_src < RDI_INTF_0) && - vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1 && - dual_vfe_sync) { - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_base[ISP_VFE0] || - !dual_vfe_res->axi_data[ISP_VFE0] || - !dual_vfe_res->vfe_base[ISP_VFE1] || - !dual_vfe_res->axi_data[ISP_VFE1]) { - pr_err("%s:%d failed vfe0 %pK %pK vfe %pK %pK\n", - __func__, __LINE__, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->axi_data[ISP_VFE0], - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->axi_data[ISP_VFE1]); - goto error; - } - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - vfe_dev->hw_info->vfe_ops.axi_ops. - enable_wm(dual_vfe_res->vfe_base[vfe_id], - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx].wm[i], - enable_wm); - } - } else if (!vfe_dev->is_split || - (stream_info->stream_src >= RDI_INTF_0 && - stream_info->stream_src <= RDI_INTF_2) || - !dual_vfe_sync) { - vfe_dev->hw_info->vfe_ops.axi_ops. - enable_wm(vfe_dev->vfe_base, stream_info->wm[i], - enable_wm); - } - if (!enable_wm) { - /* Issue a reg update for Raw Snapshot Case + + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + axi_data = &vfe_dev->axi_data; + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops.enable_wm( + vfe_dev->vfe_base, + stream_info->wm[k][i], enable_wm); + if (enable_wm) + continue; + /* + * Issue a reg update for Raw Snapshot Case * since we dont have reg update ack - */ + */ if (vfe_dev->axi_data.src_info[VFE_PIX_0]. raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { if (stream_info->stream_src == CAMIF_RAW || stream_info->stream_src == IDEAL_RAW) { vfe_dev->hw_info->vfe_ops.core_ops. @@ -1335,70 +1392,103 @@ static int msm_isp_axi_stream_enable_cfg( } } } + if (stream_info->state == START_PENDING) + axi_data->num_active_stream++; + else if (stream_info->state == STOP_PENDING) + axi_data->num_active_stream--; + } +} + +static void __msm_isp_axi_stream_update( + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts) +{ + int j; + int intf = SRC_TO_INTF(stream_info->stream_src); + struct vfe_device *vfe_dev; + int k; + + switch (stream_info->state) { + case UPDATING: + stream_info->state = ACTIVE; + break; + case STOP_PENDING: + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = STOPPING; + break; + case START_PENDING: + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = STARTING; + break; + case STOPPING: + stream_info->state = INACTIVE; + for (k = 0; k < MSM_ISP_COMP_IRQ_MAX; k++) + stream_info->composite_irq[k] = 0; + complete_all(&stream_info->inactive_comp); + break; + case STARTING: + stream_info->state = ACTIVE; + complete_all(&stream_info->active_comp); + break; + case PAUSING: + stream_info->state = PAUSED; + msm_isp_reload_ping_pong_offset(stream_info); + for (j = 0; j < stream_info->num_planes; j++) { + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + } + } + stream_info->state = RESUME_PENDING; + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = RESUMING; + break; + case RESUMING: + stream_info->runtime_output_format = stream_info->output_format; + stream_info->state = ACTIVE; + complete_all(&stream_info->active_comp); + for (j = 0; j < stream_info->num_isp; j++) { + /* notify that all streams have been updated */ + msm_isp_notify(stream_info->vfe_dev[j], + ISP_EVENT_STREAM_UPDATE_DONE, intf, ts); + atomic_set(&stream_info->vfe_dev[j]-> + axi_data.axi_cfg_update[intf], 0); + } + stream_info->update_vfe_mask = 0; + break; + default: + break; } - if (stream_info->state == START_PENDING) - axi_data->num_active_stream++; - else if (stream_info->state == STOP_PENDING) - axi_data->num_active_stream--; - return 0; -error: - return -EINVAL; } void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) + enum msm_vfe_input_src frame_src, + struct msm_isp_timestamp *ts) { int i; unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); + if (SRC_TO_INTF(stream_info->stream_src) != frame_src) { ISP_DBG("%s stream_src %d frame_src %d\n", __func__, SRC_TO_INTF( - axi_data->stream_info[i].stream_src), + stream_info->stream_src), frame_src); continue; } - if (axi_data->stream_info[i].state == UPDATING) - axi_data->stream_info[i].state = ACTIVE; - else if (axi_data->stream_info[i].state == START_PENDING || - axi_data->stream_info[i].state == STOP_PENDING) { - msm_isp_axi_stream_enable_cfg( - vfe_dev, &axi_data->stream_info[i], - axi_data->stream_info[i].state == - START_PENDING ? 1 : 0); - axi_data->stream_info[i].state = - axi_data->stream_info[i].state == - START_PENDING ? STARTING : STOPPING; - } else if (axi_data->stream_info[i].state == STARTING || - axi_data->stream_info[i].state == STOPPING) { - axi_data->stream_info[i].state = - axi_data->stream_info[i].state == STARTING ? - ACTIVE : INACTIVE; - } - } - - spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); - if (vfe_dev->axi_data.stream_update[frame_src]) { - vfe_dev->axi_data.stream_update[frame_src]--; - } - spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); - - if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF || - (vfe_dev->axi_data.pipeline_update == - DISABLE_CAMIF_IMMEDIATELY)) { - vfe_dev->hw_info->vfe_ops.stats_ops. - enable_module(vfe_dev, 0xFF, 0); - vfe_dev->axi_data.pipeline_update = NO_UPDATE; + if (stream_info->state == AVAILABLE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + __msm_isp_axi_stream_update(stream_info, ts); + spin_unlock_irqrestore(&stream_info->lock, flags); } - - if (vfe_dev->axi_data.stream_update[frame_src] == 0) - complete(&vfe_dev->stream_config_complete); } -static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, +static void msm_isp_reload_ping_pong_offset( struct msm_vfe_axi_stream *stream_info) { int i, j; @@ -1406,120 +1496,70 @@ static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, struct msm_isp_buffer *buf; int32_t buf_size_byte = 0; int32_t word_per_line = 0; + int k; + struct vfe_device *vfe_dev; + + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + if (!buf) + continue; - for (i = 0; i < 2; i++) { - buf = stream_info->buf[i]; - if (!buf) - continue; - - bit = i ? 0 : 1; + bit = i ? 0 : 1; - for (j = 0; j < stream_info->num_planes; j++) { - word_per_line = msm_isp_cal_word_per_line( + for (j = 0; j < stream_info->num_planes; j++) { + word_per_line = msm_isp_cal_word_per_line( stream_info->output_format, stream_info-> - plane_cfg[j].output_stride); - if (word_per_line < 0) { - /* 0 means no prefetch*/ - word_per_line = 0; - buf_size_byte = 0; - } else { - buf_size_byte = (word_per_line * 8 * - stream_info->plane_cfg[j]. + plane_cfg[k][j].output_stride); + if (word_per_line < 0) { + /* 0 means no prefetch*/ + word_per_line = 0; + buf_size_byte = 0; + } else { + buf_size_byte = (word_per_line * 8 * + stream_info->plane_cfg[k][j]. output_scan_lines) - stream_info-> - plane_cfg[j].plane_addr_offset; - } - - vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( - vfe_dev->vfe_base, stream_info->wm[j], bit, - buf->mapped_info[j].paddr + - stream_info->plane_cfg[j].plane_addr_offset, - buf_size_byte); - } - } -} - -void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) -{ - int i, j; - uint32_t update_state; - unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - int num_stream = 0; + plane_cfg[k][j].plane_addr_offset; + } - spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags); - for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != - frame_src) { - continue; - } - num_stream++; - stream_info = &axi_data->stream_info[i]; - if ((stream_info->stream_type == BURST_STREAM && - !stream_info->controllable_output) || - stream_info->state == AVAILABLE) - continue; - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state == PAUSING) { - /*AXI Stopped, apply update*/ - stream_info->state = PAUSED; - msm_isp_reload_ping_pong_offset(vfe_dev, stream_info); - for (j = 0; j < stream_info->num_planes; j++) vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, j); - /*Resume AXI*/ - stream_info->state = RESUME_PENDING; - if (vfe_dev->is_split) { - msm_isp_update_dual_HW_axi(vfe_dev, - stream_info); - } else { - msm_isp_axi_stream_enable_cfg( - vfe_dev, - &axi_data->stream_info[i], 1); - stream_info->state = RESUMING; + update_ping_pong_addr( + vfe_dev->vfe_base, + stream_info->wm[k][j], + bit, + buf->mapped_info[j].paddr + + stream_info->plane_cfg[k][j]. + plane_addr_offset, + buf_size_byte); } - } else if (stream_info->state == RESUMING) { - stream_info->runtime_output_format = - stream_info->output_format; - stream_info->state = ACTIVE; } - spin_unlock_irqrestore(&stream_info->lock, flags); } - spin_unlock_irqrestore(&vfe_dev->common_data->common_dev_data_lock, - flags); - if (num_stream) - update_state = atomic_dec_return( - &axi_data->axi_cfg_update[frame_src]); } static int msm_isp_update_deliver_count(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit) { - struct msm_vfe_axi_stream *temp_stream_info; int rc = 0; if (!stream_info->controllable_output) goto done; - temp_stream_info = - msm_isp_get_controllable_stream(vfe_dev, stream_info); - - if (!temp_stream_info->undelivered_request_cnt) { + if (!stream_info->undelivered_request_cnt) { pr_err_ratelimited("%s:%d error undelivered_request_cnt 0\n", __func__, __LINE__); rc = -EINVAL; goto done; } else { - temp_stream_info->undelivered_request_cnt--; - if (pingpong_bit != temp_stream_info->sw_ping_pong_bit) { + stream_info->undelivered_request_cnt--; + if (pingpong_bit != stream_info->sw_ping_pong_bit) { pr_err("%s:%d ping pong bit actual %d sw %d\n", __func__, __LINE__, pingpong_bit, - temp_stream_info->sw_ping_pong_bit); + stream_info->sw_ping_pong_bit); rc = -EINVAL; goto done; } - temp_stream_info->sw_ping_pong_bit ^= 1; + stream_info->sw_ping_pong_bit ^= 1; } done: return rc; @@ -1527,7 +1567,6 @@ done: void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event) { - uint32_t i = 0; struct msm_isp_event_data error_event; struct msm_vfe_axi_halt_cmd halt_cmd; @@ -1545,10 +1584,6 @@ void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event) /* heavy spin lock in axi halt, avoid spin lock outside. */ msm_isp_axi_halt(vfe_dev, &halt_cmd); - for (i = 0; i < VFE_AXI_SRC_MAX; i++) - vfe_dev->axi_data.stream_info[i].state = - INACTIVE; - error_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; @@ -1562,31 +1597,49 @@ int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev, struct msm_isp_buffer *buf = NULL; uint32_t pingpong_bit; struct msm_vfe_axi_stream *stream_info = NULL; + int k; for (j = 0; j < VFE_AXI_SRC_MAX; j++) { - stream_info = &vfe_dev->axi_data.stream_info[j]; - if (stream_info->state == INACTIVE) + stream_info = msm_isp_get_stream_common_data(vfe_dev, j); + if (stream_info->state == INACTIVE || + stream_info->state == AVAILABLE) continue; for (pingpong_bit = 0; pingpong_bit < 2; pingpong_bit++) { + dma_addr_t temp; + + buf = stream_info->buf[pingpong_bit]; + if (buf == NULL) { + pr_err("%s: buf NULL for stream %x num_isp %d\n", + __func__, + stream_info->stream_src, + stream_info->num_isp); + continue; + } + temp = buf->mapped_info[0].paddr + + buf->mapped_info[0].len; + pr_err("%s: stream %x ping bit %d uses buffer %pa-%pa, num_isp %d\n", + __func__, stream_info->stream_src, + pingpong_bit, + &buf->mapped_info[0].paddr, &temp, + stream_info->num_isp); + for (i = 0; i < stream_info->num_planes; i++) { - buf = stream_info->buf[pingpong_bit]; - if (buf == NULL) { - pr_err("%s: buf NULL\n", __func__); - continue; - } - pr_debug("%s: stream_id %x ping-pong %d plane %d start_addr %lu addr_offset %x len %zx stride %d scanline %d\n" + for (k = 0; k < stream_info->num_isp; k++) { + pr_debug( + "%s: stream_id %x ping-pong %d plane %d start_addr %lu addr_offset %x len %zx stride %d scanline %d\n" , __func__, stream_info->stream_id, pingpong_bit, i, (unsigned long) buf->mapped_info[i].paddr, stream_info-> - plane_cfg[i].plane_addr_offset, + plane_cfg[k][i].plane_addr_offset, buf->mapped_info[i].len, stream_info-> - plane_cfg[i].output_stride, + plane_cfg[k][i].output_stride, stream_info-> - plane_cfg[i].output_scan_lines + plane_cfg[k][i].output_scan_lines ); + } } } } @@ -1601,36 +1654,35 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( int rc = 0; uint32_t bufq_handle = 0; struct msm_isp_buffer *buf = NULL; - struct msm_vfe_axi_stream *temp_stream_info = NULL; struct msm_vfe_frame_request_queue *queue_req; + uint32_t buf_index = MSM_ISP_INVALID_BUF_INDEX; if (!stream_info->controllable_output) { bufq_handle = stream_info->bufq_handle [VFE_BUF_QUEUE_DEFAULT]; } else { - temp_stream_info = msm_isp_get_controllable_stream( - vfe_dev, stream_info); queue_req = list_first_entry_or_null( - &temp_stream_info->request_q, + &stream_info->request_q, struct msm_vfe_frame_request_queue, list); if (!queue_req) return buf; - bufq_handle = temp_stream_info-> + bufq_handle = stream_info-> bufq_handle[queue_req->buff_queue_id]; if (!bufq_handle || - temp_stream_info->request_q_cnt <= 0) { + stream_info->request_q_cnt <= 0) { pr_err_ratelimited("%s: Drop request. Shared stream is stopped.\n", __func__); return buf; } + buf_index = queue_req->buf_index; queue_req->cmd_used = 0; list_del(&queue_req->list); - temp_stream_info->request_q_cnt--; + stream_info->request_q_cnt--; } rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, bufq_handle, &buf); + vfe_dev->pdev->id, bufq_handle, buf_index, &buf); if (rc == -EFAULT) { msm_isp_halt_send_error(vfe_dev, @@ -1649,144 +1701,74 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( return buf; } -static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, - int scratch) +static int msm_isp_cfg_ping_pong_address( + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) { int i; - struct msm_isp_buffer *buf = NULL; + int j; uint32_t pingpong_bit; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + struct vfe_device *vfe_dev = stream_info->vfe_dev[0]; uint32_t buffer_size_byte = 0; int32_t word_per_line = 0; dma_addr_t paddr; - struct dual_vfe_resource *dual_vfe_res = NULL; - uint32_t vfe_id = 0; - unsigned long flags; + struct msm_isp_buffer *buf = NULL; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream_idx", __func__); - return -EINVAL; - } - /* make sure that streams are in right state */ - if ((stream_info->stream_src < RDI_INTF_0) && - vfe_dev->is_split) { - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_base[ISP_VFE0] || - !dual_vfe_res->axi_data[ISP_VFE0] || - !dual_vfe_res->vfe_base[ISP_VFE1] || - !dual_vfe_res->axi_data[ISP_VFE1]) { - pr_err("%s:%d failed vfe0 %pK %pK vfe %pK %pK\n", - __func__, __LINE__, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->axi_data[ISP_VFE0], - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->axi_data[ISP_VFE1]); - return -EINVAL; - } - } else if (!vfe_dev->is_split || - (stream_info->stream_src >= RDI_INTF_0 && - stream_info->stream_src <= RDI_INTF_2)) { - dual_vfe_res = NULL; - } else { - pr_err("%s: Error! Should not reach this case is_split %d stream_src %d\n", - __func__, vfe_dev->is_split, stream_info->stream_src); - msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); + /* Isolate pingpong_bit from pingpong_status */ + pingpong_bit = ((pingpong_status >> + stream_info->wm[0][0]) & 0x1); + + /* return if buffer already present */ + if (stream_info->buf[!pingpong_bit]) { + pr_err("stream %x buffer already set for pingpong %d\n", + stream_info->stream_src, pingpong_bit); return 0; } - if (!scratch) - buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); + buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); - /* Isolate pingpong_bit from pingpong_status */ - pingpong_bit = ((pingpong_status >> - stream_info->wm[0]) & 0x1); + if (!buf) { + msm_isp_cfg_stream_scratch(stream_info, pingpong_status); + return 0; + } for (i = 0; i < stream_info->num_planes; i++) { - if (buf) { - word_per_line = msm_isp_cal_word_per_line( - stream_info->output_format, stream_info-> - plane_cfg[i].output_stride); + paddr = buf->mapped_info[i].paddr; + ISP_DBG( + "%s: vfe %d config buf %d to pingpong %d stream %x\n", + __func__, vfe_dev->pdev->id, + buf->buf_idx, !pingpong_bit, + stream_info->stream_id); + for (j = 0; j < stream_info->num_isp; j++) { + vfe_dev = stream_info->vfe_dev[j]; + word_per_line = + msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[j][i].output_stride); if (word_per_line < 0) { /* 0 means no prefetch*/ word_per_line = 0; buffer_size_byte = 0; } else { - buffer_size_byte = (word_per_line * 8 * - stream_info->plane_cfg[i]. - output_scan_lines) - stream_info-> - plane_cfg[i].plane_addr_offset; + buffer_size_byte = + (word_per_line * 8 * + stream_info->plane_cfg[j][i]. + output_scan_lines) - + stream_info->plane_cfg[j][i]. + plane_addr_offset; } - - paddr = buf->mapped_info[i].paddr; - ISP_DBG( - "%s: vfe %d config buf %d to pingpong %d stream %x\n", - __func__, vfe_dev->pdev->id, - buf->buf_idx, !pingpong_bit, - stream_info->stream_id); - } - - if (dual_vfe_res) { - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - if (vfe_id != vfe_dev->pdev->id) - spin_lock_irqsave( - &dual_vfe_res-> - axi_data[vfe_id]-> - stream_info[stream_idx]. - lock, flags); - - if (buf) - vfe_dev->hw_info->vfe_ops.axi_ops. - update_ping_pong_addr( - dual_vfe_res->vfe_base[vfe_id], - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx].wm[i], - pingpong_bit, paddr + - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx]. - plane_cfg[i].plane_addr_offset, - buffer_size_byte); - else - msm_isp_cfg_stream_scratch( - dual_vfe_res->vfe_dev[vfe_id], - &(dual_vfe_res->axi_data - [vfe_id]-> - stream_info[stream_idx]), - pingpong_status); - - if (i == 0) { - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx]. - buf[!pingpong_bit] = - buf; - } - if (vfe_id != vfe_dev->pdev->id) - spin_unlock_irqrestore( - &dual_vfe_res-> - axi_data[vfe_id]-> - stream_info[stream_idx]. - lock, flags); - } - } else { - if (buf) - vfe_dev->hw_info->vfe_ops.axi_ops. + vfe_dev->hw_info->vfe_ops.axi_ops. update_ping_pong_addr( - vfe_dev->vfe_base, stream_info->wm[i], + vfe_dev->vfe_base, + stream_info->wm[j][i], pingpong_bit, paddr + - stream_info->plane_cfg[i]. - plane_addr_offset, + stream_info->plane_cfg[j][i]. + plane_addr_offset, buffer_size_byte); - else - msm_isp_cfg_stream_scratch(vfe_dev, - stream_info, pingpong_status); - if (0 == i) - stream_info->buf[!pingpong_bit] = buf; } - if (0 == i && buf) - buf->pingpong_bit = !pingpong_bit; } - + stream_info->buf[!pingpong_bit] = buf; + buf->pingpong_bit = !pingpong_bit; return 0; } @@ -1803,10 +1785,14 @@ static void msm_isp_handle_done_buf_frame_id_mismatch( vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; error_event.u.error_info.err_type = ISP_ERROR_FRAME_ID_MISMATCH; - ret = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx, time_stamp, - frame_id, - stream_info->runtime_output_format); + if (stream_info->buf_divert) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + else + ret = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, time_stamp, + frame_id, + stream_info->runtime_output_format); if (ret == -EFAULT) { msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); return; @@ -1825,7 +1811,7 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, int rc; unsigned long flags; struct msm_isp_event_data buf_event; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + uint32_t stream_idx = stream_info->stream_src; uint32_t buf_src; uint8_t drop_frame = 0; struct msm_isp_bufq *bufq = NULL; @@ -1875,11 +1861,16 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, buf->buf_debug.put_state_last] = MSM_ISP_BUFFER_STATE_DROP_SKIP; buf->buf_debug.put_state_last ^= 1; - rc = vfe_dev->buf_mgr->ops->buf_done( - vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx, - time_stamp, frame_id, - stream_info->runtime_output_format); + if (stream_info->buf_divert) + vfe_dev->buf_mgr->ops->put_buf( + vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + else + rc = vfe_dev->buf_mgr->ops->buf_done( + vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id, + stream_info->runtime_output_format); if (rc == -EFAULT) { msm_isp_halt_send_error(vfe_dev, @@ -1918,6 +1909,11 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, return -EINVAL; } + /* divert native buffers */ + vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, time_stamp, + frame_id); + if ((bufq != NULL) && bufq->buf_type == ISP_SHARE_BUF) msm_isp_send_event(vfe_dev->common_data-> dual_vfe_res->vfe_dev[ISP_VFE1], @@ -1957,6 +1953,7 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, unsigned long flags; struct msm_isp_bufq *bufq = NULL; uint32_t pingpong_bit; + int vfe_idx; if (!vfe_dev || !stream_info || !ts || !sof_info) { pr_err("%s %d vfe_dev %pK stream_info %pK ts %pK op_info %pK\n", @@ -1964,11 +1961,14 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, sof_info); return -EINVAL; } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + pingpong_status = ~vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev); spin_lock_irqsave(&stream_info->lock, flags); - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + pingpong_bit = + (~(pingpong_status >> stream_info->wm[vfe_idx][0]) & 0x1); done_buf = stream_info->buf[pingpong_bit]; if (done_buf) { bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr, @@ -1994,93 +1994,149 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, return 0; } -static void msm_isp_get_camif_update_state_and_halt( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state *camif_update, - int *halt) +/** + * msm_isp_input_disable() - Disable the input for given vfe + * @vfe_dev: The vfe device whose input is to be disabled + * + * Returns - void + * + * If stream count on an input line is 0 then disable the input + */ +static void msm_isp_input_disable(struct vfe_device *vfe_dev) { - int i; - struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt; - cur_pix_stream_cnt = - axi_data->src_info[VFE_PIX_0].pix_stream_count + - axi_data->src_info[VFE_PIX_0].raw_stream_count; - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src < RDI_INTF_0) - pix_stream_cnt++; - } + int ext_read = + (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); + int stream_count; + int total_stream_count = 0; + int i; - if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams - && (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) - *halt = 1; - else - *halt = 0; - - if ((pix_stream_cnt) && - (axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) { - if (cur_pix_stream_cnt == 0 && pix_stream_cnt && - stream_cfg_cmd->cmd == START_STREAM) - *camif_update = ENABLE_CAMIF; - else if (cur_pix_stream_cnt && - (cur_pix_stream_cnt - pix_stream_cnt) == 0 && - (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { - if (*halt) - *camif_update = DISABLE_CAMIF_IMMEDIATELY; - else - *camif_update = DISABLE_CAMIF; - } + for (i = 0; i < VFE_SRC_MAX; i++) + total_stream_count += axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + + for (i = 0; i < VFE_SRC_MAX; i++) { + stream_count = axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + if (stream_count) + continue; + if (axi_data->src_info[i].active == 0) + continue; + /* deactivate the input line */ + axi_data->src_info[i].active = 0; + + if (i != VFE_PIX_0 || ext_read) + continue; + /* halt camif */ + if (total_stream_count == 0) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, + DISABLE_CAMIF_IMMEDIATELY); else - *camif_update = NO_UPDATE; - } else - *camif_update = NO_UPDATE; + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); + } + + /* halt and reset hardware if all streams are disabled */ + if (total_stream_count == 0) { + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1); + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + + } } -static void msm_isp_update_camif_output_count( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +/** + * msm_isp_input_enable() - Enable the input for given vfe + * @vfe_dev: The vfe device whose input is to be enabled + * + * Returns - void + * + * Enable inout line if it is not enabled + */ +static void msm_isp_input_enable(struct vfe_device *vfe_dev, + int sync_frame_id_src) { - int i; - struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int ext_read = + (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); + int stream_count; + int i; - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return; + for (i = 0; i < VFE_SRC_MAX; i++) { + stream_count = axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + if (stream_count == 0) + continue; + if (axi_data->src_info[i].active) + continue; + /* activate the input since it is deactivated */ + axi_data->src_info[i].frame_id = 0; + axi_data->src_info[i].active = 1; + if (i >= VFE_RAW_0 && sync_frame_id_src) { + /* + * Incase PIX and RDI streams are part + * of same session, this will ensure + * RDI stream will have same frame id + * as of PIX stream + */ + axi_data->src_info[i].frame_id = + axi_data->src_info[VFE_PIX_0].frame_id; } - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src >= RDI_INTF_0) + if (i != VFE_PIX_0 || ext_read) continue; - if (stream_info->stream_src == PIX_ENCODER || - stream_info->stream_src == PIX_VIEWFINDER || - stream_info->stream_src == PIX_VIDEO || - stream_info->stream_src == IDEAL_RAW) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count++; + /* for camif input the camif needs enabling */ + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, ENABLE_CAMIF); + } +} + +/** + * msm_isp_update_intf_stream_cnt() - Update the stream count in axi interface + * @stream_info: The stream that is either being enabled/disabled + * @enable: 0 means stream is being disabled, else enabled + * + * Returns - void + */ +static void msm_isp_update_intf_stream_cnt( + struct msm_vfe_axi_stream *stream_info, + int enable) +{ + int i; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case PIX_VIDEO: + case IDEAL_RAW: + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + for (i = 0; i < stream_info->num_isp; i++) { + if (enable) + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. + stream_count++; else - vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count--; - } else if (stream_info->stream_src == CAMIF_RAW) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_PIX_0]. + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. + stream_count--; + } + break; + case CAMIF_RAW: + for (i = 0; i < stream_info->num_isp; i++) { + if (enable) + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. raw_stream_count++; else - vfe_dev->axi_data.src_info[VFE_PIX_0]. + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. raw_stream_count--; } + break; + default: + WARN(1, "Invalid steam src %d\n", stream_info->stream_src); } } @@ -2091,20 +2147,24 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) { int i, rc = 0; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint64_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; uint32_t num_pix_streams = 0; uint64_t total_bandwidth = 0; + int vfe_idx; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - stream_info = &axi_data->stream_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); if (stream_info->state == ACTIVE || stream_info->state == START_PENDING) { + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); if (stream_info->stream_src < RDI_INTF_0) { - total_pix_bandwidth += stream_info->bandwidth; + total_pix_bandwidth += + stream_info->bandwidth[vfe_idx]; num_pix_streams++; } else { - total_rdi_bandwidth += stream_info->bandwidth; + total_rdi_bandwidth += + stream_info->bandwidth[vfe_idx]; } } } @@ -2119,121 +2179,88 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) return rc; } -static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state camif_update, - uint32_t src_mask, int regUpdateCnt) -{ - int rc; - unsigned long flags; - enum msm_vfe_input_src i = 0; - spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); - - for (i = 0; i < VFE_SRC_MAX; i++) { - if (src_mask & (1 << i)) { - if (vfe_dev->axi_data.stream_update[i] > 0) { - pr_err("%s:Stream Update in progress. cnt %d\n", - __func__, - vfe_dev->axi_data.stream_update[i]); - spin_unlock_irqrestore( - &vfe_dev->shared_data_lock, flags); - return -EINVAL; - } - vfe_dev->axi_data.stream_update[i] = regUpdateCnt; - } - } - if (src_mask) { - init_completion(&vfe_dev->stream_config_complete); - vfe_dev->axi_data.pipeline_update = camif_update; - } - spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); - rc = wait_for_completion_timeout( - &vfe_dev->stream_config_complete, - msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - if (rc == 0) { - for (i = 0; i < VFE_SRC_MAX; i++) { - if (src_mask & (1 << i)) { - spin_lock_irqsave(&vfe_dev->shared_data_lock, - flags); - vfe_dev->axi_data.stream_update[i] = 0; - spin_unlock_irqrestore(&vfe_dev-> - shared_data_lock, flags); - } - } - pr_err("%s: wait timeout\n", __func__); - rc = -EBUSY; - } else { - rc = 0; - } - return rc; -} - static int msm_isp_init_stream_ping_pong_reg( - struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { int rc = 0; - if ((vfe_dev->is_split && vfe_dev->pdev->id == 1 && - stream_info->stream_src < RDI_INTF_0) || - !vfe_dev->is_split || stream_info->stream_src >= RDI_INTF_0) { - /* Set address for both PING & PONG register */ - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PING_FLAG, 0); - if (rc < 0) { - pr_err("%s: No free buffer for ping\n", - __func__); - return rc; - } - - if (stream_info->stream_type != BURST_STREAM || - stream_info->runtime_num_burst_capture > 1) - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PONG_FLAG, 0); + /* Set address for both PING & PO NG register */ + rc = msm_isp_cfg_ping_pong_address( + stream_info, VFE_PING_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", + __func__); + return rc; + } + if (stream_info->stream_type != BURST_STREAM || + stream_info->runtime_num_burst_capture > 1) + rc = msm_isp_cfg_ping_pong_address( + stream_info, VFE_PONG_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for pong\n", - __func__); - return rc; - } + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", + __func__); + return rc; } return rc; } static void msm_isp_get_stream_wm_mask( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t *wm_reload_mask) { int i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) - *wm_reload_mask |= (1 << stream_info->wm[i]); + *wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]); } int msm_isp_axi_halt(struct vfe_device *vfe_dev, struct msm_vfe_axi_halt_cmd *halt_cmd) { int rc = 0; + int i; + struct vfe_device *halt_vfes[MAX_VFE] = { NULL, NULL }; - if (atomic_read(&vfe_dev->error_info.overflow_state) == - OVERFLOW_DETECTED) { - ISP_DBG("%s: VFE%d already halted, direct return\n", - __func__, vfe_dev->pdev->id); - return rc; - } + if (vfe_dev->is_split) + for (i = 0; i < MAX_VFE; i++) + halt_vfes[i] = vfe_dev->common_data-> + dual_vfe_res->vfe_dev[i]; + else + halt_vfes[vfe_dev->pdev->id] = vfe_dev; - if (halt_cmd->overflow_detected) { - atomic_cmpxchg(&vfe_dev->error_info.overflow_state, - NO_OVERFLOW, OVERFLOW_DETECTED); - pr_err("%s: VFE%d Bus overflow detected: start recovery!\n", - __func__, vfe_dev->pdev->id); - } + for (i = 0; i < MAX_VFE; i++) { + vfe_dev = halt_vfes[i]; + if (!vfe_dev) + continue; + if (atomic_read(&vfe_dev->error_info.overflow_state) == + OVERFLOW_DETECTED) { + ISP_DBG("%s: VFE%d already halted, direct return\n", + __func__, vfe_dev->pdev->id); + continue; + } - if (halt_cmd->stop_camif) { - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + if (halt_cmd->overflow_detected) { + atomic_cmpxchg(&vfe_dev->error_info.overflow_state, + NO_OVERFLOW, OVERFLOW_DETECTED); + pr_err("%s: VFE%d Bus overflow detected: start recovery!\n", + __func__, vfe_dev->pdev->id); + } + + if (halt_cmd->stop_camif) { + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, + DISABLE_CAMIF_IMMEDIATELY); + } + rc |= vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, + halt_cmd->blocking_halt); + + /* take care of pending items in tasklet after halt */ + msm_isp_flush_tasklet(vfe_dev); } - rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, - halt_cmd->blocking_halt); return rc; } @@ -2241,12 +2268,13 @@ int msm_isp_axi_halt(struct vfe_device *vfe_dev, int msm_isp_axi_reset(struct vfe_device *vfe_dev, struct msm_vfe_axi_reset_cmd *reset_cmd) { - int rc = 0, i, j; + int rc = 0, i, k; struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t bufq_handle = 0, bufq_id = 0; struct msm_isp_timestamp timestamp; unsigned long flags; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; if (!reset_cmd) { pr_err("%s: NULL pointer reset cmd %pK\n", __func__, reset_cmd); @@ -2256,49 +2284,74 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, reset_cmd->blocking); + if (vfe_dev->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev->common_data->dual_vfe_res-> + vfe_dev[i]; + } else { + update_vfes[vfe_dev->pdev->id] = vfe_dev; + } msm_isp_get_timestamp(×tamp); - for (i = 0, j = 0; j < axi_data->num_active_stream && - i < VFE_AXI_SRC_MAX; i++, j++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { - rc = -1; - pr_err("%s invalid stream src = %d\n", __func__, - stream_info->stream_src); - break; - } - if (stream_info->state != ACTIVE) { - j--; + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) continue; - } + rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + 0, reset_cmd->blocking); - for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { - bufq_handle = stream_info->bufq_handle[bufq_id]; - if (!bufq_handle) - continue; - /* set ping pong address to scratch before flush */ - spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PONG_FLAG); - spin_unlock_irqrestore(&stream_info->lock, flags); - rc = vfe_dev->buf_mgr->ops->flush_buf( - vfe_dev->buf_mgr, vfe_dev->pdev->id, - bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, - ×tamp.buf_time, reset_cmd->frame_id); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { + stream_info = msm_isp_get_stream_common_data( + vfe_dev, i); + if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { + rc = -1; + pr_err("%s invalid stream src = %d\n", + __func__, + stream_info->stream_src); + break; } + if (stream_info->state == AVAILABLE || + stream_info->state == INACTIVE) + continue; - axi_data->src_info[SRC_TO_INTF(stream_info-> - stream_src)].frame_id = reset_cmd->frame_id; - msm_isp_reset_burst_count_and_frame_drop(vfe_dev, - stream_info); + /* handle dual stream on ISP_VFE1 turn */ + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + continue; + + for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; + bufq_id++) { + bufq_handle = stream_info->bufq_handle[bufq_id]; + if (!bufq_handle) + continue; + + /* set ping pong to scratch before flush */ + spin_lock_irqsave(&stream_info->lock, flags); + msm_isp_cfg_stream_scratch(stream_info, + VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, + VFE_PONG_FLAG); + spin_unlock_irqrestore(&stream_info->lock, + flags); + rc = vfe_dev->buf_mgr->ops->flush_buf( + vfe_dev->buf_mgr, + bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, + ×tamp.buf_time, + reset_cmd->frame_id); + if (rc == -EFAULT) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return rc; + } + + axi_data->src_info[SRC_TO_INTF(stream_info-> + stream_src)].frame_id = + reset_cmd->frame_id; + msm_isp_reset_burst_count_and_frame_drop( + vfe_dev, stream_info); + } } } @@ -2308,46 +2361,67 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, return rc; } -int msm_isp_axi_restart(struct vfe_device *vfe_dev, +int msm_isp_axi_restart(struct vfe_device *vfe_dev_ioctl, struct msm_vfe_axi_restart_cmd *restart_cmd) { - int rc = 0, i, j; + int rc = 0, i, k, j; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t wm_reload_mask = 0x0; + uint32_t wm_reload_mask = 0; unsigned long flags; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; + struct vfe_device *vfe_dev; + + if (vfe_dev_ioctl->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev_ioctl->common_data-> + dual_vfe_res->vfe_dev[i]; + } else { + update_vfes[vfe_dev_ioctl->pdev->id] = vfe_dev_ioctl; + } - vfe_dev->buf_mgr->frameId_mismatch_recovery = 0; - for (i = 0, j = 0; j < axi_data->num_active_stream && - i < VFE_AXI_SRC_MAX; i++, j++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->state != ACTIVE) { - j--; + vfe_dev_ioctl->buf_mgr->frameId_mismatch_recovery = 0; + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) continue; + vfe_dev->buf_mgr->frameId_mismatch_recovery = 0; + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { + stream_info = msm_isp_get_stream_common_data( + vfe_dev, i); + if (stream_info->state == AVAILABLE || + stream_info->state == INACTIVE) + continue; + msm_isp_get_stream_wm_mask(vfe_dev, stream_info, + &wm_reload_mask); + /* handle dual stream on ISP_VFE1 turn */ + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + for (j = 0; j < MSM_ISP_COMP_IRQ_MAX; j++) + stream_info->composite_irq[j] = 0; + msm_isp_init_stream_ping_pong_reg(stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); } - msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); - spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); - spin_unlock_irqrestore(&stream_info->lock, flags); - } - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - vfe_dev->vfe_base, wm_reload_mask); - rc = vfe_dev->hw_info->vfe_ops.axi_ops.restart(vfe_dev, 0, - restart_cmd->enable_camif); - if (rc < 0) - pr_err("%s Error restarting HW\n", __func__); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, + vfe_dev->vfe_base, wm_reload_mask); + vfe_dev->hw_info->vfe_ops.axi_ops.restart(vfe_dev, 0, + restart_cmd->enable_camif); + } return rc; } -static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev, +static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev_ioctl, struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, uint8_t cgc_override) { int i = 0, j = 0; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int k; + struct vfe_device *vfe_dev; + int vfe_idx; if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) return -EINVAL; @@ -2357,14 +2431,21 @@ static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev, VFE_AXI_SRC_MAX) { return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); for (j = 0; j < stream_info->num_planes; j++) { - if (vfe_dev->hw_info->vfe_ops.axi_ops. - update_cgc_override) + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (!vfe_dev->hw_info->vfe_ops.axi_ops. + update_cgc_override) + continue; + vfe_idx = msm_isp_get_vfe_idx_for_stream( + vfe_dev, stream_info); vfe_dev->hw_info->vfe_ops.axi_ops. update_cgc_override(vfe_dev, - stream_info->wm[j], cgc_override); + stream_info->wm[vfe_idx][j], + cgc_override); + } } } return 0; @@ -2456,8 +2537,7 @@ static int msm_isp_update_dual_HW_ms_info_at_start( static int msm_isp_update_dual_HW_ms_info_at_stop( struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update) + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; uint8_t slave_id; @@ -2476,13 +2556,13 @@ static int msm_isp_update_dual_HW_ms_info_at_stop( VFE_AXI_SRC_MAX) { return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); stream_src = SRC_TO_INTF(stream_info->stream_src); /* Remove PIX if DISABLE CAMIF */ - if (stream_src == VFE_PIX_0 && !((camif_update == DISABLE_CAMIF) - || (camif_update == DISABLE_CAMIF_IMMEDIATELY))) + if (stream_src == VFE_PIX_0 && + axi_data->src_info[VFE_PIX_0].active) continue; src_info = &axi_data->src_info[stream_src]; @@ -2517,404 +2597,489 @@ static int msm_isp_update_dual_HW_ms_info_at_stop( return rc; } -static int msm_isp_update_dual_HW_axi(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) +/** + * msm_isp_axi_wait_for_stream_cfg_done() - Wait for a stream completion + * @stream_info: The stream to wait on + * @active: Reset means wait for stream to be INACTIVE else wait for ACTIVE + * + * Returns - 0 on success else error code + */ +static int msm_isp_axi_wait_for_stream_cfg_done( + struct msm_vfe_axi_stream *stream_info, int active) +{ + int rc = -1; + unsigned long flags; + + /* No need to wait if stream is already in required state */ + spin_lock_irqsave(&stream_info->lock, flags); + if (active && ACTIVE == stream_info->state) + rc = 0; + if (!active && INACTIVE == stream_info->state) + rc = 0; + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc == 0) + return rc; + + rc = wait_for_completion_timeout( + active ? &stream_info->active_comp : + &stream_info->inactive_comp, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + + if (rc <= 0) { + rc = rc ? rc : -ETIMEDOUT; + pr_err("%s: wait for stream %x/%x state %d config failed %d\n", + __func__, + stream_info->stream_id, + stream_info->stream_src, + stream_info->state, + rc); + rc = -EINVAL; + } else { + rc = 0; + } + return rc; +} + +/** + * msm_isp_axi_wait_for_streams() - Wait for completion of a number of streams + * @streams: The streams to wait on + * @num_stream: Number of streams to wait on + * @active: Reset means wait for stream to be INACTIVE else wait for ACTIVE + * + * Returns - 0 on success else error code + */ +static int msm_isp_axi_wait_for_streams(struct msm_vfe_axi_stream **streams, + int num_stream, int active) { + int i; int rc = 0; - int vfe_id; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; + struct msm_vfe_axi_stream *stream_info; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream idx %d\n", __func__, stream_idx); + for (i = 0; i < num_stream; i++) { + stream_info = streams[i]; + rc |= msm_isp_axi_wait_for_stream_cfg_done(stream_info, active); + } + return rc; +} + +static int __msm_isp_check_stream_state(struct msm_vfe_axi_stream *stream_info, + int cmd) +{ + switch (stream_info->state) { + case AVAILABLE: return -EINVAL; + case PAUSING: + case RESUMING: + case RESUME_PENDING: + case ACTIVE: + if (cmd != 0) + return -EALREADY; + break; + case INACTIVE: + if (cmd == 0) + return -EALREADY; + break; + /* + * stream cannot be in following states since we always + * wait in ioctl for stream to be active or inactive + */ + case UPDATING: + case START_PENDING: + case STARTING: + case STOPPING: + case STOP_PENDING: + case PAUSE_PENDING: + default: + WARN(1, "Invalid state %d\n", stream_info->state); } + return 0; +} - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_dev[ISP_VFE0] || - !dual_vfe_res->vfe_dev[ISP_VFE1] || - !dual_vfe_res->axi_data[ISP_VFE0] || - !dual_vfe_res->axi_data[ISP_VFE1]) { - pr_err("%s: Error in dual vfe resource\n", __func__); - rc = -EINVAL; - } else { - if (stream_info->state == RESUME_PENDING && - (dual_vfe_res->axi_data[!vfe_dev->pdev->id]-> - stream_info[stream_idx].state == RESUME_PENDING)) { - /* Update the AXI only after both ISPs receiving the - Reg update interrupt*/ - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - rc = msm_isp_axi_stream_enable_cfg( - dual_vfe_res->vfe_dev[vfe_id], - &dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx], 1); - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx].state = - RESUMING; +static void __msm_isp_stop_axi_streams(struct msm_vfe_axi_stream **streams, + int num_streams, int cmd_type) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data; + struct msm_isp_timestamp timestamp; + int total_stream_count = 0; + uint32_t bufq_id = 0, bufq_handle = 0; + struct msm_vfe_axi_stream *stream_info; + unsigned long flags; + uint32_t intf; + int rc; + struct vfe_device *vfe_dev; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; + int k; + + msm_isp_get_timestamp(×tamp); + + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + spin_lock_irqsave(&stream_info->lock, flags); + /* + * since we can get here from start axi stream error path due + * to which the stream may be intermittent state like + * STARTING/START_PENDING, force the stream to move out of + * intermittent state so it can be made INACTIVE. The + * intermittent states update variables so better to go through + * those state transitions instead of directly forcing stream to + * be INACTIVE + */ + while (stream_info->state != ACTIVE) + __msm_isp_axi_stream_update(stream_info, + ×tamp); + msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (stream_info->num_planes > 1) + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_comp_mask(vfe_dev, stream_info); + else + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + update_vfes[vfe_dev->pdev->id] = vfe_dev; + } + init_completion(&stream_info->inactive_comp); + stream_info->state = STOP_PENDING; + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_intf_stream_cnt(stream_info, 0); + } + + for (k = 0; k < MAX_VFE; k++) { + int ext_read; + + if (!update_vfes[k]) + continue; + vfe_dev = update_vfes[k]; + axi_data = &vfe_dev->axi_data; + ext_read = + (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); + for (i = 0; i < VFE_SRC_MAX; i++) { + total_stream_count += + axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + if (i != VFE_PIX_0) + continue; + if (axi_data->src_info[i].stream_count == 0) { + vfe_dev->hw_info->vfe_ops.stats_ops. + enable_module(vfe_dev, 0xFF, 0); + /* reg update for PIX with 0 streams active */ + if (ext_read == 0) + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, VFE_PIX_0); } } + + } + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + intf = SRC_TO_INTF(stream_info->stream_src); + if (total_stream_count == 0 || + ((stream_info->stream_type == BURST_STREAM) && + stream_info->runtime_num_burst_capture == 0)) { + spin_lock_irqsave(&stream_info->lock, flags); + while (stream_info->state != INACTIVE) + __msm_isp_axi_stream_update( + stream_info, ×tamp); + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + } + + rc = msm_isp_axi_wait_for_streams(streams, num_streams, 0); + if (rc) { + pr_err("%s: wait for stream comp failed, retry...\n", __func__); + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + if (stream_info->state == INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + __msm_isp_axi_stream_update(stream_info, + ×tamp); + spin_unlock_irqrestore(&stream_info->lock, flags); + } + rc = msm_isp_axi_wait_for_streams(streams, num_streams, 0); + if (rc) { + pr_err("%s: wait for stream comp failed, force streams to inactive\n", + __func__); + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + if (stream_info->state == INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + while (stream_info->state != INACTIVE) + __msm_isp_axi_stream_update( + stream_info, ×tamp); + spin_unlock_irqrestore(&stream_info->lock, + flags); + } + } + } + /* clear buffers that are dequeued */ + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { + bufq_handle = stream_info->bufq_handle[bufq_id]; + if (!bufq_handle) + continue; + vfe_dev = stream_info->vfe_dev[0]; + rc = vfe_dev->buf_mgr->ops->flush_buf( + vfe_dev->buf_mgr, + bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, + ×tamp.buf_time, 0); + if (rc == -EFAULT) + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + } + } + + for (k = 0; k < MAX_VFE; k++) { + if (!update_vfes[k]) + continue; + msm_isp_update_stream_bandwidth(update_vfes[k]); + msm_isp_input_disable(update_vfes[k]); + } + + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + intf = SRC_TO_INTF(stream_info->stream_src); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + axi_data = &vfe_dev->axi_data; + if (axi_data->src_info[intf].stream_count == 0) + vfe_dev->reg_update_requested &= + ~(BIT(intf)); + } } - return rc; } -static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update) +static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; - uint8_t src_state, wait_for_complete = 0; - uint32_t wm_reload_mask = 0x0; + uint8_t src_state; + uint32_t wm_reload_mask[MAX_VFE] = {0, 0}; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t src_mask = 0; unsigned long flags; + struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM]; + int num_streams = 0; + struct msm_isp_timestamp timestamp; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; + int k; + uint32_t num_active_streams[MAX_VFE] = {0, 0}; + struct vfe_device *vfe_dev; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev_ioctl->axi_data; if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) return -EINVAL; - if (camif_update == ENABLE_CAMIF) { - ISP_DBG("%s: vfe %d camif enable\n", __func__, - vfe_dev->pdev->id); - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0; - } + msm_isp_get_timestamp(×tamp); for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX) src_state = axi_data->src_info[ SRC_TO_INTF(stream_info->stream_src)].active; + else { ISP_DBG("%s: invalid src info index\n", __func__); - return -EINVAL; + rc = -EINVAL; + goto error; } - - msm_isp_calculate_bandwidth(axi_data, stream_info); - msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_reset_framedrop(vfe_dev, stream_info); - rc = msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); + rc = __msm_isp_check_stream_state(stream_info, 1); + if (-EALREADY == rc) { + rc = 0; + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + goto error; + } + + msm_isp_calculate_bandwidth(stream_info); + for (k = 0; k < stream_info->num_isp; k++) { + msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k], + stream_info, &wm_reload_mask[ + stream_info->vfe_dev[k]->pdev->id]); + src_state = stream_info->vfe_dev[k]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)].active; + if (update_vfes[stream_info->vfe_dev[k]->pdev->id]) + continue; + update_vfes[stream_info->vfe_dev[k]->pdev->id] = + stream_info->vfe_dev[k]; + num_active_streams[stream_info->vfe_dev[k]->pdev->id] = + stream_info->vfe_dev[k]->axi_data. + num_active_stream; + } + msm_isp_reset_framedrop(vfe_dev_ioctl, stream_info); + rc = msm_isp_init_stream_ping_pong_reg(stream_info); if (rc < 0) { pr_err("%s: No buffer for stream%d\n", __func__, HANDLE_TO_IDX( stream_cfg_cmd->stream_handle[i])); spin_unlock_irqrestore(&stream_info->lock, flags); - return rc; + goto error; } - spin_unlock_irqrestore(&stream_info->lock, flags); - if (stream_info->num_planes > 1) { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_comp_mask(vfe_dev, stream_info); - } else { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (stream_info->num_planes > 1) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_comp_mask(vfe_dev, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + } } + init_completion(&stream_info->active_comp); stream_info->state = START_PENDING; + msm_isp_update_intf_stream_cnt(stream_info, 1); - ISP_DBG("%s, Stream 0x%x src %d src_state %d on vfe %d\n", - __func__, stream_info->stream_id, - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]), - src_state, vfe_dev->pdev->id); - + ISP_DBG("%s, Stream 0x%x src_state %d on vfe %d\n", __func__, + stream_info->stream_src, src_state, + vfe_dev_ioctl->pdev->id); if (src_state) { src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src)); - wait_for_complete = 1; } else { - if (vfe_dev->dump_reg) - msm_camera_io_dump(vfe_dev->vfe_base, - 0x1000, 1); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + + if (vfe_dev->dump_reg) + msm_camera_io_dump(vfe_dev->vfe_base, + 0x1000, 1); + } - /*Configure AXI start bits to start immediately*/ - msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info, 0); - stream_info->state = ACTIVE; - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, - SRC_TO_INTF(stream_info->stream_src)); + /* Configure AXI start bits to start immediately */ + while (stream_info->state != ACTIVE) + __msm_isp_axi_stream_update( + stream_info, ×tamp); - /* - * Active bit is set in enable_camif for PIX. - * For RDI, set it here - */ - if (SRC_TO_INTF(stream_info->stream_src) >= VFE_RAW_0 && - SRC_TO_INTF(stream_info->stream_src) < - VFE_SRC_MAX) { - /* Incase PIX and RDI streams are part of same - * session, this will ensure RDI stream will - * have same frame id as of PIX stream - */ - if (stream_cfg_cmd->sync_frame_id_src) - vfe_dev->axi_data.src_info[SRC_TO_INTF( - stream_info->stream_src)].frame_id = - vfe_dev->axi_data.src_info[VFE_PIX_0] - .frame_id; - else - vfe_dev->axi_data.src_info[SRC_TO_INTF( - stream_info->stream_src)].frame_id = 0; - vfe_dev->axi_data.src_info[SRC_TO_INTF( - stream_info->stream_src)].active = 1; + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.core_ops.reg_update( + vfe_dev, + SRC_TO_INTF(stream_info->stream_src)); } } + spin_unlock_irqrestore(&stream_info->lock, flags); + streams[num_streams++] = stream_info; } - msm_isp_update_stream_bandwidth(vfe_dev); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - vfe_dev->vfe_base, wm_reload_mask); - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - if (camif_update == ENABLE_CAMIF) { - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, camif_update); - vfe_dev->axi_data.camif_state = CAMIF_ENABLE; - vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0; + for (i = 0; i < MAX_VFE; i++) { + vfe_dev = update_vfes[i]; + if (!vfe_dev) + continue; + if (num_active_streams[i] == 0) { + /* Configure UB */ + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); + /* when start reset overflow state */ + atomic_set(&vfe_dev->error_info.overflow_state, + NO_OVERFLOW); + } + msm_isp_update_stream_bandwidth(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, + vfe_dev->vfe_base, wm_reload_mask[i]); + + msm_isp_input_enable(vfe_dev, + stream_cfg_cmd->sync_frame_id_src); } - if (wait_for_complete) { - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update, - src_mask, 2); - if (rc < 0) { - pr_err("%s: wait for config done failed\n", __func__); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])]; - stream_info->state = STOPPING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info, 0); - stream_cfg_cmd->cmd = STOP_IMMEDIATELY; - msm_isp_update_camif_output_count(vfe_dev, - stream_cfg_cmd); - } - } + rc = msm_isp_axi_wait_for_streams(streams, num_streams, 1); + if (rc < 0) { + pr_err("%s: wait for config done failed\n", __func__); + goto error; } + return 0; +error: + __msm_isp_stop_axi_streams(streams, num_streams, + STOP_STREAM); + return rc; } -static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update, - int halt) +static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev_ioctl, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; - uint8_t wait_for_complete_for_this_stream = 0; struct msm_vfe_axi_stream *stream_info = NULL; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - int ext_read = - (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); - uint32_t src_mask = 0, intf, bufq_id = 0, bufq_handle = 0; + struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM]; + int num_streams = 0; unsigned long flags; - struct msm_isp_timestamp timestamp; if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || stream_cfg_cmd->num_streams == 0) return -EINVAL; - msm_isp_get_timestamp(×tamp); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); - /* set ping pong address to scratch before stream stop */ spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PONG_FLAG); + rc = __msm_isp_check_stream_state(stream_info, 0); spin_unlock_irqrestore(&stream_info->lock, flags); - wait_for_complete_for_this_stream = 0; - - if (stream_info->num_planes > 1) - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_comp_mask(vfe_dev, stream_info); - else - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - - stream_info->state = STOP_PENDING; - - if (!halt && !ext_read && - !(stream_info->stream_type == BURST_STREAM && - stream_info->runtime_num_burst_capture == 0)) - wait_for_complete_for_this_stream = 1; - - ISP_DBG("%s: stream 0x%x, vfe %d camif %d halt %d wait %d\n", - __func__, - stream_info->stream_id, - vfe_dev->pdev->id, - camif_update, - halt, - wait_for_complete_for_this_stream); - - intf = SRC_TO_INTF(stream_info->stream_src); - if (!wait_for_complete_for_this_stream || - stream_info->state == INACTIVE || - !vfe_dev->axi_data.src_info[intf].active) { - msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info, 0); - stream_info->state = INACTIVE; - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, - SRC_TO_INTF(stream_info->stream_src)); - + if (rc) { /* - * Active bit is reset in disble_camif for PIX. - * For RDI, reset it here for not wait_for_complete - * This is assuming there is only 1 stream mapped to - * each RDI. + * continue stopping other streams as error here means + * stream is already not active */ - if (intf >= VFE_RAW_0 && - intf < VFE_SRC_MAX) { - vfe_dev->axi_data.src_info[intf].active = 0; - } - } else - src_mask |= (1 << intf); - - } - - if (src_mask) { - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update, - src_mask, 2); - if (rc < 0) { - pr_err("%s: wait for config done failed, retry...\n", - __func__); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])]; - stream_info->state = STOPPING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info, 0); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update( - vfe_dev, - SRC_TO_INTF(stream_info->stream_src)); - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, - camif_update, src_mask, 1); - if (rc < 0) { - pr_err("%s: vfe%d cfg done failed\n", - __func__, vfe_dev->pdev->id); - stream_info->state = INACTIVE; - } else - pr_err("%s: vfe%d retry success! report err!\n", - __func__, vfe_dev->pdev->id); - - rc = -EBUSY; - } - } - - /* - * Active bit is reset in disble_camif for PIX. - * For RDI, reset it here after wait_for_complete - * This is assuming there is only 1 stream mapped to each RDI - */ - for (i = VFE_RAW_0; i < VFE_SRC_MAX; i++) { - if (src_mask & (1 << i)) { - vfe_dev->axi_data.src_info[i].active = 0; - } - } - } - - if (camif_update == DISABLE_CAMIF) { - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF); - vfe_dev->axi_data.camif_state = CAMIF_DISABLE; - } else if ((camif_update == DISABLE_CAMIF_IMMEDIATELY) || - (ext_read)) { - if (!ext_read) - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, - DISABLE_CAMIF_IMMEDIATELY); - vfe_dev->axi_data.camif_state = CAMIF_STOPPED; - } - if (halt) { - /*during stop immediately, stop output then stop input*/ - vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); - vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1); - vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); - } - - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - msm_isp_update_stream_bandwidth(vfe_dev); - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { - bufq_handle = stream_info->bufq_handle[bufq_id]; - if (!bufq_handle) - continue; - - rc = vfe_dev->buf_mgr->ops->flush_buf( - vfe_dev->buf_mgr, vfe_dev->pdev->id, - bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, - ×tamp.buf_time, 0); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; - } + rc = 0; + continue; } - vfe_dev->reg_update_requested &= - ~(BIT(SRC_TO_INTF(stream_info->stream_src))); + streams[num_streams++] = stream_info; } + __msm_isp_stop_axi_streams(streams, num_streams, + stream_cfg_cmd->cmd); return rc; } - int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, ret; struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - enum msm_isp_camif_update_state camif_update; - int halt = 0; - - rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd); - if (rc < 0) { - pr_err("%s: Invalid stream state\n", __func__); - return rc; - } + int i; - if (axi_data->num_active_stream == 0) { - /*Configure UB*/ - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); - /*when start reset overflow state*/ - atomic_set(&vfe_dev->error_info.overflow_state, - NO_OVERFLOW); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + VFE_AXI_SRC_MAX) + return -EINVAL; } - msm_isp_get_camif_update_state_and_halt(vfe_dev, stream_cfg_cmd, - &camif_update, &halt); - if (camif_update == DISABLE_CAMIF) - vfe_dev->axi_data.camif_state = CAMIF_STOPPING; if (stream_cfg_cmd->cmd == START_STREAM) { msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 1); rc = msm_isp_start_axi_stream( - vfe_dev, stream_cfg_cmd, camif_update); + vfe_dev, stream_cfg_cmd); } else { rc = msm_isp_stop_axi_stream( - vfe_dev, stream_cfg_cmd, camif_update, halt); + vfe_dev, stream_cfg_cmd); msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 0); - if (axi_data->num_active_stream == 0) { - /* Reset hvx state */ - vfe_dev->hvx_cmd = HVX_DISABLE; - } /* * Use different ret value to not overwrite the error from * msm_isp_stop_axi_stream */ ret = msm_isp_update_dual_HW_ms_info_at_stop( - vfe_dev, stream_cfg_cmd, camif_update); + vfe_dev, stream_cfg_cmd); if (ret < 0) pr_warn("%s: Warning! Update dual_cam failed\n", __func__); + if (vfe_dev->axi_data.num_active_stream == 0) + vfe_dev->hvx_cmd = HVX_DISABLE; + if (vfe_dev->is_split) { + struct vfe_device *vfe_temp = + vfe_dev->common_data-> + dual_vfe_res->vfe_dev[ISP_VFE0]; + if (vfe_temp->axi_data.num_active_stream == 0) + vfe_temp->hvx_cmd = HVX_DISABLE; + } } if (rc < 0) @@ -2925,7 +3090,8 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t user_stream_id, - uint32_t frame_id, enum msm_vfe_input_src frame_src) + uint32_t frame_id, uint32_t buf_index, + enum msm_vfe_input_src frame_src) { int rc = -1; struct msm_isp_buffer *buf = NULL; @@ -2940,7 +3106,7 @@ static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev, return -EINVAL; } - stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + stream_idx = stream_info->stream_src; if (!stream_info->controllable_output) return -EINVAL; @@ -2961,7 +3127,7 @@ static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev, rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, bufq_handle, &buf); + vfe_dev->pdev->id, bufq_handle, buf_index, &buf); if (rc == -EFAULT) { msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); return rc; @@ -2999,7 +3165,7 @@ static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev, static int msm_isp_request_frame(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t user_stream_id, - uint32_t frame_id) + uint32_t frame_id, uint32_t buf_index) { struct msm_vfe_axi_stream_request_cmd stream_cfg_cmd; struct msm_vfe_frame_request_queue *queue_req; @@ -3007,10 +3173,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, unsigned long flags; int rc = 0; enum msm_vfe_input_src frame_src = 0; - struct dual_vfe_resource *dual_vfe_res = - vfe_dev->common_data->dual_vfe_res; - uint32_t vfe_id = 0; - bool dual_vfe = false; + int k; + uint32_t wm_mask = 0; + int vfe_idx; if (!vfe_dev || !stream_info) { pr_err("%s %d failed: vfe_dev %pK stream_info %pK\n", __func__, @@ -3018,16 +3183,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return -EINVAL; } - if (vfe_dev->is_split) { - if (stream_info->stream_src < RDI_INTF_0) { - if (vfe_dev->pdev->id == ISP_VFE1) { - dual_vfe = true; - } else { - /* return early for dual vfe0 */ - return 0; - } - } - } + /* return early for dual vfe0 */ + if (stream_info->num_isp > 1 && vfe_dev->pdev->id == ISP_VFE0) + return 0; if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { pr_err("%s:%d invalid stream src %d\n", __func__, __LINE__, @@ -3052,7 +3210,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, vfe_dev->axi_data.src_info[VFE_PIX_0].active); rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, - user_stream_id, frame_id, frame_src); + user_stream_id, frame_id, buf_index, frame_src); if (rc < 0) pr_err("%s:%d failed: return_empty_buffer src %d\n", __func__, __LINE__, frame_src); @@ -3067,13 +3225,13 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, stream_info->stream_id); rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, - user_stream_id, frame_id, frame_src); + user_stream_id, frame_id, buf_index, frame_src); if (rc < 0) pr_err("%s:%d failed: return_empty_buffer src %d\n", __func__, __LINE__, frame_src); stream_info->current_framedrop_period = MSM_VFE_STREAM_STOP_PERIOD; - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + msm_isp_cfg_framedrop_reg(stream_info); return 0; } @@ -3093,10 +3251,12 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if (!stream_info->bufq_handle[queue_req->buff_queue_id]) { spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s:%d request frame failed on hw stream 0x%x, request stream %d due to no bufq idx: %d\n", - __func__, __LINE__, stream_info->stream_handle, + __func__, __LINE__, + stream_info->stream_handle[0], user_stream_id, queue_req->buff_queue_id); return 0; } + queue_req->buf_index = buf_index; queue_req->cmd_used = 1; stream_info->request_q_idx = @@ -3105,14 +3265,15 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, stream_info->request_q_cnt++; stream_info->undelivered_request_cnt++; - stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle; + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle[vfe_idx]; stream_cfg_cmd.frame_skip_pattern = NO_SKIP; stream_cfg_cmd.init_frame_drop = 0; stream_cfg_cmd.burst_count = stream_info->request_q_cnt; if (stream_info->undelivered_request_cnt == 1) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info, - VFE_PING_FLAG, 0); + rc = msm_isp_cfg_ping_pong_address(stream_info, + VFE_PING_FLAG); if (rc) { spin_unlock_irqrestore(&stream_info->lock, flags); stream_info->undelivered_request_cnt--; @@ -3121,41 +3282,23 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return rc; } - vfe_id = vfe_dev->pdev->id; - if (dual_vfe) { - struct msm_vfe_axi_stream *temp_stream_info; - - temp_stream_info = msm_isp_vfe_get_stream(dual_vfe_res, - ISP_VFE0, - HANDLE_TO_IDX( - stream_info->stream_handle)); - msm_isp_get_stream_wm_mask(temp_stream_info, - &dual_vfe_res->wm_reload_mask[ISP_VFE0]); - msm_isp_get_stream_wm_mask(stream_info, - &dual_vfe_res->wm_reload_mask[ISP_VFE1]); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->wm_reload_mask[ISP_VFE0]); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->wm_reload_mask[ISP_VFE1]); - dual_vfe_res->wm_reload_mask[ISP_VFE0] = 0; - dual_vfe_res->wm_reload_mask[ISP_VFE1] = 0; - } else { - msm_isp_get_stream_wm_mask(stream_info, - &dual_vfe_res->wm_reload_mask[vfe_id]); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - vfe_dev->vfe_base, - dual_vfe_res->wm_reload_mask[vfe_id]); - dual_vfe_res->wm_reload_mask[vfe_id] = 0; + for (k = 0; k < stream_info->num_isp; k++) { + wm_mask = 0; + msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k], + stream_info, &wm_mask); + stream_info->vfe_dev[k]-> + hw_info->vfe_ops.axi_ops.reload_wm( + stream_info->vfe_dev[k], + stream_info->vfe_dev[k]->vfe_base, wm_mask); + } stream_info->sw_ping_pong_bit = 0; } else if (stream_info->undelivered_request_cnt == 2) { pingpong_status = vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status( vfe_dev); - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, 0); + rc = msm_isp_cfg_ping_pong_address( + stream_info, pingpong_status); if (rc) { stream_info->undelivered_request_cnt--; spin_unlock_irqrestore(&stream_info->lock, @@ -3172,7 +3315,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return -EINVAL; } - rc = msm_isp_calculate_framedrop(&vfe_dev->axi_data, &stream_cfg_cmd); + rc = msm_isp_calculate_framedrop(vfe_dev, &stream_cfg_cmd); if (0 == rc) msm_isp_reset_framedrop(vfe_dev, stream_info); @@ -3186,25 +3329,45 @@ static int msm_isp_add_buf_queue(struct vfe_device *vfe_dev, { int rc = 0; uint32_t bufq_id = 0; + unsigned long flags; if (stream_id == stream_info->stream_id) bufq_id = VFE_BUF_QUEUE_DEFAULT; else bufq_id = VFE_BUF_QUEUE_SHARED; + spin_lock_irqsave(&stream_info->lock, flags); - stream_info->bufq_handle[bufq_id] = - vfe_dev->buf_mgr->ops->get_bufq_handle(vfe_dev->buf_mgr, - stream_info->session_id, stream_id); if (stream_info->bufq_handle[bufq_id] == 0) { - pr_err("%s: failed: No valid buffer queue for stream: 0x%x\n", - __func__, stream_id); - rc = -EINVAL; + stream_info->bufq_handle[bufq_id] = + vfe_dev->buf_mgr->ops->get_bufq_handle(vfe_dev->buf_mgr, + stream_info->session_id, stream_id); + if (stream_info->bufq_handle[bufq_id] == 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: failed: No valid buffer queue for stream: 0x%x\n", + __func__, stream_id); + return -EINVAL; + } + } else { + uint32_t bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, + stream_info->session_id, + stream_id); + if (bufq_handle != stream_info->bufq_handle[bufq_id]) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Stream %x already has buffer q %x cannot add handle %x\n", + __func__, stream_id, + stream_info->bufq_handle[bufq_id], bufq_handle); + return -EINVAL; + } } + spin_unlock_irqrestore(&stream_info->lock, flags); + ISP_DBG("%d: Add bufq handle:0x%x, idx:%d, for stream %d on VFE %d\n", __LINE__, stream_info->bufq_handle[bufq_id], - bufq_id, stream_info->stream_handle, vfe_dev->pdev->id); + bufq_id, stream_info->stream_handle[0], + vfe_dev->pdev->id); return rc; } @@ -3221,18 +3384,102 @@ static void msm_isp_remove_buf_queue(struct vfe_device *vfe_dev, bufq_id = VFE_BUF_QUEUE_SHARED; spin_lock_irqsave(&stream_info->lock, flags); - stream_info->bufq_handle[bufq_id] = 0; + + if (stream_info->bufq_handle[bufq_id]) { + stream_info->bufq_handle[bufq_id] = 0; + if (stream_info->state == ACTIVE) + stream_info->state = UPDATING; + } spin_unlock_irqrestore(&stream_info->lock, flags); + if (stream_info->state == UPDATING) + msm_isp_axi_wait_for_stream_cfg_done(stream_info, 1); + +} + +/** + * msm_isp_stream_axi_cfg_update() - Apply axi config update to a stream + * @vfe_dev: The vfe device on which the update is to be applied + * @stream_info: Stream for which update is to be applied + * @update_info: Parameters of the update + * + * Returns - 0 on success else error code + * + * For dual vfe stream apply the update once update for both vfe is + * received. + */ +static int msm_isp_stream_axi_cfg_update(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + struct msm_vfe_axi_stream_cfg_update_info *update_info) +{ + int j; + int k; + unsigned long flags; + int vfe_idx; + if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[ + SRC_TO_INTF(stream_info->stream_src)])) { + pr_err("%s: Update in progress for vfe %d intf %d\n", + __func__, vfe_dev->pdev->id, + SRC_TO_INTF(stream_info->stream_src)); + return -EINVAL; + } + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state != ACTIVE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("Invalid stream state for axi update %d\n", + stream_info->state); + return -EINVAL; + } + if (stream_info->update_vfe_mask) { + if (stream_info->update_vfe_mask & (1 << vfe_dev->pdev->id)) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Stream %p/%x Update already in progress for vfe %d\n", + __func__, stream_info, stream_info->stream_src, + vfe_dev->pdev->id); + return -EINVAL; + } + } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + for (j = 0; j < stream_info->num_planes; j++) + stream_info->plane_cfg[vfe_idx][j] = update_info->plane_cfg[j]; + + stream_info->update_vfe_mask |= (1 << vfe_dev->pdev->id); + /* wait for update from all vfe's under stream before applying */ + if (stream_info->update_vfe_mask != stream_info->vfe_mask) { + spin_unlock_irqrestore(&stream_info->lock, flags); + return 0; + } + + atomic_set(&vfe_dev->axi_data.axi_cfg_update[ + SRC_TO_INTF(stream_info->stream_src)], 1); + stream_info->output_format = update_info->output_format; + init_completion(&stream_info->active_comp); + if (((vfe_dev->hw_info->runtime_axi_update == 0) || + (vfe_dev->dual_vfe_enable == 1))) { + stream_info->state = PAUSE_PENDING; + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = PAUSING; + } else { + for (j = 0; j < stream_info->num_planes; j++) { + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + } + } + stream_info->state = RESUMING; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + return 0; } int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) { - int rc = 0, i, j; + int rc = 0, i; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; - struct msm_vfe_axi_stream_cfg_update_info *update_info; + struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL; struct msm_isp_sw_framskip *sw_skip_info = NULL; unsigned long flags; struct msm_isp_timestamp timestamp; @@ -3243,14 +3490,15 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) return -EINVAL; for (i = 0; i < update_cmd->num_streams; i++) { - update_info = &update_cmd->update_info[i]; + update_info = (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; /*check array reference bounds*/ if (HANDLE_TO_IDX(update_info->stream_handle) >= VFE_AXI_SRC_MAX) { return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); if (SRC_TO_INTF(stream_info->stream_src) >= VFE_SRC_MAX) continue; if (stream_info->state != ACTIVE && @@ -3267,37 +3515,45 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) return -EINVAL; } if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG && - atomic_read(&axi_data->axi_cfg_update[ - SRC_TO_INTF(stream_info->stream_src)])) { + stream_info->state != ACTIVE) { pr_err("%s: AXI stream config updating\n", __func__); return -EBUSY; } } - for (i = 0; i < update_cmd->num_streams; i++) { - update_info = &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(update_info->stream_handle)]; - - switch (update_cmd->update_type) { - case ENABLE_STREAM_BUF_DIVERT: + switch (update_cmd->update_type) { + case ENABLE_STREAM_BUF_DIVERT: + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); stream_info->buf_divert = 1; - break; - case DISABLE_STREAM_BUF_DIVERT: + } + break; + case DISABLE_STREAM_BUF_DIVERT: + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); stream_info->buf_divert = 0; msm_isp_get_timestamp(×tamp); frame_id = vfe_dev->axi_data.src_info[ SRC_TO_INTF(stream_info->stream_src)].frame_id; /* set ping pong address to scratch before flush */ spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PONG_FLAG); + msm_isp_cfg_stream_scratch(stream_info, + VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, + VFE_PONG_FLAG); spin_unlock_irqrestore(&stream_info->lock, flags); - rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, - stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT], + rc = vfe_dev->buf_mgr->ops->flush_buf( + vfe_dev->buf_mgr, + stream_info->bufq_handle + [VFE_BUF_QUEUE_DEFAULT], MSM_ISP_BUFFER_FLUSH_DIVERTED, ×tamp.buf_time, frame_id); if (rc == -EFAULT) { @@ -3305,11 +3561,18 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) ISP_EVENT_BUF_FATAL_ERROR); return rc; } - break; - case UPDATE_STREAM_FRAMEDROP_PATTERN: { + } + break; + case UPDATE_STREAM_FRAMEDROP_PATTERN: { + for (i = 0; i < update_cmd->num_streams; i++) { uint32_t framedrop_period = msm_isp_get_framedrop_period( - update_info->skip_pattern); + update_info->skip_pattern); + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); spin_lock_irqsave(&stream_info->lock, flags); /* no change then break early */ if (stream_info->current_framedrop_period == @@ -3331,11 +3594,18 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) stream_info->current_framedrop_period = framedrop_period; if (stream_info->stream_type != BURST_STREAM) - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + msm_isp_cfg_framedrop_reg(stream_info); spin_unlock_irqrestore(&stream_info->lock, flags); - break; } - case UPDATE_STREAM_SW_FRAME_DROP: { + break; + } + case UPDATE_STREAM_SW_FRAME_DROP: { + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); sw_skip_info = &update_info->sw_skip_info; if (sw_skip_info->stream_src_mask != 0) { /* SW image buffer drop */ @@ -3350,88 +3620,88 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) spin_unlock_irqrestore(&stream_info->lock, flags); } - break; } - case UPDATE_STREAM_AXI_CONFIG: { - for (j = 0; j < stream_info->num_planes; j++) { - stream_info->plane_cfg[j] = - update_info->plane_cfg[j]; - } - stream_info->output_format = update_info->output_format; - if ((stream_info->state == ACTIVE) && - ((vfe_dev->hw_info->runtime_axi_update == 0) || - (vfe_dev->dual_vfe_enable == 1))) { - spin_lock_irqsave(&stream_info->lock, flags); - stream_info->state = PAUSE_PENDING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info, 1); - stream_info->state = PAUSING; - atomic_set(&axi_data-> - axi_cfg_update[SRC_TO_INTF( - stream_info->stream_src)], - UPDATE_REQUESTED); - spin_unlock_irqrestore(&stream_info->lock, - flags); - } else { - for (j = 0; j < stream_info->num_planes; j++) { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, j); - } - - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state != ACTIVE) { - stream_info->runtime_output_format = - stream_info->output_format; - } else { - stream_info->state = RESUMING; - atomic_set(&axi_data-> - axi_cfg_update[SRC_TO_INTF( - stream_info->stream_src)], - APPLYING_UPDATE_RESUME); - } - spin_unlock_irqrestore(&stream_info->lock, - flags); - } - break; + break; + } + case UPDATE_STREAM_AXI_CONFIG: { + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); + rc = msm_isp_stream_axi_cfg_update(vfe_dev, stream_info, + update_info); + if (rc) + return rc; } - case UPDATE_STREAM_REQUEST_FRAMES: { + break; + } + case UPDATE_STREAM_REQUEST_FRAMES: { + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); rc = msm_isp_request_frame(vfe_dev, stream_info, update_info->user_stream_id, - update_info->frame_id); + update_info->frame_id, + MSM_ISP_INVALID_BUF_INDEX); if (rc) pr_err("%s failed to request frame!\n", __func__); - break; } - case UPDATE_STREAM_ADD_BUFQ: { + break; + } + case UPDATE_STREAM_ADD_BUFQ: { + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); rc = msm_isp_add_buf_queue(vfe_dev, stream_info, update_info->user_stream_id); if (rc) pr_err("%s failed to add bufq!\n", __func__); - break; } - case UPDATE_STREAM_REMOVE_BUFQ: { + break; + } + case UPDATE_STREAM_REMOVE_BUFQ: { + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = + (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); msm_isp_remove_buf_queue(vfe_dev, stream_info, update_info->user_stream_id); pr_debug("%s, Remove bufq for Stream 0x%x\n", __func__, stream_info->stream_id); - if (stream_info->state == ACTIVE) { - stream_info->state = UPDATING; - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, - NO_UPDATE, (1 << SRC_TO_INTF( - stream_info->stream_src)), 2); - if (rc < 0) - pr_err("%s: wait for update failed\n", - __func__); - } - - break; - } - default: - pr_err("%s: Invalid update type\n", __func__); - return -EINVAL; } + break; + } + case UPDATE_STREAM_REQUEST_FRAMES_VER2: { + struct msm_vfe_axi_stream_cfg_update_info_req_frm *req_frm = + &update_cmd->req_frm_ver2; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(req_frm->stream_handle)); + rc = msm_isp_request_frame(vfe_dev, stream_info, + req_frm->user_stream_id, + req_frm->frame_id, + req_frm->buf_index); + if (rc) + pr_err("%s failed to request frame!\n", + __func__); + break; } + default: + pr_err("%s: Invalid update type %d\n", __func__, + update_cmd->update_type); + return -EINVAL; + } + return rc; } @@ -3446,7 +3716,7 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, unsigned long flags; struct timeval *time_stamp; uint32_t frame_id, buf_index = -1; - struct msm_vfe_axi_stream *temp_stream; + int vfe_idx; if (!ts) { pr_err("%s: Error! Invalid argument\n", __func__); @@ -3464,10 +3734,13 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id; spin_lock_irqsave(&stream_info->lock, flags); - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + pingpong_bit = (~(pingpong_status >> + stream_info->wm[vfe_idx][0]) & 0x1); for (i = 0; i < stream_info->num_planes; i++) { if (pingpong_bit != - (~(pingpong_status >> stream_info->wm[i]) & 0x1)) { + (~(pingpong_status >> + stream_info->wm[vfe_idx][i]) & 0x1)) { spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: Write master ping pong mismatch. Status: 0x%x\n", __func__, pingpong_status); @@ -3476,15 +3749,23 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } } - if (stream_info->state == INACTIVE) { - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - pingpong_status); + WARN_ON(stream_info->buf[pingpong_bit] != NULL); spin_unlock_irqrestore(&stream_info->lock, flags); - pr_err_ratelimited("%s: Warning! Stream already inactive. Drop irq handling\n", - __func__); return; } + + /* composite the irq for dual vfe */ + rc = msm_isp_composite_irq(vfe_dev, stream_info, + MSM_ISP_COMP_IRQ_PING_BUFDONE + pingpong_bit); + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc < 0) + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return; + } + done_buf = stream_info->buf[pingpong_bit]; if (vfe_dev->buf_mgr->frameId_mismatch_recovery == 1) { @@ -3494,46 +3775,28 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } - stream_info->frame_id++; if (done_buf) buf_index = done_buf->buf_idx; - rc = vfe_dev->buf_mgr->ops->update_put_buf_cnt(vfe_dev->buf_mgr, + ISP_DBG("%s: vfe %d: stream 0x%x, frame id %d, pingpong bit %d\n", + __func__, vfe_dev->pdev->id, - done_buf ? done_buf->bufq_handle : - stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT], buf_index, - time_stamp, frame_id, pingpong_bit); + stream_info->stream_id, + frame_id, + pingpong_bit); - if (rc < 0) { - spin_unlock_irqrestore(&stream_info->lock, flags); - /* this usually means a serious scheduling error */ - msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); - return; - } - /* - * Buf divert return value represent whether the buf - * can be diverted. A positive return value means - * other ISP hardware is still processing the frame. - * A negative value is error. Return in both cases. - */ - if (rc != 0) { - spin_unlock_irqrestore(&stream_info->lock, flags); - return; - } + stream_info->frame_id++; + stream_info->buf[pingpong_bit] = NULL; if (stream_info->stream_type == CONTINUOUS_STREAM || stream_info->runtime_num_burst_capture > 1) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, 0); + rc = msm_isp_cfg_ping_pong_address( + stream_info, pingpong_status); if (rc < 0) ISP_DBG("%s: Error configuring ping_pong\n", __func__); } else if (done_buf) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, 1); - if (rc < 0) - ISP_DBG("%s: Error configuring ping_pong\n", - __func__); + msm_isp_cfg_stream_scratch(stream_info, pingpong_status); } if (!done_buf) { @@ -3547,28 +3810,12 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } - temp_stream = msm_isp_get_controllable_stream(vfe_dev, - stream_info); - if (temp_stream->stream_type == BURST_STREAM && - temp_stream->runtime_num_burst_capture) { + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture) { ISP_DBG("%s: burst_frame_count: %d\n", __func__, - temp_stream->runtime_num_burst_capture); - temp_stream->runtime_num_burst_capture--; - /* - * For non controllable stream decrement the burst count for - * dual stream as well here - */ - if (!stream_info->controllable_output && vfe_dev->is_split && - RDI_INTF_0 > stream_info->stream_src) { - temp_stream = msm_isp_vfe_get_stream( - vfe_dev->common_data->dual_vfe_res, - ((vfe_dev->pdev->id == ISP_VFE0) ? - ISP_VFE1 : ISP_VFE0), - HANDLE_TO_IDX( - stream_info->stream_handle)); - temp_stream->runtime_num_burst_capture--; - } + stream_info->runtime_num_burst_capture); + stream_info->runtime_num_burst_capture--; } rc = msm_isp_update_deliver_count(vfe_dev, stream_info, @@ -3637,7 +3884,8 @@ void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, continue; } stream_idx = HANDLE_TO_IDX(comp_info->stream_handle); - stream_info = &axi_data->stream_info[stream_idx]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + stream_idx); msm_isp_process_axi_irq_stream(vfe_dev, stream_info, pingpong_status, ts); @@ -3656,7 +3904,8 @@ void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, pingpong_status); continue; } - stream_info = &axi_data->stream_info[stream_idx]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + stream_idx); msm_isp_process_axi_irq_stream(vfe_dev, stream_info, pingpong_status, ts); @@ -3670,6 +3919,7 @@ void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev) struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; int i, j; + int vfe_idx; if (!vfe_dev || !axi_data) { pr_err("%s: error %pK %pK\n", __func__, vfe_dev, axi_data); @@ -3677,14 +3927,16 @@ void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev) } for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - stream_info = &axi_data->stream_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); if (stream_info->state != ACTIVE) continue; + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); for (j = 0; j < stream_info->num_planes; j++) vfe_dev->hw_info->vfe_ops.axi_ops.enable_wm( vfe_dev->vfe_base, - stream_info->wm[j], 0); + stream_info->wm[vfe_idx][j], 0); } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index 08053aa410e7..84720f3d8625 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -14,37 +14,15 @@ #include "msm_isp.h" +#define HANDLE_TO_IDX(handle) (handle & 0xFF) #define SRC_TO_INTF(src) \ ((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \ (VFE_RAW_0 + src - RDI_INTF_0)) -int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx); - -int msm_isp_validate_axi_request( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_reserve_wm( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - int msm_isp_axi_check_stream_state( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); -int msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); @@ -62,10 +40,13 @@ int msm_isp_axi_restart(struct vfe_device *vfe_dev, struct msm_vfe_axi_restart_cmd *restart_cmd); void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); + enum msm_vfe_input_src frame_src, + struct msm_isp_timestamp *ts); -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); +void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, + enum msm_isp_comp_irq_types irq, + struct msm_isp_timestamp *ts); void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); @@ -94,6 +75,34 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, uint32_t pingpong_status, struct msm_isp_timestamp *ts); +void msm_isp_release_all_axi_stream(struct vfe_device *vfe_dev); + +static inline int msm_isp_get_vfe_idx_for_stream_user( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int vfe_idx; + + for (vfe_idx = 0; vfe_idx < stream_info->num_isp; vfe_idx++) { + if (stream_info->vfe_dev[vfe_idx] == vfe_dev) + return vfe_idx; + } + return -ENOTTY; +} + +static inline int msm_isp_get_vfe_idx_for_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info); + + if (vfe_idx < 0) { + WARN(1, "%s vfe index misssing for stream %d, vfe %d\n", + __func__, stream_info->stream_src, vfe_dev->pdev->id); + vfe_idx = 0; + } + return vfe_idx; +} + static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev, int wm, uint32_t pingpong_bit) @@ -103,18 +112,48 @@ static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev, pingpong_bit, vfe_dev->buf_mgr->scratch_buf_addr, 0); } -static inline void msm_isp_cfg_stream_scratch(struct vfe_device *vfe_dev, +static inline void msm_isp_cfg_stream_scratch( struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) { int i; + int j; uint32_t pingpong_bit; - - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); - for (i = 0; i < stream_info->num_planes; i++) - msm_isp_cfg_wm_scratch(vfe_dev, stream_info->wm[i], + int vfe_idx; + + pingpong_bit = (~(pingpong_status >> stream_info->wm[0][0]) & 0x1); + for (i = 0; i < stream_info->num_planes; i++) { + for (j = 0; j < stream_info->num_isp; j++) { + vfe_idx = msm_isp_get_vfe_idx_for_stream( + stream_info->vfe_dev[j], stream_info); + msm_isp_cfg_wm_scratch(stream_info->vfe_dev[j], + stream_info->wm[vfe_idx][i], ~pingpong_bit); + } + } stream_info->buf[pingpong_bit] = NULL; } +static inline struct msm_vfe_axi_stream *msm_isp_get_stream_common_data( + struct vfe_device *vfe_dev, int stream_idx) +{ + struct msm_vfe_common_dev_data *common_data = vfe_dev->common_data; + struct msm_vfe_axi_stream *stream_info; + + if (vfe_dev->is_split && stream_idx < RDI_INTF_0) + stream_info = &common_data->streams[stream_idx]; + else + stream_info = &common_data->streams[VFE_AXI_SRC_MAX * + vfe_dev->pdev->id + stream_idx]; + return stream_info; +} + +static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream( + struct dual_vfe_resource *dual_vfe_res, + int vfe_id, uint32_t index) +{ + return msm_isp_get_stream_common_data(dual_vfe_res->vfe_dev[vfe_id], + index); +} + #endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index 4aef6b5c7f38..f851e8c9289e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -22,59 +22,89 @@ static inline void msm_isp_stats_cfg_wm_scratch(struct vfe_device *vfe_dev, uint32_t pingpong_status) { vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( - vfe_dev->vfe_base, stream_info, + vfe_dev, stream_info, pingpong_status, vfe_dev->buf_mgr->scratch_buf_addr); } -static inline void msm_isp_stats_cfg_stream_scratch(struct vfe_device *vfe_dev, +static inline void msm_isp_stats_cfg_stream_scratch( struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status) { - uint32_t stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_idx = STATS_IDX(stream_info->stream_handle[0]); uint32_t pingpong_bit; - uint32_t stats_pingpong_offset = - vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ - stats_idx]; + uint32_t stats_pingpong_offset; + struct vfe_device *vfe_dev; + int i; + stats_pingpong_offset = stream_info->vfe_dev[0]->hw_info-> + stats_hw_info->stats_ping_pong_offset[stats_idx]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); - msm_isp_stats_cfg_wm_scratch(vfe_dev, stream_info, - pingpong_status); + for (i = 0; i < stream_info->num_isp; i++) { + vfe_dev = stream_info->vfe_dev[i]; + msm_isp_stats_cfg_wm_scratch(vfe_dev, stream_info, + pingpong_status); + } + stream_info->buf[pingpong_bit] = NULL; } -static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, +static int msm_isp_composite_stats_irq(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, + enum msm_isp_comp_irq_types irq) +{ + /* interrupt recv on same vfe w/o recv on other vfe */ + if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) { + pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n", + __func__, irq, vfe_dev->pdev->id); + return -EFAULT; + } + + stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id); + if (stream_info->composite_irq[irq] != stream_info->vfe_mask) + return 1; + + stream_info->composite_irq[irq] = 0; + + return 0; +} + +static int msm_isp_stats_cfg_ping_pong_address( struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status) { - int rc = -1, vfe_id = 0; - struct msm_isp_buffer *buf; - uint32_t pingpong_bit = 0; - uint32_t stats_pingpong_offset; + int rc = -1; + struct msm_isp_buffer *buf = NULL; uint32_t bufq_handle = stream_info->bufq_handle; - uint32_t stats_idx = STATS_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; - struct msm_vfe_stats_stream *dual_vfe_stream_info = NULL; + uint32_t stats_idx = STATS_IDX(stream_info->stream_handle[0]); + struct vfe_device *vfe_dev = stream_info->vfe_dev[0]; + uint32_t stats_pingpong_offset; + uint32_t pingpong_bit; + int k; if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type || stats_idx >= MSM_ISP_STATS_MAX) { pr_err("%s Invalid stats index %d", __func__, stats_idx); return -EINVAL; } - - stats_pingpong_offset = - vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ - stats_idx]; - + stats_pingpong_offset = vfe_dev->hw_info->stats_hw_info-> + stats_ping_pong_offset[stats_idx]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); + /* if buffer already exists then no need to replace */ + if (stream_info->buf[pingpong_bit]) + return 0; rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, bufq_handle, &buf); + vfe_dev->pdev->id, bufq_handle, + MSM_ISP_INVALID_BUF_INDEX, &buf); if (rc == -EFAULT) { msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); return rc; } - if (rc < 0 || NULL == buf) - vfe_dev->error_info.stats_framedrop_count[stats_idx]++; + if (rc < 0 || NULL == buf) { + for (k = 0; k < stream_info->num_isp; k++) + stream_info->vfe_dev[k]->error_info. + stats_framedrop_count[stats_idx]++; + } if (buf && buf->num_planes != 1) { pr_err("%s: Invalid buffer\n", __func__); @@ -82,58 +112,22 @@ static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, rc = -EINVAL; goto buf_error; } - if (vfe_dev->is_split) { - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_base[ISP_VFE0] || - !dual_vfe_res->stats_data[ISP_VFE0] || - !dual_vfe_res->vfe_base[ISP_VFE1] || - !dual_vfe_res->stats_data[ISP_VFE1]) { - pr_err("%s:%d error vfe0 %pK %pK vfe1 %pK %pK\n", - __func__, __LINE__, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->stats_data[ISP_VFE0], - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->stats_data[ISP_VFE1]); - } else { - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - dual_vfe_stream_info = &dual_vfe_res-> - stats_data[vfe_id]-> - stream_info[stats_idx]; - if (buf) - vfe_dev->hw_info->vfe_ops.stats_ops. - update_ping_pong_addr( - dual_vfe_res->vfe_base[vfe_id], - dual_vfe_stream_info, - pingpong_status, - buf->mapped_info[0].paddr + - dual_vfe_stream_info-> - buffer_offset); - else - msm_isp_stats_cfg_stream_scratch( - vfe_dev, - dual_vfe_stream_info, - pingpong_status); - dual_vfe_stream_info->buf[pingpong_bit] - = buf; - } - } - } else { - if (buf) - vfe_dev->hw_info->vfe_ops.stats_ops. - update_ping_pong_addr( - vfe_dev->vfe_base, stream_info, - pingpong_status, buf->mapped_info[0].paddr + - stream_info->buffer_offset); - else - msm_isp_stats_cfg_stream_scratch(vfe_dev, - stream_info, pingpong_status); - - stream_info->buf[pingpong_bit] = buf; + if (!buf) { + msm_isp_stats_cfg_stream_scratch(stream_info, + pingpong_status); + return 0; } + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( + vfe_dev, stream_info, pingpong_status, + buf->mapped_info[0].paddr + + stream_info->buffer_offset[k]); + } + stream_info->buf[pingpong_bit] = buf; + buf->pingpong_bit = pingpong_bit; - if (buf) - buf->pingpong_bit = pingpong_bit; return 0; buf_error: vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, @@ -155,6 +149,8 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, struct msm_isp_buffer *done_buf; uint32_t stats_pingpong_offset; uint32_t stats_idx; + int vfe_idx; + unsigned long flags; if (!vfe_dev || !ts || !buf_event || !stream_info) { pr_err("%s:%d failed: invalid params %pK %pK %pK %pK\n", @@ -163,6 +159,9 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, return -EINVAL; } frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + + spin_lock_irqsave(&stream_info->lock, flags); + sw_skip = &stream_info->sw_skip; stats_event = &buf_event->u.stats; @@ -182,73 +181,62 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, (struct msm_isp_sw_framskip)); } } - stats_idx = STATS_IDX(stream_info->stream_handle); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, stream_info); + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); stats_pingpong_offset = vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ stats_idx]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); - done_buf = stream_info->buf[pingpong_bit]; - - if (done_buf) - buf_index = done_buf->buf_idx; - - rc = vfe_dev->buf_mgr->ops->update_put_buf_cnt( - vfe_dev->buf_mgr, vfe_dev->pdev->id, stream_info->bufq_handle, - buf_index, &ts->buf_time, - frame_id, pingpong_bit); - - if (rc < 0) { - if (rc == -EFAULT) + rc = msm_isp_composite_stats_irq(vfe_dev, stream_info, + MSM_ISP_COMP_IRQ_PING_BUFDONE + pingpong_bit); + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc < 0) msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - pr_err("stats_buf_divert: update put buf cnt fail\n"); - return rc; - } - - if (rc > 0) { - ISP_DBG("%s: vfe_id %d buf_id %d bufq %x put_cnt 1\n", __func__, - vfe_dev->pdev->id, buf_index, - stream_info->bufq_handle); + ISP_EVENT_BUF_FATAL_ERROR); return rc; } + done_buf = stream_info->buf[pingpong_bit]; /* Program next buffer */ - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, stream_info, + stream_info->buf[pingpong_bit] = NULL; + rc = msm_isp_stats_cfg_ping_pong_address(stream_info, pingpong_status); - if (rc) + spin_unlock_irqrestore(&stream_info->lock, flags); + + if (!done_buf) return rc; - if (drop_buffer && done_buf) { - rc = vfe_dev->buf_mgr->ops->buf_done( + buf_index = done_buf->buf_idx; + if (drop_buffer) { + vfe_dev->buf_mgr->ops->put_buf( vfe_dev->buf_mgr, done_buf->bufq_handle, - done_buf->buf_idx, &ts->buf_time, frame_id, 0); - if (rc == -EFAULT) - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + done_buf->buf_idx); + } else { + /* divert native buffers */ + vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + done_buf->bufq_handle, done_buf->buf_idx, + &ts->buf_time, frame_id); } - - if (done_buf) { - stats_event->stats_buf_idxs - [stream_info->stats_type] = - done_buf->buf_idx; - if (NULL == comp_stats_type_mask) { - stats_event->stats_mask = - 1 << stream_info->stats_type; - ISP_DBG("%s: stats frameid: 0x%x %d bufq %x\n", - __func__, buf_event->frame_id, - stream_info->stats_type, done_buf->bufq_handle); - msm_isp_send_event(vfe_dev, - ISP_EVENT_STATS_NOTIFY + - stream_info->stats_type, - buf_event); - } else { - *comp_stats_type_mask |= - 1 << stream_info->stats_type; - } + stats_event->stats_buf_idxs + [stream_info->stats_type] = + done_buf->buf_idx; + if (comp_stats_type_mask == NULL) { + stats_event->stats_mask = + 1 << stream_info->stats_type; + ISP_DBG("%s: stats frameid: 0x%x %d bufq %x\n", + __func__, buf_event->frame_id, + stream_info->stats_type, done_buf->bufq_handle); + msm_isp_send_event(vfe_dev, + ISP_EVENT_STATS_NOTIFY + + stream_info->stats_type, + buf_event); + } else { + *comp_stats_type_mask |= + 1 << stream_info->stats_type; } return rc; @@ -275,8 +263,9 @@ static int32_t msm_isp_stats_configure(struct vfe_device *vfe_dev, for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { if (!(stats_irq_mask & (1 << i))) continue; - stream_info = &vfe_dev->stats_data.stream_info[i]; - if (stream_info->state == STATS_INACTIVE) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + if (stream_info->state == STATS_INACTIVE || + stream_info->state == STATS_STOPPING) { pr_debug("%s: Warning! Stream already inactive. Drop irq handling\n", __func__); continue; @@ -353,12 +342,17 @@ void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, } int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream_request_cmd *stream_req_cmd) + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd, + struct msm_vfe_stats_stream *stream_info) { - int rc = -1; - struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + int rc = 0; uint32_t stats_idx; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + int i; + + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask & (1 << stream_req_cmd->stats_type))) { @@ -366,16 +360,7 @@ int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, return rc; } - stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. - get_stats_idx(stream_req_cmd->stats_type); - - if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, stats_idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[stats_idx]; - if (stream_info->state != STATS_AVALIABLE) { + if (stream_info->state != STATS_AVAILABLE) { pr_err("%s: Stats already requested\n", __func__); return rc; } @@ -389,17 +374,74 @@ int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, pr_err("%s: Invalid irq subsample pattern\n", __func__); return rc; } + if (stream_req_cmd->composite_flag > + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_req_cmd->composite_flag, + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask); + return -EINVAL; + } - stream_info->session_id = stream_req_cmd->session_id; - stream_info->stream_id = stream_req_cmd->stream_id; - stream_info->composite_flag = stream_req_cmd->composite_flag; - stream_info->stats_type = stream_req_cmd->stats_type; - stream_info->buffer_offset = stream_req_cmd->buffer_offset; - stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern; - stream_info->init_stats_frame_drop = stream_req_cmd->init_frame_drop; - stream_info->irq_subsample_pattern = - stream_req_cmd->irq_subsample_pattern; - stream_info->state = STATS_INACTIVE; + if (stream_info->num_isp == 0) { + stream_info->session_id = stream_req_cmd->session_id; + stream_info->stream_id = stream_req_cmd->stream_id; + stream_info->composite_flag = stream_req_cmd->composite_flag; + stream_info->stats_type = stream_req_cmd->stats_type; + framedrop_pattern = stream_req_cmd->framedrop_pattern; + if (framedrop_pattern == SKIP_ALL) + framedrop_pattern = 0; + else + framedrop_pattern = 1; + stream_info->framedrop_pattern = framedrop_pattern; + stream_info->init_stats_frame_drop = + stream_req_cmd->init_frame_drop; + stream_info->irq_subsample_pattern = + stream_req_cmd->irq_subsample_pattern; + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + stream_info->framedrop_period = framedrop_period; + } else { + if (stream_info->vfe_mask & (1 << vfe_dev->pdev->id)) { + pr_err("%s: stats %d already requested for vfe %d\n", + __func__, stats_idx, vfe_dev->pdev->id); + return -EINVAL; + } + if (stream_info->session_id != stream_req_cmd->session_id) + rc = -EINVAL; + if (stream_info->session_id != stream_req_cmd->session_id) + rc = -EINVAL; + if (stream_info->composite_flag != + stream_req_cmd->composite_flag) + rc = -EINVAL; + if (stream_info->stats_type != stream_req_cmd->stats_type) + rc = -EINVAL; + framedrop_pattern = stream_req_cmd->framedrop_pattern; + if (framedrop_pattern == SKIP_ALL) + framedrop_pattern = 0; + else + framedrop_pattern = 1; + if (stream_info->framedrop_pattern != framedrop_pattern) + rc = -EINVAL; + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + if (stream_info->framedrop_period != framedrop_period) + rc = -EINVAL; + if (rc) { + pr_err("%s: Stats stream param mismatch between vfe\n", + __func__); + return rc; + } + } + stream_info->buffer_offset[stream_info->num_isp] = + stream_req_cmd->buffer_offset; + stream_info->vfe_dev[stream_info->num_isp] = vfe_dev; + stream_info->vfe_mask |= (1 << vfe_dev->pdev->id); + stream_info->num_isp++; + if (!vfe_dev->is_split || stream_info->num_isp == MAX_VFE) { + stream_info->state = STATS_INACTIVE; + for (i = 0; i < MSM_ISP_COMP_IRQ_MAX; i++) + stream_info->composite_irq[i] = 0; + } if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0) vfe_dev->stats_data.stream_handle_cnt++; @@ -407,7 +449,8 @@ int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, stream_req_cmd->stream_handle = (++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx; - stream_info->stream_handle = stream_req_cmd->stream_handle; + stream_info->stream_handle[stream_info->num_isp - 1] = + stream_req_cmd->stream_handle; return 0; } @@ -416,42 +459,39 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) int rc = -1; struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg; struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - uint32_t framedrop_period; uint32_t stats_idx; + unsigned long flags; - rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd); - if (rc < 0) { - pr_err("%s: create stream failed\n", __func__); - return rc; - } - - stats_idx = STATS_IDX(stream_req_cmd->stream_handle); + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { pr_err("%s Invalid stats index %d", __func__, stats_idx); return -EINVAL; } - stream_info = &stats_data->stream_info[stats_idx]; + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx); - framedrop_period = msm_isp_get_framedrop_period( - stream_req_cmd->framedrop_pattern); + spin_lock_irqsave(&stream_info->lock, flags); - if (stream_req_cmd->framedrop_pattern == SKIP_ALL) - stream_info->framedrop_pattern = 0x0; - else - stream_info->framedrop_pattern = 0x1; - stream_info->framedrop_period = framedrop_period - 1; + rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd, stream_info); + if (rc < 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: create stream failed\n", __func__); + return rc; + } if (stream_info->init_stats_frame_drop == 0) vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info); - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, + if (stream_info->state == STATS_INACTIVE) { + msm_isp_stats_cfg_stream_scratch(stream_info, VFE_PING_FLAG); - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, + msm_isp_stats_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); + } + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; } @@ -460,32 +500,112 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) int rc = -1; struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; int stats_idx = STATS_IDX(stream_release_cmd->stream_handle); struct msm_vfe_stats_stream *stream_info = NULL; + int vfe_idx; + int i; + int k; + unsigned long flags; if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { pr_err("%s Invalid stats index %d", __func__, stats_idx); return -EINVAL; } - stream_info = &stats_data->stream_info[stats_idx]; - if (stream_info->state == STATS_AVALIABLE) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx); + spin_lock_irqsave(&stream_info->lock, flags); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user( + vfe_dev, stream_info); + if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] != + stream_release_cmd->stream_handle) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Invalid stream handle %x, expected %x\n", + __func__, stream_release_cmd->stream_handle, + vfe_idx != -ENOTTY ? + stream_info->stream_handle[vfe_idx] : 0); + return -EINVAL; + } + if (stream_info->state == STATS_AVAILABLE) { + spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: stream already release\n", __func__); return rc; - } else if (stream_info->state != STATS_INACTIVE) { + } + vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); + + if (stream_info->state != STATS_INACTIVE) { stream_cfg_cmd.enable = 0; stream_cfg_cmd.num_streams = 1; stream_cfg_cmd.stream_handle[0] = stream_release_cmd->stream_handle; - rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + spin_lock_irqsave(&stream_info->lock, flags); } - vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); - memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); + for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) { + stream_info->vfe_dev[i] = stream_info->vfe_dev[k]; + stream_info->stream_handle[i] = stream_info->stream_handle[k]; + stream_info->buffer_offset[i] = stream_info->buffer_offset[k]; + } + + stream_info->vfe_dev[stream_info->num_isp] = 0; + stream_info->stream_handle[stream_info->num_isp] = 0; + stream_info->buffer_offset[stream_info->num_isp] = 0; + stream_info->num_isp--; + stream_info->vfe_mask &= ~(1 << vfe_dev->pdev->id); + if (stream_info->num_isp == 0) + stream_info->state = STATS_AVAILABLE; + + spin_unlock_irqrestore(&stream_info->lock, flags); return 0; } +void msm_isp_release_all_stats_stream(struct vfe_device *vfe_dev) +{ + struct msm_vfe_stats_stream_release_cmd + stream_release_cmd[MSM_ISP_STATS_MAX]; + struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_stats_stream *stream_info; + int i; + int vfe_idx; + int num_stream = 0; + unsigned long flags; + + stream_cfg_cmd.enable = 0; + stream_cfg_cmd.num_streams = 0; + + for (i = 0; i < MSM_ISP_STATS_MAX; i++) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == STATS_AVAILABLE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + if (vfe_idx == -ENOTTY) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_release_cmd[num_stream++].stream_handle = + stream_info->stream_handle[vfe_idx]; + if (stream_info->state == STATS_INACTIVE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_cfg_cmd.stream_handle[ + stream_cfg_cmd.num_streams] = + stream_info->stream_handle[vfe_idx]; + stream_cfg_cmd.num_streams++; + spin_unlock_irqrestore(&stream_info->lock, flags); + } + if (stream_cfg_cmd.num_streams) + msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + + for (i = 0; i < num_stream; i++) + msm_isp_release_stats_stream(vfe_dev, &stream_release_cmd[i]); +} + static int msm_isp_init_stats_ping_pong_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) @@ -497,108 +617,205 @@ static int msm_isp_init_stats_ping_pong_reg( stream_info->stream_id); if (stream_info->bufq_handle == 0) { pr_err("%s: no buf configured for stream: 0x%x\n", - __func__, stream_info->stream_handle); + __func__, stream_info->stream_handle[0]); return -EINVAL; } - if ((vfe_dev->is_split && vfe_dev->pdev->id == 1) || - !vfe_dev->is_split) { - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PING_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for ping\n", __func__); - return rc; - } - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PONG_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for pong\n", __func__); - return rc; - } + rc = msm_isp_stats_cfg_ping_pong_address( + stream_info, VFE_PING_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", __func__); + return rc; + } + rc = msm_isp_stats_cfg_ping_pong_address( + stream_info, VFE_PONG_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", __func__); + return rc; } return rc; } -void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev) +void __msm_isp_update_stats_framedrop_reg( + struct msm_vfe_stats_stream *stream_info) { - int i; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - struct msm_vfe_stats_stream *stream_info = NULL; + int k; + struct vfe_device *vfe_dev; - for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { - stream_info = &stats_data->stream_info[i]; - if (stream_info->state != STATS_ACTIVE) - continue; + if (!stream_info->init_stats_frame_drop) + return; + stream_info->init_stats_frame_drop--; + if (stream_info->init_stats_frame_drop) + return; - if (stream_info->init_stats_frame_drop) { - stream_info->init_stats_frame_drop--; - if (stream_info->init_stats_frame_drop == 0) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg( - vfe_dev, stream_info); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, + stream_info); + + } +} + +static void __msm_isp_stats_stream_update( + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t enable = 0; + uint8_t comp_flag = 0; + int k; + struct vfe_device *vfe_dev; + int index = STATS_IDX(stream_info->stream_handle[0]); + + switch (stream_info->state) { + case STATS_INACTIVE: + case STATS_ACTIVE: + case STATS_AVAILABLE: + break; + case STATS_START_PENDING: + enable = 1; + case STATS_STOP_PENDING: + stream_info->state = + (stream_info->state == STATS_START_PENDING ? + STATS_STARTING : STATS_STOPPING); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, BIT(index), enable); + comp_flag = stream_info->composite_flag; + if (comp_flag) { + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_comp_mask(vfe_dev, BIT(index), + (comp_flag - 1), enable); + } else { + if (enable) + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_wm_irq_mask(vfe_dev, + stream_info); + else + vfe_dev->hw_info->vfe_ops.stats_ops. + clear_wm_irq_mask(vfe_dev, + stream_info); } } + break; + case STATS_STARTING: + stream_info->state = STATS_ACTIVE; + complete_all(&stream_info->active_comp); + break; + case STATS_STOPPING: + stream_info->state = STATS_INACTIVE; + complete_all(&stream_info->inactive_comp); + break; } } + void msm_isp_stats_stream_update(struct vfe_device *vfe_dev) { int i; - uint32_t enable = 0; - uint8_t comp_flag = 0; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - struct msm_vfe_stats_ops *stats_ops = - &vfe_dev->hw_info->vfe_ops.stats_ops; + struct msm_vfe_stats_stream *stream_info; + unsigned long flags; for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { - if (stats_data->stream_info[i].state == STATS_START_PENDING || - stats_data->stream_info[i].state == - STATS_STOP_PENDING) { - enable = stats_data->stream_info[i].state == - STATS_START_PENDING ? 1 : 0; - stats_data->stream_info[i].state = - stats_data->stream_info[i].state == - STATS_START_PENDING ? - STATS_STARTING : STATS_STOPPING; - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, BIT(i), enable); - comp_flag = stats_data->stream_info[i].composite_flag; - if (comp_flag) - stats_ops->cfg_comp_mask(vfe_dev, BIT(i), - (comp_flag - 1), enable); - } else if (stats_data->stream_info[i].state == STATS_STARTING || - stats_data->stream_info[i].state == STATS_STOPPING) { - stats_data->stream_info[i].state = - stats_data->stream_info[i].state == - STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE; - } + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + __msm_isp_stats_stream_update(stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); } - atomic_sub(1, &stats_data->stats_update); - if (!atomic_read(&stats_data->stats_update)) - complete(&vfe_dev->stats_config_complete); } -static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev) +void msm_isp_process_stats_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_isp_comp_irq_types irq) { + int i; + struct msm_vfe_stats_stream *stream_info; + unsigned long flags; int rc; - init_completion(&vfe_dev->stats_config_complete); - atomic_set(&vfe_dev->stats_data.stats_update, 2); - rc = wait_for_completion_timeout( - &vfe_dev->stats_config_complete, + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + + spin_lock_irqsave(&stream_info->lock, flags); + + rc = msm_isp_composite_stats_irq(vfe_dev, stream_info, irq); + + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (-EFAULT == rc) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return; + } + continue; + } + + if (irq == MSM_ISP_COMP_IRQ_REG_UPD) + __msm_isp_stats_stream_update(stream_info); + else if (irq == MSM_ISP_COMP_IRQ_EPOCH && + stream_info->state == STATS_ACTIVE) + __msm_isp_update_stats_framedrop_reg(stream_info); + + spin_unlock_irqrestore(&stream_info->lock, flags); + } +} + +static int msm_isp_stats_wait_for_stream_cfg_done( + struct msm_vfe_stats_stream *stream_info, + int active) +{ + int rc = -1; + + if (active && stream_info->state == STATS_ACTIVE) + rc = 0; + if (!active && stream_info->state == STATS_INACTIVE) + rc = 0; + if (rc == 0) + return rc; + + rc = wait_for_completion_timeout(active ? &stream_info->active_comp : + &stream_info->inactive_comp, msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - if (rc == 0) { - pr_err("%s: wait timeout\n", __func__); - rc = -1; + if (rc <= 0) { + rc = rc ? rc : -ETIMEDOUT; + pr_err("%s: wait for stats stream %x idx %d state %d active %d config failed %d\n", + __func__, stream_info->stream_id, + STATS_IDX(stream_info->stream_handle[0]), + stream_info->state, active, rc); } else { rc = 0; } return rc; } +static int msm_isp_stats_wait_for_streams( + struct msm_vfe_stats_stream **streams, + int num_stream, int active) +{ + int rc = 0; + int i; + struct msm_vfe_stats_stream *stream_info; + + for (i = 0; i < num_stream; i++) { + stream_info = streams[i]; + rc |= msm_isp_stats_wait_for_stream_cfg_done(stream_info, + active); + } + return rc; +} + static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) { int i; uint32_t stats_mask = 0, idx; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + struct msm_vfe_stats_stream *stream_info; + int k; for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -607,12 +824,33 @@ static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev, pr_err("%s Invalid stats index %d", __func__, idx); return -EINVAL; } - stats_mask |= 1 << idx; + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, + idx); + if (stream_info->state == STATS_AVAILABLE) + continue; + + /* + * we update cgc after making streams inactive or before + * starting streams, so stream should be in inactive state + */ + if (stream_info->state == STATS_INACTIVE) + stats_mask |= 1 << idx; + for (k = 0; k < stream_info->num_isp; k++) { + if (update_vfes[stream_info->vfe_dev[k]->pdev->id]) + continue; + update_vfes[stream_info->vfe_dev[k]->pdev->id] = + stream_info->vfe_dev[k]; + } } - if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) { - vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override( - vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (k = 0; k < MAX_VFE; k++) { + if (!update_vfes[k]) + continue; + vfe_dev = update_vfes[k]; + if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) { + vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + } } return 0; } @@ -621,61 +859,108 @@ int msm_isp_stats_reset(struct vfe_device *vfe_dev) { int i = 0, rc = 0; struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; struct msm_isp_timestamp timestamp; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + unsigned long flags; + int k; msm_isp_get_timestamp(×tamp); - for (i = 0; i < MSM_ISP_STATS_MAX; i++) { - stream_info = &stats_data->stream_info[i]; - if (stream_info->state != STATS_ACTIVE) + if (vfe_dev->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev->common_data->dual_vfe_res-> + vfe_dev[i]; + } else { + update_vfes[vfe_dev->pdev->id] = vfe_dev; + } + + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) continue; - rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, stream_info->bufq_handle, - MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + for (i = 0; i < MSM_ISP_STATS_MAX; i++) { + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + msm_isp_stats_cfg_stream_scratch(stream_info, + VFE_PING_FLAG); + msm_isp_stats_cfg_stream_scratch(stream_info, + VFE_PONG_FLAG); + spin_unlock_irqrestore(&stream_info->lock, flags); + rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + if (rc == -EFAULT) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return rc; + } } } return rc; } -int msm_isp_stats_restart(struct vfe_device *vfe_dev) +int msm_isp_stats_restart(struct vfe_device *vfe_dev_ioctl) { int i = 0; struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + unsigned long flags; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + struct vfe_device *vfe_dev; + int k; + int j; + + if (vfe_dev_ioctl->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev_ioctl->common_data-> + dual_vfe_res->vfe_dev[i]; + } else { + update_vfes[vfe_dev_ioctl->pdev->id] = vfe_dev_ioctl; + } - for (i = 0; i < MSM_ISP_STATS_MAX; i++) { - stream_info = &stats_data->stream_info[i]; - if (stream_info->state < STATS_ACTIVE) + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) + continue; + for (i = 0; i < MSM_ISP_STATS_MAX; i++) { + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) continue; - msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + spin_lock_irqsave(&stream_info->lock, flags); + for (j = 0; j < MSM_ISP_COMP_IRQ_MAX; j++) + stream_info->composite_irq[j] = 0; + msm_isp_init_stats_ping_pong_reg(vfe_dev_ioctl, + stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); + } } return 0; } -static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, +static int msm_isp_check_stream_cfg_cmd(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) { - int i, rc = 0; - uint32_t stats_mask = 0, idx; - uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; - uint32_t num_stats_comp_mask = 0; + int i; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( - stats_data->stream_info); - if (rc < 0) - return rc; + uint32_t idx; + int vfe_idx; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -683,63 +968,99 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, pr_err("%s Invalid stats index %d", __func__, idx); return -EINVAL; } - - stream_info = &stats_data->stream_info[idx]; - if (stream_info->stream_handle != - stream_cfg_cmd->stream_handle[i]) { - pr_err("%s: Invalid stream handle: 0x%x received\n", - __func__, stream_cfg_cmd->stream_handle[i]); - continue; + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, idx); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received expected %x\n", + __func__, stream_cfg_cmd->stream_handle[i], + vfe_idx == -ENOTTY ? 0 : + stream_info->stream_handle[vfe_idx]); + return -EINVAL; } + } + return 0; +} - if (stream_info->composite_flag > num_stats_comp_mask) { - pr_err("%s: comp grp %d exceed max %d\n", - __func__, stream_info->composite_flag, - num_stats_comp_mask); - return -EINVAL; +static void __msm_isp_stop_stats_streams( + struct msm_vfe_stats_stream **streams, + int num_streams, + struct msm_isp_timestamp timestamp) +{ + int i; + int k; + struct msm_vfe_stats_stream *stream_info; + struct vfe_device *vfe_dev; + struct msm_vfe_stats_shared_data *stats_data; + unsigned long flags; + + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + spin_lock_irqsave(&stream_info->lock, flags); + init_completion(&stream_info->inactive_comp); + stream_info->state = STATS_STOP_PENDING; + if (stream_info->vfe_dev[0]-> + axi_data.src_info[VFE_PIX_0].active == 0) { + while (stream_info->state != STATS_INACTIVE) + __msm_isp_stats_stream_update(stream_info); } - rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); - if (rc < 0) { - pr_err("%s: No buffer for stream%d\n", __func__, idx); - return rc; + for (k = 0; k < stream_info->num_isp; k++) { + stats_data = &stream_info->vfe_dev[k]->stats_data; + stats_data->num_active_stream--; } - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) - stream_info->state = STATS_START_PENDING; - else - stream_info->state = STATS_ACTIVE; - - stats_data->num_active_stream++; - stats_mask |= 1 << idx; - - if (stream_info->composite_flag > 0) - comp_stats_mask[stream_info->composite_flag-1] |= - 1 << idx; - - ISP_DBG("%s: stats_mask %x %x active streams %d\n", - __func__, comp_stats_mask[0], - comp_stats_mask[1], - stats_data->num_active_stream); + msm_isp_stats_cfg_stream_scratch( + stream_info, VFE_PING_FLAG); + msm_isp_stats_cfg_stream_scratch( + stream_info, VFE_PONG_FLAG); + vfe_dev = stream_info->vfe_dev[0]; + if (vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id == + -EFAULT)) + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + spin_unlock_irqrestore(&stream_info->lock, flags); } - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); - } else { - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, stats_mask, stream_cfg_cmd->enable); - for (i = 0; i < num_stats_comp_mask; i++) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, comp_stats_mask[i], i, 1); + if (msm_isp_stats_wait_for_streams(streams, num_streams, 0)) { + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + if (stream_info->state == STATS_INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + while (stream_info->state != STATS_INACTIVE) + __msm_isp_stats_stream_update(stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); } } - return rc; } -static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, +static int msm_isp_check_stats_stream_state( + struct msm_vfe_stats_stream *stream_info, + int cmd) +{ + switch (stream_info->state) { + case STATS_AVAILABLE: + return -EINVAL; + case STATS_INACTIVE: + if (cmd == 0) + return -EALREADY; + break; + case STATS_ACTIVE: + if (cmd) + return -EALREADY; + break; + default: + WARN(1, "Invalid stats state %d\n", stream_info->state); + } + return 0; +} + +static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev_ioctl, struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; @@ -747,95 +1068,125 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; uint32_t num_stats_comp_mask = 0; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + struct msm_vfe_stats_shared_data *stats_data; + int num_stream = 0; + struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX]; struct msm_isp_timestamp timestamp; + unsigned long flags; + int k; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + uint32_t num_active_streams[MAX_VFE] = {0, 0}; + struct vfe_device *vfe_dev; msm_isp_get_timestamp(×tamp); num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - + vfe_dev_ioctl->hw_info->stats_hw_info->num_stats_comp_mask; for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[idx]; - if (stream_info->stream_handle != - stream_cfg_cmd->stream_handle[i]) { - pr_err("%s: Invalid stream handle: 0x%x received\n", - __func__, stream_cfg_cmd->stream_handle[i]); + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev_ioctl, idx); + spin_lock_irqsave(&stream_info->lock, flags); + rc = msm_isp_check_stats_stream_state(stream_info, 1); + if (rc == -EALREADY) { + spin_unlock_irqrestore(&stream_info->lock, flags); + rc = 0; continue; } - - if (stream_info->composite_flag > num_stats_comp_mask) { - pr_err("%s: comp grp %d exceed max %d\n", - __func__, stream_info->composite_flag, - num_stats_comp_mask); - return -EINVAL; + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + goto error; } + rc = msm_isp_init_stats_ping_pong_reg(vfe_dev_ioctl, + stream_info); + if (rc < 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: No buffer for stream%d\n", __func__, idx); + return rc; + } + init_completion(&stream_info->active_comp); + stream_info->state = STATS_START_PENDING; + if (vfe_dev_ioctl->axi_data.src_info[VFE_PIX_0].active == 0) { + while (stream_info->state != STATS_ACTIVE) + __msm_isp_stats_stream_update(stream_info); + } + spin_unlock_irqrestore(&stream_info->lock, flags); - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) - stream_info->state = STATS_STOP_PENDING; - else - stream_info->state = STATS_INACTIVE; - - stats_data->num_active_stream--; stats_mask |= 1 << idx; + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (update_vfes[vfe_dev->pdev->id]) + continue; + update_vfes[vfe_dev->pdev->id] = vfe_dev; + stats_data = &vfe_dev->stats_data; + num_active_streams[vfe_dev->pdev->id] = + stats_data->num_active_stream; + stats_data->num_active_stream++; + } - if (stream_info->composite_flag > 0) + if (stream_info->composite_flag) comp_stats_mask[stream_info->composite_flag-1] |= 1 << idx; - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PING_FLAG); - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PONG_FLAG); - ISP_DBG("%s: stats_mask %x %x active streams %d\n", __func__, comp_stats_mask[0], comp_stats_mask[1], stats_data->num_active_stream); + streams[num_stream++] = stream_info; } - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); - } else { - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, stats_mask, stream_cfg_cmd->enable); - for (i = 0; i < num_stats_comp_mask; i++) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, comp_stats_mask[i], i, 0); - } + for (k = 0; k < MAX_VFE; k++) { + if (!update_vfes[k] || num_active_streams[k]) + continue; + vfe_dev = update_vfes[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); } + rc = msm_isp_stats_wait_for_streams(streams, num_stream, 1); + if (rc) + goto error; + return 0; +error: + __msm_isp_stop_stats_streams(streams, num_stream, timestamp); + return rc; +} + +static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t idx; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_isp_timestamp timestamp; + int num_stream = 0; + struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX]; + unsigned long flags; + + msm_isp_get_timestamp(×tamp); + + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - stream_info = &stats_data->stream_info[idx]; - rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, stream_info->bufq_handle, - MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, idx); + spin_lock_irqsave(&stream_info->lock, flags); + rc = msm_isp_check_stats_stream_state(stream_info, 0); + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + rc = 0; + continue; } + spin_unlock_irqrestore(&stream_info->lock, flags); + streams[num_stream++] = stream_info; } + + __msm_isp_stop_stats_streams(streams, num_stream, timestamp); + return rc; } @@ -843,8 +1194,10 @@ int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0; struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg; - if (vfe_dev->stats_data.num_active_stream == 0) - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); + + rc = msm_isp_check_stream_cfg_cmd(vfe_dev, stream_cfg_cmd); + if (rc) + return rc; if (stream_cfg_cmd->enable) { msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd); @@ -863,31 +1216,37 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, i; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL; struct msm_isp_sw_framskip *sw_skip_info = NULL; + int vfe_idx; + int k; /*validate request*/ for (i = 0; i < update_cmd->num_streams; i++) { - update_info = &update_cmd->update_info[i]; + update_info = (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; /*check array reference bounds*/ if (STATS_IDX(update_info->stream_handle) > vfe_dev->hw_info->stats_hw_info->num_stats_type) { pr_err("%s: stats idx %d out of bound!", __func__, - STATS_IDX(update_info->stream_handle)); + STATS_IDX(update_info->stream_handle)); return -EINVAL; } } for (i = 0; i < update_cmd->num_streams; i++) { - update_info = &update_cmd->update_info[i]; - stream_info = &stats_data->stream_info[ - STATS_IDX(update_info->stream_handle)]; - if (stream_info->stream_handle != + update_info = (struct msm_vfe_axi_stream_cfg_update_info *) + &update_cmd->update_info[i]; + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, + STATS_IDX(update_info->stream_handle)); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] != update_info->stream_handle) { pr_err("%s: stats stream handle %x %x mismatch!\n", - __func__, stream_info->stream_handle, + __func__, vfe_idx != -ENOTTY ? + stream_info->stream_handle[vfe_idx] : 0, update_info->stream_handle); continue; } @@ -897,18 +1256,22 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) uint32_t framedrop_period = msm_isp_get_framedrop_period( update_info->skip_pattern); - if (update_info->skip_pattern == SKIP_ALL) + if (update_info->skip_pattern == + SKIP_ALL) stream_info->framedrop_pattern = 0x0; else stream_info->framedrop_pattern = 0x1; stream_info->framedrop_period = framedrop_period - 1; if (stream_info->init_stats_frame_drop == 0) - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg( - vfe_dev, stream_info); + for (k = 0; k < stream_info->num_isp; k++) + stream_info->vfe_dev[k]->hw_info-> + vfe_ops.stats_ops.cfg_wm_reg( + vfe_dev, stream_info); break; } case UPDATE_STREAM_SW_FRAME_DROP: { - sw_skip_info = &update_info->sw_skip_info; + sw_skip_info = + &update_info->sw_skip_info; if (!stream_info->sw_skip.stream_src_mask) stream_info->sw_skip = *sw_skip_info; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h index 01120b65be92..e9728f33fae1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-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 @@ -23,8 +23,58 @@ int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); -void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev); void msm_isp_stats_disable(struct vfe_device *vfe_dev); int msm_isp_stats_reset(struct vfe_device *vfe_dev); int msm_isp_stats_restart(struct vfe_device *vfe_dev); +void msm_isp_release_all_stats_stream(struct vfe_device *vfe_dev); +void msm_isp_process_stats_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_isp_comp_irq_types irq); + +static inline int msm_isp_get_vfe_idx_for_stats_stream_user( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int vfe_idx; + + for (vfe_idx = 0; vfe_idx < stream_info->num_isp; vfe_idx++) + if (stream_info->vfe_dev[vfe_idx] == vfe_dev) + return vfe_idx; + return -ENOTTY; +} + +static inline int msm_isp_get_vfe_idx_for_stats_stream( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + + if (vfe_idx < 0) { + WARN(1, "%s vfe index missing for stream %d vfe %d\n", + __func__, stream_info->stats_type, vfe_dev->pdev->id); + vfe_idx = 0; + } + return vfe_idx; +} + +static inline struct msm_vfe_stats_stream * + msm_isp_get_stats_stream_common_data( + struct vfe_device *vfe_dev, + enum msm_isp_stats_type idx) +{ + if (vfe_dev->is_split) + return &vfe_dev->common_data->stats_streams[idx]; + else + return &vfe_dev->common_data->stats_streams[idx + + MSM_ISP_STATS_MAX * vfe_dev->pdev->id]; +} + +static inline struct msm_vfe_stats_stream * + msm_isp_get_stats_stream(struct dual_vfe_resource *dual_vfe_res, + int vfe_id, + enum msm_isp_stats_type idx) +{ + return msm_isp_get_stats_stream_common_data( + dual_vfe_res->vfe_dev[vfe_id], idx); +} #endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index e47a8de30aa9..a4eb80f31984 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -25,6 +25,22 @@ static DEFINE_MUTEX(bandwidth_mgr_mutex); static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; +#define MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev) { \ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { \ + struct vfe_device *vfe1_dev = vfe_dev->common_data-> \ + dual_vfe_res->vfe_dev[ISP_VFE1]; \ + mutex_lock(&vfe1_dev->core_mutex); \ + } \ +} + +#define MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev) { \ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { \ + struct vfe_device *vfe1_dev = vfe_dev->common_data-> \ + dual_vfe_res->vfe_dev[ISP_VFE1]; \ + mutex_unlock(&vfe1_dev->core_mutex); \ + } \ +} + static uint64_t msm_isp_cpp_clk_rate; #define VFE40_8974V2_VERSION 0x1001001A @@ -354,9 +370,6 @@ void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, struct msm_vfe_fetch_engine_info *fetch_engine_info) { struct msm_isp_event_data fe_rd_done_event; - if (!fetch_engine_info->is_busy) - return; - memset(&fe_rd_done_event, 0, sizeof(struct msm_isp_event_data)); fe_rd_done_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; @@ -762,26 +775,39 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, } case VIDIOC_MSM_ISP_REQUEST_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_request_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_RELEASE_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_release_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_CFG_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_cfg_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_AXI_HALT: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_axi_halt(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_AXI_RESET: mutex_lock(&vfe_dev->core_mutex); + /* For dual vfe reset both on vfe1 call */ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { + mutex_unlock(&vfe_dev->core_mutex); + return 0; + } if (atomic_read(&vfe_dev->error_info.overflow_state) != HALT_ENFORCED) { rc = msm_isp_stats_reset(vfe_dev); @@ -796,6 +822,11 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_AXI_RESTART: mutex_lock(&vfe_dev->core_mutex); + /* For dual vfe restart both on vfe1 call */ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { + mutex_unlock(&vfe_dev->core_mutex); + return 0; + } if (atomic_read(&vfe_dev->error_info.overflow_state) != HALT_ENFORCED) { rc = msm_isp_stats_restart(vfe_dev); @@ -848,27 +879,37 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_request_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_release_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_CFG_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_cfg_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_UPDATE_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_update_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_UPDATE_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_update_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_SMMU_ATTACH: @@ -883,10 +924,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, vfe_dev->isp_raw2_debug = 0; break; case MSM_SD_UNNOTIFY_FREEZE: - break; case MSM_SD_SHUTDOWN: - while (vfe_dev->vfe_open_cnt != 0) - msm_isp_close_node(sd, NULL); break; default: @@ -1631,8 +1669,8 @@ static int msm_isp_process_iommu_page_fault(struct vfe_device *vfe_dev) { int rc = vfe_dev->buf_mgr->pagefault_debug_disable; - pr_err("%s:%d] VFE%d Handle Page fault! vfe_dev %pK\n", __func__, - __LINE__, vfe_dev->pdev->id, vfe_dev); + pr_err("%s:%d] VFE%d Handle Page fault!\n", __func__, + __LINE__, vfe_dev->pdev->id); msm_isp_halt_send_error(vfe_dev, ISP_EVENT_IOMMU_P_FAULT); @@ -1899,6 +1937,7 @@ static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain, if (vfe_dev->vfe_open_cnt > 0) { atomic_set(&vfe_dev->error_info.overflow_state, HALT_ENFORCED); + pr_err("%s: fault address is %lx\n", __func__, iova); msm_isp_process_iommu_page_fault(vfe_dev); } else { pr_err("%s: no handling, vfe open cnt = %d\n", @@ -1928,9 +1967,6 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return -EINVAL; } - if (vfe_dev->pdev->id == ISP_VFE0) - vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0; - mutex_lock(&vfe_dev->realtime_mutex); mutex_lock(&vfe_dev->core_mutex); @@ -2032,6 +2068,10 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_unlock(&vfe_dev->realtime_mutex); return 0; } + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); + msm_isp_release_all_axi_stream(vfe_dev); + msm_isp_release_all_stats_stream(vfe_dev); + /* Unregister page fault handler */ cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, @@ -2059,6 +2099,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_isp_end_avtimer(); vfe_dev->vt_enable = 0; } + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); vfe_dev->is_split = 0; mutex_unlock(&vfe_dev->core_mutex); @@ -2088,25 +2129,3 @@ void msm_isp_flush_tasklet(struct vfe_device *vfe_dev) return; } -void msm_isp_save_framedrop_values(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) -{ - struct msm_vfe_axi_stream *stream_info = NULL; - uint32_t j = 0; - unsigned long flags; - - for (j = 0; j < VFE_AXI_SRC_MAX; j++) { - stream_info = &vfe_dev->axi_data.stream_info[j]; - if (stream_info->state != ACTIVE) - continue; - if (frame_src != SRC_TO_INTF(stream_info->stream_src)) - continue; - - stream_info = - &vfe_dev->axi_data.stream_info[j]; - spin_lock_irqsave(&stream_info->lock, flags); - stream_info->activated_framedrop_period = - stream_info->requested_framedrop_period; - spin_unlock_irqrestore(&stream_info->lock, flags); - } -} diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h index 9df60c0d7383..16e3198f35b7 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h @@ -70,7 +70,5 @@ void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, struct msm_vfe_fetch_engine_info *fetch_engine_info); void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format); void msm_isp_flush_tasklet(struct vfe_device *vfe_dev); -void msm_isp_save_framedrop_values(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp); #endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c index 2af70b2ee1bf..3b38882c4c45 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c @@ -1390,7 +1390,7 @@ int msm_jpegdma_hw_get_max_downscale(struct msm_jpegdma_device *dma) */ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma) { - int i; + int i, j; int ret; unsigned int cnt; const void *property; @@ -1401,32 +1401,37 @@ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "Missing qos settings\n"); return 0; } + cnt /= 4; + if (cnt % 2) + return -EINVAL; + + dma->qos_regs_num = cnt / 2; - dma->qos_regs = kzalloc((sizeof(*dma->qos_regs) * cnt), GFP_KERNEL); + dma->qos_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) * + dma->qos_regs_num), GFP_KERNEL); if (!dma->qos_regs) return -ENOMEM; - for (i = 0; i < cnt; i = i + 2) { + for (i = 0, j = 0; i < cnt; i += 2, j++) { ret = of_property_read_u32_index(dma->dev->of_node, "qcom,qos-reg-settings", i, - &dma->qos_regs[i].reg); + &dma->qos_regs[j].reg); if (ret < 0) { - dev_err(dma->dev, "can not read qos reg %d\n", i); + dev_err(dma->dev, "can not read qos reg %d\n", j); goto error; } ret = of_property_read_u32_index(dma->dev->of_node, "qcom,qos-reg-settings", i + 1, - &dma->qos_regs[i].val); + &dma->qos_regs[j].val); if (ret < 0) { - dev_err(dma->dev, "can not read qos setting %d\n", i); + dev_err(dma->dev, "can not read qos setting %d\n", j); goto error; } - dev_dbg(dma->dev, "Qos idx %d, reg %x val %x\n", i, - dma->qos_regs[i].reg, dma->qos_regs[i].val); + dev_dbg(dma->dev, "Qos idx %d, reg %x val %x\n", j, + dma->qos_regs[j].reg, dma->qos_regs[j].val); } - dma->qos_regs_num = cnt; return 0; error: @@ -1452,7 +1457,7 @@ void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma) */ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma) { - int i; + int i, j; int ret; unsigned int cnt; const void *property; @@ -1463,33 +1468,38 @@ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "Missing vbif settings\n"); return 0; } + cnt /= 4; + if (cnt % 2) + return -EINVAL; - dma->vbif_regs = kzalloc((sizeof(*dma->vbif_regs) * cnt), GFP_KERNEL); + dma->vbif_regs_num = cnt / 2; + + dma->vbif_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) * + dma->vbif_regs_num), GFP_KERNEL); if (!dma->vbif_regs) return -ENOMEM; - for (i = 0; i < cnt; i = i + 2) { + for (i = 0, j = 0; i < cnt; i += 2, j++) { ret = of_property_read_u32_index(dma->dev->of_node, "qcom,vbif-reg-settings", i, - &dma->vbif_regs[i].reg); + &dma->vbif_regs[j].reg); if (ret < 0) { - dev_err(dma->dev, "can not read vbif reg %d\n", i); + dev_err(dma->dev, "can not read vbif reg %d\n", j); goto error; } ret = of_property_read_u32_index(dma->dev->of_node, "qcom,vbif-reg-settings", i + 1, - &dma->vbif_regs[i].val); + &dma->vbif_regs[j].val); if (ret < 0) { - dev_err(dma->dev, "can not read vbif setting %d\n", i); + dev_err(dma->dev, "can not read vbif setting %d\n", j); goto error; } - dev_dbg(dma->dev, "Vbif idx %d, reg %x val %x\n", i, - dma->vbif_regs[i].reg, dma->vbif_regs[i].val); + dev_dbg(dma->dev, "Vbif idx %d, reg %x val %x\n", j, + dma->vbif_regs[j].reg, dma->vbif_regs[j].val); } - dma->vbif_regs_num = cnt; return 0; error: @@ -1515,7 +1525,7 @@ void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma) */ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma) { - int i; + int i, j; int ret; unsigned int cnt; const void *property; @@ -1526,35 +1536,39 @@ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma) dev_dbg(dma->dev, "Missing prefetch settings\n"); return 0; } + cnt /= 4; + if (cnt % 2) + return -EINVAL; + + dma->prefetch_regs_num = cnt / 2; - dma->prefetch_regs = kcalloc(cnt, sizeof(*dma->prefetch_regs), - GFP_KERNEL); + dma->prefetch_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) * + dma->prefetch_regs_num), GFP_KERNEL); if (!dma->prefetch_regs) return -ENOMEM; - for (i = 0; i < cnt; i = i + 2) { + for (i = 0, j = 0; i < cnt; i += 2, j++) { ret = of_property_read_u32_index(dma->dev->of_node, "qcom,prefetch-reg-settings", i, - &dma->prefetch_regs[i].reg); + &dma->prefetch_regs[j].reg); if (ret < 0) { - dev_err(dma->dev, "can not read prefetch reg %d\n", i); + dev_err(dma->dev, "can not read prefetch reg %d\n", j); goto error; } ret = of_property_read_u32_index(dma->dev->of_node, "qcom,prefetch-reg-settings", i + 1, - &dma->prefetch_regs[i].val); + &dma->prefetch_regs[j].val); if (ret < 0) { dev_err(dma->dev, "can not read prefetch setting %d\n", - i); + j); goto error; } - dev_dbg(dma->dev, "Prefetch idx %d, reg %x val %x\n", i, - dma->prefetch_regs[i].reg, dma->prefetch_regs[i].val); + dev_dbg(dma->dev, "Prefetch idx %d, reg %x val %x\n", j, + dma->prefetch_regs[j].reg, dma->prefetch_regs[j].val); } - dma->prefetch_regs_num = cnt; return 0; error: diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h index c2b928d2b5d3..198d130b24fc 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h @@ -101,4 +101,61 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = { {0x38, 0xFE}, {0x81c, 0x6}, }; + +struct csiphy_settings_t csiphy_combo_mode_v5_0 = { + { + {0x818, 0x1}, + {0x81c, 0x2}, + {0x004, 0x08}, + {0x704, 0x08}, + {0x204, 0x08}, + {0x404, 0x08}, + {0x604, 0x08}, + {0x02c, 0x1}, + {0x22c, 0x1}, + {0x42c, 0x1}, + {0x62c, 0x1}, + {0x72c, 0x1}, + {0x034, 0x0f}, + {0x234, 0x0f}, + {0x434, 0x0f}, + {0x634, 0x0f}, + {0x734, 0x0f}, + {0x01c, 0x0a}, + {0x21c, 0x0a}, + {0x41c, 0x0a}, + {0x61c, 0x0a}, + {0x71c, 0x0a}, + {0x014, 0x60}, + {0x214, 0x60}, + {0x414, 0x60}, + {0x614, 0x60}, + {0x714, 0x60}, + {0x728, 0x4}, + {0x428, 0x0a}, + {0x628, 0x0e}, + {0x03c, 0xb8}, + {0x73c, 0xb8}, + {0x23c, 0xb8}, + {0x43c, 0xb8}, + {0x63c, 0xb8}, + {0x000, 0x91}, + {0x700, 0x80}, + {0x200, 0x91}, + {0x400, 0x91}, + {0x600, 0x80}, + {0x70c, 0xA5}, + {0x60c, 0xA5}, + {0x010, 0x52}, + {0x710, 0x52}, + {0x210, 0x52}, + {0x410, 0x52}, + {0x610, 0x52}, + {0x038, 0xfe}, + {0x738, 0x1f}, + {0x238, 0xfe}, + {0x438, 0xfe}, + {0x638, 0x1f}, + } +}; #endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 30af06dc64f5..bdee620e8d45 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -46,7 +46,7 @@ #define NUM_LANES_OFFSET 4 #define CSI_3PHASE_HW 1 -#define MAX_LANES 4 +#define MAX_DPHY_DATA_LN 4 #define CLOCK_OFFSET 0x700 #define CSIPHY_SOF_DEBUG_COUNT 2 @@ -55,6 +55,22 @@ static struct v4l2_file_operations msm_csiphy_v4l2_subdev_fops; +static void msm_csiphy_write_settings( + struct csiphy_device *csiphy_dev, + struct csiphy_settings_t csiphy_settings) +{ + int i = 0; + + for (i = 0; i < MAX_CSIPHY_SETTINGS; i++) { + if (csiphy_settings.settings[i].addr == 0 && + csiphy_settings.settings[i].data == 0) + break; + + msm_camera_io_w(csiphy_settings.settings[i].data, + csiphy_dev->base + csiphy_settings.settings[i].addr); + } +} + static void msm_csiphy_cphy_irq_config( struct csiphy_device *csiphy_dev, struct msm_camera_csiphy_params *csiphy_params) @@ -418,7 +434,7 @@ static int msm_csiphy_2phase_lane_config( csiphybase = csiphy_dev->base; lane_mask = csiphy_params->lane_mask & 0x1f; - for (i = 0; i < MAX_LANES; i++) { + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { if (mask == 0x2) { if (lane_mask & mask) lane_enable |= 0x80; @@ -437,7 +453,7 @@ static int msm_csiphy_2phase_lane_config( csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_3ph_cmn_ctrl6.addr); - for (i = 0, mask = 0x1; i < MAX_LANES; i++) { + for (i = 0, mask = 0x1; i < MAX_DPHY_DATA_LN; i++) { if (!(lane_mask & mask)) { if (mask == 0x2) i--; @@ -562,112 +578,134 @@ static int msm_csiphy_2phase_lane_config_v50( struct csiphy_device *csiphy_dev, struct msm_camera_csiphy_params *csiphy_params) { - uint32_t val = 0, lane_enable = 0, clk_lane, mask = 1; + uint32_t lane_enable = 0, mask = 1; uint16_t lane_mask = 0, i = 0, offset; void __iomem *csiphybase; csiphybase = csiphy_dev->base; lane_mask = csiphy_params->lane_mask & 0x1f; - for (i = 0; i < MAX_LANES; i++) { + + lane_enable = msm_camera_io_r(csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_3ph_cmn_ctrl5.addr); + + /* write settle count and lane_enable */ + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { if (mask == 0x2) { if (lane_mask & mask) lane_enable |= 0x80; i--; - } else if (lane_mask & mask) + offset = CLOCK_OFFSET; + } else if (lane_mask & mask) { lane_enable |= 0x1 << (i<<1); + offset = 0x200*i; + } + + if (lane_mask & mask) + msm_camera_io_w((csiphy_params->settle_cnt & 0xFF), + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg2.addr + offset); mask <<= 1; } - CDBG("%s:%d lane_enable: %d\n", __func__, __LINE__, lane_enable); + CDBG("%s:%d lane_enable: 0x%x\n", __func__, __LINE__, lane_enable); msm_camera_io_w(lane_enable, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_3ph_cmn_ctrl5.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl7.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl7.addr); - - for (i = 0, mask = 0x1; i < MAX_LANES; i++) { - if (!(lane_mask & mask)) { - if (mask == 0x2) - i--; - mask <<= 0x1; - continue; - } - if (mask == 0x2) { - val = 4; - offset = CLOCK_OFFSET; - clk_lane = 1; - i--; - } else { - offset = 0x200*i; - val = 0; - clk_lane = 0; - } - if (csiphy_params->combo_mode == 1) { - val |= 0xA; - if (mask == csiphy_dev->ctrl_reg-> - csiphy_reg.combo_clk_mask) { - val |= 0x4; - clk_lane = 1; - } - } - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl11.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl11.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl13.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl13.addr + offset); + /* write mode specific settings */ + if (csiphy_params->combo_mode == 1) + msm_csiphy_write_settings(csiphy_dev, + csiphy_dev->ctrl_reg->csiphy_combo_mode_settings); + else { msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg7.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg7.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.data, + mipi_csiphy_3ph_cmn_ctrl6.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.addr + offset); - if (clk_lane == 1) - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl10.data, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl10.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl15.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl15.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl0.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl0.addr + offset); + mipi_csiphy_3ph_cmn_ctrl6.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.addr + offset); - msm_camera_io_w((csiphy_params->settle_cnt & 0xFF), + mipi_csiphy_3ph_cmn_ctrl7.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg2.addr + offset); - if (clk_lane == 1) - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl3.data, csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnck_ctrl3.addr); + mipi_csiphy_3ph_cmn_ctrl7.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + + mipi_csiphy_2ph_lnck_ctrl10.data, + csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg4.addr + offset); + mipi_csiphy_2ph_lnck_ctrl10.addr); msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl14.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl14.addr + offset); - mask <<= 1; + mipi_csiphy_2ph_lnck_ctrl3.data, csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnck_ctrl3.addr); + + for (i = 0, mask = 0x1; i < MAX_DPHY_DATA_LN; i++) { + if (!(lane_mask & mask)) { + if (mask == 0x2) + i--; + mask <<= 0x1; + continue; + } + if (mask == 0x2) { + offset = CLOCK_OFFSET; + i--; + } else { + offset = 0x200*i; + } + + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl11.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl11.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl13.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl13.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg7.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg7.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg5.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg5.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl15.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl15.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl0.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl0.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg1.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg1.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg4.addr + offset); + msm_camera_io_w(csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl14.data, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_ctrl14.addr + offset); + mask <<= 1; + } } msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params); return 0; @@ -986,19 +1024,20 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) } CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { pr_err("%s: csiphy invalid state %d\n", __func__, csiphy_dev->csiphy_state); rc = -EINVAL; return rc; } - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } CDBG("%s:%d called\n", __func__, __LINE__); rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, @@ -1063,6 +1102,14 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) return rc; } csiphy_dev->csiphy_sof_debug_count = 0; + + CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { pr_err("%s: csiphy invalid state %d\n", __func__, @@ -1070,13 +1117,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) rc = -EINVAL; return rc; } - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } CDBG("%s:%d called\n", __func__, __LINE__); rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, CAM_AHB_SVS_VOTE); @@ -1651,6 +1692,8 @@ static int csiphy_probe(struct platform_device *pdev) new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v5_0; new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V50; new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW; + new_csiphy_dev->ctrl_reg->csiphy_combo_mode_settings = + csiphy_combo_mode_v5_0; } else { pr_err("%s:%d, invalid hw version : 0x%x\n", __func__, __LINE__, new_csiphy_dev->hw_dts_version); diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h index 4944ac606bc8..aba88da1157e 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h @@ -24,12 +24,17 @@ #define MAX_CSIPHY 3 #define CSIPHY_NUM_CLK_MAX 16 +#define MAX_CSIPHY_SETTINGS 120 struct csiphy_reg_t { uint32_t addr; uint32_t data; }; +struct csiphy_settings_t { + struct csiphy_reg_t settings[MAX_CSIPHY_SETTINGS]; +}; + struct csiphy_reg_parms_t { /*MIPI CSI PHY registers*/ uint32_t mipi_csiphy_lnn_cfg1_addr; @@ -140,6 +145,7 @@ struct csiphy_reg_3ph_parms_t { struct csiphy_ctrl_t { struct csiphy_reg_parms_t csiphy_reg; struct csiphy_reg_3ph_parms_t csiphy_3ph_reg; + struct csiphy_settings_t csiphy_combo_mode_settings; }; enum msm_csiphy_state_t { diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index d0ce1de1162a..5f749bd46273 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/of_gpio.h> +#include <linux/leds-qpnp-flash.h> #include "msm_flash.h" #include "msm_camera_dt_util.h" #include "msm_cci.h" @@ -491,6 +492,45 @@ static int32_t msm_flash_init( return 0; } +static int32_t msm_flash_prepare( + struct msm_flash_ctrl_t *flash_ctrl) +{ + int32_t ret = 0; + + CDBG("%s:%d: State : %d\n", + __func__, __LINE__, flash_ctrl->flash_state); + + if (flash_ctrl->switch_trigger == NULL) { + pr_err("%s:%d Invalid argument\n", + __func__, __LINE__); + return -EINVAL; + } + + if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT && + flash_ctrl->is_regulator_enabled == 0) { + ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (ret < 0) { + pr_err("%s:%d regulator enable failed ret = %d\n", + __func__, __LINE__, ret); + return ret; + } + flash_ctrl->is_regulator_enabled = 1; + } else if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_RELEASE && + flash_ctrl->is_regulator_enabled) { + ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (ret < 0) { + pr_err("%s:%d regulator disable failed ret = %d\n", + __func__, __LINE__, ret); + return ret; + } + flash_ctrl->is_regulator_enabled = 0; + } + CDBG("%s:%d:Exit\n", __func__, __LINE__); + return ret; +} + static int32_t msm_flash_low( struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data) @@ -564,15 +604,33 @@ static int32_t msm_flash_high( return 0; } +static int32_t msm_flash_query_current( + struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_query_data_t *flash_query_data) +{ + int32_t ret = -EINVAL; + int32_t max_current = -EINVAL; + + if (flash_ctrl->switch_trigger) { + ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + QUERY_MAX_CURRENT, &max_current); + if (ret < 0) { + pr_err("%s:%d Query max_avail_curr failed ret = %d\n", + __func__, __LINE__, ret); + return ret; + } + } + + flash_query_data->max_avail_curr = max_current; + CDBG("%s: %d: max_avail_curr : %d\n", __func__, __LINE__, + flash_query_data->max_avail_curr); + return 0; +} + static int32_t msm_flash_release( struct msm_flash_ctrl_t *flash_ctrl) { int32_t rc = 0; - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_RELEASE) { - pr_err("%s:%d Invalid flash state = %d", - __func__, __LINE__, flash_ctrl->flash_state); - return 0; - } rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, NULL); if (rc < 0) { @@ -600,24 +658,49 @@ static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl, rc = msm_flash_init(flash_ctrl, flash_data); break; case CFG_FLASH_RELEASE: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if (flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) { rc = flash_ctrl->func_tbl->camera_flash_release( flash_ctrl); + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; case CFG_FLASH_OFF: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if ((flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) && + (flash_ctrl->flash_state != MSM_CAMERA_FLASH_OFF)) { rc = flash_ctrl->func_tbl->camera_flash_off( flash_ctrl, flash_data); + if (!rc) + flash_ctrl->flash_state = MSM_CAMERA_FLASH_OFF; + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; case CFG_FLASH_LOW: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) || + (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) { rc = flash_ctrl->func_tbl->camera_flash_low( flash_ctrl, flash_data); + if (!rc) + flash_ctrl->flash_state = MSM_CAMERA_FLASH_LOW; + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; case CFG_FLASH_HIGH: - if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) + if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) || + (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) { rc = flash_ctrl->func_tbl->camera_flash_high( flash_ctrl, flash_data); + if (!rc) + flash_ctrl->flash_state = MSM_CAMERA_FLASH_HIGH; + } else { + CDBG(pr_fmt("Invalid state : %d\n"), + flash_ctrl->flash_state); + } break; default: rc = -EFAULT; @@ -626,11 +709,55 @@ static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl, mutex_unlock(flash_ctrl->flash_mutex); + rc = msm_flash_prepare(flash_ctrl); + if (rc < 0) { + pr_err("%s:%d Enable/Disable Regulator failed ret = %d", + __func__, __LINE__, rc); + return rc; + } + CDBG("Exit %s type %d\n", __func__, flash_data->cfg_type); return rc; } +static int32_t msm_flash_query_data(struct msm_flash_ctrl_t *flash_ctrl, + void __user *argp) +{ + int32_t rc = -EINVAL, i = 0; + struct msm_flash_query_data_t *flash_query = + (struct msm_flash_query_data_t *) argp; + + CDBG("Enter %s type %d\n", __func__, flash_query->query_type); + + switch (flash_query->query_type) { + case FLASH_QUERY_CURRENT: + if (flash_ctrl->func_tbl && flash_ctrl->func_tbl-> + camera_flash_query_current != NULL) + rc = flash_ctrl->func_tbl-> + camera_flash_query_current( + flash_ctrl, flash_query); + else { + flash_query->max_avail_curr = 0; + for (i = 0; i < flash_ctrl->flash_num_sources; i++) { + flash_query->max_avail_curr += + flash_ctrl->flash_op_current[i]; + } + rc = 0; + CDBG("%s: max_avail_curr: %d\n", __func__, + flash_query->max_avail_curr); + } + break; + default: + rc = -EFAULT; + break; + } + + CDBG("Exit %s type %d\n", __func__, flash_query->query_type); + + return rc; +} + static long msm_flash_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -662,8 +789,11 @@ static long msm_flash_subdev_ioctl(struct v4l2_subdev *sd, pr_err("fctrl->func_tbl NULL\n"); return -EINVAL; } else { - return fctrl->func_tbl->camera_flash_release(fctrl); + fctrl->func_tbl->camera_flash_release(fctrl); + return msm_flash_prepare(fctrl); } + case VIDIOC_MSM_FLASH_QUERY_DATA: + return msm_flash_query_data(fctrl, argp); default: pr_err_ratelimited("invalid cmd %d\n", cmd); return -ENOIOCTLCMD; @@ -1140,6 +1270,7 @@ static struct msm_flash_table msm_pmic_flash_table = { .camera_flash_off = msm_flash_off, .camera_flash_low = msm_flash_low, .camera_flash_high = msm_flash_high, + .camera_flash_query_current = msm_flash_query_current, }, }; @@ -1151,6 +1282,7 @@ static struct msm_flash_table msm_gpio_flash_table = { .camera_flash_off = msm_flash_off, .camera_flash_low = msm_flash_low, .camera_flash_high = msm_flash_high, + .camera_flash_query_current = NULL, }, }; @@ -1162,6 +1294,7 @@ static struct msm_flash_table msm_i2c_flash_table = { .camera_flash_off = msm_flash_i2c_write_setting_array, .camera_flash_low = msm_flash_i2c_write_setting_array, .camera_flash_high = msm_flash_i2c_write_setting_array, + .camera_flash_query_current = NULL, }, }; diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h index c82e48cddcaf..ad619fa4eb63 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-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 @@ -27,6 +27,9 @@ enum msm_camera_flash_state_t { MSM_CAMERA_FLASH_INIT, + MSM_CAMERA_FLASH_OFF, + MSM_CAMERA_FLASH_LOW, + MSM_CAMERA_FLASH_HIGH, MSM_CAMERA_FLASH_RELEASE, }; @@ -42,6 +45,9 @@ struct msm_flash_func_t { struct msm_flash_cfg_data_t *); int32_t (*camera_flash_high)(struct msm_flash_ctrl_t *, struct msm_flash_cfg_data_t *); + int32_t (*camera_flash_query_current)(struct msm_flash_ctrl_t *, + struct msm_flash_query_data_t *); + }; struct msm_flash_table { @@ -67,6 +73,7 @@ struct msm_flash_ctrl_t { /* Switch node to trigger led */ const char *switch_trigger_name; struct led_trigger *switch_trigger; + uint32_t is_regulator_enabled; /* Flash */ uint32_t flash_num_sources; diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/Makefile b/drivers/media/platform/msm/camera_v2/sensor/io/Makefile index ec958697ae13..549c35a806f7 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/Makefile +++ b/drivers/media/platform/msm/camera_v2/sensor/io/Makefile @@ -2,4 +2,5 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2/ ccflags-y += -Idrivers/media/platform/msm/camera_v2/common ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci -obj-$(CONFIG_MSMB_CAMERA) += msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_spi.o msm_camera_dt_util.o +ccflags-y += -Idrivers/misc/ +obj-$(CONFIG_MSMB_CAMERA) += msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_spi.o msm_camera_dt_util.o msm_camera_tz_i2c.o diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h index 0fbe35713d8e..785dd54d65e1 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h @@ -152,4 +152,60 @@ int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t data, enum msm_camera_i2c_data_type data_type, uint32_t delay_ms); +int32_t msm_camera_tz_i2c_register_sensor(void *s_ctrl_p); + +int32_t msm_camera_tz_i2c_power_up(struct msm_camera_i2c_client *client); + +int32_t msm_camera_tz_i2c_power_down(struct msm_camera_i2c_client *client); + +int32_t msm_camera_tz_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_tz_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_tz_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_tz_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_tz_i2c_write_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_tz_i2c_write_table_async( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_tz_i2c_write_table_sync( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_tz_i2c_write_table_sync_block( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_tz_i2c_write_seq_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting); + +int32_t msm_camera_tz_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_tz_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_sensor_tz_i2c_util(struct msm_camera_i2c_client *client, + uint16_t cci_cmd); + +int32_t msm_camera_tz_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + #endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c new file mode 100644 index 000000000000..25c152be2b71 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c @@ -0,0 +1,1093 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/ktime.h> +#include <linux/mutex.h> +#include <soc/qcom/camera2.h> +#include "qseecom_kernel.h" +#include "msm_camera_i2c.h" +#include "msm_camera_io_util.h" +#include "msm_cci.h" +#include "msm_sensor.h" + +#define QSEECOM_SBUFF_SIZE SZ_128K +#define MAX_TA_NAME 32 +#define EMPTY_QSEECOM_HANDLE NULL + +#ifndef CONFIG_MSM_SEC_CCI_TA_NAME + #define CONFIG_MSM_SEC_CCI_TA_NAME "seccamdemo64" +#endif /* CONFIG_MSM_SEC_CCI_TA_NAME */ + +/* Update version major number in case the HLOS-TA interface is changed*/ +#define TA_IF_VERSION_MAJ 0 +#define TA_IF_VERSION_MIN 1 + +#undef CDBG +#ifdef CONFIG_MSM_SEC_CCI_DEBUG + +#define CDBG(fmt, args...) pr_info(CONFIG_MSM_SEC_CCI_TA_NAME "::%s:%d - " fmt,\ + __func__, __LINE__, ##args) +#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \ + ((ret < 0) ? i2c_fn(__VA_ARGS__):ret) + +#else /* CONFIG_MSM_SEC_CCI_DEBUG */ + +#define CDBG(fmt, args...) pr_info("%s:%d - " fmt, __func__, __LINE__, ##args) +#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \ + ((ret < 0) ? -EFAULT:ret) + +#endif /* CONFIG_MSM_SEC_CCI_DEBUG */ + +#pragma pack(push, msm_camera_tz_i2c, 1) + +enum msm_camera_tz_i2c_cmd_id_t { + TZ_I2C_CMD_GET_NONE, + TZ_I2C_CMD_GET_IF_VERSION, + TZ_I2C_CMD_POWER_UP, + TZ_I2C_CMD_POWER_DOWN, + TZ_I2C_CMD_CCI_GENERIC, + TZ_I2C_CMD_CCI_READ, + TZ_I2C_CMD_CCI_READ_SEQ, + TZ_I2C_CMD_CCI_WRITE, + TZ_I2C_CMD_CCI_WRITE_SEQ, + TZ_I2C_CMD_CCI_WRITE_TABLE_ASYNC, + TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC, + TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC_BLOCK, + TZ_I2C_CMD_CCI_WRITE_TABLE, + TZ_I2C_CMD_CCI_WRITE_SEQ_TABLE, + TZ_I2C_CMD_CCI_WRITE_TABLE_W_MICRODELAY, + TZ_I2C_CMD_CCI_POLL, + TZ_I2C_CMD_CCI_WRITE_CONF_TBL, + TZ_I2C_CMD_CCI_UTIL, +}; + +enum msm_camera_tz_i2c_status_t { + TZ_I2C_STATUS_SUCCESS = 0, + TZ_I2C_STATUS_GENERAL_FAILURE = -1, + TZ_I2C_STATUS_INVALID_INPUT_PARAMS = -2, + TZ_I2C_STATUS_INVALID_SENSOR_ID = -3, + TZ_I2C_STATUS_BYPASS = -4, + TZ_I2C_STATUS_ERR_SIZE = 0x7FFFFFFF +}; + +struct msm_camera_tz_i2c_generic_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; +}; + +struct msm_camera_tz_i2c_generic_rsp_t { + enum msm_camera_tz_i2c_status_t rc; +}; + +#define msm_camera_tz_i2c_get_if_version_req_t msm_camera_tz_i2c_generic_req_t + +struct msm_camera_tz_i2c_get_if_version_rsp_t { + enum msm_camera_tz_i2c_status_t rc; + uint32_t if_version_maj; + uint32_t if_version_min; +}; + +struct msm_camera_tz_i2c_power_up_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; + int32_t sensor_id; +}; + +#define msm_camera_tz_i2c_power_up_rsp_t msm_camera_tz_i2c_generic_rsp_t + +struct msm_camera_tz_i2c_power_down_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; + int32_t sensor_id; +}; + +#define msm_camera_tz_i2c_power_down_rsp_t msm_camera_tz_i2c_generic_rsp_t + +struct msm_camera_tz_i2c_cci_generic_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; + int32_t sensor_id; + enum msm_camera_tz_i2c_cmd_id_t cci_cmd_id; + uint32_t cci_i2c_master; + uint16_t sid; + uint16_t cid; +}; + +#define msm_camera_tz_i2c_cci_generic_rsp_t msm_camera_tz_i2c_generic_rsp_t + +struct msm_camera_tz_i2c_cci_read_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; + int32_t sensor_id; + uint32_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint32_t addr; + uint32_t data_type; +}; + +struct msm_camera_tz_i2c_cci_read_rsp_t { + enum msm_camera_tz_i2c_status_t rc; + uint16_t data; +}; + +struct msm_camera_tz_i2c_cci_write_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; + int32_t sensor_id; + uint32_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint32_t addr; + uint16_t data; + uint32_t data_type; +}; + +#define msm_camera_tz_i2c_cci_write_rsp_t msm_camera_tz_i2c_generic_rsp_t + +struct msm_camera_tz_i2c_cci_util_req_t { + enum msm_camera_tz_i2c_cmd_id_t cmd_id; + int32_t sensor_id; + uint32_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint16_t cci_cmd; +}; + +#define msm_camera_tz_i2c_cci_util_rsp_t msm_camera_tz_i2c_generic_rsp_t + +#pragma pack(pop, msm_camera_tz_i2c) + +struct msm_camera_tz_i2c_sensor_info_t { + struct msm_sensor_ctrl_t *s_ctrl; + struct msm_camera_i2c_fn_t *saved_sensor_i2c_fn; + uint32_t secure; + uint32_t ta_enabled; + struct qseecom_handle *ta_qseecom_handle; + const char *ta_name; +}; + +struct msm_camera_tz_i2c_ctrl_t { + struct mutex lock; + uint32_t lock_ready; + uint32_t secure_mode; +}; + +static struct msm_camera_tz_i2c_ctrl_t msm_camera_tz_i2c_ctrl; + +static struct msm_camera_tz_i2c_sensor_info_t sensor_info[MAX_CAMERAS] = { + {NULL, NULL, 0, 0, NULL, CONFIG_MSM_SEC_CCI_TA_NAME}, + {NULL, NULL, 0, 0, NULL, CONFIG_MSM_SEC_CCI_TA_NAME}, + {NULL, NULL, 0, 0, NULL, CONFIG_MSM_SEC_CCI_TA_NAME}, + {NULL, NULL, 0, 0, NULL, CONFIG_MSM_SEC_CCI_TA_NAME}, +}; + +static int32_t msm_camera_tz_i2c_is_sensor_secure( + struct msm_camera_i2c_client *client) +{ + uint32_t index; + + if (client == NULL) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + CDBG("Enter\n"); + for (index = 0; index < MAX_CAMERAS; index++) { + if ((sensor_info[index].s_ctrl != NULL) && + sensor_info[index].secure && + (sensor_info[index].s_ctrl->sensor_i2c_client == + client)) { + CDBG("Found secure sensor ID = %d\n", + sensor_info[index].s_ctrl->id); + return sensor_info[index].s_ctrl->id; + } + } + return -EINVAL; +} + +static int32_t get_cmd_rsp_buffers( + struct qseecom_handle *ta_qseecom_handle, + void **cmd, int *cmd_len, + void **rsp, int *rsp_len) +{ + + CDBG("Enter\n"); + if ((ta_qseecom_handle == NULL) || + (cmd == NULL) || (cmd_len == NULL) || + (rsp == NULL) || (rsp_len == NULL)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + if (*cmd_len & QSEECOM_ALIGN_MASK) + *cmd_len = QSEECOM_ALIGN(*cmd_len); + + if (*rsp_len & QSEECOM_ALIGN_MASK) + *rsp_len = QSEECOM_ALIGN(*rsp_len); + + if ((*rsp_len + *cmd_len) > QSEECOM_SBUFF_SIZE) { + pr_err("%s:%d - Shared buffer too small to hold cmd=%d and rsp=%d\n", + __func__, __LINE__, + *cmd_len, *rsp_len); + return -ENOMEM; + } + + *cmd = ta_qseecom_handle->sbuf; + *rsp = ta_qseecom_handle->sbuf + *cmd_len; + return 0; +} + +static int32_t msm_camera_tz_i2c_ta_get_if_version( + struct qseecom_handle *ta_qseecom_handle, + uint32_t *if_version_maj, + uint32_t *if_version_min) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_get_if_version_req_t *cmd; + struct msm_camera_tz_i2c_get_if_version_rsp_t *rsp; + int32_t rc = 0; + + CDBG("Enter\n"); + if ((ta_qseecom_handle == NULL) || + (if_version_maj == NULL) || (if_version_min == NULL)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + cmd_len = sizeof(struct msm_camera_tz_i2c_get_if_version_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_get_if_version_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_GET_IF_VERSION; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Unable to get if version info, rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + + if (rsp->rc < 0) { + CDBG("TZ I2C App error, rc=%d\n", rsp->rc); + rc = -EFAULT; + } else { + *if_version_maj = rsp->if_version_maj; + *if_version_min = rsp->if_version_min; + CDBG("TZ I2C If version %d.%d\n", *if_version_maj, + *if_version_min); + } + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_power_up( + struct qseecom_handle *ta_qseecom_handle, + int32_t sensor_id, + uint32_t *sensor_secure) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_power_up_req_t *cmd; + struct msm_camera_tz_i2c_power_up_rsp_t *rsp; + int32_t rc = 0; + + CDBG("Enter\n"); + + if (sensor_secure == NULL) + return -EINVAL; + + *sensor_secure = 0; + if ((ta_qseecom_handle == NULL) || + (sensor_secure == NULL) || + (sensor_id < 0) || + (sensor_id >= MAX_CAMERAS)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + cmd_len = sizeof(struct msm_camera_tz_i2c_power_up_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_power_up_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_POWER_UP; + cmd->sensor_id = sensor_id; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Unable to get sensor secure status, rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + + if (rsp->rc == TZ_I2C_STATUS_SUCCESS) + *sensor_secure = 1; + CDBG("Sensor %d is %s\n", sensor_id, + (*sensor_secure)?"SECURE":"NON-SECURE"); + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_power_down( + struct qseecom_handle *ta_qseecom_handle, + int32_t sensor_id) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_power_down_req_t *cmd; + struct msm_camera_tz_i2c_power_down_rsp_t *rsp; + int32_t rc = 0; + + CDBG("Enter\n"); + + if ((ta_qseecom_handle == NULL) || + (sensor_id < 0) || + (sensor_id >= MAX_CAMERAS)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + cmd_len = sizeof(struct msm_camera_tz_i2c_power_down_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_power_down_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_POWER_DOWN; + cmd->sensor_id = sensor_id; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Failed: rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_cci_generic( + struct msm_camera_i2c_client *client, + enum msm_camera_tz_i2c_cmd_id_t cci_cmd_id) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_cci_generic_req_t *cmd; + struct msm_camera_tz_i2c_cci_generic_rsp_t *rsp; + int32_t rc = 0; + struct qseecom_handle *ta_qseecom_handle; + int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + + if ((client == NULL) || + (sensor_id < 0) || + (sensor_id >= MAX_CAMERAS)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd_id=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + cci_cmd_id); + + ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; + cmd_len = sizeof(struct msm_camera_tz_i2c_cci_generic_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_cci_generic_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_CCI_GENERIC; + cmd->sensor_id = sensor_id; + cmd->cci_cmd_id = cci_cmd_id; + cmd->cci_i2c_master = client->cci_client->cci_i2c_master; + cmd->sid = client->cci_client->sid; + cmd->cid = client->cci_client->cid; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Failed: rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + rc = rsp->rc; + CDBG("Done: rc=%d, cci_cmd_id=%d\n", rc, cci_cmd_id); + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_cci_read( + struct msm_camera_i2c_client *client, + uint32_t addr, + uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_cci_read_req_t *cmd; + struct msm_camera_tz_i2c_cci_read_rsp_t *rsp; + int32_t rc = 0; + struct qseecom_handle *ta_qseecom_handle; + int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + + if ((client == NULL) || + (data == NULL) || + (sensor_id < 0) || + (sensor_id >= MAX_CAMERAS)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, Addr=0x%X, Type=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + addr, + data_type); + + ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; + cmd_len = sizeof(struct msm_camera_tz_i2c_cci_read_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_cci_read_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_CCI_READ; + cmd->sensor_id = sensor_id; + cmd->cci_i2c_master = client->cci_client->cci_i2c_master; + cmd->sid = client->cci_client->sid; + cmd->cid = client->cci_client->cid; + cmd->addr = addr; + cmd->data_type = data_type; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Failed: rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + rc = rsp->rc; + *data = rsp->data; + + CDBG("Done: rc=%d, addr=0x%X, data=0x%X\n", rc, + addr, *data); + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_cci_write( + struct msm_camera_i2c_client *client, + uint32_t addr, + uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_cci_write_req_t *cmd; + struct msm_camera_tz_i2c_cci_write_rsp_t *rsp; + int32_t rc = 0; + struct qseecom_handle *ta_qseecom_handle; + int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + + if ((client == NULL) || + (sensor_id < 0) || + (sensor_id >= MAX_CAMERAS)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, Addr=0x%X, Data=0x%X Type=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + addr, + data, + data_type); + + ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; + cmd_len = sizeof(struct msm_camera_tz_i2c_cci_write_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_cci_write_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_CCI_WRITE; + cmd->sensor_id = sensor_id; + cmd->cci_i2c_master = client->cci_client->cci_i2c_master; + cmd->sid = client->cci_client->sid; + cmd->cid = client->cci_client->cid; + cmd->addr = addr; + cmd->data = data; + cmd->data_type = data_type; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Failed:, rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + rc = rsp->rc; + + CDBG("Done: rc=%d, addr=0x%X, data=0x%X\n", rc, + addr, data); + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_cci_util( + struct msm_camera_i2c_client *client, + uint16_t cci_cmd) +{ + int32_t cmd_len, rsp_len; + struct msm_camera_tz_i2c_cci_util_req_t *cmd; + struct msm_camera_tz_i2c_cci_util_rsp_t *rsp; + int32_t rc = 0; + struct qseecom_handle *ta_qseecom_handle; + int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + + if ((client == NULL) || + (sensor_id < 0) || + (sensor_id >= MAX_CAMERAS)) { + pr_err("%s:%d - Bad parameters\n", + __func__, __LINE__); + return -EINVAL; + } + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + cci_cmd); + + ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; + cmd_len = sizeof(struct msm_camera_tz_i2c_cci_util_req_t); + rsp_len = sizeof(struct msm_camera_tz_i2c_cci_util_rsp_t); + + rc = get_cmd_rsp_buffers(ta_qseecom_handle, + (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); + if (!rc) { + cmd->cmd_id = TZ_I2C_CMD_CCI_UTIL; + cmd->sensor_id = sensor_id; + cmd->cci_i2c_master = client->cci_client->cci_i2c_master; + cmd->sid = client->cci_client->sid; + cmd->cid = client->cci_client->cid; + cmd->cci_cmd = cci_cmd; + + rc = qseecom_send_command(ta_qseecom_handle, + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (rc < 0) { + pr_err("%s:%d - Failed: rc=%d\n", + __func__, __LINE__, + rc); + return rc; + } + rc = rsp->rc; + CDBG("Done: rc=%d, cci_cmd=%d\n", rc, cci_cmd); + } + return rc; +} + +static int32_t msm_camera_tz_i2c_ta_probe( + struct msm_camera_i2c_client *client) +{ + int32_t sensor_id = -1; + + CDBG("Enter\n"); + sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + if ((sensor_id >= 0) && sensor_info[sensor_id].ta_enabled + && msm_camera_tz_i2c_ctrl.lock_ready) { + mutex_lock(&msm_camera_tz_i2c_ctrl.lock); + return sensor_id; + } + return -EINVAL; +} + +static int32_t msm_camera_tz_i2c_ta_done(void) +{ + int32_t rc = 0; + + CDBG("Enter\n"); + if (msm_camera_tz_i2c_ctrl.lock_ready) + mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); + return rc; +} + +int32_t msm_camera_tz_i2c_power_up( + struct msm_camera_i2c_client *client) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + + if (!msm_camera_tz_i2c_ctrl.lock_ready) { + msm_camera_tz_i2c_ctrl.lock_ready = 1; + mutex_init(&msm_camera_tz_i2c_ctrl.lock); + } + + CDBG("Enter (sensor_id=%d)\n", sensor_id); + if (sensor_id >= 0) { + ktime_t startTime; + + mutex_lock(&msm_camera_tz_i2c_ctrl.lock); + if (msm_camera_tz_i2c_ctrl.secure_mode) { + mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); + return rc; + } + startTime = ktime_get(); + + CDBG("Switch to secure mode (secure sensor=%d)\n", + sensor_id); + /* Start the TA */ + if ((sensor_info[sensor_id].ta_qseecom_handle == NULL) + && (sensor_info[sensor_id].ta_name != NULL) && + ('\0' != sensor_info[sensor_id].ta_name[0])) { + uint32_t if_version_maj = 0; + uint32_t if_version_min = 0; + + sensor_info[sensor_id].ta_enabled = 0; + rc = qseecom_start_app( + &sensor_info[sensor_id].ta_qseecom_handle, + (char *)sensor_info[sensor_id].ta_name, + QSEECOM_SBUFF_SIZE); + if (!rc) { + rc = msm_camera_tz_i2c_ta_get_if_version( + sensor_info[sensor_id]. + ta_qseecom_handle, + &if_version_maj, &if_version_min); + } + + if (!rc) { + if (if_version_maj != TA_IF_VERSION_MAJ) { + CDBG("TA ver mismatch %d.%d != %d.%d\n", + if_version_maj, if_version_min, + TA_IF_VERSION_MAJ, + TA_IF_VERSION_MIN); + rc = qseecom_shutdown_app( + &sensor_info[sensor_id]. + ta_qseecom_handle); + sensor_info[sensor_id].ta_qseecom_handle + = EMPTY_QSEECOM_HANDLE; + rc = -EFAULT; + } else { + uint32_t sensor_secure = 0; + /*Notify TA & get sensor secure status*/ + rc = msm_camera_tz_i2c_ta_power_up( + sensor_info[sensor_id]. + ta_qseecom_handle, + sensor_id, + &sensor_secure); + if (!rc && sensor_secure) + /* Sensor validated by TA*/ + sensor_info[sensor_id]. + ta_enabled = 1; + else { + qseecom_shutdown_app( + &sensor_info[sensor_id]. + ta_qseecom_handle); + sensor_info[sensor_id]. + ta_qseecom_handle + = EMPTY_QSEECOM_HANDLE; + rc = -EFAULT; + } + } + } + } + CDBG("Init TA %s - %s(%d) - %llu\n", + sensor_info[sensor_id].ta_name, + (sensor_info[sensor_id].ta_enabled)?"Ok" : + "Failed", rc, ktime_us_delta(ktime_get(), + startTime)); + if (!rc) + msm_camera_tz_i2c_ctrl.secure_mode++; + mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); + } + return rc; +} + +int32_t msm_camera_tz_i2c_power_down( + struct msm_camera_i2c_client *client) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); + + if (!msm_camera_tz_i2c_ctrl.lock_ready) { + msm_camera_tz_i2c_ctrl.lock_ready = 1; + mutex_init(&msm_camera_tz_i2c_ctrl.lock); + } + + CDBG("Enter (sensor_id=%d)\n", sensor_id); + if ((sensor_id >= 0) && (msm_camera_tz_i2c_ctrl.secure_mode != 0)) { + mutex_lock(&msm_camera_tz_i2c_ctrl.lock); + if (msm_camera_tz_i2c_ctrl.secure_mode == 1) { + ktime_t startTime = ktime_get(); + + CDBG("Switch to non-secure mode (secure sensor=%d)\n", + sensor_id); + /* Shutdown the TA */ + if (sensor_info[sensor_id].ta_qseecom_handle != NULL) { + msm_camera_tz_i2c_ta_power_down( + sensor_info[sensor_id]. + ta_qseecom_handle, + sensor_id); + rc = qseecom_shutdown_app(&sensor_info[ + sensor_id].ta_qseecom_handle); + sensor_info[sensor_id].ta_qseecom_handle + = EMPTY_QSEECOM_HANDLE; + } + CDBG("Unload TA %s - %s(%d) - %llu\n", + sensor_info[sensor_id].ta_name, + (!rc)?"Ok":"Failed", rc, + ktime_us_delta(ktime_get(), startTime)); + } + msm_camera_tz_i2c_ctrl.secure_mode--; + mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); + } + return rc; +} + +int32_t msm_camera_tz_i2c_register_sensor( + void *s_ctrl_p) +{ + struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *)s_ctrl_p; + + if (s_ctrl == NULL) { + pr_err("%s:%d - invalid parameter)\n", + __func__, __LINE__); + return -EINVAL; + } + if (s_ctrl->id >= MAX_CAMERAS) { + pr_err("%s:%d - invalid ID: %d\n", + __func__, __LINE__, s_ctrl->id); + return -EINVAL; + } + + CDBG("id=%d, client=%p\n", s_ctrl->id, s_ctrl); + sensor_info[s_ctrl->id].s_ctrl = s_ctrl; + sensor_info[s_ctrl->id].secure = s_ctrl->is_secure; + return 0; +} + +int32_t msm_camera_tz_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + addr); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_read( + client, addr, data, data_type); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_read, client, addr, data, data_type); +} + +int32_t msm_camera_tz_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X, num=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + addr, + num_byte); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_READ_SEQ); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_read_seq, client, addr, data, num_byte); +} + +int32_t msm_camera_tz_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + addr); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_write( + client, addr, data, data_type); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write, client, addr, data, data_type); +} + +int32_t msm_camera_tz_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X, num=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, + addr, + num_byte); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_SEQ); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_seq, client, addr, data, num_byte); +} + +int32_t msm_camera_tz_i2c_write_table_async( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_TABLE_ASYNC); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_table_async, client, write_setting); +} + +int32_t msm_camera_tz_i2c_write_table_sync( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_table_sync, client, write_setting); +} + +int32_t msm_camera_tz_i2c_write_table_sync_block( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC_BLOCK); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_table_sync_block, client, + write_setting); +} + +int32_t msm_camera_tz_i2c_write_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_TABLE); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_table, client, write_setting); +} + +int32_t msm_camera_tz_i2c_write_seq_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_SEQ_TABLE); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_seq_table, client, write_setting); +} + +int32_t msm_camera_tz_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_TABLE_W_MICRODELAY); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_table_w_microdelay, client, + write_setting); +} + +int32_t msm_camera_tz_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_POLL); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_poll, client, addr, data, data_type); +} + +int32_t msm_camera_tz_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_generic( + client, TZ_I2C_CMD_CCI_WRITE_CONF_TBL); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_camera_cci_i2c_write_conf_tbl, client, reg_conf_tbl, size, + data_type); +} + +int32_t msm_sensor_tz_i2c_util(struct msm_camera_i2c_client *client, + uint16_t cci_cmd) +{ + int32_t rc = -EFAULT; + int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); + + CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd=%d\n", + sensor_id, + client->cci_client->cci_i2c_master, + client->cci_client->sid, + client->cci_client->cid, cci_cmd); + + if (sensor_id >= 0) { + rc = msm_camera_tz_i2c_ta_cci_util(client, cci_cmd); + msm_camera_tz_i2c_ta_done(); + } + return TZ_I2C_FN_RETURN(rc, + msm_sensor_cci_i2c_util, client, cci_cmd); +} diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c index 22d90a2baf7d..e1143c356721 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c @@ -21,6 +21,9 @@ #undef CDBG #define CDBG(fmt, args...) pr_debug(fmt, ##args) +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl; +static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl; + static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) { int idx; @@ -132,6 +135,11 @@ int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) __func__, __LINE__, power_info, sensor_i2c_client); return -EINVAL; } + + /* Power down secure session if it exist*/ + if (s_ctrl->is_secure) + msm_camera_tz_i2c_power_down(sensor_i2c_client); + return msm_camera_power_down(power_info, sensor_device_type, sensor_i2c_client); } @@ -170,7 +178,27 @@ int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) if (s_ctrl->set_mclk_23880000) msm_sensor_adjust_mclk(power_info); + CDBG("Sensor %d tagged as %s\n", s_ctrl->id, + (s_ctrl->is_secure)?"SECURE":"NON-SECURE"); + for (retry = 0; retry < 3; retry++) { + if (s_ctrl->is_secure) { + rc = msm_camera_tz_i2c_power_up(sensor_i2c_client); + if (rc < 0) { +#ifdef CONFIG_MSM_SEC_CCI_DEBUG + CDBG("Secure Sensor %d use cci\n", s_ctrl->id); + /* session is not secure */ + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; +#else /* CONFIG_MSM_SEC_CCI_DEBUG */ + return rc; +#endif /* CONFIG_MSM_SEC_CCI_DEBUG */ + } else { + /* session is secure */ + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_secure_func_tbl; + } + } rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type, sensor_i2c_client); if (rc < 0) @@ -1433,6 +1461,21 @@ static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { .i2c_write_table_sync_block = msm_camera_qup_i2c_write_table, }; +static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl = { + .i2c_read = msm_camera_tz_i2c_read, + .i2c_read_seq = msm_camera_tz_i2c_read_seq, + .i2c_write = msm_camera_tz_i2c_write, + .i2c_write_table = msm_camera_tz_i2c_write_table, + .i2c_write_seq_table = msm_camera_tz_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_tz_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_tz_i2c_util, + .i2c_write_conf_tbl = msm_camera_tz_i2c_write_conf_tbl, + .i2c_write_table_async = msm_camera_tz_i2c_write_table_async, + .i2c_write_table_sync = msm_camera_tz_i2c_write_table_sync, + .i2c_write_table_sync_block = msm_camera_tz_i2c_write_table_sync_block, +}; + int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) { struct msm_camera_cci_client *cci_client = NULL; @@ -1466,6 +1509,9 @@ int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) /* Get CCI subdev */ cci_client->cci_subdev = msm_cci_get_subdev(); + if (s_ctrl->is_secure) + msm_camera_tz_i2c_register_sensor((void *)s_ctrl); + /* Update CCI / I2C function table */ if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) s_ctrl->sensor_i2c_client->i2c_func_tbl = diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h index bd12588eada9..5d57ec8c28ff 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -88,6 +88,7 @@ struct msm_sensor_ctrl_t { enum msm_camera_stream_type_t camera_stream_type; uint32_t set_mclk_23880000; uint8_t is_csid_tg_mode; + uint32_t is_secure; }; int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 02b83c969958..43aadffa2983 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -992,7 +992,7 @@ CSID_TG: } /* Update sensor mount angle and position in media entity flag */ is_yuv = (slave_info->output_format == MSM_SENSOR_YCBCR) ? 1 : 0; - mount_pos = is_yuv << 25 | + mount_pos = ((s_ctrl->is_secure & 0x1) << 26) | is_yuv << 25 | (s_ctrl->sensordata->sensor_info->position << 16) | ((s_ctrl->sensordata-> sensor_info->sensor_mount_angle / 90) << 8); @@ -1079,6 +1079,16 @@ static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl) goto FREE_VREG_DATA; } + /* Get custom mode */ + rc = of_property_read_u32(of_node, "qcom,secure", + &s_ctrl->is_secure); + CDBG("qcom,secure = %d, rc %d", s_ctrl->is_secure, rc); + if (rc < 0) { + /* Set default to non-secure mode */ + s_ctrl->is_secure = 0; + rc = 0; + } + /* Get CCI master */ rc = of_property_read_u32(of_node, "qcom,cci-master", &s_ctrl->cci_i2c_master); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_wb.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_wb.c index 2cf22ae6a3ed..e0f44be222d6 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_wb.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_wb.c @@ -316,7 +316,7 @@ static int sde_mdp_wb_wait4comp(struct sde_mdp_ctl *ctl, void *arg) { struct sde_mdp_writeback_ctx *ctx; int rc = 0; - u64 rot_time; + u64 rot_time = 0; u32 status, mask, isr; ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index 9b08c4fe0989..76fd674d161d 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -434,6 +434,14 @@ static void sde_hw_rotator_setup_timestamp_packet( SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100); SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x80000000); SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->timestamp); + /* + * Must clear secure buffer setting for SW timestamp because + * SW timstamp buffer allocation is always non-secure region. + */ + if (ctx->is_secure) { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0); + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0); + } SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 4); SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x000037FF); SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); @@ -611,6 +619,9 @@ static void sde_hw_rotator_setup_fetchengine(struct sde_hw_rotator_context *ctx, if (flags & SDE_ROT_FLAG_SECURE_OVERLAY_SESSION) { SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0xF); ctx->is_secure = true; + } else { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0); + ctx->is_secure = false; } /* Update command queue write ptr */ @@ -703,6 +714,11 @@ static void sde_hw_rotator_setup_wbengine(struct sde_hw_rotator_context *ctx, SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY, cfg->dst_rect->x | (cfg->dst_rect->y << 16)); + if (flags & SDE_ROT_FLAG_SECURE_OVERLAY_SESSION) + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0x1); + else + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0); + /* * setup Downscale factor */ @@ -1566,8 +1582,8 @@ static int sde_hw_rotator_kickoff(struct sde_rot_hw_resource *hw, if (!ctx) { SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n", entry->item.session_id); + return -EINVAL; } - WARN_ON(ctx == NULL); ret = sde_smmu_ctrl(1); if (IS_ERR_VALUE(ret)) { @@ -1609,8 +1625,8 @@ static int sde_hw_rotator_wait4done(struct sde_rot_hw_resource *hw, if (!ctx) { SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n", entry->item.session_id); + return -EINVAL; } - WARN_ON(ctx == NULL); ret = rot->ops.wait_rotator_done(ctx, ctx->q_id, 0); @@ -1745,8 +1761,10 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) q_id = ROT_QUEUE_LOW_PRIORITY; ts = (ts >> SDE_REGDMA_SWTS_SHIFT) & SDE_REGDMA_SWTS_MASK; + } else { + SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr); + goto done_isr_handle; } - ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK]; /* @@ -1766,6 +1784,7 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) [ts & SDE_HW_ROT_REGDMA_SEG_MASK]; }; +done_isr_handle: spin_unlock(&rot->rotisr_lock); ret = IRQ_HANDLED; } else if (isr & REGDMA_INT_ERR_MASK) { diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c index 44f7af089ee9..eed177ea5bab 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c @@ -586,7 +586,7 @@ void sde_rot_ubwc_data_calc_offset(struct sde_mdp_data *data, u16 x, u16 y, struct sde_mdp_plane_sizes *ps, struct sde_mdp_format_params *fmt) { u16 macro_w, micro_w, micro_h; - u32 offset; + u32 offset = 0; int ret; ret = sde_rot_get_ubwc_micro_dim(fmt->format, µ_w, µ_h); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 05232f862e55..fdf6e1b1c5d0 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -2290,6 +2290,8 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) rc = -ENOTSUPP; break; } + + msm_dcvs_try_enable(inst); msm_comm_scale_clocks_and_bus(inst); break; case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT: diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 36b24b90b0e2..99f30d9cb97b 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1665,7 +1665,6 @@ static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) goto fail_power_mode_set; } inst->flags |= VIDC_LOW_POWER; - msm_dcvs_enc_set_power_save_mode(inst, true); dprintk(VIDC_INFO, "Power Save Mode set for inst: %pK\n", inst); } @@ -2198,6 +2197,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES: { int num_p, num_b; + u32 max_num_b_frames; temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES); num_b = temp_ctrl->val; @@ -2210,18 +2210,16 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) num_b = ctrl->val; - if (num_b) { - u32 max_num_b_frames = MAX_NUM_B_FRAMES; - property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES; - pdata = &max_num_b_frames; - rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, property_id, pdata); - if (rc) { - dprintk(VIDC_ERR, - "Failed : Setprop MAX_NUM_B_FRAMES %d\n", - rc); - break; - } + max_num_b_frames = num_b ? MAX_NUM_B_FRAMES : 0; + property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES; + pdata = &max_num_b_frames; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, property_id, pdata); + if (rc) { + dprintk(VIDC_ERR, + "Failed : Setprop MAX_NUM_B_FRAMES %d\n", + rc); + break; } property_id = HAL_CONFIG_VENC_INTRA_PERIOD; @@ -2940,6 +2938,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; } + msm_dcvs_try_enable(inst); msm_comm_scale_clocks_and_bus(inst); break; case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT: @@ -3053,8 +3052,6 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } pdata = &venc_mode; - msm_dcvs_enc_set_power_save_mode(inst, - ctrl->val == V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE); break; case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS: if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_HEVC) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 84ce75c28bf8..437ad43e23e9 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -242,8 +242,7 @@ err_invalid_input: return ret; } -static struct msm_smem *get_same_fd_buffer(struct msm_vidc_list *buf_list, - int fd) +static struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst, int fd) { struct buffer_info *temp; struct msm_smem *same_fd_handle = NULL; @@ -253,16 +252,18 @@ static struct msm_smem *get_same_fd_buffer(struct msm_vidc_list *buf_list, if (!fd) return NULL; - if (!buf_list || fd < 0) { - dprintk(VIDC_ERR, "Invalid input\n"); + if (!inst || fd < 0) { + dprintk(VIDC_ERR, "%s: Invalid input\n", __func__); goto err_invalid_input; } - mutex_lock(&buf_list->lock); - list_for_each_entry(temp, &buf_list->list, list) { + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(temp, &inst->registeredbufs.list, list) { for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) { - if (temp->fd[i] == fd && - temp->handle[i] && temp->mapped[i]) { + bool ion_hndl_matches = temp->handle[i] ? + msm_smem_compare_buffers(inst->mem_client, fd, + temp->handle[i]->smem_priv) : false; + if (ion_hndl_matches && temp->mapped[i]) { temp->same_fd_ref[i]++; dprintk(VIDC_INFO, "Found same fd buffer\n"); @@ -273,7 +274,7 @@ static struct msm_smem *get_same_fd_buffer(struct msm_vidc_list *buf_list, if (same_fd_handle) break; } - mutex_unlock(&buf_list->lock); + mutex_unlock(&inst->registeredbufs.lock); err_invalid_input: return same_fd_handle; @@ -487,8 +488,7 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) } same_fd_handle = get_same_fd_buffer( - &inst->registeredbufs, - b->m.planes[i].reserved[0]); + inst, b->m.planes[i].reserved[0]); populate_buf_info(binfo, b, i); if (same_fd_handle) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 10dcc30f4aaa..f0a3875a8f28 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -90,6 +90,7 @@ static void msm_comm_generate_session_error(struct msm_vidc_inst *inst); static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst); static void handle_session_error(enum hal_command_response cmd, void *data); static void msm_vidc_print_running_insts(struct msm_vidc_core *core); +static void msm_comm_print_debug_info(struct msm_vidc_inst *inst); bool msm_comm_turbo_session(struct msm_vidc_inst *inst) { @@ -905,7 +906,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst, call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "sess resp timeout can potentially crash the system\n"); - + msm_comm_print_debug_info(inst); BUG_ON(inst->core->resources.debug_timeout); rc = -EIO; } else { @@ -1239,8 +1240,6 @@ static void handle_event_change(enum hal_command_response cmd, void *data) inst->prop.width[OUTPUT_PORT] = event_notify->width; } - inst->seqchanged_count++; - if (inst->session_type == MSM_VIDC_DECODER) msm_dcvs_init_load(inst); @@ -1603,6 +1602,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) struct msm_vidc_cb_cmd_done *response = data; struct msm_vidc_core *core = NULL; struct hfi_device *hdev = NULL; + struct msm_vidc_inst *inst = NULL; int rc = 0; subsystem_crashed("venus"); @@ -1642,6 +1642,19 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) dprintk(VIDC_ERR, "SYS_ERROR can potentially crash the system\n"); + /* + * For SYS_ERROR, there will not be any inst pointer. + * Just grab one of the inst from instances list and + * use it. + */ + + mutex_lock(&core->lock); + inst = list_first_entry(&core->instances, + struct msm_vidc_inst, list); + mutex_unlock(&core->lock); + + msm_comm_print_debug_info(inst); + BUG_ON(core->resources.debug_timeout); } @@ -2227,11 +2240,32 @@ void handle_cmd_response(enum hal_command_response cmd, void *data) int msm_comm_scale_clocks(struct msm_vidc_core *core) { - int num_mbs_per_sec = - msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS) + + int num_mbs_per_sec, enc_mbs_per_sec, dec_mbs_per_sec; + + enc_mbs_per_sec = + msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS); + dec_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_DECODER, LOAD_CALC_NO_QUIRKS); + + if (enc_mbs_per_sec >= dec_mbs_per_sec) { + /* + * If Encoder load is higher, use that load. Encoder votes for higher + * clock. Since Encoder and Deocder run on parallel cores, this clock + * should suffice decoder usecases. + */ + num_mbs_per_sec = enc_mbs_per_sec; + } else { + /* + * If Decoder load is higher, it's tricky to decide clock. Decoder + * higher load might results less clocks than Encoder smaller load. + * At this point driver doesn't know which clock to vote. Hence use + * total load. + */ + num_mbs_per_sec = enc_mbs_per_sec + dec_mbs_per_sec; + } + return msm_comm_scale_clocks_load(core, num_mbs_per_sec, - LOAD_CALC_NO_QUIRKS); + LOAD_CALC_NO_QUIRKS); } int msm_comm_scale_clocks_load(struct msm_vidc_core *core, @@ -2431,6 +2465,7 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst) call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "ABORT timeout can potentially crash the system\n"); + msm_comm_print_debug_info(inst); BUG_ON(inst->core->resources.debug_timeout); rc = -EBUSY; @@ -2503,6 +2538,7 @@ int msm_comm_check_core_init(struct msm_vidc_core *core) { int rc = 0; struct hfi_device *hdev; + struct msm_vidc_inst *inst = NULL; mutex_lock(&core->lock); if (core->state >= VIDC_CORE_INIT_DONE) { @@ -2521,6 +2557,17 @@ int msm_comm_check_core_init(struct msm_vidc_core *core) call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "SYS_INIT timeout can potentially crash the system\n"); + /* + * For SYS_INIT, there will not be any inst pointer. + * Just grab one of the inst from instances list and + * use it. + */ + inst = list_first_entry(&core->instances, + struct msm_vidc_inst, list); + + mutex_unlock(&core->lock); + msm_comm_print_debug_info(inst); + mutex_lock(&core->lock); BUG_ON(core->resources.debug_timeout); rc = -EIO; @@ -3998,6 +4045,8 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "SESS_PROP timeout can potentially crash the system\n"); + if (inst->core->resources.debug_timeout) + msm_comm_print_debug_info(inst); BUG_ON(inst->core->resources.debug_timeout); rc = -ETIMEDOUT; @@ -4896,6 +4945,9 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) return -ENOTSUPP; } + if (!rc) + msm_dcvs_try_enable(inst); + if (!rc) { if (inst->prop.width[CAPTURE_PORT] < capability->width.min || inst->prop.height[CAPTURE_PORT] < @@ -5205,7 +5257,97 @@ int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a) msm_dcvs_init_load(inst); } msm_comm_scale_clocks_and_bus(inst); + msm_dcvs_try_enable(inst); } exit: return rc; } + +void msm_comm_print_inst_info(struct msm_vidc_inst *inst) +{ + struct buffer_info *temp; + struct internal_buf *buf; + int i = 0; + bool is_decode = false; + enum vidc_ports port; + + if (!inst) { + dprintk(VIDC_ERR, "%s - invalid param %p\n", + __func__, inst); + return; + } + + is_decode = inst->session_type == MSM_VIDC_DECODER; + port = is_decode ? OUTPUT_PORT : CAPTURE_PORT; + dprintk(VIDC_ERR, + "%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n", + is_decode ? "Decode" : "Encode", inst->fmts[port]->name, + inst->prop.height[port], inst->prop.width[port], + inst->prop.fps, inst->prop.bitrate, + !inst->bit_depth ? "8" : "10"); + + dprintk(VIDC_ERR, + "---Buffer details for inst: %p of type: %d---\n", + inst, inst->session_type); + mutex_lock(&inst->registeredbufs.lock); + dprintk(VIDC_ERR, "registered buffer list:\n"); + list_for_each_entry(temp, &inst->registeredbufs.list, list) + for (i = 0; i < temp->num_planes; i++) + dprintk(VIDC_ERR, + "type: %d plane: %d addr: %pa size: %d\n", + temp->type, i, &temp->device_addr[i], + temp->size[i]); + + mutex_unlock(&inst->registeredbufs.lock); + + mutex_lock(&inst->scratchbufs.lock); + dprintk(VIDC_ERR, "scratch buffer list:\n"); + list_for_each_entry(buf, &inst->scratchbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", + buf->buffer_type, &buf->handle->device_addr, + buf->handle->size); + mutex_unlock(&inst->scratchbufs.lock); + + mutex_lock(&inst->persistbufs.lock); + dprintk(VIDC_ERR, "persist buffer list:\n"); + list_for_each_entry(buf, &inst->persistbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", + buf->buffer_type, &buf->handle->device_addr, + buf->handle->size); + mutex_unlock(&inst->persistbufs.lock); + + mutex_lock(&inst->outputbufs.lock); + dprintk(VIDC_ERR, "dpb buffer list:\n"); + list_for_each_entry(buf, &inst->outputbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", + buf->buffer_type, &buf->handle->device_addr, + buf->handle->size); + mutex_unlock(&inst->outputbufs.lock); +} + +static void msm_comm_print_debug_info(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core = NULL; + struct msm_vidc_inst *temp = NULL; + + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "%s - invalid param %p %p\n", + __func__, inst, core); + return; + } + core = inst->core; + + dprintk(VIDC_ERR, "Venus core frequency = %lu", + msm_comm_get_clock_rate(core)); + dprintk(VIDC_ERR, "Printing instance info that caused Error\n"); + msm_comm_print_inst_info(inst); + dprintk(VIDC_ERR, "Printing remaining instances info\n"); + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + /* inst already printed above. Hence don't repeat.*/ + if (temp == inst) + continue; + msm_comm_print_inst_info(temp); + } + mutex_unlock(&core->lock); +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 337760508eb1..eac7f658eb31 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -98,4 +98,5 @@ int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst); void msm_comm_cleanup_internal_buffers(struct msm_vidc_inst *inst); int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a); bool msm_comm_turbo_session(struct msm_vidc_inst *inst); +void msm_comm_print_inst_info(struct msm_vidc_inst *inst); #endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c index c03f887be6f6..9e67ef096c63 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c @@ -20,10 +20,19 @@ ((__cur_mbpf) >= (__min_mbpf)) static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst); -static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst); static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst); static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd); +int msm_dcvs_try_enable(struct msm_vidc_inst *inst) +{ + if (!inst) { + dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, inst); + return -EINVAL; + } + inst->dcvs_mode = msm_dcvs_check_supported(inst); + return 0; +} + static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst) { int height, width; @@ -41,20 +50,27 @@ static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst) return NUM_MBS_PER_FRAME(height, width); } -static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core) +static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core, + enum session_type session_type) { int active_instances = 0; - struct msm_vidc_inst *inst = NULL; + struct msm_vidc_inst *temp = NULL; if (!core) { dprintk(VIDC_ERR, "%s: Invalid args: %pK\n", __func__, core); return -EINVAL; } + /* DCVS condition is as following + * Decoder DCVS : Only for ONE decoder session. + * Encoder DCVS : Only for ONE encoder session + ONE decoder session + */ mutex_lock(&core->lock); - list_for_each_entry(inst, &core->instances, list) { - if (inst->state >= MSM_VIDC_OPEN_DONE && - inst->state < MSM_VIDC_STOP_DONE) + list_for_each_entry(temp, &core->instances, list) { + if (temp->state >= MSM_VIDC_OPEN_DONE && + temp->state < MSM_VIDC_STOP_DONE && + (temp->session_type == session_type || + temp->session_type == MSM_VIDC_ENCODER)) active_instances++; } mutex_unlock(&core->lock); @@ -112,17 +128,12 @@ static void msm_dcvs_enc_check_and_scale_clocks(struct msm_vidc_inst *inst) { int rc = 0; - if (inst->session_type == MSM_VIDC_ENCODER && msm_vidc_enc_dcvs_mode) { - inst->dcvs_mode = msm_dcvs_check_supported(inst); - dprintk(VIDC_DBG, "%s: session DCVS %s supported\n", - __func__, inst->dcvs_mode ? "" : "not"); - - if (inst->dcvs_mode) { - rc = msm_dcvs_enc_scale_clocks(inst); - if (rc) { - dprintk(VIDC_DBG, + if (inst->session_type == MSM_VIDC_ENCODER && + msm_vidc_enc_dcvs_mode) { + rc = msm_dcvs_enc_scale_clocks(inst); + if (rc) { + dprintk(VIDC_DBG, "ENC_DCVS: error while scaling clocks\n"); - } } } } @@ -131,28 +142,14 @@ static void msm_dcvs_dec_check_and_scale_clocks(struct msm_vidc_inst *inst) { int rc = 0; - if (inst->session_type != MSM_VIDC_DECODER || !msm_vidc_dec_dcvs_mode) - return; - - if (msm_dcvs_check_supported(inst)) { - inst->dcvs_mode = true; - dprintk(VIDC_DBG, - "%s: session DCVS supported, decode_dcvs_mode = %d\n", - __func__, inst->dcvs_mode); - } else { - inst->dcvs_mode = false; - dprintk(VIDC_DBG, - "%s: session DCVS not supported, decode_dcvs_mode = %d\n", - __func__, inst->dcvs_mode); - } - - if (msm_vidc_dec_dcvs_mode && inst->dcvs_mode) { + if (inst->session_type == MSM_VIDC_DECODER && + msm_vidc_dec_dcvs_mode) { msm_dcvs_monitor_buffer(inst); rc = msm_dcvs_dec_scale_clocks(inst, false); if (rc) { dprintk(VIDC_ERR, - "%s: Failed to scale clocks in DCVS: %d\n", - __func__, rc); + "%s: Failed to scale clocks in DCVS: %d\n", + __func__, rc); } } } @@ -163,6 +160,11 @@ void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb) dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst); return; } + msm_dcvs_try_enable(inst); + if (!inst->dcvs_mode) { + dprintk(VIDC_DBG, "DCVS is not enabled\n"); + return; + } if (is_etb) msm_dcvs_enc_check_and_scale_clocks(inst); @@ -531,48 +533,6 @@ static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd) return rc; } -static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst) -{ - int num_mbs_per_frame = 0; - long int instance_load = 0; - long int dcvs_limit = 0; - bool dcvs_check_passed = false, is_codec_supported = false; - struct msm_vidc_platform_resources *res = NULL; - - if (!inst || !inst->core) { - dprintk(VIDC_ERR, "%s Invalid params\n", __func__); - return dcvs_check_passed; - } - - res = &inst->core->resources; - if (!res->dcvs_limit) { - dprintk(VIDC_ERR, - "%s Dcvs limit table uninitialized\n", __func__); - return false; - } - - is_codec_supported = - msm_dcvs_check_codec_supported( - inst->fmts[CAPTURE_PORT]->fourcc, - inst->dcvs.supported_codecs, - inst->session_type); - - num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst); - instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS); - dcvs_limit = - (long int)res->dcvs_limit[inst->session_type].min_mbpf * - res->dcvs_limit[inst->session_type].fps; - - if (msm_vidc_enc_dcvs_mode && is_codec_supported && - inst->dcvs.is_power_save_mode && - IS_VALID_DCVS_SESSION(num_mbs_per_frame, - res->dcvs_limit[inst->session_type].min_mbpf) && - IS_VALID_DCVS_SESSION(instance_load, dcvs_limit)) { - dcvs_check_passed = true; - } - return dcvs_check_passed; -} - static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst) { int num_mbs_per_frame = 0, instance_count = 0; @@ -583,6 +543,7 @@ static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst) struct hal_buffer_requirements *output_buf_req; struct dcvs_stats *dcvs; bool is_codec_supported = false; + bool is_dcvs_supported = true; struct msm_vidc_platform_resources *res = NULL; if (!inst || !inst->core || !inst->core->device) { @@ -599,104 +560,88 @@ static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst) "%s: dcvs limit table not found\n", __func__); return false; } - instance_count = msm_dcvs_count_active_instances(core); + instance_count = msm_dcvs_count_active_instances(core, + inst->session_type); + num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst); + instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS); + dcvs_limit = + (long int)res->dcvs_limit[inst->session_type].min_mbpf * + res->dcvs_limit[inst->session_type].fps; + inst->dcvs.extra_buffer_count = 0; - if (instance_count == 1 && inst->session_type == MSM_VIDC_DECODER && - !msm_comm_turbo_session(inst)) { - num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst); - instance_load = msm_comm_get_inst_load(inst, - LOAD_CALC_NO_QUIRKS); - output_buf_req = get_buff_req_buffer(inst, - msm_comm_get_hal_output_buffer(inst)); - dcvs_limit = - (long int)res->dcvs_limit[inst->session_type].min_mbpf * - res->dcvs_limit[inst->session_type].fps; - is_codec_supported = - msm_dcvs_check_codec_supported( - inst->fmts[OUTPUT_PORT]->fourcc, - inst->dcvs.supported_codecs, - inst->session_type); - if (!is_codec_supported || - !IS_VALID_DCVS_SESSION(num_mbs_per_frame, - res->dcvs_limit[inst->session_type].min_mbpf) || - !IS_VALID_DCVS_SESSION(instance_load, dcvs_limit) || - inst->seqchanged_count > 1) - return false; + if (!IS_VALID_DCVS_SESSION(num_mbs_per_frame, + res->dcvs_limit[inst->session_type].min_mbpf)) { + inst->dcvs.extra_buffer_count = 0; + is_dcvs_supported = false; + goto dcvs_decision_done; + } + + if (inst->session_type == MSM_VIDC_DECODER) { + inst->dcvs.extra_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; + output_buf_req = get_buff_req_buffer(inst, + msm_comm_get_hal_output_buffer(inst)); if (!output_buf_req) { dprintk(VIDC_ERR, - "%s: No buffer requirement for buffer type %x\n", - __func__, HAL_BUFFER_OUTPUT); + "%s: No buffer requirement for buffer type %x\n", + __func__, HAL_BUFFER_OUTPUT); return false; } - } else if (instance_count == 1 && - inst->session_type == MSM_VIDC_ENCODER && - !msm_comm_turbo_session(inst)) { - if (!msm_dcvs_enc_check(inst)) - return false; - } else { - /* - * For multiple instance use case with 4K, clocks will be scaled - * as per load in streamon, but the clocks may be scaled - * down as DCVS is running for first playback instance - * Rescaling the core clock for multiple instance use case - */ - if (!dcvs->is_clock_scaled) { - if (!msm_comm_scale_clocks(core)) { - dcvs->is_clock_scaled = true; - dprintk(VIDC_DBG, - "%s: Scaled clocks = %d\n", - __func__, dcvs->is_clock_scaled); - } else { - dprintk(VIDC_DBG, - "%s: Failed to Scale clocks. Perf might be impacted\n", - __func__); - } + is_codec_supported = + msm_dcvs_check_codec_supported( + inst->fmts[OUTPUT_PORT]->fourcc, + inst->dcvs.supported_codecs, + inst->session_type); + if (!is_codec_supported || + !msm_vidc_dec_dcvs_mode) { + inst->dcvs.extra_buffer_count = 0; + is_dcvs_supported = false; + goto dcvs_decision_done; } - /* - * For multiple instance use case turn OFF DCVS algorithm - * immediately - */ + if (msm_comm_turbo_session(inst) || + !IS_VALID_DCVS_SESSION(instance_load, dcvs_limit || + instance_count > 1)) + is_dcvs_supported = false; + } + if (inst->session_type == MSM_VIDC_ENCODER) { + inst->dcvs.extra_buffer_count = DCVS_ENC_EXTRA_OUTPUT_BUFFERS; + is_codec_supported = + msm_dcvs_check_codec_supported( + inst->fmts[CAPTURE_PORT]->fourcc, + inst->dcvs.supported_codecs, + inst->session_type); + if (!is_codec_supported || + !msm_vidc_enc_dcvs_mode) { + inst->dcvs.extra_buffer_count = 0; + is_dcvs_supported = false; + goto dcvs_decision_done; + } + if (msm_comm_turbo_session(inst) || + !IS_VALID_DCVS_SESSION(instance_load, dcvs_limit || + instance_count > 1)) + is_dcvs_supported = false; + } +dcvs_decision_done: + if (!is_dcvs_supported) { + msm_comm_scale_clocks(core); if (instance_count > 1) { mutex_lock(&core->lock); list_for_each_entry(temp, &core->instances, list) temp->dcvs_mode = false; mutex_unlock(&core->lock); } - - return false; } - - return true; + return is_dcvs_supported; } int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst) { - int extra_buffer = 0; - if (!inst) { dprintk(VIDC_ERR, "%s Invalid args\n", __func__); return 0; } - if (inst->session_type == MSM_VIDC_ENCODER) { - if (msm_dcvs_enc_check(inst)) - extra_buffer = DCVS_ENC_EXTRA_OUTPUT_BUFFERS; - } else if (inst->session_type == MSM_VIDC_DECODER) { - if (msm_dcvs_check_supported(inst)) - extra_buffer = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; - } - return extra_buffer; + return inst->dcvs.extra_buffer_count; } -void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst, - bool is_power_save_mode) -{ - if (!inst) { - dprintk(VIDC_ERR, "%s Invalid args\n", __func__); - return; - } - - inst->dcvs.is_power_save_mode = is_power_save_mode; -} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h index 17040166b1e4..d40473976ebb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.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 @@ -36,6 +36,5 @@ void msm_dcvs_init_load(struct msm_vidc_inst *inst); void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst); void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb); int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst); -void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst, - bool is_power_save_mode); +int msm_dcvs_try_enable(struct msm_vidc_inst *inst); #endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 72c1ddcf3a70..b6e74715ad07 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -204,9 +204,9 @@ struct dcvs_stats { int load_high; int min_threshold; int max_threshold; - bool is_clock_scaled; int etb_counter; bool is_power_save_mode; + unsigned int extra_buffer_count; u32 supported_codecs; }; @@ -279,7 +279,6 @@ struct msm_vidc_inst { bool in_reconfig; u32 reconfig_width; u32 reconfig_height; - u32 seqchanged_count; struct dentry *debugfs_root; void *priv; struct msm_vidc_debug debug; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 1bdc5bf2c93d..25fccab99fb3 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1238,11 +1238,6 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, { struct msm_vidc_core *core = token; struct msm_vidc_inst *inst; - struct buffer_info *temp; - struct internal_buf *buf; - int i = 0; - bool is_decode = false; - enum vidc_ports port; if (!domain || !core) { dprintk(VIDC_ERR, "%s - invalid param %pK %pK\n", @@ -1257,52 +1252,7 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, mutex_lock(&core->lock); list_for_each_entry(inst, &core->instances, list) { - is_decode = inst->session_type == MSM_VIDC_DECODER; - port = is_decode ? OUTPUT_PORT : CAPTURE_PORT; - dprintk(VIDC_ERR, - "%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n", - is_decode ? "Decode" : "Encode", inst->fmts[port]->name, - inst->prop.height[port], inst->prop.width[port], - inst->prop.fps, inst->prop.bitrate, - !inst->bit_depth ? "8" : "10"); - - dprintk(VIDC_ERR, - "---Buffer details for inst: %pK of type: %d---\n", - inst, inst->session_type); - mutex_lock(&inst->registeredbufs.lock); - dprintk(VIDC_ERR, "registered buffer list:\n"); - list_for_each_entry(temp, &inst->registeredbufs.list, list) - for (i = 0; i < temp->num_planes; i++) - dprintk(VIDC_ERR, - "type: %d plane: %d addr: %pa size: %d\n", - temp->type, i, &temp->device_addr[i], - temp->size[i]); - - mutex_unlock(&inst->registeredbufs.lock); - - mutex_lock(&inst->scratchbufs.lock); - dprintk(VIDC_ERR, "scratch buffer list:\n"); - list_for_each_entry(buf, &inst->scratchbufs.list, list) - dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", - buf->buffer_type, &buf->handle->device_addr, - buf->handle->size); - mutex_unlock(&inst->scratchbufs.lock); - - mutex_lock(&inst->persistbufs.lock); - dprintk(VIDC_ERR, "persist buffer list:\n"); - list_for_each_entry(buf, &inst->persistbufs.list, list) - dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", - buf->buffer_type, &buf->handle->device_addr, - buf->handle->size); - mutex_unlock(&inst->persistbufs.lock); - - mutex_lock(&inst->outputbufs.lock); - dprintk(VIDC_ERR, "dpb buffer list:\n"); - list_for_each_entry(buf, &inst->outputbufs.list, list) - dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n", - buf->buffer_type, &buf->handle->device_addr, - buf->handle->size); - mutex_unlock(&inst->outputbufs.lock); + msm_comm_print_inst_info(inst); } core->smmu_fault_handled = true; mutex_unlock(&core->lock); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h index 23d84e9f7f7a..f6120dc7d1d5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h @@ -16,6 +16,7 @@ #define DT_PARSE #include <linux/of.h> #include "msm_vidc_resources.h" +#include "msm_vidc_common.h" void msm_vidc_free_platform_resources( struct msm_vidc_platform_resources *res); diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 5a51fbcf9318..e0fb31de38ff 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -119,7 +119,7 @@ static inline bool __core_in_valid_state(struct venus_hfi_device *device) return device->state != VENUS_STATE_DEINIT; } -static void __dump_packet(u8 *packet) +static void __dump_packet(u8 *packet, enum vidc_msg_prio log_level) { u32 c = 0, packet_size = *(u32 *)packet; const int row_size = 32; @@ -132,7 +132,7 @@ static void __dump_packet(u8 *packet) packet_size % row_size : row_size; hex_dump_to_buffer(packet + c * row_size, bytes_to_read, row_size, 4, row, sizeof(row), false); - dprintk(VIDC_PKT, "%s\n", row); + dprintk(log_level, "%s\n", row); } } @@ -342,7 +342,7 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, if (msm_vidc_debug & VIDC_PKT) { dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo); - __dump_packet(packet); + __dump_packet(packet, VIDC_PKT); } packet_size_in_words = (*(u32 *)packet) >> 2; @@ -548,7 +548,7 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, if (msm_vidc_debug & VIDC_PKT) { dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo); - __dump_packet(packet); + __dump_packet(packet, VIDC_PKT); } return rc; @@ -2517,7 +2517,6 @@ static int venus_hfi_session_clean(void *session) mutex_lock(&device->lock); __session_clean(sess_close); - __flush_debug_queue(device, NULL); mutex_unlock(&device->lock); return 0; @@ -3337,6 +3336,7 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) { bool local_packet = false; enum vidc_msg_prio log_level = VIDC_FW; + unsigned int pending_packet_count = 0; if (!device) { dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); @@ -3361,6 +3361,23 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) log_level = VIDC_ERR; } + /* + * In FATAL situation, print all the pending messages in msg + * queue. This is useful for debugging. At this time, message + * queues may be corrupted. Hence don't trust them and just print + * first max_packets packets. + */ + + if (local_packet) { + dprintk(VIDC_ERR, + "Printing all pending messages in message Queue\n"); + while (!__iface_msgq_read(device, packet) && + pending_packet_count < max_packets) { + __dump_packet(packet, log_level); + pending_packet_count++; + } + } + while (!__iface_dbgq_read(device, packet)) { struct hfi_msg_sys_coverage_packet *pkt = (struct hfi_msg_sys_coverage_packet *) packet; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 11f39791ec33..33bdd81065e8 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1502,7 +1502,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * Will sleep if required for nonblocking == false. */ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, - void *pb, int nonblocking) + int nonblocking) { unsigned long flags; int ret; @@ -1523,10 +1523,10 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, /* * Only remove the buffer from done_list if v4l2_buffer can handle all * the planes. + * Verifying planes is NOT necessary since it already has been checked + * before the buffer is queued/prepared. So it can never fail. */ - ret = call_bufop(q, verify_planes_array, *vb, pb); - if (!ret) - list_del(&(*vb)->done_entry); + list_del(&(*vb)->done_entry); spin_unlock_irqrestore(&q->done_lock, flags); return ret; @@ -1604,7 +1604,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking) struct vb2_buffer *vb = NULL; int ret; - ret = __vb2_get_done_vb(q, &vb, pb, nonblocking); + ret = __vb2_get_done_vb(q, &vb, nonblocking); if (ret < 0) return ret; diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c index 3c3b517f1d1c..dbec5923fcf0 100644 --- a/drivers/media/v4l2-core/videobuf2-memops.c +++ b/drivers/media/v4l2-core/videobuf2-memops.c @@ -49,7 +49,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start, vec = frame_vector_create(nr); if (!vec) return ERR_PTR(-ENOMEM); - ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec); + ret = get_vaddr_frames(start, nr, write, 1, vec); if (ret < 0) goto out_destroy; /* We accept only complete set of PFNs */ diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 68aa31ae553a..6255513f54c7 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -445,7 +445,6 @@ int intel_lpss_probe(struct device *dev, err_remove_ltr: intel_lpss_debugfs_remove(lpss); intel_lpss_ltr_hide(lpss); - intel_lpss_unregister_clock(lpss); err_clk_register: ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index 9eb75d876577..ea5ac972b096 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.c @@ -543,7 +543,8 @@ static int i2c_pmic_probe(struct i2c_client *client, } rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, - i2c_pmic_irq_handler, IRQF_ONESHOT, + i2c_pmic_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, "i2c_pmic_stat_irq", chip); if (rc < 0) { pr_err("Couldn't request irq %d rc=%d\n", client->irq, rc); diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 0c5754341991..b6a476cd882d 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -450,10 +450,22 @@ int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res) { int i, ret; u8 irq_level[wcd9xxx_res->num_irq_regs]; + struct irq_domain *domain; + struct device_node *pnode; mutex_init(&wcd9xxx_res->irq_lock); mutex_init(&wcd9xxx_res->nested_irq_lock); + pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node); + if (unlikely(!pnode)) + return -EINVAL; + + domain = irq_find_host(pnode); + if (unlikely(!domain)) + return -EINVAL; + + wcd9xxx_res->domain = domain; + wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res); if (!wcd9xxx_res->irq) { pr_warn("%s: irq driver is not yet initialized\n", __func__); @@ -553,7 +565,6 @@ void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res) if (wcd9xxx_res->irq) { disable_irq_wake(wcd9xxx_res->irq); free_irq(wcd9xxx_res->irq, wcd9xxx_res); - /* Release parent's of node */ wcd9xxx_res->irq = 0; wcd9xxx_irq_put_upstream_irq(wcd9xxx_res); } @@ -626,19 +637,14 @@ wcd9xxx_irq_add_domain(struct device_node *node, static struct wcd9xxx_irq_drv_data * wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res) { - struct device_node *pnode; struct irq_domain *domain; - pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node); - /* Shouldn't happen */ - if (unlikely(!pnode)) - return NULL; + domain = wcd9xxx_res->domain; - domain = irq_find_host(pnode); - if (unlikely(!domain)) + if (domain) + return domain->host_data; + else return NULL; - - return (struct wcd9xxx_irq_drv_data *)domain->host_data; } static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset) @@ -669,10 +675,6 @@ static unsigned int wcd9xxx_irq_get_upstream_irq( { struct wcd9xxx_irq_drv_data *data; - /* Hold parent's of node */ - if (!of_node_get(of_irq_find_parent(wcd9xxx_res->dev->of_node))) - return -EINVAL; - data = wcd9xxx_get_irq_drv_d(wcd9xxx_res); if (!data) { pr_err("%s: interrupt controller is not registerd\n", __func__); @@ -686,8 +688,7 @@ static unsigned int wcd9xxx_irq_get_upstream_irq( static void wcd9xxx_irq_put_upstream_irq( struct wcd9xxx_core_resource *wcd9xxx_res) { - /* Hold parent's of node */ - of_node_put(of_irq_find_parent(wcd9xxx_res->dev->of_node)); + wcd9xxx_res->domain = NULL; } static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c index 38286831a02c..fab594992df3 100644 --- a/drivers/mfd/wcd9xxx-utils.c +++ b/drivers/mfd/wcd9xxx-utils.c @@ -265,8 +265,17 @@ static u32 wcd9xxx_validate_dmic_sample_rate(struct device *dev, __func__, div_factor, mclk_rate); break; case 6: - /* DIV 6 is valid only for 12.288 MCLK */ - if (mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) + /* + * DIV 6 is valid for both 9.6MHz and 12.288MHz + * MCLK on Tavil. Older codecs support DIV6 only + * for 12.288MHz MCLK. + */ + if ((mclk_rate == WCD9XXX_MCLK_CLK_9P6HZ) && + (of_device_is_compatible(dev->of_node, + "qcom,tavil-slim-pgd"))) + dev_dbg(dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + else if (mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) goto undefined_rate; break; default: diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 9f0d9b7b7e17..8a08ca61062a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -439,7 +439,7 @@ config ARM_CHARLCD still useful. config BMP085 - tristate + bool depends on SYSFS config BMP085_I2C diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index f1a0b99f5a9a..15e88078ba1e 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -216,7 +216,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) */ value = swab16(value); - if (dpot->uid == DPOT_UID(AD5274_ID)) + if (dpot->uid == DPOT_UID(AD5271_ID)) value = value >> 2; return value; default: diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index efbb6945eb18..09a406058c46 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -288,6 +288,7 @@ unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq, void cxl_unmap_irq(unsigned int virq, void *cookie) { free_irq(virq, cookie); + irq_dispose_mapping(virq); } static int cxl_register_one_irq(struct cxl *adapter, diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c index 6a451bd65bf3..8310b4dbff06 100644 --- a/drivers/misc/mic/scif/scif_rma.c +++ b/drivers/misc/mic/scif/scif_rma.c @@ -1511,7 +1511,7 @@ off_t scif_register_pinned_pages(scif_epd_t epd, if ((map_flags & SCIF_MAP_FIXED) && ((ALIGN(offset, PAGE_SIZE) != offset) || (offset < 0) || - (len > LONG_MAX - offset))) + (offset + (off_t)len < offset))) return -EINVAL; might_sleep(); @@ -1614,7 +1614,7 @@ off_t scif_register(scif_epd_t epd, void *addr, size_t len, off_t offset, if ((map_flags & SCIF_MAP_FIXED) && ((ALIGN(offset, PAGE_SIZE) != offset) || (offset < 0) || - (len > LONG_MAX - offset))) + (offset + (off_t)len < offset))) return -EINVAL; /* Unsupported protection requested */ @@ -1732,8 +1732,7 @@ scif_unregister(scif_epd_t epd, off_t offset, size_t len) /* Offset is not page aligned or offset+len wraps around */ if ((ALIGN(offset, PAGE_SIZE) != offset) || - (offset < 0) || - (len > LONG_MAX - offset)) + (offset + (off_t)len < offset)) return -EINVAL; err = scif_verify_epd(ep); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index a15211fd33aa..3402a1b581cf 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1607,6 +1607,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { + ptr_svc->listener_in_use = true; ptr_svc->rcv_req_flag = 1; wake_up_interruptible(&ptr_svc->rcv_req_wq); break; @@ -1689,6 +1690,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, (const void *)&send_data_rsp, sizeof(send_data_rsp), resp, sizeof(*resp)); + ptr_svc->listener_in_use = false; if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); @@ -1712,6 +1714,101 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, return ret; } +int __qseecom_process_reentrancy_blocked_on_listener( + struct qseecom_command_scm_resp *resp, + struct qseecom_registered_app_list *ptr_app, + struct qseecom_dev_handle *data) +{ + struct qseecom_registered_listener_list *list_ptr; + int ret = 0; + struct qseecom_continue_blocked_request_ireq ireq; + struct qseecom_command_scm_resp continue_resp; + sigset_t new_sigset, old_sigset; + unsigned long flags; + bool found_app = false; + + if (!resp || !data) { + pr_err("invalid resp or data pointer\n"); + ret = -EINVAL; + goto exit; + } + + /* find app_id & img_name from list */ + if (!ptr_app) { + spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); + list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, + list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp(ptr_app->app_name, + data->client.app_name))) { + found_app = true; + break; + } + } + spin_unlock_irqrestore(&qseecom.registered_app_list_lock, + flags); + if (!found_app) { + pr_err("app_id %d (%s) is not found\n", + data->client.app_id, + (char *)data->client.app_name); + ret = -ENOENT; + goto exit; + } + } + + list_ptr = __qseecom_find_svc(resp->data); + if (!list_ptr) { + pr_err("Invalid listener ID\n"); + ret = -ENODATA; + goto exit; + } + pr_debug("lsntr %d in_use = %d\n", + resp->data, list_ptr->listener_in_use); + ptr_app->blocked_on_listener_id = resp->data; + /* sleep until listener is available */ + do { + qseecom.app_block_ref_cnt++; + ptr_app->app_blocked = true; + sigfillset(&new_sigset); + sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); + mutex_unlock(&app_access_lock); + do { + if (!wait_event_freezable( + list_ptr->listener_block_app_wq, + !list_ptr->listener_in_use)) { + break; + } + } while (1); + mutex_lock(&app_access_lock); + sigprocmask(SIG_SETMASK, &old_sigset, NULL); + ptr_app->app_blocked = false; + qseecom.app_block_ref_cnt--; + } while (list_ptr->listener_in_use == true); + ptr_app->blocked_on_listener_id = 0; + /* notify the blocked app that listener is available */ + pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n", + resp->data, data->client.app_id, + data->client.app_name); + ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; + ireq.app_id = data->client.app_id; + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + &ireq, sizeof(ireq), + &continue_resp, sizeof(continue_resp)); + if (ret) { + pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n", + data->client.app_id, + data->client.app_name, ret); + goto exit; + } + /* + * After TZ app is unblocked, then continue to next case + * for incomplete request processing + */ + resp->result = QSEOS_RESULT_INCOMPLETE; +exit: + return ret; +} + static int __qseecom_reentrancy_process_incomplete_cmd( struct qseecom_dev_handle *data, struct qseecom_command_scm_resp *resp) @@ -1725,7 +1822,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( sigset_t new_sigset; sigset_t old_sigset; - while (resp->result == QSEOS_RESULT_INCOMPLETE) { + while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id @@ -1812,16 +1909,37 @@ static int __qseecom_reentrancy_process_incomplete_cmd( if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; + goto exit; } - if ((resp->result != QSEOS_RESULT_SUCCESS) && - (resp->result != QSEOS_RESULT_INCOMPLETE)) { + + switch (resp->result) { + case QSEOS_RESULT_BLOCKED_ON_LISTENER: + pr_warn("send lsr %d rsp, but app %d block on lsr %d\n", + lstnr, data->client.app_id, resp->data); + if (lstnr == resp->data) { + pr_err("lstnr %d should not be blocked!\n", + lstnr); + ret = -EINVAL; + goto exit; + } + ret = __qseecom_process_reentrancy_blocked_on_listener( + resp, NULL, data); + if (ret) { + pr_err("failed to process App(%d) %s blocked on listener %d\n", + data->client.app_id, + data->client.app_name, resp->data); + goto exit; + } + case QSEOS_RESULT_SUCCESS: + case QSEOS_RESULT_INCOMPLETE: + break; + default: pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", resp->result, data->client.app_id, lstnr); ret = -EINVAL; + goto exit; } +exit: if (lstnr == RPMB_SERVICE) __qseecom_disable_clk(CLK_QSEE); @@ -2669,63 +2787,21 @@ int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp, struct qseecom_registered_app_list *ptr_app, struct qseecom_dev_handle *data) { - struct qseecom_registered_listener_list *list_ptr; int ret = 0; - struct qseecom_continue_blocked_request_ireq ireq; - struct qseecom_command_scm_resp continue_resp; - sigset_t new_sigset, old_sigset; switch (resp->result) { case QSEOS_RESULT_BLOCKED_ON_LISTENER: - pr_debug("App(%d) %s is blocked on listener %d\n", + pr_warn("App(%d) %s is blocked on listener %d\n", data->client.app_id, data->client.app_name, resp->data); - list_ptr = __qseecom_find_svc(resp->data); - if (!list_ptr) { - pr_err("Invalid listener ID\n"); - return -ENODATA; - } - ptr_app->blocked_on_listener_id = resp->data; - list_ptr->listener_in_use = true; - /* sleep until listener is available */ - while (list_ptr->listener_in_use == true) { - qseecom.app_block_ref_cnt++; - ptr_app->app_blocked = true; - sigfillset(&new_sigset); - sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); - mutex_unlock(&app_access_lock); - do { - if (!wait_event_freezable( - list_ptr->listener_block_app_wq, - !list_ptr->listener_in_use)) { - break; - } - } while (1); - mutex_lock(&app_access_lock); - sigprocmask(SIG_SETMASK, &old_sigset, NULL); - ptr_app->app_blocked = false; - qseecom.app_block_ref_cnt--; - } - /* notify the blocked app that listener is available */ - pr_debug("Lsntr %d is available, unblock app(%d) %s in TZ\n", - resp->data, data->client.app_id, - data->client.app_name); - ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; - ireq.app_id = data->client.app_id; - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, - &ireq, sizeof(ireq), - &continue_resp, sizeof(continue_resp)); + ret = __qseecom_process_reentrancy_blocked_on_listener( + resp, ptr_app, data); if (ret) { - pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n", - data->client.app_id, - data->client.app_name, ret); + pr_err("failed to process App(%d) %s is blocked on listener %d\n", + data->client.app_id, data->client.app_name, resp->data); return ret; } - /* - * After TZ app is unblocked, then continue to next case - * for incomplete request processing - */ - resp->result = QSEOS_RESULT_INCOMPLETE; + case QSEOS_RESULT_INCOMPLETE: qseecom.app_block_ref_cnt++; ptr_app->app_blocked = true; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 0568769fd94a..be3ccf2536d9 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -3707,6 +3707,19 @@ static void sdhci_msm_init(struct sdhci_host *host) msm_host->pdata->pm_qos_data.latency); } +static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct sdhci_msm_slot_reg_data *curr_slot = msm_host->pdata->vreg_data; + u32 max_curr = 0; + + if (curr_slot && curr_slot->vdd_data) + max_curr = curr_slot->vdd_data->hpm_uA; + + return max_curr; +} + static struct sdhci_ops sdhci_msm_ops = { .crypto_engine_cfg = sdhci_msm_ice_cfg, .crypto_cfg_reset = sdhci_msm_ice_cfg_reset, @@ -3732,6 +3745,7 @@ static struct sdhci_ops sdhci_msm_ops = { .init = sdhci_msm_init, .pre_req = sdhci_msm_pre_req, .post_req = sdhci_msm_post_req, + .get_current_limit = sdhci_msm_get_current_limit, }; static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 14ed8e775e6a..0542ba51445f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2337,9 +2337,10 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) switch (host->timing) { /* HS400 tuning is done in HS200 mode */ case MMC_TIMING_MMC_HS400: - err = -EINVAL; - goto out_unlock; - + if (!(mmc->caps2 & MMC_CAP2_HS400_POST_TUNING)) { + err = -EINVAL; + goto out_unlock; + } case MMC_TIMING_MMC_HS200: /* * Periodic re-tuning for HS400 is not expected to be needed, so diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index 4a07ba1195b5..12c6190c6e33 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -309,36 +309,6 @@ static const u16 brcmnand_regs_v60[] = { [BRCMNAND_FC_BASE] = 0x400, }; -/* BRCMNAND v7.1 */ -static const u16 brcmnand_regs_v71[] = { - [BRCMNAND_CMD_START] = 0x04, - [BRCMNAND_CMD_EXT_ADDRESS] = 0x08, - [BRCMNAND_CMD_ADDRESS] = 0x0c, - [BRCMNAND_INTFC_STATUS] = 0x14, - [BRCMNAND_CS_SELECT] = 0x18, - [BRCMNAND_CS_XOR] = 0x1c, - [BRCMNAND_LL_OP] = 0x20, - [BRCMNAND_CS0_BASE] = 0x50, - [BRCMNAND_CS1_BASE] = 0, - [BRCMNAND_CORR_THRESHOLD] = 0xdc, - [BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0, - [BRCMNAND_UNCORR_COUNT] = 0xfc, - [BRCMNAND_CORR_COUNT] = 0x100, - [BRCMNAND_CORR_EXT_ADDR] = 0x10c, - [BRCMNAND_CORR_ADDR] = 0x110, - [BRCMNAND_UNCORR_EXT_ADDR] = 0x114, - [BRCMNAND_UNCORR_ADDR] = 0x118, - [BRCMNAND_SEMAPHORE] = 0x150, - [BRCMNAND_ID] = 0x194, - [BRCMNAND_ID_EXT] = 0x198, - [BRCMNAND_LL_RDATA] = 0x19c, - [BRCMNAND_OOB_READ_BASE] = 0x200, - [BRCMNAND_OOB_READ_10_BASE] = 0, - [BRCMNAND_OOB_WRITE_BASE] = 0x280, - [BRCMNAND_OOB_WRITE_10_BASE] = 0, - [BRCMNAND_FC_BASE] = 0x400, -}; - enum brcmnand_cs_reg { BRCMNAND_CS_CFG_EXT = 0, BRCMNAND_CS_CFG, @@ -434,9 +404,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) } /* Register offsets */ - if (ctrl->nand_version >= 0x0701) - ctrl->reg_offsets = brcmnand_regs_v71; - else if (ctrl->nand_version >= 0x0600) + if (ctrl->nand_version >= 0x0600) ctrl->reg_offsets = brcmnand_regs_v60; else if (ctrl->nand_version >= 0x0500) ctrl->reg_offsets = brcmnand_regs_v50; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ce7b2cab5762..3ff583f165cd 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3979,6 +3979,7 @@ static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, * This is the first phase of the normal nand_scan() function. It reads the * flash ID and sets up MTD fields accordingly. * + * The mtd->owner field must be set to the module of the caller. */ int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) @@ -4402,12 +4403,19 @@ EXPORT_SYMBOL(nand_scan_tail); * * This fills out all the uninitialized function pointers with the defaults. * The flash ID is read and the mtd/chip structures are filled with the - * appropriate values. + * appropriate values. The mtd->owner field must be set to the module of the + * caller. */ int nand_scan(struct mtd_info *mtd, int maxchips) { int ret; + /* Many callers got this wrong, so check for it for a while... */ + if (!mtd->owner && caller_is_module()) { + pr_crit("%s called with NULL mtd->owner!\n", __func__); + BUG(); + } + ret = nand_scan_ident(mtd, maxchips, NULL); if (!ret) ret = nand_scan_tail(mtd); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 37e4135ab213..32477c4eb421 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1067,6 +1067,45 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +static int micron_quad_enable(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + + write_enable(nor); + + /* set EVCR, enable quad I/O */ + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1); + if (ret < 0) { + dev_err(nor->dev, "error while writing EVCR register\n"); + return ret; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + /* read EVCR and check it */ + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + if (val & EVCR_QUAD_EN_MICRON) { + dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); + return -EINVAL; + } + + return 0; +} + static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) { int status; @@ -1080,7 +1119,12 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) } return status; case SNOR_MFR_MICRON: - return 0; + status = micron_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Micron quad-read not enabled\n"); + return -EINVAL; + } + return status; default: status = spansion_quad_enable(nor); if (status) { diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 2ff465848b65..8f76f4558a88 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -1412,7 +1412,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = -EIO; - netdev->hw_features = NETIF_F_HW_VLAN_CTAG_RX; + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX; netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); /* Init PHY as early as possible due to power saving issue */ diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index d1c217eaf417..206b6a71a545 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -550,7 +550,6 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs, nicvf_config_vlan_stripping(nic, nic->netdev->features); /* Enable Receive queue */ - memset(&rq_cfg, 0, sizeof(struct rq_cfg)); rq_cfg.ena = 1; rq_cfg.tcp_ena = 0; nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, *(u64 *)&rq_cfg); @@ -583,7 +582,6 @@ void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs, qidx, (u64)(cq->dmem.phys_base)); /* Enable Completion queue */ - memset(&cq_cfg, 0, sizeof(struct cq_cfg)); cq_cfg.ena = 1; cq_cfg.reset = 0; cq_cfg.caching = 0; @@ -632,7 +630,6 @@ static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs, qidx, (u64)(sq->dmem.phys_base)); /* Enable send queue & set queue size */ - memset(&sq_cfg, 0, sizeof(struct sq_cfg)); sq_cfg.ena = 1; sq_cfg.reset = 0; sq_cfg.ldwb = 0; @@ -669,7 +666,6 @@ static void nicvf_rbdr_config(struct nicvf *nic, struct queue_set *qs, /* Enable RBDR & set queue size */ /* Buffer size should be in multiples of 128 bytes */ - memset(&rbdr_cfg, 0, sizeof(struct rbdr_cfg)); rbdr_cfg.ena = 1; rbdr_cfg.reset = 0; rbdr_cfg.ldwb = 0; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index f6147ffc7fbc..b2a32209ffbf 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1557,15 +1557,9 @@ fec_enet_rx(struct net_device *ndev, int budget) struct fec_enet_private *fep = netdev_priv(ndev); for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) { - int ret; - - ret = fec_enet_rx_queue(ndev, + clear_bit(queue_id, &fep->work_rx); + pkt_received += fec_enet_rx_queue(ndev, budget - pkt_received, queue_id); - - if (ret < budget - pkt_received) - clear_bit(queue_id, &fep->work_rx); - - pkt_received += ret; } return pkt_received; } diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 1257b18e6b90..973dade2d07f 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -270,17 +270,11 @@ jme_reset_mac_processor(struct jme_adapter *jme) } static inline void -jme_clear_pm_enable_wol(struct jme_adapter *jme) +jme_clear_pm(struct jme_adapter *jme) { jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs); } -static inline void -jme_clear_pm_disable_wol(struct jme_adapter *jme) -{ - jwrite32(jme, JME_PMCS, PMCS_STMASK); -} - static int jme_reload_eeprom(struct jme_adapter *jme) { @@ -1859,7 +1853,7 @@ jme_open(struct net_device *netdev) struct jme_adapter *jme = netdev_priv(netdev); int rc; - jme_clear_pm_disable_wol(jme); + jme_clear_pm(jme); JME_NAPI_ENABLE(jme); tasklet_init(&jme->linkch_task, jme_link_change_tasklet, @@ -1931,11 +1925,11 @@ jme_wait_link(struct jme_adapter *jme) static void jme_powersave_phy(struct jme_adapter *jme) { - if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) { + if (jme->reg_pmcs) { jme_set_100m_half(jme); if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN)) jme_wait_link(jme); - jme_clear_pm_enable_wol(jme); + jme_clear_pm(jme); } else { jme_phy_off(jme); } @@ -2652,6 +2646,9 @@ jme_set_wol(struct net_device *netdev, if (wol->wolopts & WAKE_MAGIC) jme->reg_pmcs |= PMCS_MFEN; + jwrite32(jme, JME_PMCS, jme->reg_pmcs); + device_set_wakeup_enable(&jme->pdev->dev, !!(jme->reg_pmcs)); + return 0; } @@ -3175,8 +3172,8 @@ jme_init_one(struct pci_dev *pdev, jme->mii_if.mdio_read = jme_mdio_read; jme->mii_if.mdio_write = jme_mdio_write; - jme_clear_pm_disable_wol(jme); - device_init_wakeup(&pdev->dev, true); + jme_clear_pm(jme); + device_set_wakeup_enable(&pdev->dev, true); jme_set_phyfifo_5level(jme); jme->pcirev = pdev->revision; @@ -3307,7 +3304,7 @@ jme_resume(struct device *dev) if (!netif_running(netdev)) return 0; - jme_clear_pm_disable_wol(jme); + jme_clear_pm(jme); jme_phy_on(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) jme_set_settings(netdev, &jme->old_ecmd); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index bbff8ec6713e..e7a5000aa12c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -704,7 +704,7 @@ static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb, if (ipv6h->nexthdr == IPPROTO_FRAGMENT || ipv6h->nexthdr == IPPROTO_HOPOPTS) return -1; - hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(ipv6h->nexthdr)); + hw_checksum = csum_add(hw_checksum, (__force __wsum)(ipv6h->nexthdr << 8)); csum_pseudo_hdr = csum_partial(&ipv6h->saddr, sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index e4019a803a9c..4421bf5463f6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -400,6 +400,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, u32 packets = 0; u32 bytes = 0; int factor = priv->cqe_factor; + u64 timestamp = 0; int done = 0; int budget = priv->tx_work_limit; u32 last_nr_txbb; @@ -439,12 +440,9 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, new_index = be16_to_cpu(cqe->wqe_index) & size_mask; do { - u64 timestamp = 0; - txbbs_skipped += last_nr_txbb; ring_index = (ring_index + last_nr_txbb) & size_mask; - - if (unlikely(ring->tx_info[ring_index].ts_requested)) + if (ring->tx_info[ring_index].ts_requested) timestamp = mlx4_en_get_cqe_ts(cqe); /* free next descriptor */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index cbd17e25beeb..1203d892e842 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1372,7 +1372,7 @@ static int mlx5e_set_dev_port_mtu(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; - u16 hw_mtu; + int hw_mtu; int err; err = mlx5_set_port_mtu(mdev, MLX5E_SW2HW_MTU(netdev->mtu), 1); @@ -1891,27 +1891,22 @@ static int mlx5e_set_features(struct net_device *netdev, return err; } -#define MXL5_HW_MIN_MTU 64 -#define MXL5E_MIN_MTU (MXL5_HW_MIN_MTU + ETH_FCS_LEN) - static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; bool was_opened; - u16 max_mtu; - u16 min_mtu; + int max_mtu; int err = 0; mlx5_query_port_max_mtu(mdev, &max_mtu, 1); max_mtu = MLX5E_HW2SW_MTU(max_mtu); - min_mtu = MLX5E_HW2SW_MTU(MXL5E_MIN_MTU); - if (new_mtu > max_mtu || new_mtu < min_mtu) { + if (new_mtu > max_mtu) { netdev_err(netdev, - "%s: Bad MTU (%d), valid range is: [%d..%d]\n", - __func__, new_mtu, min_mtu, max_mtu); + "%s: Bad MTU (%d) > (%d) Max\n", + __func__, new_mtu, max_mtu); return -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 53a793bc2e3d..a87e773e93f3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -246,8 +246,8 @@ int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, } EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status); -static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu, - u16 *max_mtu, u16 *oper_mtu, u8 port) +static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, int *admin_mtu, + int *max_mtu, int *oper_mtu, u8 port) { u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; @@ -267,7 +267,7 @@ static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu, *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); } -int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port) +int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port) { u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; @@ -282,14 +282,14 @@ int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port) } EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); -void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, +void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, u8 port) { mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port); } EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); -void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu, +void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu, u8 port) { mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port); diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 96a5028621c8..bdd83d95ec0a 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -617,13 +617,8 @@ static const struct usb_device_id mbim_devs[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0bdb, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&cdc_mbim_info, }, - - /* Some Huawei devices, ME906s-158 (12d1:15c1) and E3372 - * (12d1:157d), are known to fail unless the NDP is placed - * after the IP packets. Applying the quirk to all Huawei - * devices is broader than necessary, but harmless. - */ - { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), + /* Huawei E3372 fails unless NDP comes after the IP packets */ + { USB_DEVICE_AND_INTERFACE_INFO(0x12d1, 0x157d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end, }, /* default entry */ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 1b271b99c49e..8f8793004b9f 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -274,9 +274,6 @@ void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah, }; static const int inc[4] = { 0, 100, 0, 0 }; - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - cur_bin = -6000; upper = bin + 100; lower = bin - 100; @@ -427,9 +424,14 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, int tmp, new; int i; + int8_t mask_m[123]; + int8_t mask_p[123]; int cur_bb_spur; bool is2GHz = IS_CHAN_2GHZ(chan); + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); if (AR_NO_SPUR == cur_bb_spur) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 53d7445a5d12..db6624527d99 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -178,9 +178,14 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, int i; struct chan_centers centers; + int8_t mask_m[123]; + int8_t mask_p[123]; int cur_bb_spur; bool is2GHz = IS_CHAN_2GHZ(chan); + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + ath9k_hw_get_channel_centers(ah, chan, ¢ers); freq = centers.synth_center; diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 801c94859084..5d9329168699 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -2761,14 +2761,8 @@ static void cnss_crash_shutdown(const struct subsys_desc *subsys) wdrv = penv->driver; pdev = penv->pdev; - penv->dump_data.version = CNSS_DUMP_FORMAT_VER; - strlcpy(penv->dump_data.name, CNSS_DUMP_NAME, - sizeof(penv->dump_data.name)); - if (pdev && wdrv && wdrv->crash_shutdown) wdrv->crash_shutdown(pdev); - - penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2; } void cnss_device_self_recovery(void) @@ -2829,6 +2823,28 @@ static struct notifier_block mnb = { .notifier_call = cnss_modem_notifier_nb, }; +static int cnss_init_dump_entry(void) +{ + struct msm_dump_entry dump_entry; + + if (!penv) + return -ENODEV; + + if (!penv->ramdump_dynamic) + return 0; + + penv->dump_data.addr = penv->ramdump_phys; + penv->dump_data.len = penv->ramdump_size; + penv->dump_data.version = CNSS_DUMP_FORMAT_VER; + penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2; + strlcpy(penv->dump_data.name, CNSS_DUMP_NAME, + sizeof(penv->dump_data.name)); + dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN; + dump_entry.addr = virt_to_phys(&penv->dump_data); + + return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); +} + static int cnss_probe(struct platform_device *pdev) { int ret = 0; @@ -2836,7 +2852,6 @@ static int cnss_probe(struct platform_device *pdev) const char *client_desc; struct device *dev = &pdev->dev; u32 rc_num; - struct msm_dump_entry dump_entry; struct resource *res; u32 ramdump_size = 0; u32 smmu_iova_address[2]; @@ -2952,18 +2967,10 @@ static int cnss_probe(struct platform_device *pdev) goto skip_ramdump; } - if (penv->ramdump_dynamic) { - penv->dump_data.addr = penv->ramdump_phys; - penv->dump_data.len = penv->ramdump_size; - dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN; - dump_entry.addr = virt_to_phys(&penv->dump_data); - - ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); - if (ret) { - pr_err("%s: Dump table setup failed: %d\n", - __func__, ret); - goto err_ramdump_create; - } + ret = cnss_init_dump_entry(); + if (ret) { + pr_err("%s: Dump table setup failed: %d\n", __func__, ret); + goto err_ramdump_create; } penv->ramdump_dev = create_ramdump_device(penv->subsysdesc.name, diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c index f773c5993d44..01b969ec627f 100644 --- a/drivers/net/wireless/cnss/cnss_sdio.c +++ b/drivers/net/wireless/cnss/cnss_sdio.c @@ -21,6 +21,8 @@ #include <linux/slab.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> #include <linux/io.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> @@ -46,7 +48,7 @@ /* Values for Dynamic Ramdump Collection*/ #define CNSS_DUMP_FORMAT_VER 0x11 #define CNSS_DUMP_MAGIC_VER_V2 0x42445953 -#define CNSS_DUMP_NAME "CNSS_WLAN" +#define CNSS_DUMP_NAME "CNSS_WLAN_SDIO" #define CNSS_PINCTRL_SLEEP_STATE "sleep" #define CNSS_PINCTRL_ACTIVE_STATE "active" @@ -60,7 +62,11 @@ struct cnss_sdio_regulator { struct cnss_sdio_info { struct cnss_sdio_wlan_driver *wdrv; struct sdio_func *func; + struct mmc_card *card; + struct mmc_host *host; + struct device *dev; const struct sdio_device_id *id; + bool skip_wlan_en_toggle; }; struct cnss_ssr_info { @@ -212,19 +218,103 @@ void cnss_sdio_remove_pm_qos(void) } EXPORT_SYMBOL(cnss_sdio_remove_pm_qos); +static int cnss_put_hw_resources(struct device *dev) +{ + int ret = -EINVAL; + struct cnss_sdio_info *info; + struct mmc_host *host; + + if (!cnss_pdata) + return ret; + + info = &cnss_pdata->cnss_sdio_info; + + if (info->skip_wlan_en_toggle) { + pr_debug("%s: HW doesn't support wlan toggling\n", __func__); + return 0; + } + + host = info->host; + + if (!host) { + pr_err("%s: MMC host is invalid\n", __func__); + return 0; + } + + ret = mmc_power_save_host(host); + if (ret) { + pr_err("%s: Failed to Power Save Host err:%d\n", __func__, + ret); + return ret; + } + + if (!cnss_pdata->regulator.wlan_vreg) { + pr_debug("%s: wlan_vreg regulator is invalid\n", __func__); + return ret; + } + + regulator_disable(cnss_pdata->regulator.wlan_vreg); + + return ret; +} + +static int cnss_get_hw_resources(struct device *dev) +{ + int ret = -EINVAL; + struct mmc_host *host; + struct cnss_sdio_info *info; + + if (!cnss_pdata) + return ret; + + info = &cnss_pdata->cnss_sdio_info; + + if (info->skip_wlan_en_toggle) { + pr_debug("%s: HW doesn't support wlan toggling\n", __func__); + return 0; + } + + host = info->host; + + ret = regulator_enable(cnss_pdata->regulator.wlan_vreg); + if (ret) { + pr_err("%s: Failed to enable wlan vreg\n", __func__); + return ret; + } + + ret = mmc_power_restore_host(host); + if (ret) { + pr_err("%s: Failed to restore host power ret:%d\n", __func__, + ret); + regulator_disable(cnss_pdata->regulator.wlan_vreg); + } + + return ret; +} + static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; + int ret = 0; if (!cnss_pdata) return -ENODEV; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; - if (wdrv && wdrv->shutdown) - wdrv->shutdown(cnss_info->func); - return 0; + if (!wdrv) + return 0; + if (!wdrv->shutdown) + return 0; + + wdrv->shutdown(cnss_info->func); + ret = cnss_put_hw_resources(cnss_info->dev); + + if (ret) + pr_err("%s: Failed to put hw resources\n", __func__); + + return ret; } static int cnss_sdio_powerup(const struct subsys_desc *subsys) @@ -238,11 +328,23 @@ static int cnss_sdio_powerup(const struct subsys_desc *subsys) cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; - if (wdrv && wdrv->reinit) { - ret = wdrv->reinit(cnss_info->func, cnss_info->id); - if (ret) - pr_err("%s: wlan reinit error=%d\n", __func__, ret); + + if (!wdrv) + return 0; + + if (!wdrv->reinit) + return 0; + + ret = cnss_get_hw_resources(cnss_info->dev); + if (ret) { + pr_err("%s: Failed to power up HW\n", __func__); + return ret; } + + ret = wdrv->reinit(cnss_info->func, cnss_info->id); + if (ret) + pr_err("%s: wlan reinit error=%d\n", __func__, ret); + return ret; } @@ -551,25 +653,41 @@ int cnss_get_restart_level(void) } EXPORT_SYMBOL(cnss_get_restart_level); -static int cnss_sdio_wlan_inserted( - struct sdio_func *func, - const struct sdio_device_id *id) +static int cnss_sdio_wlan_inserted(struct sdio_func *func, + const struct sdio_device_id *id) { + struct cnss_sdio_info *info; + if (!cnss_pdata) return -ENODEV; - cnss_pdata->cnss_sdio_info.func = func; - cnss_pdata->cnss_sdio_info.id = id; + info = &cnss_pdata->cnss_sdio_info; + + info->func = func; + info->card = func->card; + info->host = func->card->host; + info->id = id; + info->dev = &func->dev; + + cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev); + + pr_info("%s: SDIO Device is Probed\n", __func__); return 0; } static void cnss_sdio_wlan_removed(struct sdio_func *func) { + struct cnss_sdio_info *info; + if (!cnss_pdata) return; - cnss_pdata->cnss_sdio_info.func = NULL; - cnss_pdata->cnss_sdio_info.id = NULL; + info = &cnss_pdata->cnss_sdio_info; + + info->host = NULL; + info->card = NULL; + info->func = NULL; + info->id = NULL; } #if defined(CONFIG_PM) @@ -577,6 +695,8 @@ static int cnss_sdio_wlan_suspend(struct device *dev) { struct cnss_sdio_wlan_driver *wdrv; struct cnss_sdio_bus_bandwidth *bus_bandwidth; + struct sdio_func *func; + int error = 0; if (!cnss_pdata) @@ -588,11 +708,13 @@ static int cnss_sdio_wlan_suspend(struct device *dev) bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE); } + func = cnss_pdata->cnss_sdio_info.func; wdrv = cnss_pdata->cnss_sdio_info.wdrv; if (!wdrv) { /* This can happen when no wlan driver loaded (no register to * platform driver). */ + sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); pr_debug("wlan driver not registered\n"); return 0; } @@ -692,29 +814,49 @@ EXPORT_SYMBOL(cnss_sdio_configure_spdt); int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver) { struct cnss_sdio_info *cnss_info; - int error = 0; + struct device *dev; + int error = -EINVAL; if (!cnss_pdata) return -ENODEV; cnss_info = &cnss_pdata->cnss_sdio_info; + dev = cnss_info->dev; + if (cnss_info->wdrv) pr_debug("%s:wdrv already exists wdrv(%p)\n", __func__, cnss_info->wdrv); + cnss_info->wdrv = driver; + + if (!driver) + return error; + + error = cnss_get_hw_resources(dev); + if (error) { + pr_err("%s: Failed to restore power err:%d\n", __func__, error); + return error; + } + error = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_ACTIVE); if (error) { pr_err("%s: Fail to set pinctrl to active state\n", __func__); - return -EFAULT; + goto put_hw; } - cnss_info->wdrv = driver; - if (driver->probe) { - error = driver->probe(cnss_info->func, cnss_info->id); - if (error) - pr_err("%s: wlan probe failed error=%d\n", __func__, - error); + error = driver->probe ? driver->probe(cnss_info->func, + cnss_info->id) : error; + if (error) { + pr_err("%s: wlan probe failed error=%d\n", __func__, error); + goto pinctrl_sleep; } + + return error; + +pinctrl_sleep: + cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP); +put_hw: + cnss_put_hw_resources(dev); return error; } EXPORT_SYMBOL(cnss_sdio_wlan_register_driver); @@ -746,10 +888,17 @@ cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver) pr_err("%s: driver not registered\n", __func__); return; } - if (cnss_info->wdrv->remove) - cnss_info->wdrv->remove(cnss_info->func); + + if (!driver) + return; + + if (!driver->remove) + return; + + driver->remove(cnss_info->func); cnss_info->wdrv = NULL; cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP); + cnss_put_hw_resources(cnss_info->dev); } EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver); @@ -1051,6 +1200,8 @@ static int cnss_sdio_init_bus_bandwidth(void) static int cnss_sdio_probe(struct platform_device *pdev) { int error; + struct device *dev = &pdev->dev; + struct cnss_sdio_info *info; if (pdev->dev.of_node) { cnss_pdata = devm_kzalloc( @@ -1065,6 +1216,7 @@ static int cnss_sdio_probe(struct platform_device *pdev) return -EINVAL; cnss_pdata->pdev = pdev; + info = &cnss_pdata->cnss_sdio_info; error = cnss_sdio_pinctrl_init(cnss_pdata, pdev); if (error) { @@ -1103,6 +1255,9 @@ static int cnss_sdio_probe(struct platform_device *pdev) } } + info->skip_wlan_en_toggle = of_property_read_bool(dev->of_node, + "qcom,skip-wlan-en-toggle"); + error = cnss_sdio_wlan_init(); if (error) { dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error); @@ -1152,15 +1307,20 @@ err_wlan_enable_regulator: static int cnss_sdio_remove(struct platform_device *pdev) { + struct cnss_sdio_info *info; + if (!cnss_pdata) return -ENODEV; + info = &cnss_pdata->cnss_sdio_info; + cnss_sdio_deinit_bus_bandwidth(); cnss_sdio_wlan_exit(); cnss_subsys_exit(); cnss_ramdump_cleanup(); + cnss_put_hw_resources(info->dev); cnss_sdio_release_resource(); - + cnss_pdata = NULL; return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f96ab2f4b90e..e88afac51c5d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1557,8 +1557,6 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) /* the fw is stopped, the aux sta is dead: clean up driver state */ iwl_mvm_del_aux_sta(mvm); - iwl_free_fw_paging(mvm); - /* * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete() * won't be called in this case). diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 13c97f665ba8..c3adf2bcdc85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -645,6 +645,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); + iwl_free_fw_paging(mvm); + iwl_mvm_tof_clean(mvm); ieee80211_free_hw(mvm->hw); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 00e0332e2544..8c7204738aa3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -731,8 +731,8 @@ static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans) */ val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0); if (val & (BIT(1) | BIT(17))) { - IWL_DEBUG_INFO(trans, - "can't access the RSA semaphore it is write protected\n"); + IWL_INFO(trans, + "can't access the RSA semaphore it is write protected\n"); return 0; } diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d6c4f0f60839..a6c8a4f7bfe9 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -313,7 +313,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, mwifiex_dbg(adapter, ERROR, "Attempt to reconnect on csa closed chan(%d)\n", bss_desc->channel); - ret = -1; goto done; } diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c index 2bb3c5799ac4..8ba19bba3156 100644 --- a/drivers/nvmem/mxs-ocotp.c +++ b/drivers/nvmem/mxs-ocotp.c @@ -94,7 +94,7 @@ static int mxs_ocotp_read(void *context, const void *reg, size_t reg_size, if (ret) goto close_banks; - while (val_size >= reg_size) { + while (val_size) { if ((offset < OCOTP_DATA_OFFSET) || (offset % 16)) { /* fill up non-data register */ *buf = 0; @@ -103,7 +103,7 @@ static int mxs_ocotp_read(void *context, const void *reg, size_t reg_size, } buf++; - val_size -= reg_size; + val_size--; offset += reg_size; } diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 0438512f4d69..0acebc87ec20 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -760,16 +760,6 @@ const void * __init of_flat_dt_match_machine(const void *default_match, } #ifdef CONFIG_BLK_DEV_INITRD -#ifndef __early_init_dt_declare_initrd -static void __early_init_dt_declare_initrd(unsigned long start, - unsigned long end) -{ - initrd_start = (unsigned long)__va(start); - initrd_end = (unsigned long)__va(end); - initrd_below_start_ok = 1; -} -#endif - /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree * @node: reference to node containing initrd location ('chosen') @@ -792,7 +782,9 @@ static void __init early_init_dt_check_for_initrd(unsigned long node) return; end = of_read_number(prop, len/4); - __early_init_dt_declare_initrd(start, end); + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", (unsigned long long)start, (unsigned long long)end); @@ -1014,16 +1006,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, } #ifdef CONFIG_HAVE_MEMBLOCK -#ifndef MIN_MEMBLOCK_ADDR -#define MIN_MEMBLOCK_ADDR __pa(PAGE_OFFSET) -#endif #ifndef MAX_MEMBLOCK_ADDR #define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0) #endif void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) { - const u64 phys_offset = MIN_MEMBLOCK_ADDR; + const u64 phys_offset = __pa(PAGE_OFFSET); if (!PAGE_ALIGNED(base)) { if (size < PAGE_SIZE - (base & ~PAGE_MASK)) { diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index e278aab1e530..3f186137e730 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -501,6 +501,7 @@ struct msm_pcie_clk_info_t { struct clk *hdl; char *name; u32 freq; + bool config_mem; bool required; }; @@ -710,49 +711,49 @@ static struct msm_pcie_gpio_info_t msm_pcie_gpio_info[MSM_PCIE_MAX_GPIO] = { static struct msm_pcie_clk_info_t msm_pcie_clk_info[MAX_RC_NUM][MSM_PCIE_MAX_CLK] = { { - {NULL, "pcie_0_ref_clk_src", 0, false}, - {NULL, "pcie_0_aux_clk", 1010000, true}, - {NULL, "pcie_0_cfg_ahb_clk", 0, true}, - {NULL, "pcie_0_mstr_axi_clk", 0, true}, - {NULL, "pcie_0_slv_axi_clk", 0, true}, - {NULL, "pcie_0_ldo", 0, true}, - {NULL, "pcie_0_smmu_clk", 0, false}, - {NULL, "pcie_phy_cfg_ahb_clk", 0, false}, - {NULL, "pcie_phy_aux_clk", 0, false}, - {NULL, "pcie_phy_reset", 0, false}, - {NULL, "pcie_phy_com_reset", 0, false}, - {NULL, "pcie_phy_nocsr_com_phy_reset", 0, false}, - {NULL, "pcie_0_phy_reset", 0, true} + {NULL, "pcie_0_ref_clk_src", 0, false, false}, + {NULL, "pcie_0_aux_clk", 1010000, false, true}, + {NULL, "pcie_0_cfg_ahb_clk", 0, false, true}, + {NULL, "pcie_0_mstr_axi_clk", 0, true, true}, + {NULL, "pcie_0_slv_axi_clk", 0, true, true}, + {NULL, "pcie_0_ldo", 0, false, true}, + {NULL, "pcie_0_smmu_clk", 0, false, false}, + {NULL, "pcie_phy_cfg_ahb_clk", 0, false, false}, + {NULL, "pcie_phy_aux_clk", 0, false, false}, + {NULL, "pcie_phy_reset", 0, false, false}, + {NULL, "pcie_phy_com_reset", 0, false, false}, + {NULL, "pcie_phy_nocsr_com_phy_reset", 0, false, false}, + {NULL, "pcie_0_phy_reset", 0, false, true} }, { - {NULL, "pcie_1_ref_clk_src", 0, false}, - {NULL, "pcie_1_aux_clk", 1010000, true}, - {NULL, "pcie_1_cfg_ahb_clk", 0, true}, - {NULL, "pcie_1_mstr_axi_clk", 0, true}, - {NULL, "pcie_1_slv_axi_clk", 0, true}, - {NULL, "pcie_1_ldo", 0, true}, - {NULL, "pcie_1_smmu_clk", 0, false}, - {NULL, "pcie_phy_cfg_ahb_clk", 0, false}, - {NULL, "pcie_phy_aux_clk", 0, false}, - {NULL, "pcie_phy_reset", 0, false}, - {NULL, "pcie_phy_com_reset", 0, false}, - {NULL, "pcie_phy_nocsr_com_phy_reset", 0, false}, - {NULL, "pcie_1_phy_reset", 0, true} + {NULL, "pcie_1_ref_clk_src", 0, false, false}, + {NULL, "pcie_1_aux_clk", 1010000, false, true}, + {NULL, "pcie_1_cfg_ahb_clk", 0, false, true}, + {NULL, "pcie_1_mstr_axi_clk", 0, true, true}, + {NULL, "pcie_1_slv_axi_clk", 0, true, true}, + {NULL, "pcie_1_ldo", 0, false, true}, + {NULL, "pcie_1_smmu_clk", 0, false, false}, + {NULL, "pcie_phy_cfg_ahb_clk", 0, false, false}, + {NULL, "pcie_phy_aux_clk", 0, false, false}, + {NULL, "pcie_phy_reset", 0, false, false}, + {NULL, "pcie_phy_com_reset", 0, false, false}, + {NULL, "pcie_phy_nocsr_com_phy_reset", 0, false, false}, + {NULL, "pcie_1_phy_reset", 0, false, true} }, { - {NULL, "pcie_2_ref_clk_src", 0, false}, - {NULL, "pcie_2_aux_clk", 1010000, true}, - {NULL, "pcie_2_cfg_ahb_clk", 0, true}, - {NULL, "pcie_2_mstr_axi_clk", 0, true}, - {NULL, "pcie_2_slv_axi_clk", 0, true}, - {NULL, "pcie_2_ldo", 0, true}, - {NULL, "pcie_2_smmu_clk", 0, false}, - {NULL, "pcie_phy_cfg_ahb_clk", 0, false}, - {NULL, "pcie_phy_aux_clk", 0, false}, - {NULL, "pcie_phy_reset", 0, false}, - {NULL, "pcie_phy_com_reset", 0, false}, - {NULL, "pcie_phy_nocsr_com_phy_reset", 0, false}, - {NULL, "pcie_2_phy_reset", 0, true} + {NULL, "pcie_2_ref_clk_src", 0, false, false}, + {NULL, "pcie_2_aux_clk", 1010000, false, true}, + {NULL, "pcie_2_cfg_ahb_clk", 0, false, true}, + {NULL, "pcie_2_mstr_axi_clk", 0, true, true}, + {NULL, "pcie_2_slv_axi_clk", 0, true, true}, + {NULL, "pcie_2_ldo", 0, false, true}, + {NULL, "pcie_2_smmu_clk", 0, false, false}, + {NULL, "pcie_phy_cfg_ahb_clk", 0, false, false}, + {NULL, "pcie_phy_aux_clk", 0, false, false}, + {NULL, "pcie_phy_reset", 0, false, false}, + {NULL, "pcie_phy_com_reset", 0, false, false}, + {NULL, "pcie_phy_nocsr_com_phy_reset", 0, false, false}, + {NULL, "pcie_2_phy_reset", 0, false, true} } }; @@ -760,13 +761,13 @@ static struct msm_pcie_clk_info_t static struct msm_pcie_clk_info_t msm_pcie_pipe_clk_info[MAX_RC_NUM][MSM_PCIE_MAX_PIPE_CLK] = { { - {NULL, "pcie_0_pipe_clk", 125000000, true}, + {NULL, "pcie_0_pipe_clk", 125000000, true, true}, }, { - {NULL, "pcie_1_pipe_clk", 125000000, true}, + {NULL, "pcie_1_pipe_clk", 125000000, true, true}, }, { - {NULL, "pcie_2_pipe_clk", 125000000, true}, + {NULL, "pcie_2_pipe_clk", 125000000, true, true}, } }; @@ -861,6 +862,32 @@ static inline void msm_pcie_write_reg_field(void *base, u32 offset, wmb(); } +static inline void msm_pcie_config_clock_mem(struct msm_pcie_dev_t *dev, + struct msm_pcie_clk_info_t *info) +{ + int ret; + + ret = clk_set_flags(info->hdl, CLKFLAG_NORETAIN_MEM); + if (ret) + PCIE_ERR(dev, + "PCIe: RC%d can't configure core memory for clk %s: %d.\n", + dev->rc_idx, info->name, ret); + else + PCIE_DBG2(dev, + "PCIe: RC%d configured core memory for clk %s.\n", + dev->rc_idx, info->name); + + ret = clk_set_flags(info->hdl, CLKFLAG_NORETAIN_PERIPH); + if (ret) + PCIE_ERR(dev, + "PCIe: RC%d can't configure peripheral memory for clk %s: %d.\n", + dev->rc_idx, info->name, ret); + else + PCIE_DBG2(dev, + "PCIe: RC%d configured peripheral memory for clk %s.\n", + dev->rc_idx, info->name); +} + #if defined(CONFIG_ARCH_FSM9010) #define PCIE20_PARF_PHY_STTS 0x3c #define PCIE2_PHY_RESET_CTRL 0x44 @@ -3450,6 +3477,9 @@ static int msm_pcie_clk_init(struct msm_pcie_dev_t *dev) if (i >= MSM_PCIE_MAX_CLK - (dev->common_phy ? 4 : 1)) clk_reset(info->hdl, CLK_RESET_DEASSERT); + if (info->config_mem) + msm_pcie_config_clock_mem(dev, info); + if (info->freq) { rc = clk_set_rate(info->hdl, info->freq); if (rc) { @@ -3543,6 +3573,9 @@ static int msm_pcie_pipe_clk_init(struct msm_pcie_dev_t *dev) clk_reset(info->hdl, CLK_RESET_DEASSERT); + if (info->config_mem) + msm_pcie_config_clock_mem(dev, info); + if (info->freq) { rc = clk_set_rate(info->hdl, info->freq); if (rc) { @@ -3921,8 +3954,8 @@ static int msm_pcie_get_resources(struct msm_pcie_dev_t *dev, cnt = of_property_count_strings((&pdev->dev)->of_node, "clock-names"); if (cnt > 0) { - clkfreq = kzalloc(cnt * sizeof(*clkfreq), - GFP_KERNEL); + clkfreq = kzalloc((MSM_PCIE_MAX_CLK + MSM_PCIE_MAX_PIPE_CLK) * + sizeof(*clkfreq), GFP_KERNEL); if (!clkfreq) { PCIE_ERR(dev, "PCIe: memory alloc failed for RC%d\n", dev->rc_idx); diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.c b/drivers/phy/phy-qcom-ufs-qmp-v3.c index 6b8dbc29f6e8..57c23f70eb63 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-v3.c +++ b/drivers/phy/phy-qcom-ufs-qmp-v3.c @@ -23,12 +23,26 @@ int ufs_qcom_phy_qmp_v3_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, int err; int tbl_size_A, tbl_size_B; struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; + u8 major = ufs_qcom_phy->host_ctrl_rev_major; + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; + u16 step = ufs_qcom_phy->host_ctrl_rev_step; tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); tbl_B = phy_cal_table_rate_B; - tbl_A = phy_cal_table_rate_A; - tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A); + if ((major == 0x3) && (minor == 0x000) && (step == 0x0000)) { + tbl_A = phy_cal_table_rate_A_3_0_0; + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_0_0); + } else if ((major == 0x3) && (minor == 0x001) && (step == 0x0000)) { + tbl_A = phy_cal_table_rate_A_3_1_0; + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_0); + } else { + dev_err(ufs_qcom_phy->dev, + "%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n", + __func__, major, minor, step); + err = -ENODEV; + goto out; + } err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, @@ -39,6 +53,8 @@ int ufs_qcom_phy_qmp_v3_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n", __func__, err); + +out: return err; } diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h index 8b77e3a7fee2..cda57855acb5 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-v3.h +++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h @@ -133,9 +133,12 @@ #define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x34) #define UFS_PHY_LINECFG_DISABLE PHY_OFF(0x130) #define UFS_PHY_RX_SYM_RESYNC_CTRL PHY_OFF(0x134) +#define UFS_PHY_RX_SIGDET_CTRL1 PHY_OFF(0x13C) #define UFS_PHY_RX_SIGDET_CTRL2 PHY_OFF(0x140) #define UFS_PHY_RX_PWM_GEAR_BAND PHY_OFF(0x14C) #define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x160) +#define UFS_PHY_TX_MID_TERM_CTRL1 PHY_OFF(0x1BC) +#define UFS_PHY_MULTI_LANE_CTRL1 PHY_OFF(0x1C4) /* UFS PHY TX registers */ #define QSERDES_TX0_TRANSCEIVER_BIAS_EN TX_OFF(0, 0x5C) @@ -143,6 +146,9 @@ #define QSERDES_TX0_LANE_MODE_2 TX_OFF(0, 0x90) #define QSERDES_TX0_LANE_MODE_3 TX_OFF(0, 0x94) +#define QSERDES_TX1_LANE_MODE_1 TX_OFF(1, 0x8C) + + /* UFS PHY RX registers */ #define QSERDES_RX0_UCDR_SVS_SO_GAIN_HALF RX_OFF(0, 0x24) #define QSERDES_RX0_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(0, 0x28) @@ -163,6 +169,22 @@ #define QSERDES_RX0_SIGDET_DEGLITCH_CNTRL RX_OFF(0, 0x10C) #define QSERDES_RX0_RX_INTERFACE_MODE RX_OFF(0, 0x11C) +#define QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF RX_OFF(1, 0x24) +#define QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(1, 0x28) +#define QSERDES_RX1_UCDR_SVS_SO_GAIN RX_OFF(1, 0x2C) +#define QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN RX_OFF(1, 0x30) +#define QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE RX_OFF(1, 0x34) +#define QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW RX_OFF(1, 0x3C) +#define QSERDES_RX1_UCDR_PI_CONTROLS RX_OFF(1, 0x44) +#define QSERDES_RX1_RX_TERM_BW RX_OFF(1, 0x7C) +#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(1, 0xD4) +#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3 RX_OFF(1, 0xD8) +#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4 RX_OFF(1, 0xDC) +#define QSERDES_RX1_SIGDET_CNTRL RX_OFF(1, 0x104) +#define QSERDES_RX1_SIGDET_LVL RX_OFF(1, 0x108) +#define QSERDES_RX1_SIGDET_DEGLITCH_CNTRL RX_OFF(1, 0x10C) +#define QSERDES_RX1_RX_INTERFACE_MODE RX_OFF(1, 0x11C) + #define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1) /* @@ -177,10 +199,70 @@ struct ufs_qcom_phy_qmp_v3 { struct ufs_qcom_phy common_cfg; }; -static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_0_0[] = { + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xD5), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0A), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xDA), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0C), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x3F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xC1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX0_LANE_MODE_1, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_SIGDET_LVL, 0x24), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_SIGDET_CNTRL, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_SIGDET_DEGLITCH_CNTRL, 0x1E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_INTERFACE_MODE, 0x40), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_FO_GAIN, 0x0B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_TERM_BW, 0x5B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4, 0x1D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN_HALF, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x4B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0xF1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_COUNT_LOW, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6C), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03), +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_0[] = { UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x06), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xD5), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x04), @@ -230,10 +312,29 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x4B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0xF1), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_COUNT_LOW, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_LANE_MODE_1, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_LVL, 0x24), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_CNTRL, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_DEGLITCH_CNTRL, 0x1E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_INTERFACE_MODE, 0x40), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN, 0x0B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_TERM_BW, 0x5B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4, 0x1D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x4B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0xF1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6C), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_MID_TERM_CTRL1, 0x43), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL1, 0x0F), }; static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 3d8019eb3d84..5c717275a7fa 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -939,8 +939,7 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev); int eint_num, virq, eint_offset; unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc; - static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000, - 128000, 256000}; + static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256}; const struct mtk_desc_pin *pin; struct irq_data *d; @@ -958,9 +957,9 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, if (!mtk_eint_can_en_debounce(pctl, eint_num)) return -ENOSYS; - dbnc = ARRAY_SIZE(debounce_time); - for (i = 0; i < ARRAY_SIZE(debounce_time); i++) { - if (debounce <= debounce_time[i]) { + dbnc = ARRAY_SIZE(dbnc_arr); + for (i = 0; i < ARRAY_SIZE(dbnc_arr); i++) { + if (debounce <= dbnc_arr[i]) { dbnc = i; break; } diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index b3235fd2950c..33edd07d9149 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -717,11 +717,9 @@ static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev, break; case PIN_CONFIG_BIAS_PULL_UP: conf |= ATMEL_PIO_PUEN_MASK; - conf &= (~ATMEL_PIO_PDEN_MASK); break; case PIN_CONFIG_BIAS_PULL_DOWN: conf |= ATMEL_PIO_PDEN_MASK; - conf &= (~ATMEL_PIO_PUEN_MASK); break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: if (arg == 0) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 23b6b8c29a99..ef04b962c3d5 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1273,9 +1273,9 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, /* Parse pins in each row from LSB */ while (mask) { - bit_pos = __ffs(mask); + bit_pos = ffs(mask); pin_num_from_lsb = bit_pos / pcs->bits_per_pin; - mask_pos = ((pcs->fmask) << bit_pos); + mask_pos = ((pcs->fmask) << (bit_pos - 1)); val_pos = val & mask_pos; submask = mask & mask_pos; @@ -1847,7 +1847,7 @@ static int pcs_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "pinctrl-single,function-mask", &pcs->fmask); if (!ret) { - pcs->fshift = __ffs(pcs->fmask); + pcs->fshift = ffs(pcs->fmask) - 1; pcs->fmax = pcs->fmask >> pcs->fshift; } else { /* If mask property doesn't exist, function mux is invalid. */ diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index 8e583203abda..838b78c1934d 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -2136,11 +2136,11 @@ int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, connect_fail: ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl, - dl_chan_params->teth_prot); + IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot)); alloc_dl_chan_fail: if (connect_params->teth_prot != IPA_USB_DIAG) ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl, - ul_chan_params->teth_prot); + IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot)); bad_params: mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c index bf6352452283..209264d69b26 100644 --- a/drivers/platform/msm/ipa/ipa_rm.c +++ b/drivers/platform/msm/ipa/ipa_rm.c @@ -267,17 +267,18 @@ static int _ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, time = wait_for_completion_timeout( &((struct ipa_rm_resource_cons *)consumer)-> request_consumer_in_progress, - HZ); + HZ * 5); result = 0; if (!time) { IPA_RM_ERR("TIMEOUT waiting for %s GRANT event.", ipa_rm_resource_str(depends_on_name)); result = -ETIME; - } - IPA_RM_DBG("%s waited for %s GRANT %lu time.\n", + } else { + IPA_RM_DBG("%s waited for %s GRANT %lu time.\n", ipa_rm_resource_str(resource_name), ipa_rm_resource_str(depends_on_name), time); + } } IPA_RM_DBG("EXIT with %d\n", result); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index a2f1c5c9af27..9cb0b1f3c379 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -575,6 +575,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_v4_nat_del nat_del; struct ipa_ioc_rm_dependency rm_depend; size_t sz; + int pre_entry; IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd)); @@ -623,11 +624,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - + pre_entry = + ((struct ipa_ioc_nat_dma_cmd *)header)->entries; pyld_sz = sizeof(struct ipa_ioc_nat_dma_cmd) + - ((struct ipa_ioc_nat_dma_cmd *)header)->entries * - sizeof(struct ipa_ioc_nat_dma_one); + pre_entry * sizeof(struct ipa_ioc_nat_dma_one); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -638,7 +639,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_nat_dma_cmd *)param)->entries, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_nat_dma_cmd((struct ipa_ioc_nat_dma_cmd *)param)) { retval = -EFAULT; break; @@ -663,10 +672,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_hdr *)header)->num_hdrs; pyld_sz = sizeof(struct ipa_ioc_add_hdr) + - ((struct ipa_ioc_add_hdr *)header)->num_hdrs * - sizeof(struct ipa_hdr_add); + pre_entry * sizeof(struct ipa_hdr_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -676,6 +686,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_hdr *)param)->num_hdrs, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_add_hdr((struct ipa_ioc_add_hdr *)param)) { retval = -EFAULT; break; @@ -692,10 +711,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_hdr *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_hdr) + - ((struct ipa_ioc_del_hdr *)header)->num_hdls * - sizeof(struct ipa_hdr_del); + pre_entry * sizeof(struct ipa_hdr_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -705,6 +725,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_hdr *)param)->num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_del_hdr((struct ipa_ioc_del_hdr *)param)) { retval = -EFAULT; break; @@ -721,10 +750,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_rt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_add_rt_rule) + - ((struct ipa_ioc_add_rt_rule *)header)->num_rules * - sizeof(struct ipa_rt_rule_add); + pre_entry * sizeof(struct ipa_rt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -734,6 +764,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_rt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) { retval = -EFAULT; break; @@ -750,10 +790,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_mdfy_rt_rule) + - ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules * - sizeof(struct ipa_rt_rule_mdfy); + pre_entry * sizeof(struct ipa_rt_rule_mdfy); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -763,6 +804,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_mdfy_rt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_mdfy_rt_rule((struct ipa_ioc_mdfy_rt_rule *)param)) { retval = -EFAULT; break; @@ -779,10 +830,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_rt_rule *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_rt_rule) + - ((struct ipa_ioc_del_rt_rule *)header)->num_hdls * - sizeof(struct ipa_rt_rule_del); + pre_entry * sizeof(struct ipa_rt_rule_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -792,6 +844,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_rt_rule *)param)->num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) { retval = -EFAULT; break; @@ -808,10 +869,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_flt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_add_flt_rule) + - ((struct ipa_ioc_add_flt_rule *)header)->num_rules * - sizeof(struct ipa_flt_rule_add); + pre_entry * sizeof(struct ipa_flt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -821,6 +883,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_flt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) { retval = -EFAULT; break; @@ -837,10 +909,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_flt_rule *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_flt_rule) + - ((struct ipa_ioc_del_flt_rule *)header)->num_hdls * - sizeof(struct ipa_flt_rule_del); + pre_entry * sizeof(struct ipa_flt_rule_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -850,6 +923,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_flt_rule *)param)-> + num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) { retval = -EFAULT; break; @@ -866,10 +949,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_mdfy_flt_rule) + - ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules * - sizeof(struct ipa_flt_rule_mdfy); + pre_entry * sizeof(struct ipa_flt_rule_mdfy); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -879,6 +963,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_mdfy_flt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_mdfy_flt_rule((struct ipa_ioc_mdfy_flt_rule *)param)) { retval = -EFAULT; break; @@ -992,9 +1086,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - - pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *) - header)->num_tx_props * + pre_entry = + ((struct ipa_ioc_query_intf_tx_props *) + header)->num_tx_props; + pyld_sz = sz + pre_entry * sizeof(struct ipa_ioc_tx_intf_prop); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -1005,6 +1100,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_query_intf_tx_props *) + param)->num_tx_props + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_query_intf_tx_props *) + param)->num_tx_props, pre_entry); + retval = -EFAULT; + break; + } if (ipa_query_intf_tx_props( (struct ipa_ioc_query_intf_tx_props *)param)) { retval = -1; @@ -1027,9 +1132,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - - pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *) - header)->num_rx_props * + pre_entry = + ((struct ipa_ioc_query_intf_rx_props *) + header)->num_rx_props; + pyld_sz = sz + pre_entry * sizeof(struct ipa_ioc_rx_intf_prop); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -1040,6 +1146,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_query_intf_rx_props *) + param)->num_rx_props != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_query_intf_rx_props *) + param)->num_rx_props, pre_entry); + retval = -EFAULT; + break; + } if (ipa_query_intf_rx_props( (struct ipa_ioc_query_intf_rx_props *)param)) { retval = -1; @@ -1062,9 +1177,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - - pyld_sz = sz + ((struct ipa_ioc_query_intf_ext_props *) - header)->num_ext_props * + pre_entry = + ((struct ipa_ioc_query_intf_ext_props *) + header)->num_ext_props; + pyld_sz = sz + pre_entry * sizeof(struct ipa_ioc_ext_intf_prop); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -1075,6 +1191,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_query_intf_ext_props *) + param)->num_ext_props != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_query_intf_ext_props *) + param)->num_ext_props, pre_entry); + retval = -EFAULT; + break; + } if (ipa_query_intf_ext_props( (struct ipa_ioc_query_intf_ext_props *)param)) { retval = -1; @@ -1091,8 +1216,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - pyld_sz = sizeof(struct ipa_msg_meta) + + pre_entry = ((struct ipa_msg_meta *)header)->msg_len; + pyld_sz = sizeof(struct ipa_msg_meta) + + pre_entry; param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -1102,6 +1229,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_msg_meta *)param)->msg_len + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_msg_meta *)param)->msg_len, + pre_entry); + retval = -EFAULT; + break; + } if (ipa_pull_msg((struct ipa_msg_meta *)param, (char *)param + sizeof(struct ipa_msg_meta), ((struct ipa_msg_meta *)param)->msg_len) != @@ -1218,10 +1354,12 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_hdr_proc_ctx *) + header)->num_proc_ctxs; pyld_sz = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + - ((struct ipa_ioc_add_hdr_proc_ctx *)header)->num_proc_ctxs * - sizeof(struct ipa_hdr_proc_ctx_add); + pre_entry * sizeof(struct ipa_hdr_proc_ctx_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -1231,6 +1369,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *) + param)->num_proc_ctxs != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_hdr_proc_ctx *) + param)->num_proc_ctxs, pre_entry); + retval = -EFAULT; + break; + } if (ipa2_add_hdr_proc_ctx( (struct ipa_ioc_add_hdr_proc_ctx *)param)) { retval = -EFAULT; @@ -1247,10 +1394,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_hdr_proc_ctx) + - ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls * - sizeof(struct ipa_hdr_proc_ctx_del); + pre_entry * sizeof(struct ipa_hdr_proc_ctx_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -1260,6 +1408,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *) + param)->num_hdls != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_hdr_proc_ctx *)param)-> + num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa2_del_hdr_proc_ctx( (struct ipa_ioc_del_hdr_proc_ctx *)param)) { retval = -EFAULT; @@ -3612,6 +3770,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, ipa_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge; ipa_ctx->ipa_bam_remote_mode = resource_p->ipa_bam_remote_mode; ipa_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt; + ipa_ctx->ipa_wdi2 = resource_p->ipa_wdi2; ipa_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size; ipa_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size; ipa_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset; @@ -4150,6 +4309,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_hw_mode = 0; ipa_drv_res->ipa_bam_remote_mode = false; ipa_drv_res->modem_cfg_emb_pipe_flt = false; + ipa_drv_res->ipa_wdi2 = false; ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; @@ -4216,6 +4376,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->modem_cfg_emb_pipe_flt ? "True" : "False"); + ipa_drv_res->ipa_wdi2 = + of_property_read_bool(pdev->dev.of_node, + "qcom,ipa-wdi2"); + IPADBG(": WDI-2.0 = %s\n", + ipa_drv_res->ipa_wdi2 + ? "True" : "False"); + ipa_drv_res->skip_uc_pipe_reset = of_property_read_bool(pdev->dev.of_node, "qcom,skip-uc-pipe-reset"); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index c0ac544fa271..695c8bc4cbc0 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -2397,7 +2397,7 @@ begin: if (skb->len < IPA_PKT_STATUS_SIZE) { WARN_ON(sys->prev_skb != NULL); IPADBG("status straddles buffer\n"); - sys->prev_skb = skb; + sys->prev_skb = skb_copy(skb, GFP_KERNEL); sys->len_partial = skb->len; return rc; } @@ -2482,7 +2482,7 @@ begin: !status->exception) { WARN_ON(sys->prev_skb != NULL); IPADBG("Ins header in next buffer\n"); - sys->prev_skb = skb; + sys->prev_skb = skb_copy(skb, GFP_KERNEL); sys->len_partial = skb->len; return rc; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 5b8abb25cfb0..581a5f9d8a2e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -50,6 +50,9 @@ #define IPA_DL_CHECKSUM_LENGTH (8) #define IPA_NUM_DESC_PER_SW_TX (2) #define IPA_GENERIC_RX_POOL_SZ 1000 +#define IPA_UC_FINISH_MAX 6 +#define IPA_UC_WAIT_MIN_SLEEP 1000 +#define IPA_UC_WAII_MAX_SLEEP 1200 #define IPA_MAX_STATUS_STAT_NUM 30 @@ -890,6 +893,14 @@ struct ipa_uc_ctx { u32 uc_status; bool uc_zip_error; u32 uc_error_type; + phys_addr_t rdy_ring_base_pa; + phys_addr_t rdy_ring_rp_pa; + u32 rdy_ring_size; + phys_addr_t rdy_comp_ring_base_pa; + phys_addr_t rdy_comp_ring_wp_pa; + u32 rdy_comp_ring_size; + u32 *rdy_ring_rp_va; + u32 *rdy_comp_ring_wp_va; }; /** @@ -994,6 +1005,7 @@ struct ipacm_client_info { * @use_ipa_teth_bridge: use tethering bridge driver * @ipa_bam_remote_mode: ipa bam is in remote mode * @modem_cfg_emb_pipe_flt: modem configure embedded pipe filtering rules + * @ipa_wdi2: using wdi-2.0 * @ipa_bus_hdl: msm driver handle for the data path bus * @ctrl: holds the core specific operations based on * core version (vtable like) @@ -1081,6 +1093,7 @@ struct ipa_context { bool use_ipa_teth_bridge; bool ipa_bam_remote_mode; bool modem_cfg_emb_pipe_flt; + bool ipa_wdi2; /* featurize if memory footprint becomes a concern */ struct ipa_stats stats; void *smem_pipe_mem; @@ -1171,6 +1184,7 @@ struct ipa_plat_drv_res { u32 ee; bool ipa_bam_remote_mode; bool modem_cfg_emb_pipe_flt; + bool ipa_wdi2; u32 wan_rx_ring_size; u32 lan_rx_ring_size; bool skip_uc_pipe_reset; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c index a1072638b281..4e79fec076e2 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c @@ -25,12 +25,14 @@ #define IPA_WDI_RESUMED BIT(2) #define IPA_UC_POLL_SLEEP_USEC 100 -#define IPA_WDI_RX_RING_RES 0 -#define IPA_WDI_RX_RING_RP_RES 1 -#define IPA_WDI_TX_RING_RES 2 -#define IPA_WDI_CE_RING_RES 3 -#define IPA_WDI_CE_DB_RES 4 -#define IPA_WDI_MAX_RES 5 +#define IPA_WDI_RX_RING_RES 0 +#define IPA_WDI_RX_RING_RP_RES 1 +#define IPA_WDI_RX_COMP_RING_RES 2 +#define IPA_WDI_RX_COMP_RING_WP_RES 3 +#define IPA_WDI_TX_RING_RES 4 +#define IPA_WDI_CE_RING_RES 5 +#define IPA_WDI_CE_DB_RES 6 +#define IPA_WDI_MAX_RES 7 struct ipa_wdi_res { struct ipa_wdi_buffer_info *res; @@ -232,6 +234,21 @@ struct IpaHwWdiTxSetUpCmdData_t { u8 reserved; } __packed; +struct IpaHwWdi2TxSetUpCmdData_t { + u32 comp_ring_base_pa; + u32 comp_ring_base_pa_hi; + u16 comp_ring_size; + u16 reserved_comp_ring; + u32 ce_ring_base_pa; + u32 ce_ring_base_pa_hi; + u16 ce_ring_size; + u16 reserved_ce_ring; + u32 ce_ring_doorbell_pa; + u32 ce_ring_doorbell_pa_hi; + u16 num_tx_buffers; + u8 ipa_pipe_number; + u8 reserved; +} __packed; /** * struct IpaHwWdiRxSetUpCmdData_t - Structure holding the parameters for * IPA_CPU_2_HW_CMD_WDI_RX_SET_UP command. @@ -253,6 +270,19 @@ struct IpaHwWdiRxSetUpCmdData_t { u8 ipa_pipe_number; } __packed; +struct IpaHwWdi2RxSetUpCmdData_t { + u32 rx_ring_base_pa; + u32 rx_ring_base_pa_hi; + u32 rx_ring_size; + u32 rx_ring_rp_pa; + u32 rx_ring_rp_pa_hi; + u32 rx_comp_ring_base_pa; + u32 rx_comp_ring_base_pa_hi; + u32 rx_comp_ring_size; + u32 rx_comp_ring_wp_pa; + u32 rx_comp_ring_wp_pa_hi; + u8 ipa_pipe_number; +} __packed; /** * union IpaHwWdiRxExtCfgCmdData_t - Structure holding the parameters for * IPA_CPU_2_HW_CMD_WDI_RX_EXT_CFG command. @@ -560,7 +590,10 @@ static void ipa_release_uc_smmu_mappings(enum ipa_client_type client) end = IPA_WDI_CE_DB_RES; } else { start = IPA_WDI_RX_RING_RES; - end = IPA_WDI_RX_RING_RP_RES; + if (ipa_ctx->ipa_wdi2) + end = IPA_WDI_RX_COMP_RING_WP_RES; + else + end = IPA_WDI_RX_RING_RP_RES; } for (i = start; i <= end; i++) { @@ -708,6 +741,8 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, struct ipa_mem_buffer cmd; struct IpaHwWdiTxSetUpCmdData_t *tx; struct IpaHwWdiRxSetUpCmdData_t *rx; + struct IpaHwWdi2TxSetUpCmdData_t *tx_2; + struct IpaHwWdi2RxSetUpCmdData_t *rx_2; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; unsigned long va; phys_addr_t pa; @@ -760,7 +795,10 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPADBG("client=%d ep=%d\n", in->sys.client, ipa_ep_idx); if (IPA_CLIENT_IS_CONS(in->sys.client)) { - cmd.size = sizeof(*tx); + if (ipa_ctx->ipa_wdi2) + cmd.size = sizeof(*tx_2); + else + cmd.size = sizeof(*tx); IPADBG("comp_ring_base_pa=0x%pa\n", &in->u.dl.comp_ring_base_pa); IPADBG("comp_ring_size=%d\n", in->u.dl.comp_ring_size); @@ -770,10 +808,59 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, &in->u.dl.ce_door_bell_pa); IPADBG("num_tx_buffers=%d\n", in->u.dl.num_tx_buffers); } else { - cmd.size = sizeof(*rx); - IPADBG("rx_ring_base_pa=0x%pa\n", &in->u.ul.rdy_ring_base_pa); - IPADBG("rx_ring_size=%d\n", in->u.ul.rdy_ring_size); - IPADBG("rx_ring_rp_pa=0x%pa\n", &in->u.ul.rdy_ring_rp_pa); + if (ipa_ctx->ipa_wdi2) { + /* WDI2.0 feature */ + cmd.size = sizeof(*rx_2); + IPADBG("rdy_ring_rp value =%d\n", + *in->u.ul.rdy_ring_rp_va); + IPADBG("rx_comp_ring_wp value=%d\n", + *in->u.ul.rdy_comp_ring_wp_va); + ipa_ctx->uc_ctx.rdy_ring_rp_va = + in->u.ul.rdy_ring_rp_va; + ipa_ctx->uc_ctx.rdy_comp_ring_wp_va = + in->u.ul.rdy_comp_ring_wp_va; + } else { + cmd.size = sizeof(*rx); + } + IPADBG("rx_ring_base_pa=0x%pa\n", + &in->u.ul.rdy_ring_base_pa); + IPADBG("rx_ring_size=%d\n", + in->u.ul.rdy_ring_size); + IPADBG("rx_ring_rp_pa=0x%pa\n", + &in->u.ul.rdy_ring_rp_pa); + + IPADBG("rx_comp_ring_base_pa=0x%pa\n", + &in->u.ul.rdy_comp_ring_base_pa); + IPADBG("rx_comp_ring_size=%d\n", + in->u.ul.rdy_comp_ring_size); + IPADBG("rx_comp_ring_wp_pa=0x%pa\n", + &in->u.ul.rdy_comp_ring_wp_pa); + + ipa_ctx->uc_ctx.rdy_ring_base_pa = + in->u.ul.rdy_ring_base_pa; + ipa_ctx->uc_ctx.rdy_ring_rp_pa = + in->u.ul.rdy_ring_rp_pa; + ipa_ctx->uc_ctx.rdy_ring_size = + in->u.ul.rdy_ring_size; + ipa_ctx->uc_ctx.rdy_comp_ring_base_pa = + in->u.ul.rdy_comp_ring_base_pa; + ipa_ctx->uc_ctx.rdy_comp_ring_wp_pa = + in->u.ul.rdy_comp_ring_wp_pa; + ipa_ctx->uc_ctx.rdy_comp_ring_size = + in->u.ul.rdy_comp_ring_size; + + /* check if the VA is empty */ + if (!in->u.ul.rdy_ring_rp_va && ipa_ctx->ipa_wdi2) { + IPAERR("rdy_ring_rp_va is empty, wdi2.0(%d)\n", + ipa_ctx->ipa_wdi2); + goto dma_alloc_fail; + } + if (!in->u.ul.rdy_comp_ring_wp_va && + ipa_ctx->ipa_wdi2) { + IPAERR("comp_ring_wp_va is empty, wdi2.0(%d)\n", + ipa_ctx->ipa_wdi2); + goto dma_alloc_fail; + } } cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size, @@ -785,14 +872,16 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, } if (IPA_CLIENT_IS_CONS(in->sys.client)) { - tx = (struct IpaHwWdiTxSetUpCmdData_t *)cmd.base; + if (ipa_ctx->ipa_wdi2) { + tx_2 = (struct IpaHwWdi2TxSetUpCmdData_t *)cmd.base; - len = in->smmu_enabled ? in->u.dl_smmu.comp_ring_size : - in->u.dl.comp_ring_size; - IPADBG("TX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, + len = in->smmu_enabled ? in->u.dl_smmu.comp_ring_size : + in->u.dl.comp_ring_size; + IPADBG("TX_2 ring smmu_en=%d ring_size=%d %d\n", + in->smmu_enabled, in->u.dl_smmu.comp_ring_size, in->u.dl.comp_ring_size); - if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES, + if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES, in->smmu_enabled, in->u.dl.comp_ring_base_pa, &in->u.dl_smmu.comp_ring, @@ -802,47 +891,121 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPAERR("fail to create uc mapping TX ring.\n"); result = -ENOMEM; goto uc_timeout; - } - tx->comp_ring_base_pa = va; - tx->comp_ring_size = len; - - len = in->smmu_enabled ? in->u.dl_smmu.ce_ring_size : - in->u.dl.ce_ring_size; - IPADBG("TX CE ring smmu_en=%d ring_size=%d %d\n", - in->smmu_enabled, - in->u.dl_smmu.ce_ring_size, - in->u.dl.ce_ring_size); - if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES, + } + tx_2->comp_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + tx_2->comp_ring_base_pa = (u32) (va & 0xFFFFFFFF); + tx_2->comp_ring_size = len; + IPADBG("TX_2 comp_ring_base_pa_hi=0x%08x :0x%08x\n", + tx_2->comp_ring_base_pa_hi, + tx_2->comp_ring_base_pa); + + len = in->smmu_enabled ? in->u.dl_smmu.ce_ring_size : + in->u.dl.ce_ring_size; + IPADBG("TX_2 CE ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, - in->u.dl.ce_ring_base_pa, - &in->u.dl_smmu.ce_ring, - len, - false, - &va)) { + in->u.dl_smmu.ce_ring_size, + in->u.dl.ce_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES, + in->smmu_enabled, + in->u.dl.ce_ring_base_pa, + &in->u.dl_smmu.ce_ring, + len, + false, + &va)) { IPAERR("fail to create uc mapping CE ring.\n"); result = -ENOMEM; goto uc_timeout; - } - tx->ce_ring_base_pa = va; - tx->ce_ring_size = len; + } + tx_2->ce_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + tx_2->ce_ring_base_pa = (u32) (va & 0xFFFFFFFF); + tx_2->ce_ring_size = len; + IPADBG("TX_2 ce_ring_base_pa_hi=0x%08x :0x%08x\n", + tx_2->ce_ring_base_pa_hi, + tx_2->ce_ring_base_pa); + + pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa : + in->u.dl.ce_door_bell_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES, + in->smmu_enabled, + pa, + NULL, + 4, + true, + &va)) { + IPAERR("fail to create uc mapping CE DB.\n"); + result = -ENOMEM; + goto uc_timeout; + } + tx_2->ce_ring_doorbell_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + tx_2->ce_ring_doorbell_pa = (u32) (va & 0xFFFFFFFF); + IPADBG("TX_2 ce_ring_doorbell_pa_hi=0x%08x :0x%08x\n", + tx_2->ce_ring_doorbell_pa_hi, + tx_2->ce_ring_doorbell_pa); + + tx_2->num_tx_buffers = in->u.dl.num_tx_buffers; + tx_2->ipa_pipe_number = ipa_ep_idx; + } else { + tx = (struct IpaHwWdiTxSetUpCmdData_t *)cmd.base; + len = in->smmu_enabled ? in->u.dl_smmu.comp_ring_size : + in->u.dl.comp_ring_size; + IPADBG("TX ring smmu_en=%d ring_size=%d %d\n", + in->smmu_enabled, + in->u.dl_smmu.comp_ring_size, + in->u.dl.comp_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES, + in->smmu_enabled, + in->u.dl.comp_ring_base_pa, + &in->u.dl_smmu.comp_ring, + len, + false, + &va)) { + IPAERR("fail to create uc mapping TX ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + tx->comp_ring_base_pa = va; + tx->comp_ring_size = len; - pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa : - in->u.dl.ce_door_bell_pa; - if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES, + len = in->smmu_enabled ? in->u.dl_smmu.ce_ring_size : + in->u.dl.ce_ring_size; + IPADBG("TX CE ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, - pa, - NULL, - 4, - true, - &va)) { + in->u.dl_smmu.ce_ring_size, + in->u.dl.ce_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES, + in->smmu_enabled, + in->u.dl.ce_ring_base_pa, + &in->u.dl_smmu.ce_ring, + len, + false, + &va)) { + IPAERR("fail to create uc mapping CE ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + tx->ce_ring_base_pa = va; + tx->ce_ring_size = len; + pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa : + in->u.dl.ce_door_bell_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES, + in->smmu_enabled, + pa, + NULL, + 4, + true, + &va)) { IPAERR("fail to create uc mapping CE DB.\n"); result = -ENOMEM; goto uc_timeout; + } + tx->ce_ring_doorbell_pa = va; + tx->num_tx_buffers = in->u.dl.num_tx_buffers; + tx->ipa_pipe_number = ipa_ep_idx; } - tx->ce_ring_doorbell_pa = va; - tx->num_tx_buffers = in->u.dl.num_tx_buffers; - tx->ipa_pipe_number = ipa_ep_idx; if (ipa_ctx->ipa_hw_type >= IPA_HW_v2_5) { out->uc_door_bell_pa = ipa_ctx->ipa_wrapper_base + @@ -859,43 +1022,141 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPA_HW_WDI_TX_MBOX_START_INDEX % 32); } } else { - rx = (struct IpaHwWdiRxSetUpCmdData_t *)cmd.base; + if (ipa_ctx->ipa_wdi2) { + rx_2 = (struct IpaHwWdi2RxSetUpCmdData_t *)cmd.base; - len = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_size : - in->u.ul.rdy_ring_size; - IPADBG("RX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, + len = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_size : + in->u.ul.rdy_ring_size; + IPADBG("RX_2 ring smmu_en=%d ring_size=%d %d\n", + in->smmu_enabled, in->u.ul_smmu.rdy_ring_size, in->u.ul.rdy_ring_size); - if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES, + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES, + in->smmu_enabled, + in->u.ul.rdy_ring_base_pa, + &in->u.ul_smmu.rdy_ring, + len, + false, + &va)) { + IPAERR("fail to create uc RX_2 ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx_2->rx_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_ring_base_pa = (u32) (va & 0xFFFFFFFF); + rx_2->rx_ring_size = len; + IPADBG("RX_2 rx_ring_base_pa_hi=0x%08x:0x%08x\n", + rx_2->rx_ring_base_pa_hi, + rx_2->rx_ring_base_pa); + + pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa : + in->u.ul.rdy_ring_rp_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES, + in->smmu_enabled, + pa, + NULL, + 4, + false, + &va)) { + IPAERR("fail to create uc RX_2 rng RP\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx_2->rx_ring_rp_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_ring_rp_pa = (u32) (va & 0xFFFFFFFF); + IPADBG("RX_2 rx_ring_rp_pa_hi=0x%08x :0x%08x\n", + rx_2->rx_ring_rp_pa_hi, + rx_2->rx_ring_rp_pa); + len = in->smmu_enabled ? + in->u.ul_smmu.rdy_comp_ring_size : + in->u.ul.rdy_comp_ring_size; + IPADBG("RX_2 ring smmu_en=%d comp_ring_size=%d %d\n", in->smmu_enabled, - in->u.ul.rdy_ring_base_pa, - &in->u.ul_smmu.rdy_ring, - len, - false, - &va)) { - IPAERR("fail to create uc mapping RX ring.\n"); + in->u.ul_smmu.rdy_comp_ring_size, + in->u.ul.rdy_comp_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_COMP_RING_RES, + in->smmu_enabled, + in->u.ul.rdy_comp_ring_base_pa, + &in->u.ul_smmu.rdy_comp_ring, + len, + false, + &va)) { + IPAERR("fail to create uc RX_2 comp_ring.\n"); result = -ENOMEM; goto uc_timeout; - } - rx->rx_ring_base_pa = va; - rx->rx_ring_size = len; + } + rx_2->rx_comp_ring_base_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_comp_ring_base_pa = (u32) (va & 0xFFFFFFFF); + rx_2->rx_comp_ring_size = len; + IPADBG("RX_2 rx_comp_ring_base_pa_hi=0x%08x:0x%08x\n", + rx_2->rx_comp_ring_base_pa_hi, + rx_2->rx_comp_ring_base_pa); + + pa = in->smmu_enabled ? + in->u.ul_smmu.rdy_comp_ring_wp_pa : + in->u.ul.rdy_comp_ring_wp_pa; + if (ipa_create_uc_smmu_mapping( + IPA_WDI_RX_COMP_RING_WP_RES, + in->smmu_enabled, + pa, + NULL, + 4, + false, + &va)) { + IPAERR("fail to create uc RX_2 comp_rng WP\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx_2->rx_comp_ring_wp_pa_hi = + (u32) ((va & 0xFFFFFFFF00000000) >> 32); + rx_2->rx_comp_ring_wp_pa = (u32) (va & 0xFFFFFFFF); + IPADBG("RX_2 rx_comp_ring_wp_pa_hi=0x%08x:0x%08x\n", + rx_2->rx_comp_ring_wp_pa_hi, + rx_2->rx_comp_ring_wp_pa); + rx_2->ipa_pipe_number = ipa_ep_idx; + } else { + rx = (struct IpaHwWdiRxSetUpCmdData_t *)cmd.base; - pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa : - in->u.ul.rdy_ring_rp_pa; - if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES, + len = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_size : + in->u.ul.rdy_ring_size; + IPADBG("RX ring smmu_en=%d ring_size=%d %d\n", in->smmu_enabled, - pa, - NULL, - 4, - false, - &va)) { + in->u.ul_smmu.rdy_ring_size, + in->u.ul.rdy_ring_size); + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES, + in->smmu_enabled, + in->u.ul.rdy_ring_base_pa, + &in->u.ul_smmu.rdy_ring, + len, + false, + &va)) { + IPAERR("fail to create uc mapping RX ring.\n"); + result = -ENOMEM; + goto uc_timeout; + } + rx->rx_ring_base_pa = va; + rx->rx_ring_size = len; + + pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa : + in->u.ul.rdy_ring_rp_pa; + if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES, + in->smmu_enabled, + pa, + NULL, + 4, + false, + &va)) { IPAERR("fail to create uc mapping RX rng RP\n"); result = -ENOMEM; goto uc_timeout; + } + rx->rx_ring_rp_pa = va; + rx->ipa_pipe_number = ipa_ep_idx; } - rx->rx_ring_rp_pa = va; - rx->ipa_pipe_number = ipa_ep_idx; if (ipa_ctx->ipa_hw_type >= IPA_HW_v2_5) { out->uc_door_bell_pa = ipa_ctx->ipa_wrapper_base + @@ -1127,6 +1388,7 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl) union IpaHwWdiCommonChCmdData_t disable; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; u32 prod_hdl; + int i; if (unlikely(!ipa_ctx)) { IPAERR("IPA driver was not initialized\n"); @@ -1143,6 +1405,28 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl) if (result) return result; + /* checking rdy_ring_rp_pa matches the rdy_comp_ring_wp_pa on WDI2.0 */ + if (ipa_ctx->ipa_wdi2) { + for (i = 0; i < IPA_UC_FINISH_MAX; i++) { + IPADBG("(%d) rp_value(%u), comp_wp_value(%u)\n", + i, + *ipa_ctx->uc_ctx.rdy_ring_rp_va, + *ipa_ctx->uc_ctx.rdy_comp_ring_wp_va); + if (*ipa_ctx->uc_ctx.rdy_ring_rp_va != + *ipa_ctx->uc_ctx.rdy_comp_ring_wp_va) { + usleep_range(IPA_UC_WAIT_MIN_SLEEP, + IPA_UC_WAII_MAX_SLEEP); + } else { + break; + } + } + /* In case ipa_uc still haven't processed all + * pending descriptors, we have to assert + */ + if (i == IPA_UC_FINISH_MAX) + BUG(); + } + IPADBG("ep=%d\n", clnt_hdl); ep = &ipa_ctx->ep[clnt_hdl]; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index c9120ce83da8..1df2bc6b902c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -596,6 +596,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_v4_nat_del nat_del; struct ipa_ioc_rm_dependency rm_depend; size_t sz; + int pre_entry; IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd)); @@ -649,11 +650,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - + pre_entry = + ((struct ipa_ioc_nat_dma_cmd *)header)->entries; pyld_sz = sizeof(struct ipa_ioc_nat_dma_cmd) + - ((struct ipa_ioc_nat_dma_cmd *)header)->entries * - sizeof(struct ipa_ioc_nat_dma_one); + pre_entry * sizeof(struct ipa_ioc_nat_dma_one); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -664,7 +665,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_nat_dma_cmd *)param)->entries, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_nat_dma_cmd((struct ipa_ioc_nat_dma_cmd *)param)) { retval = -EFAULT; break; @@ -689,10 +698,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_hdr *)header)->num_hdrs; pyld_sz = sizeof(struct ipa_ioc_add_hdr) + - ((struct ipa_ioc_add_hdr *)header)->num_hdrs * - sizeof(struct ipa_hdr_add); + pre_entry * sizeof(struct ipa_hdr_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -702,6 +712,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_hdr *)param)->num_hdrs, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_add_hdr((struct ipa_ioc_add_hdr *)param)) { retval = -EFAULT; break; @@ -718,10 +737,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_hdr *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_hdr) + - ((struct ipa_ioc_del_hdr *)header)->num_hdls * - sizeof(struct ipa_hdr_del); + pre_entry * sizeof(struct ipa_hdr_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -731,6 +751,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_hdr *)param)->num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_del_hdr((struct ipa_ioc_del_hdr *)param)) { retval = -EFAULT; break; @@ -747,10 +776,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_rt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_add_rt_rule) + - ((struct ipa_ioc_add_rt_rule *)header)->num_rules * - sizeof(struct ipa_rt_rule_add); + pre_entry * sizeof(struct ipa_rt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -760,6 +790,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_rt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) { retval = -EFAULT; break; @@ -776,10 +816,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_add_rt_rule_after) + - ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules * - sizeof(struct ipa_rt_rule_add); + pre_entry * sizeof(struct ipa_rt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -789,6 +830,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_rt_rule_after *)param)-> + num_rules != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_rt_rule_after *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_add_rt_rule_after( (struct ipa_ioc_add_rt_rule_after *)param)) { @@ -807,10 +858,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_mdfy_rt_rule) + - ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules * - sizeof(struct ipa_rt_rule_mdfy); + pre_entry * sizeof(struct ipa_rt_rule_mdfy); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -820,6 +872,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_mdfy_rt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_mdfy_rt_rule((struct ipa_ioc_mdfy_rt_rule *)param)) { retval = -EFAULT; break; @@ -836,10 +898,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_rt_rule *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_rt_rule) + - ((struct ipa_ioc_del_rt_rule *)header)->num_hdls * - sizeof(struct ipa_rt_rule_del); + pre_entry * sizeof(struct ipa_rt_rule_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -849,6 +912,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_rt_rule *)param)->num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) { retval = -EFAULT; break; @@ -865,10 +937,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_flt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_add_flt_rule) + - ((struct ipa_ioc_add_flt_rule *)header)->num_rules * - sizeof(struct ipa_flt_rule_add); + pre_entry * sizeof(struct ipa_flt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -878,6 +951,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_flt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) { retval = -EFAULT; break; @@ -895,10 +978,12 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_flt_rule_after *)header)-> + num_rules; pyld_sz = sizeof(struct ipa_ioc_add_flt_rule_after) + - ((struct ipa_ioc_add_flt_rule_after *)header)->num_rules * - sizeof(struct ipa_flt_rule_add); + pre_entry * sizeof(struct ipa_flt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -908,6 +993,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_flt_rule_after *)param)-> + num_rules != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_flt_rule_after *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_add_flt_rule_after( (struct ipa_ioc_add_flt_rule_after *)param)) { retval = -EFAULT; @@ -925,10 +1020,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_flt_rule *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_flt_rule) + - ((struct ipa_ioc_del_flt_rule *)header)->num_hdls * - sizeof(struct ipa_flt_rule_del); + pre_entry * sizeof(struct ipa_flt_rule_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -938,6 +1034,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_flt_rule *)param)-> + num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) { retval = -EFAULT; break; @@ -954,10 +1060,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules; pyld_sz = sizeof(struct ipa_ioc_mdfy_flt_rule) + - ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules * - sizeof(struct ipa_flt_rule_mdfy); + pre_entry * sizeof(struct ipa_flt_rule_mdfy); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -967,6 +1074,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_mdfy_flt_rule *)param)-> + num_rules, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_mdfy_flt_rule((struct ipa_ioc_mdfy_flt_rule *)param)) { retval = -EFAULT; break; @@ -1080,9 +1197,10 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - - pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *) - header)->num_tx_props * + pre_entry = + ((struct ipa_ioc_query_intf_tx_props *) + header)->num_tx_props; + pyld_sz = sz + pre_entry * sizeof(struct ipa_ioc_tx_intf_prop); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -1093,6 +1211,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_query_intf_tx_props *) + param)->num_tx_props + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_query_intf_tx_props *) + param)->num_tx_props, pre_entry); + retval = -EFAULT; + break; + } if (ipa3_query_intf_tx_props( (struct ipa_ioc_query_intf_tx_props *)param)) { retval = -1; @@ -1115,9 +1243,10 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - - pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *) - header)->num_rx_props * + pre_entry = + ((struct ipa_ioc_query_intf_rx_props *) + header)->num_rx_props; + pyld_sz = sz + pre_entry * sizeof(struct ipa_ioc_rx_intf_prop); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -1128,6 +1257,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_query_intf_rx_props *) + param)->num_rx_props != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_query_intf_rx_props *) + param)->num_rx_props, pre_entry); + retval = -EFAULT; + break; + } if (ipa3_query_intf_rx_props( (struct ipa_ioc_query_intf_rx_props *)param)) { retval = -1; @@ -1150,9 +1288,10 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - - pyld_sz = sz + ((struct ipa_ioc_query_intf_ext_props *) - header)->num_ext_props * + pre_entry = + ((struct ipa_ioc_query_intf_ext_props *) + header)->num_ext_props; + pyld_sz = sz + pre_entry * sizeof(struct ipa_ioc_ext_intf_prop); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { @@ -1163,6 +1302,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_query_intf_ext_props *) + param)->num_ext_props != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_query_intf_ext_props *) + param)->num_ext_props, pre_entry); + retval = -EFAULT; + break; + } if (ipa3_query_intf_ext_props( (struct ipa_ioc_query_intf_ext_props *)param)) { retval = -1; @@ -1179,8 +1327,10 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - pyld_sz = sizeof(struct ipa_msg_meta) + + pre_entry = ((struct ipa_msg_meta *)header)->msg_len; + pyld_sz = sizeof(struct ipa_msg_meta) + + pre_entry; param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -1190,6 +1340,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_msg_meta *)param)->msg_len + != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_msg_meta *)param)->msg_len, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_pull_msg((struct ipa_msg_meta *)param, (char *)param + sizeof(struct ipa_msg_meta), ((struct ipa_msg_meta *)param)->msg_len) != @@ -1306,10 +1465,12 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_add_hdr_proc_ctx *) + header)->num_proc_ctxs; pyld_sz = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + - ((struct ipa_ioc_add_hdr_proc_ctx *)header)->num_proc_ctxs * - sizeof(struct ipa_hdr_proc_ctx_add); + pre_entry * sizeof(struct ipa_hdr_proc_ctx_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -1319,6 +1480,15 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *) + param)->num_proc_ctxs != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_add_hdr_proc_ctx *) + param)->num_proc_ctxs, pre_entry); + retval = -EFAULT; + break; + } if (ipa3_add_hdr_proc_ctx( (struct ipa_ioc_add_hdr_proc_ctx *)param)) { retval = -EFAULT; @@ -1335,10 +1505,11 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + pre_entry = + ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls; pyld_sz = sizeof(struct ipa_ioc_del_hdr_proc_ctx) + - ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls * - sizeof(struct ipa_hdr_proc_ctx_del); + pre_entry * sizeof(struct ipa_hdr_proc_ctx_del); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; @@ -1348,6 +1519,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + /* add check in case user-space module compromised */ + if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *) + param)->num_hdls != pre_entry)) { + IPAERR("current %d pre %d\n", + ((struct ipa_ioc_del_hdr_proc_ctx *)param)-> + num_hdls, + pre_entry); + retval = -EFAULT; + break; + } if (ipa3_del_hdr_proc_ctx( (struct ipa_ioc_del_hdr_proc_ctx *)param)) { retval = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 19eb1ee9c881..9e346f12a108 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3836,6 +3836,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, union __packed gsi_channel_scratch ch_scratch; struct ipa_gsi_ep_config *gsi_ep_info; dma_addr_t dma_addr; + dma_addr_t evt_dma_addr; int result; if (!ep) { @@ -3844,13 +3845,13 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, } ep->gsi_evt_ring_hdl = ~0; + memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props)); /* * allocate event ring for all interrupt-policy * pipes and IPA consumers pipes */ if (ep->sys->policy != IPA_POLICY_NOINTR_MODE || IPA_CLIENT_IS_CONS(ep->client)) { - memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props)); gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV; gsi_evt_ring_props.intr = GSI_INTR_IRQ; gsi_evt_ring_props.re_size = @@ -3859,8 +3860,13 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, gsi_evt_ring_props.ring_len = IPA_GSI_EVT_RING_LEN; gsi_evt_ring_props.ring_base_vaddr = dma_alloc_coherent(ipa3_ctx->pdev, IPA_GSI_EVT_RING_LEN, - &dma_addr, 0); - gsi_evt_ring_props.ring_base_addr = dma_addr; + &evt_dma_addr, GFP_KERNEL); + if (!gsi_evt_ring_props.ring_base_vaddr) { + IPAERR("fail to dma alloc %u bytes\n", + IPA_GSI_EVT_RING_LEN); + return -ENOMEM; + } + gsi_evt_ring_props.ring_base_addr = evt_dma_addr; /* copy mem info */ ep->gsi_mem_info.evt_ring_len = gsi_evt_ring_props.ring_len; @@ -3895,7 +3901,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, if (!gsi_ep_info) { IPAERR("Invalid ep number\n"); result = -EINVAL; - goto fail_alloc_evt_ring; + goto fail_get_gsi_ep_info; } else gsi_channel_props.ch_id = gsi_ep_info->ipa_gsi_chan_num; @@ -3914,7 +3920,12 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, gsi_channel_props.ring_len = 2 * in->desc_fifo_sz; gsi_channel_props.ring_base_vaddr = dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, - &dma_addr, 0); + &dma_addr, GFP_KERNEL); + if (!gsi_channel_props.ring_base_vaddr) { + IPAERR("fail to dma alloc %u bytes\n", + gsi_channel_props.ring_len); + goto fail_alloc_channel_ring; + } gsi_channel_props.ring_base_addr = dma_addr; /* copy mem info */ @@ -3950,7 +3961,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch); if (result != GSI_STATUS_SUCCESS) { IPAERR("failed to write scratch %d\n", result); - goto fail_start_channel; + goto fail_write_channel_scratch; } result = gsi_start_channel(ep->gsi_chan_hdl); @@ -3962,17 +3973,25 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, return 0; fail_start_channel: +fail_write_channel_scratch: if (gsi_dealloc_channel(ep->gsi_chan_hdl) != GSI_STATUS_SUCCESS) { IPAERR("Failed to dealloc GSI chan.\n"); BUG(); } fail_alloc_channel: + dma_free_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, + gsi_channel_props.ring_base_vaddr, dma_addr); +fail_alloc_channel_ring: +fail_get_gsi_ep_info: if (ep->gsi_evt_ring_hdl != ~0) { gsi_dealloc_evt_ring(ep->gsi_evt_ring_hdl); ep->gsi_evt_ring_hdl = ~0; } fail_alloc_evt_ring: + if (gsi_evt_ring_props.ring_base_vaddr) + dma_free_coherent(ipa3_ctx->pdev, IPA_GSI_EVT_RING_LEN, + gsi_evt_ring_props.ring_base_vaddr, evt_dma_addr); IPAERR("Return with err: %d\n", result); return result; } diff --git a/drivers/platform/msm/ipa/test/Makefile b/drivers/platform/msm/ipa/test/Makefile index e1686e608906..c20fd2b42487 100644 --- a/drivers/platform/msm/ipa/test/Makefile +++ b/drivers/platform/msm/ipa/test/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o -ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o +ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o diff --git a/drivers/platform/msm/ipa/test/ipa_test_dma.c b/drivers/platform/msm/ipa/test/ipa_test_dma.c new file mode 100644 index 000000000000..af1b584b0d8c --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_test_dma.c @@ -0,0 +1,931 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/ipa.h> +#include "../ipa_v3/ipa_i.h" +#include "ipa_ut_framework.h" + +#define IPA_TEST_DMA_WQ_NAME_BUFF_SZ 64 +#define IPA_TEST_DMA_MT_TEST_NUM_WQ 500 +#define IPA_TEST_DMA_MEMCPY_BUFF_SIZE 16384 +#define IPA_TEST_DMA_MAX_PKT_SIZE 0xFF00 +#define IPA_DMA_TEST_LOOP_NUM 1000 +#define IPA_DMA_TEST_INT_LOOP_NUM 50 +#define IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM 128 +#define IPA_DMA_RUN_TEST_UNIT_IN_LOOP(test_unit, iters, rc, args...) \ + do { \ + int __i; \ + for (__i = 0; __i < iters; __i++) { \ + IPA_UT_LOG(#test_unit " START iter %d\n", __i); \ + rc = test_unit(args); \ + if (!rc) \ + continue; \ + IPA_UT_LOG(#test_unit " failed %d\n", rc); \ + break; \ + } \ + } while (0) + +/** + * struct ipa_test_dma_async_user_data - user_data structure for async memcpy + * @src_mem: source memory buffer + * @dest_mem: destination memory buffer + * @call_serial_number: Id of the caller + * @copy_done: Completion object + */ +struct ipa_test_dma_async_user_data { + struct ipa_mem_buffer src_mem; + struct ipa_mem_buffer dest_mem; + int call_serial_number; + struct completion copy_done; +}; + +/** + * ipa_test_dma_setup() - Suite setup function + */ +static int ipa_test_dma_setup(void **ppriv) +{ + int rc; + + IPA_UT_DBG("Start Setup\n"); + + if (!ipa3_ctx) { + IPA_UT_ERR("No IPA ctx\n"); + return -EINVAL; + } + + rc = ipa_dma_init(); + if (rc) + IPA_UT_ERR("Fail to init ipa_dma - return code %d\n", rc); + else + IPA_UT_DBG("ipa_dma_init() Completed successfully!\n"); + + *ppriv = NULL; + + return rc; +} + +/** + * ipa_test_dma_teardown() - Suite teardown function + */ +static int ipa_test_dma_teardown(void *priv) +{ + IPA_UT_DBG("Start Teardown\n"); + ipa_dma_destroy(); + return 0; +} + +static int ipa_test_dma_alloc_buffs(struct ipa_mem_buffer *src, + struct ipa_mem_buffer *dest, + int size) +{ + int i; + static int val = 1; + int rc; + + val++; + src->size = size; + src->base = dma_alloc_coherent(ipa3_ctx->pdev, src->size, + &src->phys_base, GFP_KERNEL); + if (!src->base) { + IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); + IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); + return -ENOMEM; + } + + dest->size = size; + dest->base = dma_alloc_coherent(ipa3_ctx->pdev, dest->size, + &dest->phys_base, GFP_KERNEL); + if (!dest->base) { + IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); + IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); + rc = -ENOMEM; + goto fail_alloc_dest; + } + + memset(dest->base, 0, dest->size); + for (i = 0; i < src->size; i++) + memset(src->base + i, (val + i) & 0xFF, 1); + rc = memcmp(dest->base, src->base, dest->size); + if (rc == 0) { + IPA_UT_LOG("dest & src buffers are equal\n"); + IPA_UT_TEST_FAIL_REPORT("dest & src buffers are equal"); + rc = -EFAULT; + goto fail_buf_cmp; + } + + return 0; + +fail_buf_cmp: + dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, + dest->phys_base); +fail_alloc_dest: + dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, + src->phys_base); + return rc; +} + +static void ipa_test_dma_destroy_buffs(struct ipa_mem_buffer *src, + struct ipa_mem_buffer *dest) +{ + dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, + src->phys_base); + dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, + dest->phys_base); +} + +/** + * ipa_test_dma_memcpy_sync() - memcpy in sync mode + * + * @size: buffer size + * @expect_fail: test expects the memcpy to fail + * + * To be run during tests + * 1. Alloc src and dst buffers + * 2. sync memcpy src to dst via dma + * 3. compare src and dts if memcpy succeeded as expected + */ +static int ipa_test_dma_memcpy_sync(int size, bool expect_fail) +{ + int rc = 0; + int i; + struct ipa_mem_buffer src_mem; + struct ipa_mem_buffer dest_mem; + u8 *src; + u8 *dest; + + rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); + if (rc) { + IPA_UT_LOG("fail to alloc buffers\n"); + IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); + return rc; + } + + rc = ipa_dma_sync_memcpy(dest_mem.phys_base, src_mem.phys_base, size); + if (!expect_fail && rc) { + IPA_UT_LOG("fail to sync memcpy - rc = %d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); + goto free_buffs; + } + if (expect_fail && !rc) { + IPA_UT_LOG("sync memcpy succeeded while expected to fail\n"); + IPA_UT_TEST_FAIL_REPORT( + "sync memcpy succeeded while expected to fail"); + rc = -EFAULT; + goto free_buffs; + } + + if (!rc) { + /* if memcpy succeeded, compare the buffers */ + rc = memcmp(dest_mem.base, src_mem.base, size); + if (rc) { + IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); + IPA_UT_TEST_FAIL_REPORT( + "BAD memcpy - buffs are not equals"); + src = src_mem.base; + dest = dest_mem.base; + for (i = 0; i < size; i++) { + if (*(src + i) != *(dest + i)) { + IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", + i, *(src + i), *(dest + i)); + } + } + } + } else { + /* if memcpy failed as expected, update the rc */ + rc = 0; + } + +free_buffs: + ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); + return rc; +} + +static void ipa_test_dma_async_memcpy_cb(void *comp_obj) +{ + struct completion *xfer_done; + + if (!comp_obj) { + IPA_UT_ERR("Invalid Input\n"); + return; + } + xfer_done = (struct completion *)comp_obj; + complete(xfer_done); +} + +static void ipa_test_dma_async_memcpy_cb_user_data(void *user_param) +{ + int rc; + int i; + u8 *src; + u8 *dest; + struct ipa_test_dma_async_user_data *udata = + (struct ipa_test_dma_async_user_data *)user_param; + + if (!udata) { + IPA_UT_ERR("Invalid user param\n"); + return; + } + + rc = memcmp(udata->dest_mem.base, udata->src_mem.base, + udata->src_mem.size); + if (rc) { + IPA_UT_LOG("BAD memcpy - buffs are not equal sn=%d\n", + udata->call_serial_number); + IPA_UT_TEST_FAIL_REPORT( + "BAD memcpy - buffs are not equal"); + src = udata->src_mem.base; + dest = udata->dest_mem.base; + for (i = 0; i < udata->src_mem.size; i++) { + if (*(src + i) != *(dest + i)) { + IPA_UT_ERR("byte: %d 0x%x != 0x%x\n", i, + *(src + i), *(dest + i)); + } + } + return; + } + + IPA_UT_LOG("Notify on async memcopy sn=%d\n", + udata->call_serial_number); + complete(&(udata->copy_done)); +} + +/** + * ipa_test_dma_memcpy_async() - memcpy in async mode + * + * @size: buffer size + * @expect_fail: test expected the memcpy to fail + * + * To be run during tests + * 1. Alloc src and dst buffers + * 2. async memcpy src to dst via dma and wait for completion + * 3. compare src and dts if memcpy succeeded as expected + */ +static int ipa_test_dma_memcpy_async(int size, bool expect_fail) +{ + int rc = 0; + int i; + struct ipa_mem_buffer src_mem; + struct ipa_mem_buffer dest_mem; + u8 *src; + u8 *dest; + struct completion xfer_done; + + rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); + if (rc) { + IPA_UT_LOG("fail to alloc buffers\n"); + IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); + return rc; + } + + init_completion(&xfer_done); + rc = ipa_dma_async_memcpy(dest_mem.phys_base, src_mem.phys_base, size, + ipa_test_dma_async_memcpy_cb, &xfer_done); + if (!expect_fail && rc) { + IPA_UT_LOG("fail to initiate async memcpy - rc=%d\n", + rc); + IPA_UT_TEST_FAIL_REPORT("async memcpy initiate failed"); + goto free_buffs; + } + if (expect_fail && !rc) { + IPA_UT_LOG("async memcpy succeeded while expected to fail\n"); + IPA_UT_TEST_FAIL_REPORT( + "async memcpy succeeded while expected to fail"); + rc = -EFAULT; + goto free_buffs; + } + + if (!rc) { + /* if memcpy succeeded, compare the buffers */ + wait_for_completion(&xfer_done); + rc = memcmp(dest_mem.base, src_mem.base, size); + if (rc) { + IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); + IPA_UT_TEST_FAIL_REPORT( + "BAD memcpy - buffs are not equals"); + src = src_mem.base; + dest = dest_mem.base; + for (i = 0; i < size; i++) { + if (*(src + i) != *(dest + i)) { + IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", + i, *(src + i), *(dest + i)); + } + } + } + } else { + /* if memcpy failed as expected, update the rc */ + rc = 0; + } + +free_buffs: + ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); + return rc; +} + +/** + * ipa_test_dma_sync_async_memcpy() - memcpy in sync and then async mode + * + * @size: buffer size + * + * To be run during tests + * 1. several sync memcopy in row + * 2. several async memcopy - + * back-to-back (next async try initiated after prev is completed) + */ +static int ipa_test_dma_sync_async_memcpy(int size) +{ + int rc; + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, + IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); + if (rc) { + IPA_UT_LOG("sync memcopy fail rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcopy fail"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, + IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); + if (rc) { + IPA_UT_LOG("async memcopy fail rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("async memcopy fail"); + return rc; + } + + return 0; +} + +/** + * TEST: test control API - enable/disable dma + * 1. enable dma + * 2. disable dma + */ +static int ipa_test_dma_control_api(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: memcpy before dma enable + * + * 1. sync memcpy - should fail + * 2. async memcpy - should fail + */ +static int ipa_test_dma_memcpy_before_enable(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); + if (rc) { + IPA_UT_LOG("sync memcpy succeeded unexpectedly rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); + return rc; + } + + rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); + if (rc) { + IPA_UT_LOG("async memcpy succeeded unexpectedly rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); + return rc; + } + + return 0; +} + +/** + * TEST: Sync memory copy + * + * 1. dma enable + * 2. sync memcpy + * 3. dma disable + */ +static int ipa_test_dma_sync_memcpy(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Async memory copy + * + * 1. dma enable + * 2. async memcpy + * 3. dma disable + */ +static int ipa_test_dma_async_memcpy(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("async memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("async memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Iteration of sync memory copy + * + * 1. dma enable + * 2. sync memcpy in loop - in row + * 3. dma disable + */ +static int ipa_test_dma_sync_memcpy_in_loop(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, + IPA_DMA_TEST_LOOP_NUM, rc, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("Iterations of sync memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("Iterations of sync memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Iteration of async memory copy + * + * 1. dma enable + * 2. async memcpy in loop - back-to-back + * next async copy is initiated once previous one completed + * 3. dma disable + */ +static int ipa_test_dma_async_memcpy_in_loop(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, + IPA_DMA_TEST_LOOP_NUM, rc, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("Iterations of async memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("Iterations of async memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/** + * TEST: Iteration of interleaved sync and async memory copy + * + * 1. dma enable + * 2. sync and async memcpy in loop - interleaved + * 3. dma disable + */ +static int ipa_test_dma_interleaved_sync_async_memcpy_in_loop(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_sync_async_memcpy, + IPA_DMA_TEST_INT_LOOP_NUM, rc, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE); + if (rc) { + IPA_UT_LOG( + "Iterations of interleaved sync async memcpy failed rc=%d\n" + , rc); + IPA_UT_TEST_FAIL_REPORT( + "Iterations of interleaved sync async memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +static atomic_t ipa_test_dma_mt_test_pass; + +static void ipa_test_dma_wrapper_test_one_sync(struct work_struct *work) +{ + int rc; + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("fail sync memcpy from thread rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail sync memcpy from thread"); + return; + } + atomic_inc(&ipa_test_dma_mt_test_pass); +} + +static void ipa_test_dma_wrapper_test_one_async(struct work_struct *work) +{ + int rc; + + rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); + if (rc) { + IPA_UT_LOG("fail async memcpy from thread rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail async memcpy from thread"); + return; + } + atomic_inc(&ipa_test_dma_mt_test_pass); +} + +/** + * TEST: Multiple threads running sync and sync mem copy + * + * 1. dma enable + * 2. In-loop + * 2.1 create wq for sync memcpy + * 2.2 create wq for async memcpy + * 2.3 queue sync memcpy work + * 2.4 queue async memcoy work + * 3. In-loop + * 3.1 flush and destroy wq sync + * 3.2 flush and destroy wq async + * 3. dma disable + */ +static int ipa_test_dma_mt_sync_async(void *priv) +{ + int rc; + int i; + static struct workqueue_struct *wq_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + static struct workqueue_struct *wq_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + static struct work_struct work_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + static struct work_struct work_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; + char buff[IPA_TEST_DMA_WQ_NAME_BUFF_SZ]; + + memset(wq_sync, 0, sizeof(wq_sync)); + memset(wq_sync, 0, sizeof(wq_async)); + memset(work_async, 0, sizeof(work_async)); + memset(work_sync, 0, sizeof(work_sync)); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + atomic_set(&ipa_test_dma_mt_test_pass, 0); + for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { + snprintf(buff, sizeof(buff), "ipa_test_dmaSwq%d", i); + wq_sync[i] = create_singlethread_workqueue(buff); + if (!wq_sync[i]) { + IPA_UT_ERR("failed to create sync wq#%d\n", i); + rc = -EFAULT; + goto fail_create_wq; + } + snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipa_test_dmaAwq%d", i); + wq_async[i] = create_singlethread_workqueue(buff); + if (!wq_async[i]) { + IPA_UT_ERR("failed to create async wq#%d\n", i); + rc = -EFAULT; + goto fail_create_wq; + } + + INIT_WORK(&work_sync[i], ipa_test_dma_wrapper_test_one_sync); + queue_work(wq_sync[i], &work_sync[i]); + INIT_WORK(&work_async[i], ipa_test_dma_wrapper_test_one_async); + queue_work(wq_async[i], &work_async[i]); + } + + for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { + flush_workqueue(wq_sync[i]); + destroy_workqueue(wq_sync[i]); + flush_workqueue(wq_async[i]); + destroy_workqueue(wq_async[i]); + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + if ((2 * IPA_TEST_DMA_MT_TEST_NUM_WQ) != + atomic_read(&ipa_test_dma_mt_test_pass)) { + IPA_UT_LOG( + "Multi-threaded sync/async memcopy failed passed=%d\n" + , atomic_read(&ipa_test_dma_mt_test_pass)); + IPA_UT_TEST_FAIL_REPORT( + "Multi-threaded sync/async memcopy failed"); + return -EFAULT; + } + + return 0; + +fail_create_wq: + (void)ipa_dma_disable(); + for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { + if (wq_sync[i]) + destroy_workqueue(wq_sync[i]); + if (wq_async[i]) + destroy_workqueue(wq_async[i]); + } + + return rc; +} + +/** + * TEST: Several parallel async memory copy iterations + * + * 1. create several user_data structures - one per iteration + * 2. allocate buffs. Give slice for each iteration + * 3. iterations of async mem copy + * 4. wait for all to complete + * 5. dma disable + */ +static int ipa_test_dma_parallel_async_memcpy_in_loop(void *priv) +{ + int rc; + struct ipa_test_dma_async_user_data *udata; + struct ipa_mem_buffer all_src_mem; + struct ipa_mem_buffer all_dest_mem; + int i; + bool is_fail = false; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + udata = kzalloc(IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM * + sizeof(struct ipa_test_dma_async_user_data), GFP_KERNEL); + if (!udata) { + IPA_UT_ERR("fail allocate user_data array\n"); + (void)ipa_dma_disable(); + return -ENOMEM; + } + + rc = ipa_test_dma_alloc_buffs(&all_src_mem, &all_dest_mem, + IPA_TEST_DMA_MEMCPY_BUFF_SIZE); + if (rc) { + IPA_UT_LOG("fail to alloc buffers\n"); + IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); + kfree(udata); + (void)ipa_dma_disable(); + return rc; + } + + for (i = 0 ; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) { + udata[i].src_mem.size = + IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM; + udata[i].src_mem.base = all_src_mem.base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + udata[i].src_mem.phys_base = all_src_mem.phys_base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + + udata[i].dest_mem.size = + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + udata[i].dest_mem.base = all_dest_mem.base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + udata[i].dest_mem.phys_base = all_dest_mem.phys_base + i * + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); + + udata[i].call_serial_number = i + 1; + init_completion(&(udata[i].copy_done)); + rc = ipa_dma_async_memcpy(udata[i].dest_mem.phys_base, + udata[i].src_mem.phys_base, + (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / + IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM), + ipa_test_dma_async_memcpy_cb_user_data, &udata[i]); + if (rc) { + IPA_UT_LOG("async memcpy initiation fail i=%d rc=%d\n", + i, rc); + is_fail = true; + } + } + + for (i = 0; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) + wait_for_completion(&udata[i].copy_done); + + ipa_test_dma_destroy_buffs(&all_src_mem, &all_dest_mem); + kfree(udata); + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + if (is_fail) { + IPA_UT_LOG("async memcopy failed\n"); + IPA_UT_TEST_FAIL_REPORT("async memcopy failed"); + return -EFAULT; + } + + return 0; +} + +/** + * TEST: Sync memory copy + * + * 1. dma enable + * 2. sync memcpy with max packet size + * 3. dma disable + */ +static int ipa_test_dma_sync_memcpy_max_pkt_size(void *priv) +{ + int rc; + + IPA_UT_LOG("Test Start\n"); + + rc = ipa_dma_enable(); + if (rc) { + IPA_UT_LOG("DMA enable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail enable dma"); + return rc; + } + + rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MAX_PKT_SIZE, false); + if (rc) { + IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); + (void)ipa_dma_disable(); + return rc; + } + + rc = ipa_dma_disable(); + if (rc) { + IPA_UT_LOG("DMA disable failed rc=%d\n", rc); + IPA_UT_TEST_FAIL_REPORT("fail disable dma"); + return rc; + } + + return 0; +} + +/* Suite definition block */ +IPA_UT_DEFINE_SUITE_START(dma, "DMA for GSI", + ipa_test_dma_setup, ipa_test_dma_teardown) +{ + IPA_UT_ADD_TEST(control_api, + "Control API", + ipa_test_dma_control_api, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(memcpy_before_enable, + "Call memcpy before dma enable and expect it to fail", + ipa_test_dma_memcpy_before_enable, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(sync_memcpy, + "Sync memory copy", + ipa_test_dma_sync_memcpy, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(async_memcpy, + "Async memory copy", + ipa_test_dma_async_memcpy, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(sync_memcpy_in_loop, + "Several sync memory copy iterations", + ipa_test_dma_sync_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(async_memcpy_in_loop, + "Several async memory copy iterations", + ipa_test_dma_async_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(interleaved_sync_async_memcpy_in_loop, + "Several interleaved sync and async memory copy iterations", + ipa_test_dma_interleaved_sync_async_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(multi_threaded_multiple_sync_async_memcpy, + "Several multi-threaded sync and async memory copy iterations", + ipa_test_dma_mt_sync_async, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(parallel_async_memcpy_in_loop, + "Several parallel async memory copy iterations", + ipa_test_dma_parallel_async_memcpy_in_loop, + true, IPA_HW_v3_0, IPA_HW_MAX), + IPA_UT_ADD_TEST(sync_memcpy_max_pkt_size, + "Sync memory copy with max packet size", + ipa_test_dma_sync_memcpy_max_pkt_size, + true, IPA_HW_v3_0, IPA_HW_MAX), +} IPA_UT_DEFINE_SUITE_END(dma); diff --git a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h index 944800f8e4be..bbb8b771ba0b 100644 --- a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h +++ b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h @@ -21,6 +21,7 @@ * No importance for order. */ IPA_UT_DECLARE_SUITE(mhi); +IPA_UT_DECLARE_SUITE(dma); IPA_UT_DECLARE_SUITE(example); @@ -31,6 +32,7 @@ IPA_UT_DECLARE_SUITE(example); IPA_UT_DEFINE_ALL_SUITES_START { IPA_UT_REGISTER_SUITE(mhi), + IPA_UT_REGISTER_SUITE(dma), IPA_UT_REGISTER_SUITE(example), } IPA_UT_DEFINE_ALL_SUITES_END; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index f774cb576ffa..b0f62141ea4d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -131,7 +131,7 @@ MODULE_LICENSE("GPL"); /* Field definitions */ #define HCI_ACCEL_MASK 0x7fff #define HCI_HOTKEY_DISABLE 0x0b -#define HCI_HOTKEY_ENABLE 0x09 +#define HCI_HOTKEY_ENABLE 0x01 #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 #define HCI_LCD_BRIGHTNESS_BITS 3 #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index b1c3441b285a..545a1e684b25 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -227,6 +227,8 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(usb_otg), POWER_SUPPLY_ATTR(battery_charging_enabled), POWER_SUPPLY_ATTR(charging_enabled), + POWER_SUPPLY_ATTR(step_charging_enabled), + POWER_SUPPLY_ATTR(step_charging_step), POWER_SUPPLY_ATTR(pin_enabled), POWER_SUPPLY_ATTR(input_suspend), POWER_SUPPLY_ATTR(input_voltage_regulation), diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 90a93064ca84..0be535194b49 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -38,15 +38,15 @@ static struct smb_params v1_params = { .fv = { .name = "float voltage", .reg = FLOAT_VOLTAGE_CFG_REG, - .min_u = 2500000, - .max_u = 5000000, - .step_u = 10000, + .min_u = 3487500, + .max_u = 4920000, + .step_u = 7500, }, .usb_icl = { .name = "usb input current limit", .reg = USBIN_CURRENT_LIMIT_CFG_REG, .min_u = 0, - .max_u = 6000000, + .max_u = 4800000, .step_u = 25000, }, .icl_stat = { @@ -112,8 +112,90 @@ static struct smb_params v1_params = { .max_u = 1575000, .step_u = 25000, }, + .step_soc_threshold[0] = { + .name = "step charge soc threshold 1", + .reg = STEP_CHG_SOC_OR_BATT_V_TH1_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc_threshold[1] = { + .name = "step charge soc threshold 2", + .reg = STEP_CHG_SOC_OR_BATT_V_TH2_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc_threshold[2] = { + .name = "step charge soc threshold 3", + .reg = STEP_CHG_SOC_OR_BATT_V_TH3_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc_threshold[3] = { + .name = "step charge soc threshold 4", + .reg = STEP_CHG_SOC_OR_BATT_V_TH4_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc = { + .name = "step charge soc", + .reg = STEP_CHG_SOC_VBATT_V_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + .set_proc = smblib_mapping_soc_from_field_value, + }, + .step_cc_delta[0] = { + .name = "step charge current delta 1", + .reg = STEP_CHG_CURRENT_DELTA1_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[1] = { + .name = "step charge current delta 2", + .reg = STEP_CHG_CURRENT_DELTA2_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[2] = { + .name = "step charge current delta 3", + .reg = STEP_CHG_CURRENT_DELTA3_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[3] = { + .name = "step charge current delta 4", + .reg = STEP_CHG_CURRENT_DELTA4_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[4] = { + .name = "step charge current delta 5", + .reg = STEP_CHG_CURRENT_DELTA5_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, }; +#define STEP_CHARGING_MAX_STEPS 5 struct smb_dt_props { bool suspend_input; int fcc_ua; @@ -121,6 +203,8 @@ struct smb_dt_props { int dc_icl_ua; int fv_uv; int wipower_max_uw; + u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1]; + s32 step_cc_delta[STEP_CHARGING_MAX_STEPS]; }; struct smb2 { @@ -150,6 +234,28 @@ static int smb2_parse_dt(struct smb2 *chip) return -EINVAL; } + chg->step_chg_enabled = true; + + if (of_property_count_u32_elems(node, "qcom,step-soc-thresholds") + != STEP_CHARGING_MAX_STEPS - 1) + chg->step_chg_enabled = false; + + rc = of_property_read_u32_array(node, "qcom,step-soc-thresholds", + chip->dt.step_soc_threshold, + STEP_CHARGING_MAX_STEPS - 1); + if (rc < 0) + chg->step_chg_enabled = false; + + if (of_property_count_u32_elems(node, "qcom,step-current-deltas") + != STEP_CHARGING_MAX_STEPS) + chg->step_chg_enabled = false; + + rc = of_property_read_u32_array(node, "qcom,step-current-deltas", + chip->dt.step_cc_delta, + STEP_CHARGING_MAX_STEPS); + if (rc < 0) + chg->step_chg_enabled = false; + chip->dt.suspend_input = of_property_read_bool(node, "qcom,suspend-input"); @@ -218,6 +324,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, + POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -277,6 +384,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED: rc = smblib_get_prop_input_current_settled(chg, val); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW: + rc = smblib_get_prop_usb_current_now(chg, val); + break; default: pr_err("get prop %d is not supported\n", psp); rc = -EINVAL; @@ -476,42 +586,51 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, + POWER_SUPPLY_PROP_CHARGER_TEMP, + POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, }; static int smb2_batt_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { + int rc; struct smb_charger *chg = power_supply_get_drvdata(psy); switch (psp) { case POWER_SUPPLY_PROP_STATUS: - smblib_get_prop_batt_status(chg, val); + rc = smblib_get_prop_batt_status(chg, val); break; case POWER_SUPPLY_PROP_HEALTH: - smblib_get_prop_batt_health(chg, val); + rc = smblib_get_prop_batt_health(chg, val); break; case POWER_SUPPLY_PROP_PRESENT: - smblib_get_prop_batt_present(chg, val); + rc = smblib_get_prop_batt_present(chg, val); break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: - smblib_get_prop_input_suspend(chg, val); + rc = smblib_get_prop_input_suspend(chg, val); break; case POWER_SUPPLY_PROP_CHARGE_TYPE: - smblib_get_prop_batt_charge_type(chg, val); + rc = smblib_get_prop_batt_charge_type(chg, val); break; case POWER_SUPPLY_PROP_CAPACITY: - smblib_get_prop_batt_capacity(chg, val); + rc = smblib_get_prop_batt_capacity(chg, val); break; case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: - smblib_get_prop_system_temp_level(chg, val); + rc = smblib_get_prop_system_temp_level(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + rc = smblib_get_prop_charger_temp(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: + rc = smblib_get_prop_charger_temp_max(chg, val); break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; } - return 0; + return rc; } static int smb2_batt_set_prop(struct power_supply *psy, @@ -669,6 +788,73 @@ static int smb2_init_vconn_regulator(struct smb2 *chip) /*************************** * HARDWARE INITIALIZATION * ***************************/ +static int smb2_config_step_charging(struct smb2 *chip) +{ + struct smb_charger *chg = &chip->chg; + int rc = 0; + int i; + + if (!chg->step_chg_enabled) + return rc; + + for (i = 0; i < STEP_CHARGING_MAX_STEPS - 1; i++) { + rc = smblib_set_charge_param(chg, + &chg->param.step_soc_threshold[i], + chip->dt.step_soc_threshold[i]); + if (rc < 0) { + pr_err("Couldn't configure soc thresholds rc = %d\n", + rc); + goto err_out; + } + } + + for (i = 0; i < STEP_CHARGING_MAX_STEPS; i++) { + rc = smblib_set_charge_param(chg, &chg->param.step_cc_delta[i], + chip->dt.step_cc_delta[i]); + if (rc < 0) { + pr_err("Couldn't configure cc delta rc = %d\n", + rc); + goto err_out; + } + } + + rc = smblib_write(chg, STEP_CHG_UPDATE_REQUEST_TIMEOUT_CFG_REG, + STEP_CHG_UPDATE_REQUEST_TIMEOUT_40S); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure soc request timeout reg rc=%d\n", + rc); + goto err_out; + } + + rc = smblib_write(chg, STEP_CHG_UPDATE_FAIL_TIMEOUT_CFG_REG, + STEP_CHG_UPDATE_FAIL_TIMEOUT_120S); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure soc fail timeout reg rc=%d\n", + rc); + goto err_out; + } + + /* + * enable step charging, source soc, standard mode, go to final + * state in case of failure. + */ + rc = smblib_write(chg, CHGR_STEP_CHG_MODE_CFG_REG, + STEP_CHARGING_ENABLE_BIT | + STEP_CHARGING_SOURCE_SELECT_BIT | + STEP_CHARGING_SOC_FAIL_OPTION_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure charger rc=%d\n", rc); + goto err_out; + } + + return 0; +err_out: + chg->step_chg_enabled = false; + return rc; +} + static int smb2_config_wipower_input_power(struct smb2 *chip, int uw) { int rc; @@ -833,6 +1019,14 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + /* configure step charging */ + rc = smb2_config_step_charging(chip); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure step charging rc=%d\n", + rc); + return rc; + } + /* configure wipower watts */ rc = smb2_config_wipower_input_power(chip, chip->dt.wipower_max_uw); if (rc < 0) { @@ -840,6 +1034,16 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + /* configure PMI stat output to enable and disable parallel charging */ + rc = smblib_masked_write(chg, STAT_CFG_REG, + STAT_PARALLEL_CFG_BIT | STAT_SW_OVERRIDE_CFG_BIT, + STAT_PARALLEL_CFG_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure signal for parallel rc=%d\n", rc); + return rc; + } + return rc; } @@ -856,6 +1060,8 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_usb_source_change(0, &irq_data); smblib_handle_chg_state_change(0, &irq_data); smblib_handle_icl_change(0, &irq_data); + smblib_handle_step_chg_state_change(0, &irq_data); + smblib_handle_step_chg_soc_update_request(0, &irq_data); return 0; } @@ -875,9 +1081,12 @@ static struct smb2_irq_info smb2_irqs[] = { /* CHARGER IRQs */ { "chg-error", smblib_handle_debug }, { "chg-state-change", smblib_handle_chg_state_change, true }, - { "step-chg-state-change", smblib_handle_debug }, - { "step-chg-soc-update-fail", smblib_handle_debug }, - { "step-chg-soc-update-request", smblib_handle_debug }, + { "step-chg-state-change", smblib_handle_step_chg_state_change, + true }, + { "step-chg-soc-update-fail", smblib_handle_step_chg_soc_update_fail, + true }, + { "step-chg-soc-update-request", + smblib_handle_step_chg_soc_update_request, true }, /* OTG IRQs */ { "otg-fail", smblib_handle_debug }, { "otg-overcurrent", smblib_handle_debug }, @@ -1023,7 +1232,11 @@ static int smb2_probe(struct platform_device *pdev) return -EINVAL; } - smblib_init(chg); + rc = smblib_init(chg); + if (rc < 0) { + pr_err("Smblib_init failed rc=%d\n", rc); + goto cleanup; + } rc = smb2_parse_dt(chip); if (rc < 0) { diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 60534bdddd26..ee4f65430d8b 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -12,6 +12,7 @@ #include <linux/device.h> #include <linux/regmap.h> +#include <linux/iio/consumer.h> #include <linux/power_supply.h> #include <linux/regulator/driver.h> #include <linux/irq.h> @@ -82,12 +83,40 @@ unlock: return rc; } +static int smblib_get_step_charging_adjustment(struct smb_charger *chg, + int *cc_offset) +{ + int step_state; + int rc; + u8 stat; + + if (!chg->step_chg_enabled) { + *cc_offset = 0; + return 0; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + + step_state = (stat & STEP_CHARGING_STATUS_MASK) >> 3; + rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state], + cc_offset); + + return rc; +} + static void smblib_fcc_split_ua(struct smb_charger *chg, int total_fcc, int *master_ua, int *slave_ua) { int rc, cc_reduction_ua = 0; + int step_cc_delta; int master_percent = min(max(*chg->pl.master_percent, 0), 100); union power_supply_propval pval = {0, }; + int effective_fcc; /* * if master_percent is 0, s/w will configure master's fcc to zero and @@ -111,10 +140,21 @@ static void smblib_fcc_split_ua(struct smb_charger *chg, int total_fcc, } } - total_fcc = max(0, total_fcc - cc_reduction_ua); - *master_ua = (total_fcc * master_percent) / 100; - *slave_ua = (total_fcc - *master_ua) * chg->pl.taper_percent / 100; - *master_ua += cc_reduction_ua; + rc = smblib_get_step_charging_adjustment(chg, &step_cc_delta); + if (rc < 0) + step_cc_delta = 0; + + /* + * During JEITA condition and with step_charging enabled, PMI will + * pick the lower of the two value: (FCC - JEITA current compensation) + * or (FCC + step_charging current delta) + */ + + effective_fcc = min(max(0, total_fcc - cc_reduction_ua), + max(0, total_fcc + step_cc_delta)); + *master_ua = (effective_fcc * master_percent) / 100; + *slave_ua = (effective_fcc - *master_ua) * chg->pl.taper_percent / 100; + *master_ua = max(0, *master_ua + total_fcc - effective_fcc); } /******************** @@ -246,6 +286,28 @@ int smblib_set_charge_param(struct smb_charger *chg, return rc; } +static int step_charge_soc_update(struct smb_charger *chg, int capacity) +{ + int rc = 0; + + rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity); + if (rc < 0) { + dev_err(chg->dev, "Error in updating soc, rc=%d\n", rc); + return rc; + } + + rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG, + STEP_CHG_SOC_VBATT_V_UPDATE_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n", + rc); + return rc; + } + + return rc; +} + int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; @@ -394,6 +456,41 @@ static int smblib_register_notifier(struct smb_charger *chg) return 0; } +int smblib_mapping_soc_from_field_value(struct smb_chg_param *param, + int val_u, u8 *val_raw) +{ + if (val_u > param->max_u || val_u < param->min_u) + return -EINVAL; + + *val_raw = val_u << 1; + + return 0; +} + +int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param, + u8 val_raw) +{ + int val_u = val_raw * param->step_u + param->min_u; + + if (val_u > param->max_u) + val_u -= param->max_u * 2; + + return val_u; +} + +int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param, + int val_u, u8 *val_raw) +{ + if (val_u > param->max_u || val_u < param->min_u - param->max_u) + return -EINVAL; + + val_u += param->max_u * 2 - param->min_u; + val_u %= param->max_u * 2; + *val_raw = val_u / param->step_u; + + return 0; +} + /********************* * VOTABLE CALLBACKS * *********************/ @@ -1076,12 +1173,20 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val) { - if (chg->vbus_present) - val->intval = MICRO_5V; - else - val->intval = 0; + int rc = 0; - return 0; + rc = smblib_get_prop_usb_present(chg, val); + if (rc < 0 || !val->intval) + return rc; + + if (!chg->iio.usbin_v_chan || + PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER) + chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v"); + + if (IS_ERR(chg->iio.usbin_v_chan)) + return PTR_ERR(chg->iio.usbin_v_chan); + + return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval); } int smblib_get_prop_usb_current_max(struct smb_charger *chg, @@ -1091,6 +1196,59 @@ int smblib_get_prop_usb_current_max(struct smb_charger *chg, return 0; } +int smblib_get_prop_usb_current_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc = 0; + + rc = smblib_get_prop_usb_present(chg, val); + if (rc < 0 || !val->intval) + return rc; + + if (!chg->iio.usbin_i_chan || + PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER) + chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i"); + + if (IS_ERR(chg->iio.usbin_i_chan)) + return PTR_ERR(chg->iio.usbin_i_chan); + + return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval); +} + +int smblib_get_prop_charger_temp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->iio.temp_chan || + PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER) + chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp"); + + if (IS_ERR(chg->iio.temp_chan)) + return PTR_ERR(chg->iio.temp_chan); + + rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval); + val->intval /= 100; + return rc; +} + +int smblib_get_prop_charger_temp_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->iio.temp_max_chan || + PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER) + chg->iio.temp_max_chan = iio_channel_get(chg->dev, + "charger_temp_max"); + if (IS_ERR(chg->iio.temp_max_chan)) + return PTR_ERR(chg->iio.temp_max_chan); + + rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval); + val->intval /= 100; + return rc; +} + int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val) { @@ -1427,6 +1585,57 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) return IRQ_HANDLED; } +irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (chg->step_chg_enabled) + rerun_election(chg->fcc_votable); + + return IRQ_HANDLED; +} + +irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (chg->step_chg_enabled) + rerun_election(chg->fcc_votable); + + return IRQ_HANDLED; +} + +#define STEP_SOC_REQ_MS 3000 +irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + int rc; + union power_supply_propval pval = {0, }; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (!chg->bms_psy) { + schedule_delayed_work(&chg->step_soc_req_work, + msecs_to_jiffies(STEP_SOC_REQ_MS)); + return IRQ_HANDLED; + } + + rc = smblib_get_prop_batt_capacity(chg, &pval); + if (rc < 0) + dev_err(chg->dev, "Couldn't get batt capacity rc=%d\n", rc); + else + step_charge_soc_update(chg, pval.intval); + + return IRQ_HANDLED; +} + irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) { struct smb_irq_data *irq_data = data; @@ -1774,13 +1983,29 @@ static void smblib_hvdcp_detect_work(struct work_struct *work) } } -static void smblib_bms_update_work(struct work_struct *work) +static void bms_update_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, bms_update_work); power_supply_changed(chg->batt_psy); } +static void step_soc_req_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + step_soc_req_work.work); + union power_supply_propval pval = {0, }; + int rc; + + rc = smblib_get_prop_batt_capacity(chg, &pval); + if (rc < 0) { + dev_err(chg->dev, "Couldn't get batt capacity rc=%d\n", rc); + return; + } + + step_charge_soc_update(chg, pval.intval); +} + static void smblib_pl_detect_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, @@ -1829,7 +2054,7 @@ done: vote(chg->awake_votable, PL_VOTER, false, 0); } -int smblib_create_votables(struct smb_charger *chg) +static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; @@ -1923,15 +2148,52 @@ int smblib_create_votables(struct smb_charger *chg) return rc; } +static void smblib_destroy_votables(struct smb_charger *chg) +{ + if (chg->usb_suspend_votable) + destroy_votable(chg->usb_suspend_votable); + if (chg->dc_suspend_votable) + destroy_votable(chg->dc_suspend_votable); + if (chg->fcc_max_votable) + destroy_votable(chg->fcc_max_votable); + if (chg->fcc_votable) + destroy_votable(chg->fcc_votable); + if (chg->fv_votable) + destroy_votable(chg->fv_votable); + if (chg->usb_icl_votable) + destroy_votable(chg->usb_icl_votable); + if (chg->dc_icl_votable) + destroy_votable(chg->dc_icl_votable); + if (chg->pd_allowed_votable) + destroy_votable(chg->pd_allowed_votable); + if (chg->awake_votable) + destroy_votable(chg->awake_votable); + if (chg->pl_disable_votable) + destroy_votable(chg->pl_disable_votable); +} + +static void smblib_iio_deinit(struct smb_charger *chg) +{ + if (!IS_ERR_OR_NULL(chg->iio.temp_chan)) + iio_channel_release(chg->iio.temp_chan); + if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan)) + iio_channel_release(chg->iio.temp_max_chan); + if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan)) + iio_channel_release(chg->iio.usbin_i_chan); + if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan)) + iio_channel_release(chg->iio.usbin_v_chan); +} + int smblib_init(struct smb_charger *chg) { int rc = 0; mutex_init(&chg->write_lock); - INIT_WORK(&chg->bms_update_work, smblib_bms_update_work); + INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work); + INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work); chg->fake_capacity = -EINVAL; switch (chg->mode) { @@ -1943,6 +2205,7 @@ int smblib_init(struct smb_charger *chg) return rc; } + chg->bms_psy = power_supply_get_by_name("bms"); chg->pl.psy = power_supply_get_by_name("parallel"); rc = smblib_register_notifier(chg); @@ -1965,18 +2228,19 @@ int smblib_init(struct smb_charger *chg) int smblib_deinit(struct smb_charger *chg) { - destroy_votable(chg->usb_suspend_votable); - destroy_votable(chg->dc_suspend_votable); - destroy_votable(chg->fcc_max_votable); - destroy_votable(chg->fcc_votable); - destroy_votable(chg->fv_votable); - destroy_votable(chg->usb_icl_votable); - destroy_votable(chg->dc_icl_votable); - destroy_votable(chg->pd_allowed_votable); - destroy_votable(chg->awake_votable); - destroy_votable(chg->pl_disable_votable); - - power_supply_unreg_notifier(&chg->nb); + switch (chg->mode) { + case PARALLEL_MASTER: + power_supply_unreg_notifier(&chg->nb); + smblib_destroy_votables(chg); + break; + case PARALLEL_SLAVE: + break; + default: + dev_err(chg->dev, "Unsupported mode %d\n", chg->mode); + return -EINVAL; + } + + smblib_iio_deinit(chg); return 0; } diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index b56cd24adde1..1b0c221b4764 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -76,6 +76,9 @@ struct smb_params { struct smb_chg_param dc_icl_div2_mid_hv; struct smb_chg_param dc_icl_div2_hv; struct smb_chg_param jeita_cc_comp; + struct smb_chg_param step_soc_threshold[4]; + struct smb_chg_param step_soc; + struct smb_chg_param step_cc_delta[5]; }; struct parallel_params { @@ -85,10 +88,18 @@ struct parallel_params { int slave_fcc; }; +struct smb_iio { + struct iio_channel *temp_chan; + struct iio_channel *temp_max_chan; + struct iio_channel *usbin_i_chan; + struct iio_channel *usbin_v_chan; +}; + struct smb_charger { struct device *dev; struct regmap *regmap; struct smb_params param; + struct smb_iio iio; int *debug_mask; enum smb_mode mode; @@ -133,6 +144,7 @@ struct smb_charger { struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; struct delayed_work pl_taper_work; + struct delayed_work step_soc_req_work; /* cached status */ int voltage_min_uv; @@ -145,6 +157,8 @@ struct smb_charger { int *thermal_mitigation; int fake_capacity; + + bool step_chg_enabled; }; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); @@ -161,6 +175,13 @@ int smblib_set_charge_param(struct smb_charger *chg, int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend); int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend); +int smblib_mapping_soc_from_field_value(struct smb_chg_param *param, + int val_u, u8 *val_raw); +int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param, + u8 val_raw); +int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param, + int val_u, u8 *val_raw); + int smblib_vbus_regulator_enable(struct regulator_dev *rdev); int smblib_vbus_regulator_disable(struct regulator_dev *rdev); int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev); @@ -171,6 +192,9 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev); irqreturn_t smblib_handle_debug(int irq, void *data); irqreturn_t smblib_handle_chg_state_change(int irq, void *data); +irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data); +irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data); +irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data); irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data); irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data); irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data); @@ -220,6 +244,8 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_usb_current_max(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_usb_current_now(struct smb_charger *chg, + union power_supply_propval *val); int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_typec_mode(struct smb_charger *chg, @@ -230,6 +256,10 @@ int smblib_get_prop_pd_allowed(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_charger_temp(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_charger_temp_max(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_usb_current_max(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h index b03e8a7e0403..0d5222ec08f8 100644 --- a/drivers/power/qcom-charger/smb-reg.h +++ b/drivers/power/qcom-charger/smb-reg.h @@ -283,6 +283,36 @@ enum { #define IADC_SYNC_CNV_SEL_BIT BIT(1) #define VADC_SYNC_CNV_SEL_BIT BIT(0) +#define CHGR_STEP_CHG_MODE_CFG_REG (CHGR_BASE + 0xB0) +#define STEP_CHARGING_SOC_FAIL_OPTION_BIT BIT(3) +#define STEP_CHARGING_MODE_SELECT_BIT BIT(2) +#define STEP_CHARGING_SOURCE_SELECT_BIT BIT(1) +#define STEP_CHARGING_ENABLE_BIT BIT(0) + +#define STEP_CHG_UPDATE_REQUEST_TIMEOUT_CFG_REG (CHGR_BASE + 0xB1) +#define STEP_CHG_UPDATE_REQUEST_TIMEOUT_CFG_MASK GENMASK(0, 1) +#define STEP_CHG_UPDATE_REQUEST_TIMEOUT_5S 0 +#define STEP_CHG_UPDATE_REQUEST_TIMEOUT_10S 1 +#define STEP_CHG_UPDATE_REQUEST_TIMEOUT_20S 2 +#define STEP_CHG_UPDATE_REQUEST_TIMEOUT_40S 3 + +#define STEP_CHG_UPDATE_FAIL_TIMEOUT_CFG_REG (CHGR_BASE + 0xB2) +#define STEP_CHG_UPDATE_FAIL_TIMEOUT_CFG_MASK GENMASK(0, 1) +#define STEP_CHG_UPDATE_FAIL_TIMEOUT_10S 0 +#define STEP_CHG_UPDATE_FAIL_TIMEOUT_30S 1 +#define STEP_CHG_UPDATE_FAIL_TIMEOUT_60S 2 +#define STEP_CHG_UPDATE_FAIL_TIMEOUT_120S 3 + +#define STEP_CHG_SOC_OR_BATT_V_TH1_REG (CHGR_BASE + 0xB3) +#define STEP_CHG_SOC_OR_BATT_V_TH2_REG (CHGR_BASE + 0xB4) +#define STEP_CHG_SOC_OR_BATT_V_TH3_REG (CHGR_BASE + 0xB5) +#define STEP_CHG_SOC_OR_BATT_V_TH4_REG (CHGR_BASE + 0xB6) +#define STEP_CHG_CURRENT_DELTA1_REG (CHGR_BASE + 0xB7) +#define STEP_CHG_CURRENT_DELTA2_REG (CHGR_BASE + 0xB8) +#define STEP_CHG_CURRENT_DELTA3_REG (CHGR_BASE + 0xB9) +#define STEP_CHG_CURRENT_DELTA4_REG (CHGR_BASE + 0xBA) +#define STEP_CHG_CURRENT_DELTA5_REG (CHGR_BASE + 0xBB) + /* OTG Peripheral Registers */ #define RID_CC_CONTROL_23_16_REG (OTG_BASE + 0x06) #define RID_CC_CONTROL_23_BIT BIT(7) diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index 259e9f31e243..cc72772dba88 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -47,8 +47,8 @@ static struct smb_params v1_params = { .name = "fast charge current", .reg = FAST_CHARGE_CURRENT_CFG_REG, .min_u = 0, - .max_u = 4500000, - .step_u = 25000, + .max_u = 5000000, + .step_u = 50000, }, .fv = { .name = "float voltage", diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index 5d5adee16886..423ce087cd9c 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -274,8 +274,8 @@ static int brcmstb_pwm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); p->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(p->base)) { - ret = PTR_ERR(p->base); + if (!p->base) { + ret = -ENOMEM; goto out_clk; } diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 5cf4a97e0304..f2e1a39ce0f3 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -221,10 +221,10 @@ static const struct regulator_desc axp22x_regulators[] = { AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), AXP_DESC(AXP22X, ELDO3, "eldo3", "eldoin", 700, 3300, 100, AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), - AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100, + AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 1800, 3300, 100, AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), - AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 700, 3300, 100, + AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 1800, 3300, 100, AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000), diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 27a5deb1213e..d49d8606da15 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -150,7 +150,7 @@ static void regulator_lock_supply(struct regulator_dev *rdev) { int i; - for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++) + for (i = 0; rdev->supply; rdev = rdev_get_supply(rdev), i++) mutex_lock_nested(&rdev->mutex, i); } diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index fe5dbbeac15e..b0439871c41a 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -242,8 +242,8 @@ static const int msmcobalt_v2_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { #define MSMCOBALT_MMSS_CPR_SENSOR_COUNT 35 -#define MSMCOBALT_MMSS_AGING_SENSOR_ID 17 -#define MSMCOBALT_MMSS_AGING_BYPASS_MASK0 0 +#define MSMCOBALT_MMSS_AGING_SENSOR_ID 29 +#define MSMCOBALT_MMSS_AGING_BYPASS_MASK0 (GENMASK(23, 0)) #define MSMCOBALT_MMSS_MAX_TEMP_POINTS 3 #define MSMCOBALT_MMSS_TEMP_SENSOR_ID_START 12 diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c index 6e8db03fe16e..232373092746 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -3523,7 +3523,7 @@ cleanup: if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) { rc2 = cpr3_ctrl_clear_cpr4_config(ctrl); - if (rc) { + if (rc2) { cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n", rc2); rc = rc2; @@ -3725,6 +3725,17 @@ static int cpr3_regulator_aging_adjust(struct cpr3_controller *ctrl) return 0; } + /* + * Verify that the aging possible register (if specified) has an + * acceptable value. + */ + if (ctrl->aging_possible_reg) { + reg = readl_relaxed(ctrl->aging_possible_reg); + reg &= ctrl->aging_possible_mask; + if (reg != ctrl->aging_possible_val) + return 0; + } + restore_current_corner = kcalloc(vreg_count, sizeof(*restore_current_corner), GFP_KERNEL); restore_vreg_enabled = kcalloc(vreg_count, @@ -3798,7 +3809,7 @@ static int cpr3_regulator_aging_adjust(struct cpr3_controller *ctrl) max_aging_volt = max(max_aging_volt, aging_volt); } else { cpr3_err(ctrl, "CPR aging measurement failed after %d tries, rc=%d\n", - rc, CPR3_AGING_RETRY_COUNT); + j, rc); ctrl->aging_failed = true; ctrl->aging_required = false; goto cleanup; @@ -5992,6 +6003,21 @@ int cpr3_regulator_register(struct platform_device *pdev, } ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res)); + if (ctrl->aging_possible_mask) { + /* + * Aging possible register address is required if an aging + * possible mask has been specified. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "aging_allowed"); + if (!res || !res->start) { + cpr3_err(ctrl, "CPR aging allowed address is missing\n"); + return -ENXIO; + } + ctrl->aging_possible_reg = devm_ioremap(dev, res->start, + resource_size(res)); + } + if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH) { ctrl->irq = platform_get_irq_byname(pdev, "cpr"); if (ctrl->irq < 0) { diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index 0907518722df..8897def3ef76 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -532,6 +532,9 @@ struct cpr3_panic_regs_info { * that this CPR3 controller manages. * @cpr_ctrl_base: Virtual address of the CPR3 controller base register * @fuse_base: Virtual address of fuse row 0 + * @aging_possible_reg: Virtual address of an optional platform-specific + * register that must be ready to determine if it is + * possible to perform an aging measurement. * @list: list head used in a global cpr3-regulator list so that * cpr3-regulator structs can be found easily in RAM dumps * @thread: Array of CPR3 threads managed by the CPR3 controller @@ -671,6 +674,11 @@ struct cpr3_panic_regs_info { * @aging_sensor: Array of CPR3 aging sensors which are used to perform * aging measurements at a runtime. * @aging_sensor_count: Number of elements in the aging_sensor array + * @aging_possible_mask: Optional bitmask used to mask off the + * aging_possible_reg register. + * @aging_possible_val: Optional value that the masked aging_possible_reg + * register must have in order for a CPR aging measurement + * to be possible. * @step_quot_fixed: Fixed step quotient value used for target quotient * adjustment if use_dynamic_step_quot is not set. * This parameter is only relevant for CPR4 controllers @@ -721,6 +729,7 @@ struct cpr3_controller { int ctrl_id; void __iomem *cpr_ctrl_base; void __iomem *fuse_base; + void __iomem *aging_possible_reg; struct list_head list; struct cpr3_thread *thread; int thread_count; @@ -784,6 +793,8 @@ struct cpr3_controller { bool aging_failed; struct cpr3_aging_sensor_info *aging_sensor; int aging_sensor_count; + u32 aging_possible_mask; + u32 aging_possible_val; u32 step_quot_fixed; u32 initial_temp_band; diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 9d55e9af2e7c..51179f28fcf5 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -1169,6 +1169,24 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl) of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage", &ctrl->aging_ref_volt); + /* Aging possible bitmask is optional */ + ctrl->aging_possible_mask = 0; + of_property_read_u32(ctrl->dev->of_node, + "qcom,cpr-aging-allowed-reg-mask", + &ctrl->aging_possible_mask); + + if (ctrl->aging_possible_mask) { + /* + * Aging possible register value required if bitmask is + * specified + */ + rc = cpr3_parse_ctrl_u32(ctrl, + "qcom,cpr-aging-allowed-reg-value", + &ctrl->aging_possible_val, 0, UINT_MAX); + if (rc) + return rc; + } + if (of_find_property(ctrl->dev->of_node, "clock-names", NULL)) { ctrl->core_clk = devm_clk_get(ctrl->dev, "core_clk"); if (IS_ERR(ctrl->core_clk)) { diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index 083459f96ac4..284180b0e72f 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -69,8 +69,9 @@ struct cprh_msmcobalt_kbss_fuses { /* * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0. + * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1. */ -#define CPRH_MSMCOBALT_KBSS_FUSE_COMBO_COUNT 8 +#define CPRH_MSMCOBALT_KBSS_FUSE_COMBO_COUNT 16 /* * Constants which define the name of each fuse corner. @@ -206,11 +207,19 @@ msmcobalt_v1_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { * Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v2 */ static const int -msmcobalt_v2_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { - 688000, - 756000, - 828000, - 1056000, +msmcobalt_v2_kbss_fuse_ref_volt[2][MSMCOBALT_KBSS_FUSE_CORNERS] = { + [MSMCOBALT_KBSS_POWER_CLUSTER_ID] = { + 688000, + 756000, + 828000, + 1056000, + }, + [MSMCOBALT_KBSS_PERFORMANCE_CLUSTER_ID] = { + 756000, + 756000, + 828000, + 1056000, + }, }; #define MSMCOBALT_KBSS_FUSE_STEP_VOLT 10000 @@ -391,7 +400,7 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages( { struct device_node *node = vreg->of_node; struct cprh_msmcobalt_kbss_fuses *fuse = vreg->platform_fuses; - int i, j, soc_revision, rc = 0; + int i, j, soc_revision, id, rc = 0; bool allow_interpolation; u64 freq_low, volt_low, freq_high, volt_high; const int *ref_volt; @@ -407,13 +416,12 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages( goto done; } + id = vreg->thread->ctrl->ctrl_id; soc_revision = vreg->thread->ctrl->soc_revision; if (soc_revision == 1) ref_volt = msmcobalt_v1_kbss_fuse_ref_volt; - else if (soc_revision == 2) - ref_volt = msmcobalt_v2_kbss_fuse_ref_volt; else - ref_volt = msmcobalt_v2_kbss_fuse_ref_volt; + ref_volt = msmcobalt_v2_kbss_fuse_ref_volt[id]; for (i = 0; i < vreg->fuse_corner_count; i++) { fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse( diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index b6d831b84e1d..72fc3c32db49 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -305,7 +305,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_s2mps11_buck67810(num, min, step) { \ +#define regulator_desc_s2mps11_buck6_10(num, min, step) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -321,22 +321,6 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_s2mps11_buck9 { \ - .name = "BUCK9", \ - .id = S2MPS11_BUCK9, \ - .ops = &s2mps11_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = MIN_3000_MV, \ - .uV_step = STEP_25_MV, \ - .n_voltages = S2MPS11_BUCK9_N_VOLTAGES, \ - .ramp_delay = S2MPS11_RAMP_DELAY, \ - .vsel_reg = S2MPS11_REG_B9CTRL2, \ - .vsel_mask = S2MPS11_BUCK9_VSEL_MASK, \ - .enable_reg = S2MPS11_REG_B9CTRL1, \ - .enable_mask = S2MPS11_ENABLE_MASK \ -} - static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_ldo(1, STEP_25_MV), regulator_desc_s2mps11_ldo(2, STEP_50_MV), @@ -381,11 +365,11 @@ static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_buck1_4(3), regulator_desc_s2mps11_buck1_4(4), regulator_desc_s2mps11_buck5, - regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck9, - regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV), + regulator_desc_s2mps11_buck6_10(6, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck6_10(7, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck6_10(8, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck6_10(9, MIN_3000_MV, STEP_25_MV), + regulator_desc_s2mps11_buck6_10(10, MIN_750_MV, STEP_12_5_MV), }; static struct regulator_ops s2mps14_reg_ops; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 27343e1c43ef..58f5d3b8e981 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -202,10 +202,9 @@ static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id, } } - if (i >= s5m8767->num_regulators) - return -EINVAL; - - *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; + if (i < s5m8767->num_regulators) + *enable_ctrl = + s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; return 0; } @@ -938,12 +937,8 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) else regulators[id].vsel_mask = 0xff; - ret = s5m8767_get_register(s5m8767, id, &enable_reg, + s5m8767_get_register(s5m8767, id, &enable_reg, &enable_val); - if (ret) { - dev_err(s5m8767->dev, "error reading registers\n"); - return ret; - } regulators[id].enable_reg = enable_reg; regulators[id].enable_mask = S5M8767_ENCTRL_MASK; regulators[id].enable_val = enable_val; diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index d5c1b057a739..05a51ef52703 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -187,9 +187,9 @@ ds1685_rtc_end_data_access(struct ds1685_priv *rtc) * Only use this where you are certain another lock will not be held. */ static inline void -ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags) +ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags) { - spin_lock_irqsave(&rtc->lock, *flags); + spin_lock_irqsave(&rtc->lock, flags); ds1685_rtc_switch_to_bank1(rtc); } @@ -1304,7 +1304,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev, { struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 reg = 0, bit = 0, tmp; - unsigned long flags; + unsigned long flags = 0; long int val = 0; const struct ds1685_rtc_ctrl_regs *reg_info = ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name); @@ -1325,7 +1325,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev, bit = reg_info->bit; /* Safe to spinlock during a write. */ - ds1685_rtc_begin_ctrl_access(rtc, &flags); + ds1685_rtc_begin_ctrl_access(rtc, flags); tmp = rtc->read(rtc, reg); rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit)))); ds1685_rtc_end_ctrl_access(rtc, flags); diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index b1b4746a0eab..097325d96db5 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -144,7 +144,7 @@ static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm) * it does not seem to carry it over a subsequent write/read. * So we'll limit ourself to 100 years, starting at 2000 for now. */ - buf[6] = bin2bcd(tm->tm_year - 100); + buf[6] = tm->tm_year - 100; /* * CTL1 only contains TEST-mode bits apart from stop, diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 725dccae24e7..7184a0eda793 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -465,7 +465,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, MAX77686_RTCIRQ_RTCA1); - if (info->virq <= 0) { + if (!info->virq) { ret = -ENXIO; goto err_rtc; } diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 17341feadad1..bd911bafb809 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -65,6 +65,7 @@ static const struct i2c_device_id rx8025_id[] = { { "rx8025", 0 }, + { "rv8803", 1 }, { } }; MODULE_DEVICE_TABLE(i2c, rx8025_id); diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index e1b86bb01062..f64c282275b3 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -272,13 +272,12 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id) } static const struct rtc_class_ops vr41xx_rtc_ops = { - .release = vr41xx_rtc_release, - .ioctl = vr41xx_rtc_ioctl, - .read_time = vr41xx_rtc_read_time, - .set_time = vr41xx_rtc_set_time, - .read_alarm = vr41xx_rtc_read_alarm, - .set_alarm = vr41xx_rtc_set_alarm, - .alarm_irq_enable = vr41xx_rtc_alarm_irq_enable, + .release = vr41xx_rtc_release, + .ioctl = vr41xx_rtc_ioctl, + .read_time = vr41xx_rtc_read_time, + .set_time = vr41xx_rtc_set_time, + .read_alarm = vr41xx_rtc_read_alarm, + .set_alarm = vr41xx_rtc_set_alarm, }; static int rtc_probe(struct platform_device *pdev) diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig index 0b331c9c0a8f..e5647d59224f 100644 --- a/drivers/scsi/device_handler/Kconfig +++ b/drivers/scsi/device_handler/Kconfig @@ -13,13 +13,13 @@ menuconfig SCSI_DH config SCSI_DH_RDAC tristate "LSI RDAC Device Handler" - depends on SCSI_DH && SCSI + depends on SCSI_DH help If you have a LSI RDAC select y. Otherwise, say N. config SCSI_DH_HP_SW tristate "HP/COMPAQ MSA Device Handler" - depends on SCSI_DH && SCSI + depends on SCSI_DH help If you have a HP/COMPAQ MSA device that requires START_STOP to be sent to start it and cannot upgrade the firmware then select y. @@ -27,13 +27,13 @@ config SCSI_DH_HP_SW config SCSI_DH_EMC tristate "EMC CLARiiON Device Handler" - depends on SCSI_DH && SCSI + depends on SCSI_DH help If you have a EMC CLARiiON select y. Otherwise, say N. config SCSI_DH_ALUA tristate "SPC-3 ALUA Device Handler" - depends on SCSI_DH && SCSI + depends on SCSI_DH help SCSI Device handler for generic SPC-3 Asymmetric Logical Unit Access (ALUA). diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b0d92b84bcdc..db9446c612da 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2855,7 +2855,7 @@ lpfc_online(struct lpfc_hba *phba) } vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) { + if (vports != NULL) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); @@ -2872,8 +2872,7 @@ lpfc_online(struct lpfc_hba *phba) } spin_unlock_irq(shost->host_lock); } - } - lpfc_destroy_vport_work_array(phba, vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_unblock_mgmt_io(phba); return 0; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 00ce3e269a43..97a1c1c33b05 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -6282,13 +6282,12 @@ out: } for (i = 0; i < ioc->sge_count; i++) { - if (kbuff_arr[i]) { + if (kbuff_arr[i]) dma_free_coherent(&instance->pdev->dev, le32_to_cpu(kern_sge32[i].length), kbuff_arr[i], le32_to_cpu(kern_sge32[i].phys_addr)); kbuff_arr[i] = NULL; - } } megasas_return_cmd(instance, cmd); diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 634254a52301..5d0ec42a9317 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4214,7 +4214,7 @@ static struct scsi_host_template qla1280_driver_template = { .eh_bus_reset_handler = qla1280_eh_bus_reset, .eh_host_reset_handler = qla1280_eh_adapter_reset, .bios_param = qla1280_biosparam, - .can_queue = MAX_OUTSTANDING_COMMANDS, + .can_queue = 0xfffff, .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 60dc8b21044a..bfa82ca64499 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -127,10 +127,10 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) if (!host->is_lane_clks_enabled) return; - if (host->hba->lanes_per_direction > 1) + if (host->tx_l1_sync_clk) clk_disable_unprepare(host->tx_l1_sync_clk); clk_disable_unprepare(host->tx_l0_sync_clk); - if (host->hba->lanes_per_direction > 1) + if (host->rx_l1_sync_clk) clk_disable_unprepare(host->rx_l1_sync_clk); clk_disable_unprepare(host->rx_l0_sync_clk); @@ -161,17 +161,14 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) if (err) goto disable_tx_l0; - err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", - host->tx_l1_sync_clk); - if (err) - goto disable_rx_l1; + /* The tx lane1 clk could be muxed, hence keep this optional */ + if (host->tx_l1_sync_clk) + ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", + host->tx_l1_sync_clk); } host->is_lane_clks_enabled = true; goto out; -disable_rx_l1: - if (host->hba->lanes_per_direction > 1) - clk_disable_unprepare(host->rx_l1_sync_clk); disable_tx_l0: clk_disable_unprepare(host->tx_l0_sync_clk); disable_rx_l0: @@ -202,8 +199,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) if (err) goto out; - err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", - &host->tx_l1_sync_clk); + /* The tx lane1 clk could be muxed, hence keep this optional */ + ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", + &host->tx_l1_sync_clk); } out: return err; @@ -2089,6 +2087,11 @@ static inline int ufs_qcom_configure_lpm(struct ufs_hba *hba, bool enable) if (!ufs_qcom_cap_svs2(host)) goto out; + if (!((host->hw_ver.major == 0x3) && + (host->hw_ver.minor == 0x0) && + (host->hw_ver.step == 0x0))) + goto out; + /* * The link should be put in hibern8 state before * configuring the PHY to enter/exit SVS2 mode. diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index ea4dd2ce4e1d..fbde0d318584 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -167,6 +167,7 @@ static int ngd_qmi_available(struct notifier_block *n, unsigned long code, SLIM_INFO(dev, "Slimbus QMI NGD CB received event:%ld\n", code); switch (code) { case QMI_SERVER_ARRIVE: + atomic_set(&dev->ssr_in_progress, 0); schedule_work(&dev->dsp.dom_up); break; default: @@ -214,6 +215,8 @@ static int dsp_domr_notify_cb(struct notifier_block *n, unsigned long code, switch (code) { case SUBSYS_BEFORE_SHUTDOWN: case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: + SLIM_INFO(dev, "SLIM DSP SSR notify cb:%lu\n", code); + atomic_set(&dev->ssr_in_progress, 1); /* wait for current transaction */ mutex_lock(&dev->tx_lock); /* make sure autosuspend is not called until ADSP comes up*/ @@ -866,7 +869,7 @@ static int ngd_bulk_wr(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc, } if (dev->bulk.size > dev->bulk.buf_sz) { void *temp = krealloc(dev->bulk.base, dev->bulk.size, - GFP_KERNEL); + GFP_KERNEL | GFP_DMA); if (!temp) { ret = -ENOMEM; goto retpath; @@ -1316,8 +1319,10 @@ hw_init_retry: if (ret) { SLIM_WARN(dev, "SLIM power req failed:%d, retry:%d\n", ret, retries); - msm_slim_qmi_power_request(dev, false); - if (retries < INIT_MX_RETRIES) { + if (!atomic_read(&dev->ssr_in_progress)) + msm_slim_qmi_power_request(dev, false); + if (retries < INIT_MX_RETRIES && + !atomic_read(&dev->ssr_in_progress)) { retries++; goto hw_init_retry; } @@ -1416,7 +1421,8 @@ capability_retry: SLIM_WARN(dev, "slim capability time-out:%d, stat:0x%x,cfg:0x%x\n", retries, laddr, cfg); - if (retries < INIT_MX_RETRIES) { + if ((retries < INIT_MX_RETRIES) && + !atomic_read(&dev->ssr_in_progress)) { retries++; goto capability_retry; } @@ -1683,7 +1689,7 @@ static int ngd_slim_probe(struct platform_device *pdev) /* typical txn numbers and size used in bulk operation */ dev->bulk.buf_sz = SLIM_MAX_TXNS * 8; - dev->bulk.base = kzalloc(dev->bulk.buf_sz, GFP_KERNEL); + dev->bulk.base = kzalloc(dev->bulk.buf_sz, GFP_KERNEL | GFP_DMA); if (!dev->bulk.base) { ret = -ENOMEM; goto err_nobulk; @@ -1780,6 +1786,7 @@ static int ngd_slim_probe(struct platform_device *pdev) dev->ee = 1; dev->irq = irq->start; dev->bam.irq = bam_irq->start; + atomic_set(&dev->ssr_in_progress, 0); if (rxreg_access) dev->use_rx_msgqs = MSM_MSGQ_DISABLED; @@ -1938,6 +1945,7 @@ static int ngd_slim_runtime_resume(struct device *device) struct platform_device *pdev = to_platform_device(device); struct msm_slim_ctrl *dev = platform_get_drvdata(pdev); int ret = 0; + mutex_lock(&dev->tx_lock); if (dev->state >= MSM_CTRL_ASLEEP) ret = ngd_slim_power_up(dev, false); diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h index 7616e714299c..65b9fae8040b 100644 --- a/drivers/slimbus/slim-msm.h +++ b/drivers/slimbus/slim-msm.h @@ -314,6 +314,7 @@ struct msm_slim_ctrl { void (*rx_slim)(struct msm_slim_ctrl *dev, u8 *buf); u32 current_rx_buf[10]; int current_count; + atomic_t ssr_in_progress; }; struct msm_sat_chan { diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index f54d9c3f4f3d..20a4a3c7fdf0 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -30,6 +30,7 @@ #include "glink_private.h" #include "glink_xprt_if.h" +#define GLINK_CTX_CANARY 0x58544324 /* "$CTX" */ /* Number of internal IPC Logging log pages */ #define NUM_LOG_PAGES 10 #define GLINK_PM_QOS_HOLDOFF_MS 10 @@ -38,6 +39,8 @@ #define GLINK_QOS_DEF_MTU 2048 #define GLINK_KTHREAD_PRIO 1 + +static rwlock_t magic_lock; /** * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * @max_rate_kBps: Maximum rate supported by the priority bucket. @@ -308,6 +311,7 @@ struct channel_ctx { unsigned long req_rate_kBps; uint32_t tx_intent_cnt; uint32_t tx_cnt; + uint32_t magic_number; }; static struct glink_core_if core_impl; @@ -436,6 +440,37 @@ static void glink_core_deinit_xprt_qos_cfg( #define GLINK_GET_CH_TX_STATE(ctx) \ ((ctx)->tx_intent_cnt || (ctx)->tx_cnt) +static int glink_get_ch_ctx(struct channel_ctx *ctx) +{ + unsigned long flags; + + if (!ctx) + return -EINVAL; + read_lock_irqsave(&magic_lock, flags); + if (ctx->magic_number != GLINK_CTX_CANARY) { + read_unlock_irqrestore(&magic_lock, flags); + return -EINVAL; + } + rwref_get(&ctx->ch_state_lhb2); + read_unlock_irqrestore(&magic_lock, flags); + return 0; +} + +static int glink_put_ch_ctx(struct channel_ctx *ctx, bool update_magic) +{ + unsigned long flags; + + if (!update_magic) { + rwref_put(&ctx->ch_state_lhb2); + return 0; + } + write_lock_irqsave(&magic_lock, flags); + ctx->magic_number = 0; + rwref_put(&ctx->ch_state_lhb2); + write_unlock_irqrestore(&magic_lock, flags); + return 0; +} + /** * glink_ssr() - Clean up locally for SSR by simulating remote close * @subsystem: The name of the subsystem being restarted @@ -2583,7 +2618,7 @@ void *glink_open(const struct glink_open_config *cfg) GLINK_INFO_CH(ctx, "%s: Created channel, sent OPEN command. ctx %p\n", __func__, ctx); - + ctx->magic_number = GLINK_CTX_CANARY; return ctx; } EXPORT_SYMBOL(glink_open); @@ -2681,15 +2716,19 @@ int glink_close(void *handle) unsigned long flags; bool is_empty = false; - if (!ctx) - return -EINVAL; + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; GLINK_INFO_CH(ctx, "%s: Closing channel, ctx: %p\n", __func__, ctx); - if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) + if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) { + glink_put_ch_ctx(ctx, false); return 0; + } if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) { /* close already pending */ + glink_put_ch_ctx(ctx, false); return -EBUSY; } @@ -2754,6 +2793,7 @@ relock: xprt_ctx = ctx->transport_ptr; rwref_put(&ctx->ch_state_lhb2); rwref_read_put(&xprt_ctx->xprt_state_lhb0); + glink_put_ch_ctx(ctx, true); return ret; } EXPORT_SYMBOL(glink_close); @@ -2812,29 +2852,30 @@ static int glink_tx_common(void *handle, void *pkt_priv, if (!size) return -EINVAL; - if (!ctx) - return -EINVAL; + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; rwref_read_get_atomic(&ctx->ch_state_lhb2, is_atomic); if (!(vbuf_provider || pbuf_provider)) { - rwref_read_put(&ctx->ch_state_lhb2); - return -EINVAL; + ret = -EINVAL; + goto glink_tx_common_err; } if (!ch_is_fully_opened(ctx)) { - rwref_read_put(&ctx->ch_state_lhb2); - return -EBUSY; + ret = -EBUSY; + goto glink_tx_common_err; } if (size > GLINK_MAX_PKT_SIZE) { - rwref_read_put(&ctx->ch_state_lhb2); - return -EINVAL; + ret = -EINVAL; + goto glink_tx_common_err; } if (unlikely(tx_flags & GLINK_TX_TRACER_PKT)) { if (!(ctx->transport_ptr->capabilities & GCAP_TRACER_PKT)) { - rwref_read_put(&ctx->ch_state_lhb2); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto glink_tx_common_err; } tracer_pkt_log_event(data, GLINK_CORE_TX); } @@ -2846,16 +2887,16 @@ static int glink_tx_common(void *handle, void *pkt_priv, GLINK_ERR_CH(ctx, "%s: R[%u]:%zu Intent not present for lcid\n", __func__, riid, size); - rwref_read_put(&ctx->ch_state_lhb2); - return -EAGAIN; + ret = -EAGAIN; + goto glink_tx_common_err; } if (is_atomic && !(ctx->transport_ptr->capabilities & GCAP_AUTO_QUEUE_RX_INT)) { GLINK_ERR_CH(ctx, "%s: Cannot request intent in atomic context\n", __func__); - rwref_read_put(&ctx->ch_state_lhb2); - return -EINVAL; + ret = -EINVAL; + goto glink_tx_common_err; } /* request intent of correct size */ @@ -2865,20 +2906,18 @@ static int glink_tx_common(void *handle, void *pkt_priv, if (ret) { GLINK_ERR_CH(ctx, "%s: Request intent failed %d\n", __func__, ret); - rwref_read_put(&ctx->ch_state_lhb2); - return ret; + goto glink_tx_common_err; } while (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size, &cookie)) { - rwref_get(&ctx->ch_state_lhb2); rwref_read_put(&ctx->ch_state_lhb2); if (is_atomic) { GLINK_ERR_CH(ctx, "%s Intent of size %zu not ready\n", __func__, size); - rwref_put(&ctx->ch_state_lhb2); - return -EAGAIN; + ret = -EAGAIN; + goto glink_tx_common_err_2; } if (ctx->transport_ptr->local_state == GLINK_XPRT_DOWN @@ -2886,8 +2925,8 @@ static int glink_tx_common(void *handle, void *pkt_priv, GLINK_ERR_CH(ctx, "%s: Channel closed while waiting for intent\n", __func__); - rwref_put(&ctx->ch_state_lhb2); - return -EBUSY; + ret = -EBUSY; + goto glink_tx_common_err_2; } /* wait for the remote intent req ack */ @@ -2897,8 +2936,8 @@ static int glink_tx_common(void *handle, void *pkt_priv, GLINK_ERR_CH(ctx, "%s: Intent request ack with size: %zu not granted for lcid\n", __func__, size); - rwref_put(&ctx->ch_state_lhb2); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto glink_tx_common_err_2; } if (!ctx->int_req_ack) { @@ -2906,8 +2945,8 @@ static int glink_tx_common(void *handle, void *pkt_priv, "%s: Intent Request with size: %zu %s", __func__, size, "not granted for lcid\n"); - rwref_put(&ctx->ch_state_lhb2); - return -EAGAIN; + ret = -EAGAIN; + goto glink_tx_common_err_2; } /* wait for the rx_intent from remote side */ @@ -2917,13 +2956,12 @@ static int glink_tx_common(void *handle, void *pkt_priv, GLINK_ERR_CH(ctx, "%s: Intent request with size: %zu not granted for lcid\n", __func__, size); - rwref_put(&ctx->ch_state_lhb2); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto glink_tx_common_err_2; } reinit_completion(&ctx->int_req_complete); rwref_read_get(&ctx->ch_state_lhb2); - rwref_put(&ctx->ch_state_lhb2); } } @@ -2943,8 +2981,8 @@ static int glink_tx_common(void *handle, void *pkt_priv, if (!tx_info) { GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__); ch_push_remote_rx_intent(ctx, intent_size, riid, cookie); - rwref_read_put(&ctx->ch_state_lhb2); - return -ENOMEM; + ret = -ENOMEM; + goto glink_tx_common_err; } rwref_lock_init(&tx_info->pkt_ref, glink_tx_pkt_release); INIT_LIST_HEAD(&tx_info->list_done); @@ -2970,7 +3008,10 @@ static int glink_tx_common(void *handle, void *pkt_priv, else xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info); +glink_tx_common_err: rwref_read_put(&ctx->ch_state_lhb2); +glink_tx_common_err_2: + glink_put_ch_ctx(ctx, false); return ret; } @@ -3011,13 +3052,15 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) struct glink_core_rx_intent *intent_ptr; int ret = 0; - if (!ctx) - return -EINVAL; + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { /* Can only queue rx intents if channel is fully opened */ GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } @@ -3026,13 +3069,16 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) GLINK_ERR_CH(ctx, "%s: Intent pointer allocation failed size[%zu]\n", __func__, size); + glink_put_ch_ctx(ctx, false); return -ENOMEM; } GLINK_DBG_CH(ctx, "%s: L[%u]:%zu\n", __func__, intent_ptr->id, intent_ptr->intent_size); - if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) + if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) { + glink_put_ch_ctx(ctx, false); return ret; + } /* notify remote side of rx intent */ ret = ctx->transport_ptr->ops->tx_cmd_local_rx_intent( @@ -3040,7 +3086,7 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size) if (ret) /* unable to transmit, dequeue intent */ ch_remove_local_rx_intent(ctx, intent_ptr->id); - + glink_put_ch_ctx(ctx, false); return ret; } EXPORT_SYMBOL(glink_queue_rx_intent); @@ -3059,20 +3105,25 @@ bool glink_rx_intent_exists(void *handle, size_t size) struct channel_ctx *ctx = (struct channel_ctx *)handle; struct glink_core_rx_intent *intent; unsigned long flags; + int ret; if (!ctx || !ch_is_fully_opened(ctx)) return false; + ret = glink_get_ch_ctx(ctx); + if (ret) + return false; spin_lock_irqsave(&ctx->local_rx_intent_lst_lock_lhc1, flags); list_for_each_entry(intent, &ctx->local_rx_intent_list, list) { if (size <= intent->intent_size) { spin_unlock_irqrestore( &ctx->local_rx_intent_lst_lock_lhc1, flags); + glink_put_ch_ctx(ctx, false); return true; } } spin_unlock_irqrestore(&ctx->local_rx_intent_lst_lock_lhc1, flags); - + glink_put_ch_ctx(ctx, false); return false; } EXPORT_SYMBOL(glink_rx_intent_exists); @@ -3093,11 +3144,15 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse) uint32_t id; int ret = 0; + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; liid_ptr = ch_get_local_rx_intent_notified(ctx, ptr); if (IS_ERR_OR_NULL(liid_ptr)) { /* invalid pointer */ GLINK_ERR_CH(ctx, "%s: Invalid pointer %p\n", __func__, ptr); + glink_put_ch_ctx(ctx, false); return -EINVAL; } @@ -3123,7 +3178,7 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse) /* send rx done */ ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops, ctx->lcid, id, reuse); - + glink_put_ch_ctx(ctx, false); return ret; } EXPORT_SYMBOL(glink_rx_done); @@ -3171,12 +3226,13 @@ int glink_sigs_set(void *handle, uint32_t sigs) struct channel_ctx *ctx = (struct channel_ctx *)handle; int ret; - if (!ctx) - return -EINVAL; - + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } @@ -3186,6 +3242,7 @@ int glink_sigs_set(void *handle, uint32_t sigs) ctx->lcid, ctx->lsigs); GLINK_INFO_CH(ctx, "%s: Sent SIGNAL SET command\n", __func__); + glink_put_ch_ctx(ctx, false); return ret; } EXPORT_SYMBOL(glink_sigs_set); @@ -3201,17 +3258,22 @@ EXPORT_SYMBOL(glink_sigs_set); int glink_sigs_local_get(void *handle, uint32_t *sigs) { struct channel_ctx *ctx = (struct channel_ctx *)handle; + int ret; - if (!ctx || !sigs) + if (!sigs) return -EINVAL; - + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } *sigs = ctx->lsigs; + glink_put_ch_ctx(ctx, false); return 0; } EXPORT_SYMBOL(glink_sigs_local_get); @@ -3227,17 +3289,23 @@ EXPORT_SYMBOL(glink_sigs_local_get); int glink_sigs_remote_get(void *handle, uint32_t *sigs) { struct channel_ctx *ctx = (struct channel_ctx *)handle; + int ret; - if (!ctx || !sigs) + if (!sigs) return -EINVAL; + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } *sigs = ctx->rsigs; + glink_put_ch_ctx(ctx, false); return 0; } EXPORT_SYMBOL(glink_sigs_remote_get); @@ -3333,12 +3401,16 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size) int ret; unsigned long req_rate_kBps; - if (!ctx || !latency_us || !pkt_size) + if (!latency_us || !pkt_size) return -EINVAL; + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } @@ -3348,7 +3420,7 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size) if (ret < 0) GLINK_ERR_CH(ctx, "%s: QoS %lu:%zu cannot be met\n", __func__, latency_us, pkt_size); - + glink_put_ch_ctx(ctx, false); return ret; } EXPORT_SYMBOL(glink_qos_latency); @@ -3366,16 +3438,18 @@ int glink_qos_cancel(void *handle) struct channel_ctx *ctx = (struct channel_ctx *)handle; int ret; - if (!ctx) - return -EINVAL; - + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } ret = glink_qos_reset_priority(ctx); + glink_put_ch_ctx(ctx, false); return ret; } EXPORT_SYMBOL(glink_qos_cancel); @@ -3396,12 +3470,13 @@ int glink_qos_start(void *handle) int ret; unsigned long flags; - if (!ctx) - return -EINVAL; - + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return -EBUSY; } @@ -3410,6 +3485,7 @@ int glink_qos_start(void *handle) ret = glink_qos_add_ch_tx_intent(ctx); spin_unlock(&ctx->tx_lists_lock_lhc3); spin_unlock_irqrestore(&ctx->transport_ptr->tx_ready_lock_lhb3, flags); + glink_put_ch_ctx(ctx, false); return ret; } EXPORT_SYMBOL(glink_qos_start); @@ -3428,16 +3504,20 @@ EXPORT_SYMBOL(glink_qos_start); unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size) { struct channel_ctx *ctx = (struct channel_ctx *)handle; + int ret; - if (!ctx) - return (unsigned long)-EINVAL; + ret = glink_get_ch_ctx(ctx); + if (ret) + return (unsigned long)ret; if (!ch_is_fully_opened(ctx)) { GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", __func__); + glink_put_ch_ctx(ctx, false); return (unsigned long)-EBUSY; } + glink_put_ch_ctx(ctx, false); return ctx->transport_ptr->ops->get_power_vote_ramp_time( ctx->transport_ptr->ops, glink_prio_to_power_state(ctx->transport_ptr, @@ -3521,12 +3601,16 @@ EXPORT_SYMBOL(glink_rpm_mask_rx_interrupt); int glink_wait_link_down(void *handle) { struct channel_ctx *ctx = (struct channel_ctx *)handle; + int ret; - if (!ctx) - return -EINVAL; - if (!ctx->transport_ptr) + ret = glink_get_ch_ctx(ctx); + if (ret) + return ret; + if (!ctx->transport_ptr) { + glink_put_ch_ctx(ctx, false); return -EOPNOTSUPP; - + } + glink_put_ch_ctx(ctx, false); return ctx->transport_ptr->ops->wait_link_down(ctx->transport_ptr->ops); } EXPORT_SYMBOL(glink_wait_link_down); @@ -6019,6 +6103,7 @@ EXPORT_SYMBOL(glink_get_xprt_log_ctx); static int glink_init(void) { log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "glink", 0); + rwlock_init(&magic_lock); if (!log_ctx) GLINK_ERR("%s: unable to create log context\n", __func__); glink_debugfs_init(); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index aff9683b394f..26b1cad9d5aa 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -208,15 +208,15 @@ enum icnss_debug_quirks { PDR_ONLY, }; -#define ICNSS_QUIRKS_DEFAULT ( \ - BIT(SSR_ONLY) \ - ) +#define ICNSS_QUIRKS_DEFAULT 0 unsigned long quirks = ICNSS_QUIRKS_DEFAULT; module_param(quirks, ulong, 0600); void *icnss_ipc_log_context; +#define ICNSS_EVENT_PENDING 2989 + enum icnss_driver_event_type { ICNSS_DRIVER_EVENT_SERVER_ARRIVE, ICNSS_DRIVER_EVENT_SERVER_EXIT, @@ -370,6 +370,7 @@ static struct icnss_priv { struct notifier_block get_service_nb; void *modem_notify_handler; struct notifier_block modem_ssr_nb; + struct wakeup_source ws; } *penv; static void icnss_hw_write_reg(void *base, u32 offset, u32 val) @@ -486,6 +487,7 @@ static int icnss_driver_event_post(enum icnss_driver_event_type type, event->type = type; event->data = data; init_completion(&event->complete); + event->ret = ICNSS_EVENT_PENDING; event->sync = sync; spin_lock_irqsave(&penv->event_lock, flags); @@ -494,12 +496,26 @@ static int icnss_driver_event_post(enum icnss_driver_event_type type, penv->stats.events[type].posted++; queue_work(penv->event_wq, &penv->event_work); - if (sync) { - ret = wait_for_completion_interruptible(&event->complete); - if (ret == 0) - ret = event->ret; - kfree(event); + + if (!sync) + return ret; + + ret = wait_for_completion_interruptible(&event->complete); + + icnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n", + icnss_driver_event_to_str(type), type, penv->state, ret, + event->ret); + + spin_lock_irqsave(&penv->event_lock, flags); + if (ret == -ERESTARTSYS && event->ret == ICNSS_EVENT_PENDING) { + event->sync = false; + spin_unlock_irqrestore(&penv->event_lock, flags); + return ret; } + spin_unlock_irqrestore(&penv->event_lock, flags); + + ret = event->ret; + kfree(event); return ret; } @@ -1039,7 +1055,7 @@ int icnss_hw_reset(struct icnss_priv *priv) MPM_WCSSAON_CONFIG_FORCE_ACTIVE, 1); icnss_hw_poll_reg_field(priv->mem_base_va, SR_WCSSAON_SR_LSB_OFFSET, - SR_WCSSAON_SR_LSB_RETENTION_STATUS, 1, 10, + SR_WCSSAON_SR_LSB_RETENTION_STATUS, 1, 100, ICNSS_HW_REG_RETRY); for (i = 0; i < ICNSS_HW_REG_RETRY; i++) { @@ -1546,6 +1562,13 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) goto out; } + /* During recovery do not send mode request for WLAN OFF as + * FW not able to process it. + */ + if (test_bit(ICNSS_PD_RESTART, &penv->state) && + mode == QMI_WLFW_OFF_V01) + return 0; + icnss_pr_dbg("Sending Mode request, state: 0x%lx, mode: %d\n", penv->state, mode); @@ -1886,6 +1909,9 @@ static int icnss_call_driver_reinit(struct icnss_priv *priv) if (!priv->ops || !priv->ops->reinit) goto out; + if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) + goto out; + icnss_hw_power_on(priv); ret = priv->ops->reinit(&priv->pdev->dev); @@ -1916,6 +1942,8 @@ static int icnss_driver_event_fw_ready_ind(void *data) if (!penv) return -ENODEV; + __pm_stay_awake(&penv->ws); + set_bit(ICNSS_FW_READY, &penv->state); icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state); @@ -1933,7 +1961,10 @@ static int icnss_driver_event_fw_ready_ind(void *data) else ret = icnss_call_driver_probe(penv); + __pm_relax(&penv->ws); + out: + __pm_relax(&penv->ws); return ret; } @@ -1941,10 +1972,10 @@ static int icnss_driver_event_register_driver(void *data) { int ret = 0; - if (penv->ops) { - ret = -EEXIST; - goto out; - } + if (penv->ops) + return -EEXIST; + + __pm_stay_awake(&penv->ws); penv->ops = data; @@ -1971,16 +2002,21 @@ static int icnss_driver_event_register_driver(void *data) set_bit(ICNSS_DRIVER_PROBED, &penv->state); + __pm_relax(&penv->ws); + return 0; power_off: icnss_hw_power_off(penv); out: + __pm_relax(&penv->ws); return ret; } static int icnss_driver_event_unregister_driver(void *data) { + __pm_stay_awake(&penv->ws); + if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) { penv->ops = NULL; goto out; @@ -1996,6 +2032,7 @@ static int icnss_driver_event_unregister_driver(void *data) icnss_hw_power_off(penv); out: + __pm_relax(&penv->ws); return 0; } @@ -2012,6 +2049,9 @@ static int icnss_qmi_pd_event_service_down(struct icnss_priv *priv, void *data) if (!priv->ops || !priv->ops->shutdown) goto out; + if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) + goto out; + priv->ops->shutdown(&priv->pdev->dev); out: @@ -2071,11 +2111,15 @@ static void icnss_driver_event_work(struct work_struct *work) penv->stats.events[event->type].processed++; + spin_lock_irqsave(&penv->event_lock, flags); if (event->sync) { event->ret = ret; complete(&event->complete); - } else - kfree(event); + continue; + } + spin_unlock_irqrestore(&penv->event_lock, flags); + + kfree(event); spin_lock_irqsave(&penv->event_lock, flags); } @@ -2372,6 +2416,9 @@ int icnss_register_driver(struct icnss_driver_ops *ops) ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER, true, ops); + if (ret == -ERESTARTSYS) + ret = 0; + out: return ret; } @@ -2890,7 +2937,7 @@ static int icnss_get_vreg_info(struct device *dev, reg = devm_regulator_get_optional(dev, vreg_info->name); - if (IS_ERR(reg) == -EPROBE_DEFER) { + if (PTR_ERR(reg) == -EPROBE_DEFER) { icnss_pr_err("EPROBE_DEFER for regulator: %s\n", vreg_info->name); ret = PTR_ERR(reg); @@ -2910,7 +2957,6 @@ static int icnss_get_vreg_info(struct device *dev, vreg_info->name, ret); goto done; } - } vreg_info->reg = reg; @@ -3502,6 +3548,8 @@ static int icnss_probe(struct platform_device *pdev) spin_lock_init(&priv->event_lock); spin_lock_init(&priv->on_off_lock); + wakeup_source_init(&priv->ws, "icnss_ws"); + priv->event_wq = alloc_workqueue("icnss_driver_event", WQ_UNBOUND, 1); if (!priv->event_wq) { icnss_pr_err("Workqueue creation failed\n"); @@ -3563,6 +3611,8 @@ static int icnss_remove(struct platform_device *pdev) icnss_bw_deinit(penv); + wakeup_source_trash(&penv->ws); + icnss_hw_power_off(penv); dev_set_drvdata(&pdev->dev, NULL); diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 5eaf2db32d21..03a1591e5b09 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -795,45 +795,23 @@ static int msm_rpm_read_sleep_ack(void) { int ret; char buf[MAX_ERR_BUFFER_SIZE] = {0}; - uint32_t msg_id; if (glink_enabled) ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); else { ret = msm_rpm_read_smd_data(buf); - if (!ret) { - /* - * Mimic Glink behavior to ensure that the - * data is read and the msg is removed from - * the wait list. We should have gotten here - * only when there are no drivers waiting on - * ACKs. msm_rpm_get_entry_from_msg_id() - * return non-NULL only then. - */ - msg_id = msm_rpm_get_msg_id_from_ack(buf); - msm_rpm_process_ack(msg_id, 0); + if (!ret) ret = smd_is_pkt_avail(msm_rpm_data.ch_info); - } } return ret; } -static void msm_rpm_flush_noack_messages(void) -{ - while (!list_empty(&msm_rpm_wait_list)) { - if (!msm_rpm_read_sleep_ack()) - break; - } -} - static int msm_rpm_flush_requests(bool print) { struct rb_node *t; int ret; int count = 0; - msm_rpm_flush_noack_messages(); - for (t = rb_first(&tr_root); t; t = rb_next(t)) { struct slp_buf *s = rb_entry(t, struct slp_buf, node); @@ -1102,18 +1080,14 @@ static void msm_rpm_notify(void *data, unsigned event) bool msm_rpm_waiting_for_ack(void) { - bool ret = false; + bool ret; unsigned long flags; - struct msm_rpm_wait_data *elem = NULL; spin_lock_irqsave(&msm_rpm_list_lock, flags); - elem = list_first_entry_or_null(&msm_rpm_wait_list, - struct msm_rpm_wait_data, list); - if (elem) - ret = !elem->delete_on_ack; + ret = list_empty(&msm_rpm_wait_list); spin_unlock_irqrestore(&msm_rpm_list_lock, flags); - return ret; + return !ret; } static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id) diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 4a65c5bda146..534c58937a56 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -419,7 +419,6 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) if (error) { dev_err(dev, "failed to handle node %s: %d\n", node->name, error); - of_node_put(node); goto err_out; } } diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 73c8ea0b1360..b25dc71b0ea9 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -111,7 +111,7 @@ static const struct lpss_config lpss_platforms[] = { .reg_general = -1, .reg_ssp = 0x20, .reg_cs_ctrl = 0x24, - .reg_capabilities = -1, + .reg_capabilities = 0xfc, .rx_threshold = 1, .tx_threshold_lo = 32, .tx_threshold_hi = 56, diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 035767c02072..79a8bc4f6cec 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -265,10 +265,7 @@ static inline u32 rx_max(struct rockchip_spi *rs) static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) { u32 ser; - struct spi_master *master = spi->master; - struct rockchip_spi *rs = spi_master_get_devdata(master); - - pm_runtime_get_sync(rs->dev); + struct rockchip_spi *rs = spi_master_get_devdata(spi->master); ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK; @@ -293,8 +290,6 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) ser &= ~(1 << spi->chip_select); writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER); - - pm_runtime_put_sync(rs->dev); } static int rockchip_spi_prepare_message(struct spi_master *master, diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 5044c6198332..64318fcfacf2 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -94,7 +94,6 @@ struct ti_qspi { #define QSPI_FLEN(n) ((n - 1) << 0) #define QSPI_WLEN_MAX_BITS 128 #define QSPI_WLEN_MAX_BYTES 16 -#define QSPI_WLEN_MASK QSPI_WLEN(QSPI_WLEN_MAX_BITS) /* STATUS REGISTER */ #define BUSY 0x01 @@ -225,16 +224,16 @@ static inline int ti_qspi_poll_wc(struct ti_qspi *qspi) return -ETIMEDOUT; } -static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t, - int count) +static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) { - int wlen, xfer_len; + int wlen, count, xfer_len; unsigned int cmd; const u8 *txbuf; u32 data; txbuf = t->tx_buf; cmd = qspi->cmd | QSPI_WR_SNGL; + count = t->len; wlen = t->bits_per_word >> 3; /* in bytes */ xfer_len = wlen; @@ -294,10 +293,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t, return 0; } -static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, - int count) +static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) { - int wlen; + int wlen, count; unsigned int cmd; u8 *rxbuf; @@ -314,6 +312,7 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, cmd |= QSPI_RD_SNGL; break; } + count = t->len; wlen = t->bits_per_word >> 3; /* in bytes */ while (count) { @@ -344,13 +343,12 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, return 0; } -static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t, - int count) +static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) { int ret; if (t->tx_buf) { - ret = qspi_write_msg(qspi, t, count); + ret = qspi_write_msg(qspi, t); if (ret) { dev_dbg(qspi->dev, "Error while writing\n"); return ret; @@ -358,7 +356,7 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t, } if (t->rx_buf) { - ret = qspi_read_msg(qspi, t, count); + ret = qspi_read_msg(qspi, t); if (ret) { dev_dbg(qspi->dev, "Error while reading\n"); return ret; @@ -375,8 +373,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, struct spi_device *spi = m->spi; struct spi_transfer *t; int status = 0, ret; - unsigned int frame_len_words, transfer_len_words; - int wlen; + int frame_length; /* setup device control reg */ qspi->dc = 0; @@ -388,38 +385,30 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, if (spi->mode & SPI_CS_HIGH) qspi->dc |= QSPI_CSPOL(spi->chip_select); - frame_len_words = 0; - list_for_each_entry(t, &m->transfers, transfer_list) - frame_len_words += t->len / (t->bits_per_word >> 3); - frame_len_words = min_t(unsigned int, frame_len_words, QSPI_FRAME); + frame_length = (m->frame_length << 3) / spi->bits_per_word; + + frame_length = clamp(frame_length, 0, QSPI_FRAME); /* setup command reg */ qspi->cmd = 0; qspi->cmd |= QSPI_EN_CS(spi->chip_select); - qspi->cmd |= QSPI_FLEN(frame_len_words); + qspi->cmd |= QSPI_FLEN(frame_length); ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); mutex_lock(&qspi->list_lock); list_for_each_entry(t, &m->transfers, transfer_list) { - qspi->cmd = ((qspi->cmd & ~QSPI_WLEN_MASK) | - QSPI_WLEN(t->bits_per_word)); - - wlen = t->bits_per_word >> 3; - transfer_len_words = min(t->len / wlen, frame_len_words); + qspi->cmd |= QSPI_WLEN(t->bits_per_word); - ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen); + ret = qspi_transfer_msg(qspi, t); if (ret) { dev_dbg(qspi->dev, "transfer message failed\n"); mutex_unlock(&qspi->list_lock); return -EINVAL; } - m->actual_length += transfer_len_words * wlen; - frame_len_words -= transfer_len_words; - if (frame_len_words == 0) - break; + m->actual_length += t->len; } mutex_unlock(&qspi->list_lock); diff --git a/drivers/staging/rdma/hfi1/TODO b/drivers/staging/rdma/hfi1/TODO index 4c6f1d7d2eaf..05de0dad8762 100644 --- a/drivers/staging/rdma/hfi1/TODO +++ b/drivers/staging/rdma/hfi1/TODO @@ -3,4 +3,4 @@ July, 2015 - Remove unneeded file entries in sysfs - Remove software processing of IB protocol and place in library for use by qib, ipath (if still present), hfi1, and eventually soft-roce -- Replace incorrect uAPI + diff --git a/drivers/staging/rdma/hfi1/file_ops.c b/drivers/staging/rdma/hfi1/file_ops.c index c851e51b1dc3..aae9826ec62b 100644 --- a/drivers/staging/rdma/hfi1/file_ops.c +++ b/drivers/staging/rdma/hfi1/file_ops.c @@ -62,8 +62,6 @@ #include <linux/cred.h> #include <linux/uio.h> -#include <rdma/ib.h> - #include "hfi.h" #include "pio.h" #include "device.h" @@ -216,10 +214,6 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data, int uctxt_required = 1; int must_be_root = 0; - /* FIXME: This interface cannot continue out of staging */ - if (WARN_ON_ONCE(!ib_safe_file_access(fp))) - return -EACCES; - if (count < sizeof(cmd)) { ret = -EINVAL; goto bail; diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 7106288efae3..e845841ab036 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -545,14 +545,15 @@ static int rockchip_configure_from_dt(struct device *dev, thermal->chip->tshut_temp); thermal->tshut_temp = thermal->chip->tshut_temp; } else { - if (shut_temp > INT_MAX) { - dev_err(dev, "Invalid tshut temperature specified: %d\n", - shut_temp); - return -ERANGE; - } thermal->tshut_temp = shut_temp; } + if (thermal->tshut_temp > INT_MAX) { + dev_err(dev, "Invalid tshut temperature specified: %d\n", + thermal->tshut_temp); + return -ERANGE; + } + if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) { dev_warn(dev, "Missing tshut mode property, using default (%s)\n", diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 670eda466438..9fdb06e08d4b 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/of_device.h> @@ -197,13 +198,13 @@ struct msm_port { static void msm_write(struct uart_port *port, unsigned int val, unsigned int off) { - writel_relaxed(val, port->membase + off); + writel_relaxed_no_log(val, port->membase + off); } static unsigned int msm_read(struct uart_port *port, unsigned int off) { - return readl_relaxed(port->membase + off); + return readl_relaxed_no_log(port->membase + off); } /* @@ -403,8 +404,12 @@ static void msm_stop_tx(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); + if (pm_runtime_get_sync(port->dev) < 0) + return; msm_port->imr &= ~UART_IMR_TXLEV; msm_write(port, msm_port->imr, UART_IMR); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static void msm_start_tx(struct uart_port *port) @@ -416,8 +421,12 @@ static void msm_start_tx(struct uart_port *port) if (dma->count) return; + if (pm_runtime_get_sync(port->dev) < 0) + return; msm_port->imr |= UART_IMR_TXLEV; msm_write(port, msm_port->imr, UART_IMR); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static void msm_reset_dm_count(struct uart_port *port, int count) @@ -439,6 +448,8 @@ static void msm_complete_tx_dma(void *args) unsigned int count; u32 val; + if (pm_runtime_get_sync(port->dev) < 0) + return; spin_lock_irqsave(&port->lock, flags); /* Already stopped */ @@ -475,6 +486,8 @@ static void msm_complete_tx_dma(void *args) msm_handle_tx(port); done: spin_unlock_irqrestore(&port->lock, flags); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) @@ -547,6 +560,8 @@ static void msm_complete_rx_dma(void *args) unsigned long flags; u32 val; + if (pm_runtime_get_sync(port->dev) < 0) + return; spin_lock_irqsave(&port->lock, flags); /* Already stopped */ @@ -598,6 +613,8 @@ done: if (count) tty_flip_buffer_push(tport); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static void msm_start_rx_dma(struct msm_port *msm_port) @@ -672,19 +689,28 @@ static void msm_stop_rx(struct uart_port *port) struct msm_port *msm_port = UART_TO_MSM(port); struct msm_dma *dma = &msm_port->rx_dma; + if (pm_runtime_get_sync(port->dev) < 0) + return; msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); msm_write(port, msm_port->imr, UART_IMR); if (dma->chan) msm_stop_dma(port, dma); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static void msm_enable_ms(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); + if (pm_runtime_get_sync(port->dev) < 0) + return; + msm_port->imr |= UART_IMR_DELTA_CTS; msm_write(port, msm_port->imr, UART_IMR); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) @@ -931,6 +957,8 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) unsigned int misr; u32 val; + if (pm_runtime_get_sync(port->dev) < 0) + return IRQ_NONE; spin_lock_irqsave(&port->lock, flags); misr = msm_read(port, UART_MISR); msm_write(port, 0, UART_IMR); /* disable interrupt */ @@ -964,13 +992,25 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ spin_unlock_irqrestore(&port->lock, flags); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); return IRQ_HANDLED; } static unsigned int msm_tx_empty(struct uart_port *port) { - return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; + int ret; + + ret = pm_runtime_get_sync(port->dev); + if (ret < 0) + return ret; + + ret = msm_read(port, UART_SR) & UART_SR_TX_EMPTY ? TIOCSER_TEMT : 0; + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + + return ret; } static unsigned int msm_get_mctrl(struct uart_port *port) @@ -999,6 +1039,8 @@ static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; + if (pm_runtime_get_sync(port->dev) < 0) + return; mr = msm_read(port, UART_MR1); if (!(mctrl & TIOCM_RTS)) { @@ -1009,14 +1051,20 @@ static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) mr |= UART_MR1_RX_RDY_CTL; msm_write(port, mr, UART_MR1); } + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static void msm_break_ctl(struct uart_port *port, int break_ctl) { + if (pm_runtime_get_sync(port->dev) < 0) + return; if (break_ctl) msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); else msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } struct msm_baud_map { @@ -1157,15 +1205,6 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, return baud; } -static void msm_init_clock(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - clk_prepare_enable(msm_port->clk); - clk_prepare_enable(msm_port->pclk); - msm_serial_set_mnd_regs(port); -} - static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); @@ -1180,7 +1219,22 @@ static int msm_startup(struct uart_port *port) if (unlikely(ret)) return ret; - msm_init_clock(port); + /* + * UART clk must be kept enabled to + * avoid losing received character + */ + ret = clk_prepare_enable(msm_port->clk); + if (ret) + return ret; + ret = clk_prepare(msm_port->pclk); + if (ret) + return ret; + + ret = pm_runtime_get_sync(port->dev); + if (ret < 0) + goto err; + + msm_serial_set_mnd_regs(port); if (likely(port->fifosize > 12)) rfr_level = port->fifosize - 12; @@ -1206,19 +1260,34 @@ static int msm_startup(struct uart_port *port) msm_request_rx_dma(msm_port, msm_port->uart.mapbase); } + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + return 0; + +err: + clk_unprepare(msm_port->pclk); + clk_disable_unprepare(msm_port->clk); + free_irq(port->irq, port); + return ret; } static void msm_shutdown(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); + if (pm_runtime_get_sync(port->dev) < 0) + return; + msm_port->imr = 0; msm_write(port, 0, UART_IMR); /* disable interrupts */ if (msm_port->is_uartdm) msm_release_dma(msm_port); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + clk_unprepare(msm_port->pclk); clk_disable_unprepare(msm_port->clk); free_irq(port->irq, port); @@ -1232,6 +1301,8 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int baud, mr; + if (pm_runtime_get_sync(port->dev) < 0) + return; spin_lock_irqsave(&port->lock, flags); if (dma->chan) /* Terminate if any */ @@ -1305,6 +1376,8 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, msm_start_rx_dma(msm_port); spin_unlock_irqrestore(&port->lock, flags); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static const char *msm_type(struct uart_port *port) @@ -1385,12 +1458,26 @@ static void msm_power(struct uart_port *port, unsigned int state, switch (state) { case 0: - clk_prepare_enable(msm_port->clk); - clk_prepare_enable(msm_port->pclk); + /* + * UART clk must be kept enabled to + * avoid losing received character + */ + if (clk_prepare_enable(msm_port->clk)) + return; + if (clk_prepare(msm_port->pclk)) { + clk_disable_unprepare(msm_port->clk); + return; + } + if (pm_runtime_get_sync(port->dev) < 0) { + clk_unprepare(msm_port->pclk); + clk_disable_unprepare(msm_port->clk); + return; + } break; case 3: + pm_runtime_put(port->dev); + clk_unprepare(msm_port->pclk); clk_disable_unprepare(msm_port->clk); - clk_disable_unprepare(msm_port->pclk); break; default: pr_err("msm_serial: Unknown PM state %d\n", state); @@ -1632,7 +1719,11 @@ static void msm_console_write(struct console *co, const char *s, port = msm_get_port_from_line(co->index); msm_port = UART_TO_MSM(port); + if (pm_runtime_get_sync(port->dev) < 0) + return; __msm_console_write(port, s, count, msm_port->is_uartdm); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); } static int __init msm_console_setup(struct console *co, char *options) @@ -1651,7 +1742,7 @@ static int __init msm_console_setup(struct console *co, char *options) if (unlikely(!port->membase)) return -ENXIO; - msm_init_clock(port); + msm_serial_set_mnd_regs(port); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1794,6 +1885,12 @@ static int msm_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, port); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 500); + pm_runtime_irq_safe(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + return uart_add_one_port(&msm_uart_driver, port); } @@ -1802,6 +1899,7 @@ static int msm_serial_remove(struct platform_device *pdev) struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&msm_uart_driver, port); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1812,12 +1910,67 @@ static const struct of_device_id msm_match_table[] = { {} }; +#ifdef CONFIG_PM +static int msm_serial_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct msm_port *msm_port = UART_TO_MSM(port); + + if (msm_port->is_uartdm) + clk_disable(msm_port->pclk); + + return 0; +} + +static int msm_serial_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct msm_port *msm_port = UART_TO_MSM(port); + int ret; + + if (msm_port->is_uartdm) { + ret = clk_enable(msm_port->pclk); + if (ret) + return ret; + } + + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int msm_serial_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + + uart_suspend_port(&msm_uart_driver, port); + + return 0; +} + +static int msm_serial_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + + uart_resume_port(&msm_uart_driver, port); + + return 0; +} +#endif + +static const struct dev_pm_ops msm_serial_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(msm_serial_suspend, msm_serial_resume) + SET_RUNTIME_PM_OPS(msm_serial_runtime_suspend, + msm_serial_runtime_resume, NULL) +}; + static struct platform_driver msm_platform_driver = { .remove = msm_serial_remove, .probe = msm_serial_probe, .driver = { .name = "msm_serial", .of_match_table = msm_match_table, + .pm = &msm_serial_pm_ops, }, }; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 63a06ab6ba03..51c7507b0444 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -38,6 +38,7 @@ #include <linux/major.h> #include <linux/module.h> #include <linux/mm.h> +#include <linux/notifier.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -115,6 +116,8 @@ struct sci_port { struct timer_list rx_timer; unsigned int rx_timeout; #endif + + struct notifier_block freq_transition; }; #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS @@ -1603,6 +1606,29 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) return ret; } +/* + * Here we define a transition notifier so that we can update all of our + * ports' baud rate when the peripheral clock changes. + */ +static int sci_notifier(struct notifier_block *self, + unsigned long phase, void *p) +{ + struct sci_port *sci_port; + unsigned long flags; + + sci_port = container_of(self, struct sci_port, freq_transition); + + if (phase == CPUFREQ_POSTCHANGE) { + struct uart_port *port = &sci_port->port; + + spin_lock_irqsave(&port->lock, flags); + port->uartclk = clk_get_rate(sci_port->iclk); + spin_unlock_irqrestore(&port->lock, flags); + } + + return NOTIFY_OK; +} + static const struct sci_irq_desc { const char *desc; irq_handler_t handler; @@ -2533,6 +2559,9 @@ static int sci_remove(struct platform_device *dev) { struct sci_port *port = platform_get_drvdata(dev); + cpufreq_unregister_notifier(&port->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); + uart_remove_one_port(&sci_uart_driver, &port->port); sci_cleanup_single(port); @@ -2685,6 +2714,16 @@ static int sci_probe(struct platform_device *dev) if (ret) return ret; + sp->freq_transition.notifier_call = sci_notifier; + + ret = cpufreq_register_notifier(&sp->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); + if (unlikely(ret < 0)) { + uart_remove_one_port(&sci_uart_driver, &sp->port); + sci_cleanup_single(sp); + return ret; + } + #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); #endif diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index b8b580e5ae6e..9eb1cff28bd4 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -74,15 +74,6 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, if (companion->bus != pdev->bus || PCI_SLOT(companion->devfn) != slot) continue; - - /* - * Companion device should be either UHCI,OHCI or EHCI host - * controller, otherwise skip. - */ - if (companion->class != CL_UHCI && companion->class != CL_OHCI && - companion->class != CL_EHCI) - continue; - companion_hcd = pci_get_drvdata(companion); if (!companion_hcd || !companion_hcd->self.root_hub) continue; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 2c26ae1e3eb7..1fb5ce9caf98 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1006,6 +1006,7 @@ struct dwc3 { /* IRQ timing statistics */ int irq; unsigned long irq_cnt; + unsigned long ep_cmd_timeout_cnt; unsigned bh_completion_time[MAX_INTR_STATS]; unsigned bh_handled_evt_cnt[MAX_INTR_STATS]; unsigned bh_dbg_index; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 37a3c954a1dd..8189096f95c2 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1694,7 +1694,7 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event) break; case DWC3_CONTROLLER_RESTART_USB_SESSION: dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESTART_USB_SESSION received\n"); - dwc3_restart_usb_work(&mdwc->restart_usb_work); + schedule_work(&mdwc->restart_usb_work); break; default: dev_dbg(mdwc->dev, "unknown dwc3 event\n"); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index acaa99615d33..d90df256796c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -340,7 +340,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { struct dwc3_ep *dep = dwc->eps[ep]; - u32 timeout = 1500; + u32 timeout = 3000; u32 reg; trace_dwc3_gadget_ep_cmd(dep, cmd, params); @@ -380,6 +380,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, "Command Timed Out"); dev_err(dwc->dev, "%s command timeout for %s\n", dwc3_gadget_ep_cmd_string(cmd), dep->name); + if (!(cmd & DWC3_DEPCMD_ENDTRANSFER)) { + dwc->ep_cmd_timeout_cnt++; + dwc3_notify_event(dwc, + DWC3_CONTROLLER_RESTART_USB_SESSION); + } return -ETIMEDOUT; } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3d17fd93c787..a99405261306 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -27,6 +27,14 @@ #define SSUSB_GADGET_VBUS_DRAW_UNITS 8 #define HSUSB_GADGET_VBUS_DRAW_UNITS 2 +/* + * Based on enumerated USB speed, draw power with set_config and resume + * HSUSB: 500mA, SSUSB: 900mA + */ +#define USB_VBUS_DRAW(speed)\ + (speed == USB_SPEED_SUPER ?\ + SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW) + static bool enable_l1_for_hs; module_param(enable_l1_for_hs, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(enable_l1_for_hs, "Enable support for L1 LPM for HS devices"); @@ -749,7 +757,6 @@ static int set_config(struct usb_composite_dev *cdev, struct usb_gadget *gadget = cdev->gadget; struct usb_configuration *c = NULL; int result = -EINVAL; - unsigned power = gadget_is_otg(gadget) ? 8 : 100; int tmp; /* @@ -863,14 +870,8 @@ static int set_config(struct usb_composite_dev *cdev, } } - /* Allow 900mA to draw with Super-Speed */ - if (gadget->speed == USB_SPEED_SUPER) - power = SSUSB_GADGET_VBUS_DRAW; - else - power = CONFIG_USB_GADGET_VBUS_DRAW; - done: - usb_gadget_vbus_draw(gadget, power); + usb_gadget_vbus_draw(gadget, USB_VBUS_DRAW(gadget->speed)); if (result >= 0 && cdev->delayed_status) result = USB_GADGET_DELAYED_STATUS; return result; @@ -2319,7 +2320,6 @@ void composite_resume(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; - u16 maxpower; int ret; unsigned long flags; @@ -2352,10 +2352,7 @@ void composite_resume(struct usb_gadget *gadget) f->resume(f); } - maxpower = cdev->config->MaxPower; - - usb_gadget_vbus_draw(gadget, maxpower ? - maxpower : CONFIG_USB_GADGET_VBUS_DRAW); + usb_gadget_vbus_draw(gadget, USB_VBUS_DRAW(gadget->speed)); } spin_unlock_irqrestore(&cdev->lock, flags); diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 908cfb33bf99..3908bc151c2b 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -609,8 +609,7 @@ static ssize_t acc_read(struct file *fp, char __user *buf, { struct acc_dev *dev = fp->private_data; struct usb_request *req; - ssize_t r = count; - unsigned xfer; + ssize_t r = count, xfer, len; int ret = 0; pr_debug("acc_read(%zu)\n", count); @@ -623,6 +622,8 @@ static ssize_t acc_read(struct file *fp, char __user *buf, if (count > BULK_BUFFER_SIZE) count = BULK_BUFFER_SIZE; + len = ALIGN(count, dev->ep_out->maxpacket); + /* we will block until we're online */ pr_debug("acc_read: waiting for online\n"); ret = wait_event_interruptible(dev->read_wq, dev->online); @@ -640,7 +641,7 @@ static ssize_t acc_read(struct file *fp, char __user *buf, requeue_req: /* queue a request */ req = dev->rx_req[0]; - req->length = count; + req->length = len; dev->rx_done = 0; ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); if (ret < 0) { @@ -936,6 +937,8 @@ int acc_ctrlrequest(struct usb_composite_dev *cdev, memset(dev->serial, 0, sizeof(dev->serial)); dev->start_requested = 0; dev->audio_mode = 0; + strlcpy(dev->manufacturer, "Android", ACC_STRING_SIZE); + strlcpy(dev->model, "Android", ACC_STRING_SIZE); } } @@ -1239,13 +1242,13 @@ static int acc_setup(void) INIT_DELAYED_WORK(&dev->start_work, acc_start_work); INIT_WORK(&dev->hid_work, acc_hid_work); - /* _acc_dev must be set before calling usb_gadget_register_driver */ - _acc_dev = dev; - ret = misc_register(&acc_device); if (ret) goto err; + /* _acc_dev must be set before calling usb_gadget_register_driver */ + _acc_dev = dev; + return 0; err: diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 78c1ce793b5b..e1302108a917 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -66,6 +66,7 @@ struct cserial { struct usb_request *notify_req; struct usb_cdc_line_coding port_line_coding; u8 pending; + u8 q_again; u8 data_id; u16 serial_state; u16 port_handshake_bits; @@ -538,8 +539,6 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value, } req = port->port_usb.notify_req; - port->port_usb.notify_req = NULL; - port->port_usb.pending = false; req->length = len; notify = req->buf; @@ -559,7 +558,9 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value, if (status < 0) { pr_err("port %s can't notify serial state, %d\n", port->name, status); - port->port_usb.notify_req = req; + spin_lock_irqsave(&port->port_lock, flags); + port->port_usb.pending = false; + spin_unlock_irqrestore(&port->port_lock, flags); } return status; @@ -569,18 +570,24 @@ static int port_notify_serial_state(struct cserial *cser) { struct f_cdev *port = cser_to_port(cser); int status; + unsigned long flags; struct usb_composite_dev *cdev = port->port_usb.func.config->cdev; - if (port->port_usb.notify_req) { + spin_lock_irqsave(&port->port_lock, flags); + if (!port->port_usb.pending) { + port->port_usb.pending = true; + spin_unlock_irqrestore(&port->port_lock, flags); dev_dbg(&cdev->gadget->dev, "port %d serial state %04x\n", port->port_num, port->port_usb.serial_state); status = usb_cser_notify(port, USB_CDC_NOTIFY_SERIAL_STATE, 0, &port->port_usb.serial_state, sizeof(port->port_usb.serial_state)); + spin_lock_irqsave(&port->port_lock, flags); } else { - port->port_usb.pending = true; + port->port_usb.q_again = true; status = 0; } + spin_unlock_irqrestore(&port->port_lock, flags); return status; } @@ -588,14 +595,17 @@ static int port_notify_serial_state(struct cserial *cser) static void usb_cser_notify_complete(struct usb_ep *ep, struct usb_request *req) { struct f_cdev *port = req->context; - u8 doit = false; - - if (req->status != -ESHUTDOWN) - doit = port->port_usb.pending; - port->port_usb.notify_req = req; + unsigned long flags; - if (doit && port->is_connected) + spin_lock_irqsave(&port->port_lock, flags); + port->port_usb.pending = false; + if (req->status != -ESHUTDOWN && port->port_usb.q_again) { + port->port_usb.q_again = false; + spin_unlock_irqrestore(&port->port_lock, flags); port_notify_serial_state(&port->port_usb); + spin_lock_irqsave(&port->port_lock, flags); + } + spin_unlock_irqrestore(&port->port_lock, flags); } static void dun_cser_connect(struct cserial *cser) { @@ -674,8 +684,11 @@ static int dun_cser_send_ctrl_bits(struct cserial *cser, int ctrl_bits) static void usb_cser_free_req(struct usb_ep *ep, struct usb_request *req) { - kfree(req->buf); - usb_ep_free_request(ep, req); + if (req) { + kfree(req->buf); + usb_ep_free_request(ep, req); + req = NULL; + } } static void usb_cser_free_requests(struct usb_ep *ep, struct list_head *head) @@ -820,7 +833,6 @@ static void usb_cser_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req); - port->port_usb.notify_req = NULL; } static int usb_cser_alloc_requests(struct usb_ep *ep, struct list_head *head, @@ -1452,6 +1464,8 @@ int usb_cser_connect(struct f_cdev *port) cser->out->driver_data = port; spin_lock_irqsave(&port->port_lock, flags); + cser->pending = false; + cser->q_again = false; port->is_connected = true; spin_unlock_irqrestore(&port->port_lock, flags); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 278d251d8235..c5fd3ce3ed9a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -710,7 +710,6 @@ static void ffs_user_copy_worker(struct work_struct *work) work); int ret = io_data->req->status ? io_data->req->status : io_data->req->actual; - bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD; ffs_log("enter: ret %d", ret); @@ -724,11 +723,13 @@ static void ffs_user_copy_worker(struct work_struct *work) io_data->kiocb->ki_complete(io_data->kiocb, ret, ret); - if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd) + if (io_data->ffs->ffs_eventfd && + !(io_data->kiocb->ki_flags & IOCB_EVENTFD)) eventfd_signal(io_data->ffs->ffs_eventfd, 1); usb_ep_free_request(io_data->ep, io_data->req); + io_data->kiocb->private = NULL; if (io_data->read) kfree(io_data->to_free); kfree(io_data->buf); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index e32348d17b26..80c9928e948e 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -36,6 +36,7 @@ MODULE_PARM_DESC(num_out_bufs, static struct workqueue_struct *ipa_usb_wq; +static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi, enum gsi_ctrl_notify_state); @@ -553,6 +554,7 @@ static void ipa_work_handler(struct work_struct *w) struct device *dev; struct device *gad_dev; struct f_gsi *gsi; + bool block_db; event = read_event(d_port); @@ -665,7 +667,27 @@ static void ipa_work_handler(struct work_struct *w) } break; case STATE_CONNECTED: - if (event == EVT_DISCONNECTED) { + if (event == EVT_DISCONNECTED || event == EVT_HOST_NRDY) { + if (peek_event(d_port) == EVT_HOST_READY) { + read_event(d_port); + log_event_dbg("%s: NO_OP NRDY_RDY", __func__); + break; + } + + if (event == EVT_HOST_NRDY) { + log_event_dbg("%s: ST_CON_HOST_NRDY\n", + __func__); + block_db = true; + /* stop USB ringing doorbell to GSI(OUT_EP) */ + usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, + GSI_EP_OP_SET_CLR_BLOCK_DBL); + gsi_rndis_ipa_reset_trigger(gsi); + usb_gsi_ep_op(d_port->in_ep, NULL, + GSI_EP_OP_ENDXFER); + usb_gsi_ep_op(d_port->out_ep, NULL, + GSI_EP_OP_ENDXFER); + } + ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; usb_gadget_autopm_put_async(d_port->gadget); @@ -1269,7 +1291,7 @@ static void gsi_rndis_open(struct f_gsi *rndis) rndis_signal_connect(rndis->params); } -void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis) +static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis) { unsigned long flags; @@ -1301,12 +1323,11 @@ void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param) d_port = &rndis->d_port; - if (enable) { - gsi_rndis_ipa_reset_trigger(rndis); - usb_gsi_ep_op(d_port->in_ep, NULL, GSI_EP_OP_ENDXFER); - usb_gsi_ep_op(d_port->out_ep, NULL, GSI_EP_OP_ENDXFER); - post_event(d_port, EVT_DISCONNECTED); + if (enable) { + log_event_dbg("%s: posting HOST_NRDY\n", __func__); + post_event(d_port, EVT_HOST_NRDY); } else { + log_event_dbg("%s: posting HOST_READY\n", __func__); post_event(d_port, EVT_HOST_READY); } @@ -1359,6 +1380,12 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi, return -ENODEV; } + if (atomic_inc_return(&gsi->c_port.notify_count) != 1) { + log_event_dbg("delay ep_queue: notify req is busy %d", + atomic_read(&gsi->c_port.notify_count)); + return 0; + } + event = req->buf; switch (state) { @@ -1414,12 +1441,6 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi, log_event_dbg("send Notify type %02x", event->bNotificationType); - if (atomic_inc_return(&gsi->c_port.notify_count) != 1) { - log_event_dbg("delay ep_queue: notify req is busy %d", - atomic_read(&gsi->c_port.notify_count)); - return 0; - } - return queue_notification_request(gsi); } @@ -1469,7 +1490,8 @@ static void gsi_rndis_response_available(void *_rndis) { struct f_gsi *gsi = _rndis; - gsi_ctrl_send_notification(gsi, GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE); + gsi_ctrl_send_notification(gsi, + GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE); } static void gsi_rndis_command_complete(struct usb_ep *ep, @@ -2056,6 +2078,8 @@ static void gsi_suspend(struct usb_function *f) queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); } + log_event_dbg("%s: notify_count = %d\n", + __func__, atomic_read(&gsi->c_port.notify_count)); log_event_dbg("gsi suspended"); } @@ -2080,6 +2104,21 @@ static void gsi_resume(struct usb_function *f) else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; + if (gsi->c_port.notify && !gsi->c_port.notify->desc) + config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); + + log_event_dbg("%s: notify_count = %d\n", + __func__, atomic_read(&gsi->c_port.notify_count)); + + /* Send notification to host for RMNET, RNDIS and MBIM Interface */ + if ((gsi->prot_id == IPA_USB_MBIM || + gsi->prot_id == IPA_USB_RNDIS || + gsi->prot_id == IPA_USB_RMNET) && + (atomic_read(&gsi->c_port.notify_count) >= 1)) { + log_event_dbg("%s: force_queue\n", __func__); + queue_notification_request(gsi); + } + if (!remote_wakeup_allowed) { /* Configure EPs for GSI */ @@ -2110,11 +2149,6 @@ static void gsi_resume(struct usb_function *f) post_event(&gsi->d_port, EVT_RESUMED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); - - if (gsi->c_port.notify && !gsi->c_port.notify->desc) - config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); - - atomic_set(&gsi->c_port.notify_count, 0); log_event_dbg("%s: completed", __func__); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ac298e632d73..2ac142e3cce9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1923,12 +1923,6 @@ no_bw: kfree(xhci->rh_bw); kfree(xhci->ext_caps); - xhci->usb2_ports = NULL; - xhci->usb3_ports = NULL; - xhci->port_array = NULL; - xhci->rh_bw = NULL; - xhci->ext_caps = NULL; - xhci->page_size = 0; xhci->page_shift = 0; xhci->bus_state[0].bus_suspended = 0; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index ea4fb4b0cd44..6c47c26b5df7 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -48,7 +48,6 @@ #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 -#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 static const char hcd_name[] = "xhci_hcd"; @@ -157,8 +156,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI)) { + pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f20f0b0d26ef..dd7669331d00 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1113,8 +1113,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Resume root hubs only when have pending events. */ status = readl(&xhci->op_regs->status); if (status & STS_EINT) { - usb_hcd_resume_root_hub(xhci->shared_hcd); usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); } } @@ -1129,10 +1129,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Re-enable port polling. */ xhci_dbg(xhci, "%s: starting port polling.\n", __func__); - set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); - usb_hcd_poll_rh_status(xhci->shared_hcd); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); + set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + usb_hcd_poll_rh_status(xhci->shared_hcd); return retval; } diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 23a4ac11af36..b222c3c5f7b4 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -34,12 +34,8 @@ #define QUSB2PHY_PLL_COMMON_STATUS_ONE 0x1A0 #define CORE_READY_STATUS BIT(0) -/* In case Efuse register shows zero, use this value */ -#define TUNE2_DEFAULT_HIGH_NIBBLE 0xB -#define TUNE2_DEFAULT_LOW_NIBBLE 0x3 - -/* Get TUNE2's high nibble value read from efuse */ -#define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask) +/* Get TUNE value from efuse bit-mask */ +#define TUNE_VAL_MASK(val, pos, mask) ((val >> pos) & mask) #define QUSB2PHY_INTR_CTRL 0x22C #define DMSE_INTR_HIGH_SEL BIT(4) @@ -52,7 +48,7 @@ #define DMSE_INTERRUPT BIT(1) #define DPSE_INTERRUPT BIT(0) -#define QUSB2PHY_PORT_TUNE2 0x240 +#define QUSB2PHY_PORT_TUNE1 0x23c #define QUSB2PHY_1P8_VOL_MIN 1800000 /* uV */ #define QUSB2PHY_1P8_VOL_MAX 1800000 /* uV */ @@ -65,14 +61,17 @@ #define LINESTATE_DP BIT(0) #define LINESTATE_DM BIT(1) -unsigned int phy_tune2; -module_param(phy_tune2, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2"); +#define QUSB2PHY_PLL_ANALOG_CONTROLS_ONE 0x0 + +unsigned int phy_tune1; +module_param(phy_tune1, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune1, "QUSB PHY v2 TUNE1"); struct qusb_phy { struct usb_phy phy; void __iomem *base; - void __iomem *tune2_efuse_reg; + void __iomem *efuse_reg; + void __iomem *tcsr_clamp_dig_n; struct clk *ref_clk_src; struct clk *ref_clk; @@ -88,9 +87,9 @@ struct qusb_phy { int host_init_seq_len; int *qusb_phy_host_init_seq; - u32 tune2_val; - int tune2_efuse_bit_pos; - int tune2_efuse_num_of_bits; + u32 tune_val; + int efuse_bit_pos; + int efuse_num_of_bits; bool power_enabled; bool clocks_enabled; @@ -324,40 +323,34 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) return ret; } -static void qusb_phy_get_tune2_param(struct qusb_phy *qphy) +static void qusb_phy_get_tune1_param(struct qusb_phy *qphy) { - u8 num_of_bits; + u8 reg; u32 bit_mask = 1; pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__, - qphy->tune2_efuse_num_of_bits, - qphy->tune2_efuse_bit_pos); + qphy->efuse_num_of_bits, + qphy->efuse_bit_pos); /* get bit mask based on number of bits to use with efuse reg */ - if (qphy->tune2_efuse_num_of_bits) { - num_of_bits = qphy->tune2_efuse_num_of_bits; - bit_mask = (bit_mask << num_of_bits) - 1; - } + bit_mask = (bit_mask << qphy->efuse_num_of_bits) - 1; /* - * Read EFUSE register having TUNE2 parameter's high nibble. - * If efuse register shows value as 0x0, then use default value - * as 0xB as high nibble. Otherwise use efuse register based - * value for this purpose. + * if efuse reg is updated (i.e non-zero) then use it to program + * tune parameters */ - qphy->tune2_val = readl_relaxed(qphy->tune2_efuse_reg); - pr_debug("%s(): bit_mask:%d efuse based tune2 value:%d\n", - __func__, bit_mask, qphy->tune2_val); - - qphy->tune2_val = TUNE2_HIGH_NIBBLE_VAL(qphy->tune2_val, - qphy->tune2_efuse_bit_pos, bit_mask); - - if (!qphy->tune2_val) - qphy->tune2_val = TUNE2_DEFAULT_HIGH_NIBBLE; - - /* Get TUNE2 byte value using high and low nibble value */ - qphy->tune2_val = ((qphy->tune2_val << 0x4) | - TUNE2_DEFAULT_LOW_NIBBLE); + qphy->tune_val = readl_relaxed(qphy->efuse_reg); + pr_debug("%s(): bit_mask:%d efuse based tune1 value:%d\n", + __func__, bit_mask, qphy->tune_val); + + qphy->tune_val = TUNE_VAL_MASK(qphy->tune_val, + qphy->efuse_bit_pos, bit_mask); + reg = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE1); + if (qphy->tune_val) { + reg = reg & 0x0f; + reg |= (qphy->tune_val << 4); + } + qphy->tune_val = reg; } static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, @@ -454,27 +447,22 @@ static int qusb_phy_init(struct usb_phy *phy) if (qphy->qusb_phy_init_seq) qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq, qphy->init_seq_len, 0); - /* - * Check for EFUSE value only if tune2_efuse_reg is available - * and try to read EFUSE value only once i.e. not every USB - * cable connect case. - */ - if (qphy->tune2_efuse_reg) { - if (!qphy->tune2_val) - qusb_phy_get_tune2_param(qphy); + if (qphy->efuse_reg) { + if (!qphy->tune_val) + qusb_phy_get_tune1_param(qphy); - pr_debug("%s(): Programming TUNE2 parameter as:%x\n", __func__, - qphy->tune2_val); - writel_relaxed(qphy->tune2_val, - qphy->base + QUSB2PHY_PORT_TUNE2); + pr_debug("%s(): Programming TUNE1 parameter as:%x\n", __func__, + qphy->tune_val); + writel_relaxed(qphy->tune_val, + qphy->base + QUSB2PHY_PORT_TUNE1); } - /* If phy_tune2 modparam set, override tune2 value */ - if (phy_tune2) { - pr_debug("%s(): (modparam) TUNE2 val:0x%02x\n", - __func__, phy_tune2); - writel_relaxed(phy_tune2, - qphy->base + QUSB2PHY_PORT_TUNE2); + /* If phy_tune1 modparam set, override tune1 value */ + if (phy_tune1) { + pr_debug("%s(): (modparam) TUNE1 val:0x%02x\n", + __func__, phy_tune1); + writel_relaxed(phy_tune1, + qphy->base + QUSB2PHY_PORT_TUNE1); } /* ensure above writes are completed before re-enabling PHY */ @@ -554,6 +542,11 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) /* Bus suspend case */ if (qphy->cable_connected || (qphy->phy.flags & PHY_HOST_MODE)) { + + /* enable clock bypass */ + writel_relaxed(0x90, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); + /* Disable all interrupts */ writel_relaxed(0x00, qphy->base + QUSB2PHY_INTR_CTRL); @@ -584,15 +577,20 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) wmb(); qusb_phy_enable_clocks(qphy, false); } else { /* Cable disconnect case */ - /* Disable all interrupts */ - writel_relaxed(0x00, - qphy->base + QUSB2PHY_INTR_CTRL); - /* Put PHY into non-driving mode */ - writel_relaxed(0x23, - qphy->base + QUSB2PHY_PWR_CTRL1); + clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + usleep_range(100, 150); + clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); - /* Makes sure that above write goes through */ + /* enable clock bypass */ + writel_relaxed(0x90, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); + + writel_relaxed(0x0, qphy->tcsr_clamp_dig_n); + /* + * clamp needs asserted before + * power/clocks can be turned off + */ wmb(); qusb_phy_enable_clocks(qphy, false); @@ -604,6 +602,11 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) if (qphy->cable_connected || (qphy->phy.flags & PHY_HOST_MODE)) { qusb_phy_enable_clocks(qphy, true); + + /* disable clock bypass */ + writel_relaxed(0x80, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); + /* Clear all interrupts on resume */ writel_relaxed(0x00, qphy->base + QUSB2PHY_INTR_CTRL); @@ -611,6 +614,16 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) /* Makes sure that above write goes through */ wmb(); } else { /* Cable connect case */ + writel_relaxed(0x1, qphy->tcsr_clamp_dig_n); + + /* + * clamp needs de-asserted before + * power/clocks can be turned on + */ + wmb(); + + clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + qusb_phy_enable_power(qphy, true, true); qusb_phy_enable_clocks(qphy, true); } @@ -735,23 +748,33 @@ static int qusb_phy_probe(struct platform_device *pdev) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "tune2_efuse_addr"); + "tcsr_clamp_dig_n_1p8"); + if (res) { + qphy->tcsr_clamp_dig_n = devm_ioremap_resource(dev, res); + if (IS_ERR(qphy->tcsr_clamp_dig_n)) { + dev_dbg(dev, "couldn't ioremap tcsr_clamp_dig_n\n"); + return PTR_ERR(qphy->tcsr_clamp_dig_n); + } + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "efuse_addr"); if (res) { - qphy->tune2_efuse_reg = devm_ioremap_nocache(dev, res->start, + qphy->efuse_reg = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!IS_ERR_OR_NULL(qphy->tune2_efuse_reg)) { + if (!IS_ERR_OR_NULL(qphy->efuse_reg)) { ret = of_property_read_u32(dev->of_node, - "qcom,tune2-efuse-bit-pos", - &qphy->tune2_efuse_bit_pos); + "qcom,efuse-bit-pos", + &qphy->efuse_bit_pos); if (!ret) { ret = of_property_read_u32(dev->of_node, - "qcom,tune2-efuse-num-bits", - &qphy->tune2_efuse_num_of_bits); + "qcom,efuse-num-bits", + &qphy->efuse_num_of_bits); } if (ret) { dev_err(dev, - "DT Value for tune2 efuse is invalid.\n"); + "DT Value for efuse is invalid.\n"); return -EINVAL; } } diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 529e4ea76a96..87235a5a4f99 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -89,6 +89,7 @@ struct msm_ssphy_qmp { struct clk *pipe_clk; struct clk *phy_reset; struct clk *phy_phy_reset; + bool power_enabled; bool clk_enabled; bool cable_connected; bool in_suspend; @@ -159,38 +160,47 @@ static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy, } } - -static int msm_ssusb_qmp_config_vdd(struct msm_ssphy_qmp *phy, int high) +static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on) { - int min, ret; + int min, rc = 0; - min = high ? 1 : 0; /* low or none? */ - ret = regulator_set_voltage(phy->vdd, phy->vdd_levels[min], - phy->vdd_levels[2]); - if (ret) { - dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n"); - return ret; - } + dev_dbg(phy->phy.dev, "reg (%s)\n", on ? "HPM" : "LPM"); - dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n", - phy->vdd_levels[min], phy->vdd_levels[2]); - return ret; -} + if (phy->power_enabled == on) { + dev_dbg(phy->phy.dev, "PHYs' regulators status %d\n", + phy->power_enabled); + return 0; + } -static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on) -{ - int rc = 0; + phy->power_enabled = on; - dev_dbg(phy->phy.dev, "reg (%s)\n", on ? "HPM" : "LPM"); + min = on ? 1 : 0; /* low or none? */ if (!on) goto disable_regulators; + rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min], + phy->vdd_levels[2]); + if (rc) { + dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n"); + return rc; + } + + dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n", + phy->vdd_levels[min], phy->vdd_levels[2]); + + rc = regulator_enable(phy->vdd); + if (rc) { + dev_err(phy->phy.dev, + "regulator_enable(phy->vdd) failed, ret=%d", + rc); + goto unconfig_vdd; + } rc = regulator_set_load(phy->core_ldo, USB_SSPHY_HPM_LOAD); if (rc < 0) { dev_err(phy->phy.dev, "Unable to set HPM of core_ldo\n"); - return rc; + goto disable_vdd; } rc = regulator_set_voltage(phy->core_ldo, @@ -226,6 +236,18 @@ put_core_ldo_lpm: if (rc < 0) dev_err(phy->phy.dev, "Unable to set LPM of core_ldo\n"); +disable_vdd: + rc = regulator_disable(phy->vdd); + if (rc) + dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d", + rc); + +unconfig_vdd: + rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min], + phy->vdd_levels[2]); + if (rc) + dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n"); + return rc < 0 ? rc : 0; } @@ -263,6 +285,14 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) if (phy->emulation) return 0; + ret = msm_ssusb_qmp_ldo_enable(phy, 1); + if (ret) { + dev_err(phy->phy.dev, + "msm_ssusb_qmp_ldo_enable(1) failed, ret=%d\n", + ret); + return ret; + } + if (!phy->clk_enabled) { if (phy->ref_clk_src) clk_prepare_enable(phy->ref_clk_src); @@ -408,12 +438,6 @@ static int msm_ssphy_power_enable(struct msm_ssphy_qmp *phy, bool on) */ if (!host && !phy->cable_connected) { if (on) { - ret = regulator_enable(phy->vdd); - if (ret) - dev_err(phy->phy.dev, - "regulator_enable(phy->vdd) failed, ret=%d", - ret); - ret = msm_ssusb_qmp_ldo_enable(phy, 1); if (ret) dev_err(phy->phy.dev, @@ -425,11 +449,6 @@ static int msm_ssphy_power_enable(struct msm_ssphy_qmp *phy, bool on) dev_err(phy->phy.dev, "msm_ssusb_qmp_ldo_enable(0) failed, ret=%d\n", ret); - - ret = regulator_disable(phy->vdd); - if (ret) - dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d", - ret); } } @@ -733,24 +752,6 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) goto err; } - ret = msm_ssusb_qmp_config_vdd(phy, 1); - if (ret) { - dev_err(dev, "ssusb vdd_dig configuration failed\n"); - goto err; - } - - ret = regulator_enable(phy->vdd); - if (ret) { - dev_err(dev, "unable to enable the ssusb vdd_dig\n"); - goto unconfig_ss_vdd; - } - - ret = msm_ssusb_qmp_ldo_enable(phy, 1); - if (ret) { - dev_err(dev, "ssusb vreg enable failed\n"); - goto disable_ss_vdd; - } - phy->ref_clk_src = devm_clk_get(dev, "ref_clk_src"); if (IS_ERR(phy->ref_clk_src)) phy->ref_clk_src = NULL; @@ -772,16 +773,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.type = USB_PHY_TYPE_USB3; ret = usb_add_phy_dev(&phy->phy); - if (ret) - goto disable_ss_ldo; - return 0; -disable_ss_ldo: - msm_ssusb_qmp_ldo_enable(phy, 0); -disable_ss_vdd: - regulator_disable(phy->vdd); -unconfig_ss_vdd: - msm_ssusb_qmp_config_vdd(phy, 0); err: return ret; } @@ -799,8 +791,6 @@ static int msm_ssphy_qmp_remove(struct platform_device *pdev) if (phy->ref_clk_src) clk_disable_unprepare(phy->ref_clk_src); msm_ssusb_qmp_ldo_enable(phy, 0); - regulator_disable(phy->vdd); - msm_ssusb_qmp_config_vdd(phy, 0); clk_disable_unprepare(phy->aux_clk); clk_disable_unprepare(phy->cfg_ahb_clk); clk_disable_unprepare(phy->pipe_clk); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index a2b43a6e7fa7..bdc0f2f24f19 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -108,7 +108,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ - { USB_DEVICE(0x10C4, 0x82F4) }, /* Starizona MicroTouch */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ @@ -118,7 +117,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ - { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ @@ -142,8 +140,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ - { USB_DEVICE(0x12B8, 0xEC60) }, /* Link G4 ECU */ - { USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index e40da7759a0e..facaaf003f19 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -741,17 +741,6 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) if (!(size > 0)) return 0; - if (size > urb->transfer_buffer_length) { - /* should not happen, probably malicious packet */ - if (ud->side == USBIP_STUB) { - usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); - return 0; - } else { - usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); - return -EPIPE; - } - } - ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); if (ret != size) { dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 9868d8a5c1ed..42ea4028cfe1 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2249,6 +2249,7 @@ config XEN_FBDEV_FRONTEND select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC select XEN_XENBUS_FRONTEND default y help diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index d00510029c93..0081725c6b5b 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -209,7 +209,8 @@ static struct fb_videomode known_lcd_panels[] = { .lower_margin = 2, .hsync_len = 0, .vsync_len = 0, - .sync = FB_SYNC_CLK_INVERT, + .sync = FB_SYNC_CLK_INVERT | + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, }, /* Sharp LK043T1DG01 */ [1] = { @@ -223,7 +224,7 @@ static struct fb_videomode known_lcd_panels[] = { .lower_margin = 2, .hsync_len = 41, .vsync_len = 10, - .sync = 0, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .flag = 0, }, [2] = { @@ -238,7 +239,7 @@ static struct fb_videomode known_lcd_panels[] = { .lower_margin = 10, .hsync_len = 10, .vsync_len = 10, - .sync = 0, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .flag = 0, }, [3] = { diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index fe6ce30d0c89..e8d68059581f 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -27,7 +27,6 @@ #include "mdss_dba_utils.h" #define DT_CMD_HDR 6 -#define MIN_REFRESH_RATE 48 #define DEFAULT_MDP_TRANSFER_TIME 14000 #define VSYNC_DELAY msecs_to_jiffies(17) @@ -1907,10 +1906,10 @@ static int mdss_dsi_set_refresh_rate_range(struct device_node *pan_node, __func__, __LINE__); /* - * Since min refresh rate is not specified when dynamic - * fps is enabled, using minimum as 30 + * If min refresh rate is not specified, set it to the + * default panel refresh rate. */ - pinfo->min_fps = MIN_REFRESH_RATE; + pinfo->min_fps = pinfo->mipi.frame_rate; rc = 0; } diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index eb02cad2a634..37081e5e4a0b 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -2971,28 +2971,6 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote) return hpd; } -int msm_hdmi_register_audio_codec(struct platform_device *pdev, - struct msm_ext_disp_audio_codec_ops *ops) -{ - struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev); - int ret = 0; - - if (!hdmi_ctrl || !ops) { - DEV_ERR("%s: invalid input\n", __func__); - return -EPROBE_DEFER; - } - - ret = msm_ext_disp_register_audio_codec(hdmi_ctrl->ext_pdev, ops); - if (ret) { - pr_err("%s: failed to register codec\n", __func__); - goto end; - } - -end: - return ret; -} /* hdmi_tx_audio_register */ -EXPORT_SYMBOL(msm_hdmi_register_audio_codec); - static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl) { u32 rate = 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index f35156a2cfcb..cd842cecc945 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1364,6 +1364,7 @@ static void mdss_mdp_memory_retention_enter(void) } } + __mdss_mdp_reg_access_clk_enable(mdata, true); if (mdss_mdp_clk) { clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM); clk_set_flags(mdss_mdp_clk, CLKFLAG_PERIPH_OFF_SET); @@ -1375,6 +1376,7 @@ static void mdss_mdp_memory_retention_enter(void) clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_SET); clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_NORETAIN_PERIPH); } + __mdss_mdp_reg_access_clk_enable(mdata, false); } static void mdss_mdp_memory_retention_exit(void) @@ -1396,7 +1398,7 @@ static void mdss_mdp_memory_retention_exit(void) } } - + __mdss_mdp_reg_access_clk_enable(mdata, true); if (mdss_mdp_clk) { clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_MEM); clk_set_flags(mdss_mdp_clk, CLKFLAG_RETAIN_PERIPH); @@ -1408,6 +1410,7 @@ static void mdss_mdp_memory_retention_exit(void) clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_RETAIN_PERIPH); clk_set_flags(mdss_mdp_lut_clk, CLKFLAG_PERIPH_OFF_CLEAR); } + __mdss_mdp_reg_access_clk_enable(mdata, false); } /** diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index ed55057e1d7e..abc048866313 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4315,9 +4315,11 @@ void mdss_mdp_check_ctl_reset_status(struct mdss_mdp_ctl *ctl) return; pr_debug("hw ctl reset is set for ctl:%d\n", ctl->num); - status = mdss_mdp_poll_ctl_reset_status(ctl, 5); + /* poll for at least ~1 frame */ + status = mdss_mdp_poll_ctl_reset_status(ctl, 320); if (status) { - pr_err("hw recovery is not complete for ctl:%d\n", ctl->num); + pr_err("hw recovery is not complete for ctl:%d status:0x%x\n", + ctl->num, status); MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt", "dbg_bus", "vbif_dbg_bus", "panic"); } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index cee168a33f85..3aadb3950442 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -411,22 +411,28 @@ static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl, if (test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map)) { struct mdss_panel_data *pdata = ctl->panel_data; - u32 hsync_period = p->hsync_pulse_width + p->h_back_porch + - p->width + p->h_front_porch; - u32 vsync_period = p->vsync_pulse_width + p->v_back_porch + - p->height + p->v_front_porch; - u32 min_fps = pdata->panel_info.min_fps; - u32 diff_fps = abs(pdata->panel_info.default_fps - min_fps); - u32 vtotal = mdss_panel_get_vtotal(&pdata->panel_info); - - int add_porches = mult_frac(vtotal, diff_fps, min_fps); - - u32 vsync_period_slow = vsync_period + add_porches; - u32 avr_vtotal = vsync_period_slow * hsync_period; + struct mdss_panel_info *pinfo = &pdata->panel_info; + u32 avr_vtotal = pinfo->saved_avr_vtotal; + + if (!pinfo->saved_avr_vtotal) { + u32 hsync_period = p->hsync_pulse_width + + p->h_back_porch + p->width + p->h_front_porch; + u32 vsync_period = p->vsync_pulse_width + + p->v_back_porch + p->height + p->v_front_porch; + u32 min_fps = pinfo->min_fps; + u32 default_fps = mdss_panel_get_framerate(pinfo); + u32 diff_fps = abs(default_fps - min_fps); + u32 vtotal = mdss_panel_get_vtotal(pinfo); + int add_porches = mult_frac(vtotal, diff_fps, min_fps); + u32 vsync_period_slow = vsync_period + add_porches; + + avr_vtotal = vsync_period_slow * hsync_period; + pinfo->saved_avr_vtotal = avr_vtotal; + } mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_VTOTAL, avr_vtotal); - MDSS_XLOG(min_fps, vsync_period, vsync_period_slow, avr_vtotal); + MDSS_XLOG(pinfo->min_fps, pinfo->default_fps, avr_vtotal); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 04e3c09e36d7..9dda467e53cc 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -4429,16 +4429,20 @@ static int __mdss_overlay_src_split_sort(struct msm_fb_data_type *mfd, __overlay_swap_func); for (i = 0; i < num_ovs; i++) { + if (ovs[i].z_order >= MDSS_MDP_MAX_STAGE) { + pr_err("invalid stage:%u\n", ovs[i].z_order); + return -EINVAL; + } if (ovs[i].dst_rect.x < left_lm_w) { if (left_lm_zo_cnt[ovs[i].z_order] == 2) { - pr_err("more than 2 ov @ stage%d on left lm\n", + pr_err("more than 2 ov @ stage%u on left lm\n", ovs[i].z_order); return -EINVAL; } left_lm_zo_cnt[ovs[i].z_order]++; } else { if (right_lm_zo_cnt[ovs[i].z_order] == 2) { - pr_err("more than 2 ov @ stage%d on right lm\n", + pr_err("more than 2 ov @ stage%u on right lm\n", ovs[i].z_order); return -EINVAL; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index efd09302de45..ee1cd8fd623e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -2152,7 +2152,7 @@ static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num, bool pa_side_enabled = false; side = pp_num_to_side(ctl, num); - if (side < 0) + if (side < 0 || !pp_sts) return; if (pp_driver_ops.pp_opmode_config) { @@ -2217,7 +2217,7 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer) { u32 ad_flags, flags, dspp_num, opmode = 0, ad_bypass; struct mdp_pgc_lut_data *pgc_config; - struct pp_sts_type *pp_sts; + struct pp_sts_type *pp_sts = NULL; char __iomem *base, *addr = NULL; int ret = 0; struct mdss_data_type *mdata; diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c index 61911810b2c0..97025b3a9c23 100644 --- a/drivers/video/fbdev/msm/mdss_panel.c +++ b/drivers/video/fbdev/msm/mdss_panel.c @@ -644,7 +644,6 @@ void mdss_panel_info_from_timing(struct mdss_panel_timing *pt, pinfo->dsc_enc_total = pt->dsc_enc_total; pinfo->fbc = pt->fbc; pinfo->compression_mode = pt->compression_mode; - pinfo->default_fps = pinfo->mipi.frame_rate; pinfo->roi_alignment = pt->roi_alignment; pinfo->te = pt->te; diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 1137c4475cab..81b6fa7d35b3 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -722,6 +722,9 @@ struct mdss_panel_info { /* debugfs structure for the panel */ struct mdss_panel_debugfs_info *debugfs_info; + + /* stores initial adaptive variable refresh vtotal value */ + u32 saved_avr_vtotal; }; struct mdss_panel_timing { diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index 903cab1ac059..e229f52057d4 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -636,6 +636,12 @@ end: return ret; } +int msm_hdmi_register_audio_codec(struct platform_device *pdev, + struct msm_ext_disp_audio_codec_ops *ops) +{ + return msm_ext_disp_register_audio_codec(pdev, ops); +} + int msm_ext_disp_register_audio_codec(struct platform_device *pdev, struct msm_ext_disp_audio_codec_ops *ops) { diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 364bc44610c1..12eab503efd1 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -152,8 +152,6 @@ static DECLARE_WAIT_QUEUE_HEAD(balloon_wq); static void balloon_process(struct work_struct *work); static DECLARE_DELAYED_WORK(balloon_worker, balloon_process); -static void release_memory_resource(struct resource *resource); - /* When ballooning out (allocating memory to return to Xen) we don't really want the kernel to try too hard since that can trigger the oom killer. */ #define GFP_BALLOON \ @@ -270,20 +268,6 @@ static struct resource *additional_memory_resource(phys_addr_t size) return NULL; } -#ifdef CONFIG_SPARSEMEM - { - unsigned long limit = 1UL << (MAX_PHYSMEM_BITS - PAGE_SHIFT); - unsigned long pfn = res->start >> PAGE_SHIFT; - - if (pfn > limit) { - pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n", - pfn, limit); - release_memory_resource(res); - return NULL; - } - } -#endif - return res; } diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index f4edd6df3df2..38272ad24551 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -316,6 +316,7 @@ static int evtchn_resize_ring(struct per_user_data *u) { unsigned int new_size; evtchn_port_t *new_ring, *old_ring; + unsigned int p, c; /* * Ensure the ring is large enough to capture all possible @@ -345,17 +346,20 @@ static int evtchn_resize_ring(struct per_user_data *u) /* * Copy the old ring contents to the new ring. * - * To take care of wrapping, a full ring, and the new index - * pointing into the second half, simply copy the old contents - * twice. + * If the ring contents crosses the end of the current ring, + * it needs to be copied in two chunks. * * +---------+ +------------------+ - * |34567 12| -> |34567 1234567 12| - * +-----p-c-+ +-------c------p---+ + * |34567 12| -> | 1234567 | + * +-----p-c-+ +------------------+ */ - memcpy(new_ring, old_ring, u->ring_size * sizeof(*u->ring)); - memcpy(new_ring + u->ring_size, old_ring, - u->ring_size * sizeof(*u->ring)); + p = evtchn_ring_offset(u, u->ring_prod); + c = evtchn_ring_offset(u, u->ring_cons); + if (p < c) { + memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring)); + memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring)); + } else + memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring)); u->ring = new_ring; u->ring_size = new_size; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 0f5d05bf2131..b7fcc0de0b2f 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -457,7 +457,7 @@ struct dentry *debugfs_create_automount(const char *name, if (unlikely(!inode)) return failed_creating(dentry); - make_empty_dir_inode(inode); + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; inode->i_flags |= S_AUTOMOUNT; inode->i_private = data; dentry->d_fsdata = (void *)f; diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index 1a0835073663..1acac7fd21b2 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -469,3 +469,59 @@ uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size) return size; return 0; } + +/* + * Validate dentries for encrypted directories to make sure we aren't + * potentially caching stale data after a key has been added or + * removed. + */ +static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct inode *dir = d_inode(dentry->d_parent); + struct ext4_crypt_info *ci = EXT4_I(dir)->i_crypt_info; + int dir_has_key, cached_with_key; + + if (!ext4_encrypted_inode(dir)) + return 0; + + if (ci && ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD)))) + ci = NULL; + + /* this should eventually be an flag in d_flags */ + cached_with_key = dentry->d_fsdata != NULL; + dir_has_key = (ci != NULL); + + /* + * If the dentry was cached without the key, and it is a + * negative dentry, it might be a valid name. We can't check + * if the key has since been made available due to locking + * reasons, so we fail the validation so ext4_lookup() can do + * this check. + * + * We also fail the validation if the dentry was created with + * the key present, but we no longer have the key, or vice versa. + */ + if ((!cached_with_key && d_is_negative(dentry)) || + (!cached_with_key && dir_has_key) || + (cached_with_key && !dir_has_key)) { +#if 0 /* Revalidation debug */ + char buf[80]; + char *cp = simple_dname(dentry, buf, sizeof(buf)); + + if (IS_ERR(cp)) + cp = (char *) "???"; + pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata, + cached_with_key, d_is_negative(dentry), + dir_has_key); +#endif + return 0; + } + return 1; +} + +const struct dentry_operations ext4_encrypted_d_ops = { + .d_revalidate = ext4_d_revalidate, +}; diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 1d1bca74f844..33f5e2a50cf8 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -111,6 +111,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) int dir_has_error = 0; struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; + if (ext4_encrypted_inode(inode)) { + err = ext4_get_encryption_info(inode); + if (err && err != -ENOKEY) + return err; + } + if (is_dx_dir(inode)) { err = ext4_dx_readdir(file, ctx); if (err != ERR_BAD_DX_DIR) { @@ -157,8 +163,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) index, 1); file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; bh = ext4_bread(NULL, inode, map.m_lblk, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); + if (IS_ERR(bh)) { + err = PTR_ERR(bh); + bh = NULL; + goto errout; + } } if (!bh) { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index daad932eeb38..c1b4f6ab2148 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -933,15 +933,6 @@ struct ext4_inode_info { * by other means, so we have i_data_sem. */ struct rw_semaphore i_data_sem; - /* - * i_mmap_sem is for serializing page faults with truncate / punch hole - * operations. We have to make sure that new page cannot be faulted in - * a section of the inode that is being punched. We cannot easily use - * i_data_sem for this since we need protection for the whole punch - * operation and i_data_sem ranks below transaction start so we have - * to occasionally drop it. - */ - struct rw_semaphore i_mmap_sem; struct inode vfs_inode; struct jbd2_inode *jinode; @@ -2267,6 +2258,7 @@ struct page *ext4_encrypt(struct inode *inode, struct page *plaintext_page); int ext4_decrypt(struct page *page); int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex); +extern const struct dentry_operations ext4_encrypted_d_ops; #ifdef CONFIG_EXT4_FS_ENCRYPTION int ext4_init_crypto(void); @@ -2517,7 +2509,6 @@ extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, loff_t lstart, loff_t lend); extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); -extern int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf); extern qsize_t *ext4_get_reserved_space(struct inode *inode); extern void ext4_da_update_reserve_space(struct inode *inode, int used, int quota_claim); @@ -2882,9 +2873,6 @@ static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize) return changed; } -int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, - loff_t len); - struct ext4_group_info { unsigned long bb_state; struct rb_root bb_free_root; @@ -3023,8 +3011,7 @@ extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, struct page *page); extern int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, - struct dentry *dentry, - struct inode *inode); + struct inode *dir, struct inode *inode); extern int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent, struct inode *inode); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 3578b25fccfd..551353b1b17a 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4685,6 +4685,10 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, if (len <= EXT_UNWRITTEN_MAX_LEN) flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + /* * credits to insert 1 extent into extent tree */ @@ -4748,6 +4752,8 @@ retry: goto retry; } + ext4_inode_resume_unlocked_dio(inode); + return ret > 0 ? ret2 : ret; } @@ -4764,6 +4770,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, int partial_begin, partial_end; loff_t start, end; ext4_lblk_t lblk; + struct address_space *mapping = inode->i_mapping; unsigned int blkbits = inode->i_blkbits; trace_ext4_zero_range(inode, offset, len, mode); @@ -4779,6 +4786,17 @@ static long ext4_zero_range(struct file *file, loff_t offset, } /* + * Write out all dirty pages to avoid race conditions + * Then release them. + */ + if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { + ret = filemap_write_and_wait_range(mapping, offset, + offset + len - 1); + if (ret) + return ret; + } + + /* * Round up offset. This is not fallocate, we neet to zero out * blocks, so convert interior block aligned part of the range to * unwritten and possibly manually zero out unaligned parts of the @@ -4821,10 +4839,6 @@ static long ext4_zero_range(struct file *file, loff_t offset, if (mode & FALLOC_FL_KEEP_SIZE) flags |= EXT4_GET_BLOCKS_KEEP_SIZE; - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - /* Preallocate the range including the unaligned edges */ if (partial_begin || partial_end) { ret = ext4_alloc_file_blocks(file, @@ -4833,7 +4847,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, round_down(offset, 1 << blkbits)) >> blkbits, new_size, flags, mode); if (ret) - goto out_dio; + goto out_mutex; } @@ -4842,23 +4856,16 @@ static long ext4_zero_range(struct file *file, loff_t offset, flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE); - /* - * Prevent page faults from reinstantiating pages we have - * released from page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - ret = ext4_update_disksize_before_punch(inode, offset, len); - if (ret) { - up_write(&EXT4_I(inode)->i_mmap_sem); - goto out_dio; - } - /* Now release the pages and zero block aligned part of pages */ + /* Now release the pages and zero block aligned part of pages*/ truncate_pagecache_range(inode, start, end - 1); inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags, mode); - up_write(&EXT4_I(inode)->i_mmap_sem); if (ret) goto out_dio; } @@ -4991,13 +4998,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) goto out; } - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags, mode); - ext4_inode_resume_unlocked_dio(inode); if (ret) goto out; @@ -5492,7 +5494,21 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) return ret; } + /* + * Need to round down offset to be aligned with page size boundary + * for page size > block size. + */ + ioffset = round_down(offset, PAGE_SIZE); + + /* Write out all dirty pages */ + ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, + LLONG_MAX); + if (ret) + return ret; + + /* Take mutex lock */ mutex_lock(&inode->i_mutex); + /* * There is no need to overlap collapse range with EOF, in which case * it is effectively a truncate operation @@ -5508,43 +5524,17 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) goto out_mutex; } + truncate_pagecache(inode, ioffset); + /* Wait for existing dio to complete */ ext4_inode_block_unlocked_dio(inode); inode_dio_wait(inode); - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - /* - * Need to round down offset to be aligned with page size boundary - * for page size > block size. - */ - ioffset = round_down(offset, PAGE_SIZE); - /* - * Write tail of the last page before removed range since it will get - * removed from the page cache below. - */ - ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, offset); - if (ret) - goto out_mmap; - /* - * Write data that will be shifted to preserve them when discarding - * page cache below. We are also protected from pages becoming dirty - * by i_mmap_sem. - */ - ret = filemap_write_and_wait_range(inode->i_mapping, offset + len, - LLONG_MAX); - if (ret) - goto out_mmap; - truncate_pagecache(inode, ioffset); - credits = ext4_writepage_trans_blocks(inode); handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto out_mmap; + goto out_dio; } down_write(&EXT4_I(inode)->i_data_sem); @@ -5583,8 +5573,7 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) out_stop: ext4_journal_stop(handle); -out_mmap: - up_write(&EXT4_I(inode)->i_mmap_sem); +out_dio: ext4_inode_resume_unlocked_dio(inode); out_mutex: mutex_unlock(&inode->i_mutex); @@ -5638,7 +5627,21 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) return ret; } + /* + * Need to round down to align start offset to page size boundary + * for page size > block size. + */ + ioffset = round_down(offset, PAGE_SIZE); + + /* Write out all dirty pages */ + ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, + LLONG_MAX); + if (ret) + return ret; + + /* Take mutex lock */ mutex_lock(&inode->i_mutex); + /* Currently just for extent based files */ if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { ret = -EOPNOTSUPP; @@ -5657,32 +5660,17 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) goto out_mutex; } + truncate_pagecache(inode, ioffset); + /* Wait for existing dio to complete */ ext4_inode_block_unlocked_dio(inode); inode_dio_wait(inode); - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - /* - * Need to round down to align start offset to page size boundary - * for page size > block size. - */ - ioffset = round_down(offset, PAGE_SIZE); - /* Write out all dirty pages */ - ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, - LLONG_MAX); - if (ret) - goto out_mmap; - truncate_pagecache(inode, ioffset); - credits = ext4_writepage_trans_blocks(inode); handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto out_mmap; + goto out_dio; } /* Expand file to avoid data loss if there is error while shifting */ @@ -5753,8 +5741,7 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) out_stop: ext4_journal_stop(handle); -out_mmap: - up_write(&EXT4_I(inode)->i_mmap_sem); +out_dio: ext4_inode_resume_unlocked_dio(inode); out_mutex: mutex_unlock(&inode->i_mutex); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 0d24ebcd7c9e..113837e7ba98 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -209,18 +209,15 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { int result; handle_t *handle = NULL; - struct inode *inode = file_inode(vma->vm_file); - struct super_block *sb = inode->i_sb; + struct super_block *sb = file_inode(vma->vm_file)->i_sb; bool write = vmf->flags & FAULT_FLAG_WRITE; if (write) { sb_start_pagefault(sb); file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, EXT4_DATA_TRANS_BLOCKS(sb)); - } else - down_read(&EXT4_I(inode)->i_mmap_sem); + } if (IS_ERR(handle)) result = VM_FAULT_SIGBUS; @@ -231,10 +228,8 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (write) { if (!IS_ERR(handle)) ext4_journal_stop(handle); - up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(sb); - } else - up_read(&EXT4_I(inode)->i_mmap_sem); + } return result; } @@ -251,12 +246,10 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, if (write) { sb_start_pagefault(sb); file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, ext4_chunk_trans_blocks(inode, PMD_SIZE / PAGE_SIZE)); - } else - down_read(&EXT4_I(inode)->i_mmap_sem); + } if (IS_ERR(handle)) result = VM_FAULT_SIGBUS; @@ -267,71 +260,30 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, if (write) { if (!IS_ERR(handle)) ext4_journal_stop(handle); - up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(sb); - } else - up_read(&EXT4_I(inode)->i_mmap_sem); + } return result; } static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { - int err; - struct inode *inode = file_inode(vma->vm_file); - - sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - err = __dax_mkwrite(vma, vmf, ext4_get_block_dax, - ext4_end_io_unwritten); - up_read(&EXT4_I(inode)->i_mmap_sem); - sb_end_pagefault(inode->i_sb); - - return err; -} - -/* - * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_mkwrite() - * handler we check for races agaist truncate. Note that since we cycle through - * i_mmap_sem, we are sure that also any hole punching that began before we - * were called is finished by now and so if it included part of the file we - * are working on, our pte will get unmapped and the check for pte_same() in - * wp_pfn_shared() fails. Thus fault gets retried and things work out as - * desired. - */ -static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - struct super_block *sb = inode->i_sb; - int ret = VM_FAULT_NOPAGE; - loff_t size; - - sb_start_pagefault(sb); - file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (vmf->pgoff >= size) - ret = VM_FAULT_SIGBUS; - up_read(&EXT4_I(inode)->i_mmap_sem); - sb_end_pagefault(sb); - - return ret; + return dax_mkwrite(vma, vmf, ext4_get_block_dax, + ext4_end_io_unwritten); } static const struct vm_operations_struct ext4_dax_vm_ops = { .fault = ext4_dax_fault, .pmd_fault = ext4_dax_pmd_fault, .page_mkwrite = ext4_dax_mkwrite, - .pfn_mkwrite = ext4_dax_pfn_mkwrite, + .pfn_mkwrite = dax_pfn_mkwrite, }; #else #define ext4_dax_vm_ops ext4_file_vm_ops #endif static const struct vm_operations_struct ext4_file_vm_ops = { - .fault = ext4_filemap_fault, + .fault = filemap_fault, .map_pages = filemap_map_pages, .page_mkwrite = ext4_page_mkwrite, }; diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index d884989cc83d..dfe3b9bafc0d 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -995,12 +995,11 @@ void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh, */ static int ext4_add_dirent_to_inline(handle_t *handle, struct ext4_filename *fname, - struct dentry *dentry, + struct inode *dir, struct inode *inode, struct ext4_iloc *iloc, void *inline_start, int inline_size) { - struct inode *dir = d_inode(dentry->d_parent); int err; struct ext4_dir_entry_2 *de; @@ -1245,12 +1244,11 @@ out: * the new created block. */ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, - struct dentry *dentry, struct inode *inode) + struct inode *dir, struct inode *inode) { int ret, inline_size; void *inline_start; struct ext4_iloc iloc; - struct inode *dir = d_inode(dentry->d_parent); ret = ext4_get_inode_loc(dir, &iloc); if (ret) @@ -1264,7 +1262,7 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, EXT4_INLINE_DOTDOT_SIZE; inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; - ret = ext4_add_dirent_to_inline(handle, fname, dentry, inode, &iloc, + ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, inline_start, inline_size); if (ret != -ENOSPC) goto out; @@ -1285,7 +1283,7 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, if (inline_size) { inline_start = ext4_get_inline_xattr_pos(dir, &iloc); - ret = ext4_add_dirent_to_inline(handle, fname, dentry, + ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, inline_start, inline_size); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index e31d762eedce..06bda0361e7c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3587,35 +3587,6 @@ int ext4_can_truncate(struct inode *inode) } /* - * We have to make sure i_disksize gets properly updated before we truncate - * page cache due to hole punching or zero range. Otherwise i_disksize update - * can get lost as it may have been postponed to submission of writeback but - * that will never happen after we truncate page cache. - */ -int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, - loff_t len) -{ - handle_t *handle; - loff_t size = i_size_read(inode); - - WARN_ON(!mutex_is_locked(&inode->i_mutex)); - if (offset > size || offset + len < size) - return 0; - - if (EXT4_I(inode)->i_disksize >= size) - return 0; - - handle = ext4_journal_start(inode, EXT4_HT_MISC, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ext4_update_i_disksize(inode, size); - ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - - return 0; -} - -/* * ext4_punch_hole: punches a hole in a file by releaseing the blocks * associated with the given offset and length * @@ -3680,26 +3651,17 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) } - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); first_block_offset = round_up(offset, sb->s_blocksize); last_block_offset = round_down((offset + length), sb->s_blocksize) - 1; /* Now release the pages and zero block aligned part of pages*/ - if (last_block_offset > first_block_offset) { - ret = ext4_update_disksize_before_punch(inode, offset, length); - if (ret) - goto out_dio; + if (last_block_offset > first_block_offset) truncate_pagecache_range(inode, first_block_offset, last_block_offset); - } + + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) credits = ext4_writepage_trans_blocks(inode); @@ -3746,12 +3708,16 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) if (IS_SYNC(inode)) ext4_handle_sync(handle); + /* Now release the pages again to reduce race window */ + if (last_block_offset > first_block_offset) + truncate_pagecache_range(inode, first_block_offset, + last_block_offset); + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); out_stop: ext4_journal_stop(handle); out_dio: - up_write(&EXT4_I(inode)->i_mmap_sem); ext4_inode_resume_unlocked_dio(inode); out_mutex: mutex_unlock(&inode->i_mutex); @@ -4885,7 +4851,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) } else ext4_wait_for_tail_page_commit(inode); } - down_write(&EXT4_I(inode)->i_mmap_sem); /* * Truncate pagecache after we've waited for commit * in data=journal mode to make pages freeable. @@ -4893,7 +4858,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) truncate_pagecache(inode, inode->i_size); if (shrink) ext4_truncate(inode); - up_write(&EXT4_I(inode)->i_mmap_sem); } if (!rc) { @@ -5145,8 +5109,6 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) might_sleep(); trace_ext4_mark_inode_dirty(inode, _RET_IP_); err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - return err; if (ext4_handle_valid(handle) && EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) { @@ -5177,7 +5139,9 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) } } } - return ext4_mark_iloc_dirty(handle, inode, &iloc); + if (!err) + err = ext4_mark_iloc_dirty(handle, inode, &iloc); + return err; } /* @@ -5342,8 +5306,6 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); - - down_read(&EXT4_I(inode)->i_mmap_sem); /* Delalloc case is easy... */ if (test_opt(inode->i_sb, DELALLOC) && !ext4_should_journal_data(inode) && @@ -5413,19 +5375,6 @@ retry_alloc: out_ret: ret = block_page_mkwrite_return(ret); out: - up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(inode->i_sb); return ret; } - -int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - int err; - - down_read(&EXT4_I(inode)->i_mmap_sem); - err = filemap_fault(vma, vmf); - up_read(&EXT4_I(inode)->i_mmap_sem); - - return err; -} diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index a969ab39f302..c9aad3b8951f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -273,7 +273,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, struct ext4_filename *fname, struct ext4_dir_entry_2 **res_dir); static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, - struct dentry *dentry, struct inode *inode); + struct inode *dir, struct inode *inode); /* checksumming functions */ void initialize_dirent_tail(struct ext4_dir_entry_tail *t, @@ -1558,6 +1558,24 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi struct ext4_dir_entry_2 *de; struct buffer_head *bh; + if (ext4_encrypted_inode(dir)) { + int res = ext4_get_encryption_info(dir); + + /* + * This should be a properly defined flag for + * dentry->d_flags when we uplift this to the VFS. + * d_fsdata is set to (void *) 1 if if the dentry is + * created while the directory was encrypted and we + * don't have access to the key. + */ + dentry->d_fsdata = NULL; + if (ext4_encryption_info(dir)) + dentry->d_fsdata = (void *) 1; + d_set_d_op(dentry, &ext4_encrypted_d_ops); + if (res && res != -ENOKEY) + return ERR_PTR(res); + } + if (dentry->d_name.len > EXT4_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); @@ -1928,10 +1946,9 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, * directory, and adds the dentry to the indexed directory. */ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, - struct dentry *dentry, + struct inode *dir, struct inode *inode, struct buffer_head *bh) { - struct inode *dir = d_inode(dentry->d_parent); struct buffer_head *bh2; struct dx_root *root; struct dx_frame frames[2], *frame; @@ -2086,8 +2103,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, return retval; if (ext4_has_inline_data(dir)) { - retval = ext4_try_add_inline_entry(handle, &fname, - dentry, inode); + retval = ext4_try_add_inline_entry(handle, &fname, dir, inode); if (retval < 0) goto out; if (retval == 1) { @@ -2097,7 +2113,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, } if (is_dx(dir)) { - retval = ext4_dx_add_entry(handle, &fname, dentry, inode); + retval = ext4_dx_add_entry(handle, &fname, dir, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) goto out; ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); @@ -2119,7 +2135,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, if (blocks == 1 && !dx_fallback && ext4_has_feature_dir_index(sb)) { - retval = make_indexed_dir(handle, &fname, dentry, + retval = make_indexed_dir(handle, &fname, dir, inode, bh); bh = NULL; /* make_indexed_dir releases bh */ goto out; @@ -2154,12 +2170,11 @@ out: * Returns 0 for success, or a negative error value */ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, - struct dentry *dentry, struct inode *inode) + struct inode *dir, struct inode *inode) { struct dx_frame frames[2], *frame; struct dx_entry *entries, *at; struct buffer_head *bh; - struct inode *dir = d_inode(dentry->d_parent); struct super_block *sb = dir->i_sb; struct ext4_dir_entry_2 *de; int err; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 852c26806af2..ba1cf0bf2f81 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -958,7 +958,6 @@ static void init_once(void *foo) INIT_LIST_HEAD(&ei->i_orphan); init_rwsem(&ei->xattr_sem); init_rwsem(&ei->i_data_sem); - init_rwsem(&ei->i_mmap_sem); inode_init_once(&ei->vfs_inode); } diff --git a/fs/ext4/truncate.h b/fs/ext4/truncate.h index c70d06a383e2..011ba6670d99 100644 --- a/fs/ext4/truncate.h +++ b/fs/ext4/truncate.h @@ -10,10 +10,8 @@ */ static inline void ext4_truncate_failed_write(struct inode *inode) { - down_write(&EXT4_I(inode)->i_mmap_sem); truncate_inode_pages(inode->i_mapping, inode->i_size); ext4_truncate(inode); - up_write(&EXT4_I(inode)->i_mmap_sem); } /* diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 6b6b3e751f8c..06fd5f7f993d 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -232,6 +232,27 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) return error; } +static int +__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, + void *end, const char *function, unsigned int line) +{ + struct ext4_xattr_entry *entry = IFIRST(header); + int error = -EFSCORRUPTED; + + if (((void *) header >= end) || + (header->h_magic != le32_to_cpu(EXT4_XATTR_MAGIC))) + goto errout; + error = ext4_xattr_check_names(entry, end, entry); +errout: + if (error) + __ext4_error_inode(inode, function, line, 0, + "corrupted in-inode xattr"); + return error; +} + +#define xattr_check_inode(inode, header, end) \ + __xattr_check_inode((inode), (header), (end), __func__, __LINE__) + static inline int ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size) { @@ -343,7 +364,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, header = IHDR(inode, raw_inode); entry = IFIRST(header); end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = ext4_xattr_check_names(entry, end, entry); + error = xattr_check_inode(inode, header, end); if (error) goto cleanup; error = ext4_xattr_find_entry(&entry, name_index, name, @@ -474,7 +495,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) raw_inode = ext4_raw_inode(&iloc); header = IHDR(inode, raw_inode); end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header)); + error = xattr_check_inode(inode, header, end); if (error) goto cleanup; error = ext4_xattr_list_entries(dentry, IFIRST(header), @@ -990,8 +1011,7 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, is->s.here = is->s.first; is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { - error = ext4_xattr_check_names(IFIRST(header), is->s.end, - IFIRST(header)); + error = xattr_check_inode(inode, header, is->s.end); if (error) return error; /* Find the named attribute. */ @@ -1288,6 +1308,10 @@ retry: last = entry; total_ino = sizeof(struct ext4_xattr_ibody_header); + error = xattr_check_inode(inode, header, end); + if (error) + goto cleanup; + free = ext4_xattr_free_space(last, &min_offs, base, &total_ino); if (free >= new_extra_isize) { entry = IFIRST(header); diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 204659a5f6db..735d7522a3a9 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -203,8 +203,6 @@ int get_rock_ridge_filename(struct iso_directory_record *de, int retnamlen = 0; int truncate = 0; int ret = 0; - char *p; - int len; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; @@ -269,17 +267,12 @@ repeat: rr->u.NM.flags); break; } - len = rr->len - 5; - if (retnamlen + len >= 254) { + if ((strlen(retname) + rr->len - 5) >= 254) { truncate = 1; break; } - p = memchr(rr->u.NM.name, '\0', len); - if (unlikely(p)) - len = p - rr->u.NM.name; - memcpy(retname + retnamlen, rr->u.NM.name, len); - retnamlen += len; - retname[retnamlen] = '\0'; + strncat(retname, rr->u.NM.name, rr->len - 5); + retnamlen += rr->len - 5; break; case SIG('R', 'E'): kfree(rs.buffer); diff --git a/fs/namei.c b/fs/namei.c index 441033da002b..558ea922a515 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2912,10 +2912,22 @@ no_open: dentry = lookup_real(dir, dentry, nd->flags); if (IS_ERR(dentry)) return PTR_ERR(dentry); - } - if (create_error && !dentry->d_inode) { - error = create_error; - goto out; + + if (create_error) { + int open_flag = op->open_flag; + + error = create_error; + if ((open_flag & O_EXCL)) { + if (!dentry->d_inode) + goto out; + } else if (!dentry->d_inode) { + goto out; + } else if ((open_flag & O_TRUNC) && + d_is_reg(dentry)) { + goto out; + } + /* will fail later, go on to get the right error */ + } } looked_up: path->dentry = dentry; @@ -4197,11 +4209,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, bool new_is_dir = false; unsigned max_links = new_dir->i_sb->s_max_links; - /* - * Check source == target. - * On overlayfs need to look at underlying inodes. - */ - if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0)) + if (source == target) return 0; error = may_delete(old_dir, old_dentry, is_dir); diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 2162434728c0..0cdf497c91ef 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -322,90 +322,3 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) brelse(di_bh); return acl; } - -int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl; - int ret; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (ret) - return ret; - ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, - acl, NULL, NULL); - posix_acl_release(acl); - return ret; -} - -/* - * Initialize the ACLs of a new inode. If parent directory has default ACL, - * then clone to new inode. Called from ocfs2_mknod. - */ -int ocfs2_init_acl(handle_t *handle, - struct inode *inode, - struct inode *dir, - struct buffer_head *di_bh, - struct buffer_head *dir_bh, - struct ocfs2_alloc_context *meta_ac, - struct ocfs2_alloc_context *data_ac) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl = NULL; - int ret = 0, ret2; - umode_t mode; - - if (!S_ISLNK(inode->i_mode)) { - if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { - acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, - dir_bh); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) { - mode = inode->i_mode & ~current_umask(); - ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); - if (ret) { - mlog_errno(ret); - goto cleanup; - } - } - } - if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - ret = ocfs2_set_acl(handle, inode, di_bh, - ACL_TYPE_DEFAULT, acl, - meta_ac, data_ac); - if (ret) - goto cleanup; - } - mode = inode->i_mode; - ret = __posix_acl_create(&acl, GFP_NOFS, &mode); - if (ret < 0) - return ret; - - ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); - if (ret2) { - mlog_errno(ret2); - ret = ret2; - goto cleanup; - } - if (ret > 0) { - ret = ocfs2_set_acl(handle, inode, - di_bh, ACL_TYPE_ACCESS, - acl, meta_ac, data_ac); - } - } -cleanup: - posix_acl_release(acl); - return ret; -} diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h index 2783a75b3999..3fce68d08625 100644 --- a/fs/ocfs2/acl.h +++ b/fs/ocfs2/acl.h @@ -35,10 +35,5 @@ int ocfs2_set_acl(handle_t *handle, struct posix_acl *acl, struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *data_ac); -extern int ocfs2_acl_chmod(struct inode *, struct buffer_head *); -extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, - struct buffer_head *, struct buffer_head *, - struct ocfs2_alloc_context *, - struct ocfs2_alloc_context *); #endif /* OCFS2_ACL_H */ diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 77d30cbd944d..0e5b4515f92e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1268,20 +1268,20 @@ bail_unlock_rw: if (size_change) ocfs2_rw_unlock(inode, 1); bail: + brelse(bh); /* Release quota pointers in case we acquired them */ for (qtype = 0; qtype < OCFS2_MAXQUOTAS; qtype++) dqput(transfer_to[qtype]); if (!status && attr->ia_valid & ATTR_MODE) { - status = ocfs2_acl_chmod(inode, bh); + status = posix_acl_chmod(inode, inode->i_mode); if (status < 0) mlog_errno(status); } if (inode_locked) ocfs2_inode_unlock(inode, 1); - brelse(bh); return status; } diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 62af9554541d..3123408da935 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -259,6 +259,7 @@ static int ocfs2_mknod(struct inode *dir, struct ocfs2_dir_lookup_result lookup = { NULL, }; sigset_t oldset; int did_block_signals = 0; + struct posix_acl *default_acl = NULL, *acl = NULL; struct ocfs2_dentry_lock *dl = NULL; trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, @@ -366,6 +367,12 @@ static int ocfs2_mknod(struct inode *dir, goto leave; } + status = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (status) { + mlog_errno(status); + goto leave; + } + handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, S_ISDIR(mode), xattr_credits)); @@ -414,8 +421,16 @@ static int ocfs2_mknod(struct inode *dir, inc_nlink(dir); } - status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh, - meta_ac, data_ac); + if (default_acl) { + status = ocfs2_set_acl(handle, inode, new_fe_bh, + ACL_TYPE_DEFAULT, default_acl, + meta_ac, data_ac); + } + if (!status && acl) { + status = ocfs2_set_acl(handle, inode, new_fe_bh, + ACL_TYPE_ACCESS, acl, + meta_ac, data_ac); + } if (status < 0) { mlog_errno(status); @@ -457,6 +472,10 @@ static int ocfs2_mknod(struct inode *dir, d_instantiate(dentry, inode); status = 0; leave: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); if (status < 0 && did_quota_inode) dquot_free_inode(inode); if (handle) diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 6a0c55d7dff0..252119860e6c 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4248,12 +4248,20 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, struct inode *inode = d_inode(old_dentry); struct buffer_head *old_bh = NULL; struct inode *new_orphan_inode = NULL; + struct posix_acl *default_acl, *acl; + umode_t mode; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) return -EOPNOTSUPP; + mode = inode->i_mode; + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) { + mlog_errno(error); + return error; + } - error = ocfs2_create_inode_in_orphan(dir, inode->i_mode, + error = ocfs2_create_inode_in_orphan(dir, mode, &new_orphan_inode); if (error) { mlog_errno(error); @@ -4292,11 +4300,16 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, /* If the security isn't preserved, we need to re-initialize them. */ if (!preserve) { error = ocfs2_init_security_and_acl(dir, new_orphan_inode, - &new_dentry->d_name); + &new_dentry->d_name, + default_acl, acl); if (error) mlog_errno(error); } out: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); if (!error) { error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode, new_dentry); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 877830b05e12..e9164f09841b 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -7197,10 +7197,12 @@ out: */ int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode, - const struct qstr *qstr) + const struct qstr *qstr, + struct posix_acl *default_acl, + struct posix_acl *acl) { - int ret = 0; struct buffer_head *dir_bh = NULL; + int ret = 0; ret = ocfs2_init_security_get(inode, dir, qstr, NULL); if (ret) { @@ -7213,9 +7215,11 @@ int ocfs2_init_security_and_acl(struct inode *dir, mlog_errno(ret); goto leave; } - ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL); - if (ret) - mlog_errno(ret); + + if (!ret && default_acl) + ret = ocfs2_iop_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + if (!ret && acl) + ret = ocfs2_iop_set_acl(inode, acl, ACL_TYPE_ACCESS); ocfs2_inode_unlock(dir, 0); brelse(dir_bh); diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index 1633cc15ea1f..f10d5b93c366 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h @@ -94,5 +94,7 @@ int ocfs2_reflink_xattrs(struct inode *old_inode, bool preserve_security); int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode, - const struct qstr *qstr); + const struct qstr *qstr, + struct posix_acl *default_acl, + struct posix_acl *acl); #endif /* OCFS2_XATTR_H */ diff --git a/fs/open.c b/fs/open.c index 157b9940dd73..6a24f988d253 100644 --- a/fs/open.c +++ b/fs/open.c @@ -840,12 +840,16 @@ EXPORT_SYMBOL(file_path); int vfs_open(const struct path *path, struct file *file, const struct cred *cred) { - struct inode *inode = vfs_select_inode(path->dentry, file->f_flags); - - if (IS_ERR(inode)) - return PTR_ERR(inode); + struct dentry *dentry = path->dentry; + struct inode *inode = dentry->d_inode; file->f_path = *path; + if (dentry->d_flags & DCACHE_OP_SELECT_INODE) { + inode = dentry->d_op->d_select_inode(dentry, file->f_flags); + if (IS_ERR(inode)) + return PTR_ERR(inode); + } + return do_dentry_open(file, inode, NULL, cred); } diff --git a/fs/pnode.c b/fs/pnode.c index 99899705b105..6367e1e435c6 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -198,15 +198,10 @@ static struct mount *next_group(struct mount *m, struct mount *origin) /* all accesses are serialized by namespace_sem */ static struct user_namespace *user_ns; -static struct mount *last_dest, *first_source, *last_source, *dest_master; +static struct mount *last_dest, *last_source, *dest_master; static struct mountpoint *mp; static struct hlist_head *list; -static inline bool peers(struct mount *m1, struct mount *m2) -{ - return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id; -} - static int propagate_one(struct mount *m) { struct mount *child; @@ -217,26 +212,24 @@ static int propagate_one(struct mount *m) /* skip if mountpoint isn't covered by it */ if (!is_subdir(mp->m_dentry, m->mnt.mnt_root)) return 0; - if (peers(m, last_dest)) { + if (m->mnt_group_id == last_dest->mnt_group_id) { type = CL_MAKE_SHARED; } else { struct mount *n, *p; - bool done; for (n = m; ; n = p) { p = n->mnt_master; - if (p == dest_master || IS_MNT_MARKED(p)) + if (p == dest_master || IS_MNT_MARKED(p)) { + while (last_dest->mnt_master != p) { + last_source = last_source->mnt_master; + last_dest = last_source->mnt_parent; + } + if (n->mnt_group_id != last_dest->mnt_group_id) { + last_source = last_source->mnt_master; + last_dest = last_source->mnt_parent; + } break; + } } - do { - struct mount *parent = last_source->mnt_parent; - if (last_source == first_source) - break; - done = parent->mnt_master == p; - if (done && peers(n, parent)) - break; - last_source = last_source->mnt_master; - } while (!done); - type = CL_SLAVE; /* beginning of peer group among the slaves? */ if (IS_MNT_SHARED(m)) @@ -288,7 +281,6 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, */ user_ns = current->nsproxy->mnt_ns->user_ns; last_dest = dest_mnt; - first_source = source_mnt; last_source = source_mnt; mp = dest_mp; list = tree_list; diff --git a/fs/proc/base.c b/fs/proc/base.c index de2dcc1d1167..98b4b03dfe31 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -954,8 +954,7 @@ static ssize_t environ_read(struct file *file, char __user *buf, int ret = 0; struct mm_struct *mm = file->private_data; - /* Ensure the process spawned far enough to have an environment. */ - if (!mm || !mm->env_end) + if (!mm) return 0; page = (char *)__get_free_page(GFP_TEMPORARY); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index be3003ef2b4e..ee79fadfc6e7 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1731,32 +1731,6 @@ static struct page *can_gather_numa_stats(pte_t pte, struct vm_area_struct *vma, return page; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static struct page *can_gather_numa_stats_pmd(pmd_t pmd, - struct vm_area_struct *vma, - unsigned long addr) -{ - struct page *page; - int nid; - - if (!pmd_present(pmd)) - return NULL; - - page = vm_normal_page_pmd(vma, addr, pmd); - if (!page) - return NULL; - - if (PageReserved(page)) - return NULL; - - nid = page_to_nid(page); - if (!node_isset(nid, node_states[N_MEMORY])) - return NULL; - - return page; -} -#endif - static int gather_pte_stats(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { @@ -1766,13 +1740,13 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, pte_t *orig_pte; pte_t *pte; -#ifdef CONFIG_TRANSPARENT_HUGEPAGE if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { + pte_t huge_pte = *(pte_t *)pmd; struct page *page; - page = can_gather_numa_stats_pmd(*pmd, vma, addr); + page = can_gather_numa_stats(huge_pte, vma, addr); if (page) - gather_stats(page, md, pmd_dirty(*pmd), + gather_stats(page, md, pte_dirty(huge_pte), HPAGE_PMD_SIZE/PAGE_SIZE); spin_unlock(ptl); return 0; @@ -1780,7 +1754,6 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, if (pmd_trans_unstable(pmd)) return 0; -#endif orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); do { struct page *page = can_gather_numa_stats(*pte, vma, addr); diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h index 827e4d3bbc7a..1cbb8338edf3 100644 --- a/include/asm-generic/fixmap.h +++ b/include/asm-generic/fixmap.h @@ -70,12 +70,12 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr) #endif /* Return a pointer with offset calculated */ -#define __set_fixmap_offset(idx, phys, flags) \ -({ \ - unsigned long ________addr; \ - __set_fixmap(idx, phys, flags); \ - ________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \ - ________addr; \ +#define __set_fixmap_offset(idx, phys, flags) \ +({ \ + unsigned long addr; \ + __set_fixmap(idx, phys, flags); \ + addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \ + addr; \ }) #define set_fixmap_offset(idx, phys) \ diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index bf2d34c9d804..e56272c919b5 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h @@ -108,15 +108,11 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 val; preempt_disable(); - if (unlikely(get_user(val, uaddr) != 0)) { - preempt_enable(); + if (unlikely(get_user(val, uaddr) != 0)) return -EFAULT; - } - if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { - preempt_enable(); + if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) return -EFAULT; - } *uval = val; preempt_enable(); diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h index cebecff536a3..461a0558bca4 100644 --- a/include/drm/drm_cache.h +++ b/include/drm/drm_cache.h @@ -39,8 +39,6 @@ static inline bool drm_arch_can_wc_memory(void) { #if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) return false; -#elif defined(CONFIG_MIPS) && defined(CONFIG_CPU_LOONGSON3) - return false; #else return true; #endif diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h index b411a0be4e67..f366d526c138 100644 --- a/include/dt-bindings/clock/msm-clocks-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-cobalt.h @@ -500,4 +500,23 @@ #define clk_audio_pmi_clk 0xcbfe416d #define clk_audio_ap_clk2 0x454d1e91 +/* GCC block resets */ +#define QUSB2PHY_PRIM_BCR 0 +#define QUSB2PHY_SEC_BCR 1 +#define BLSP1_BCR 2 +#define BLSP2_BCR 3 +#define BOOT_ROM_BCR 4 +#define PRNG_BCR 5 +#define UFS_BCR 6 +#define USB_30_BCR 7 +#define USB3_PHY_BCR 8 +#define USB3PHY_PHY_BCR 9 +#define PCIE_0_PHY_BCR 10 +#define PCIE_PHY_BCR 11 +#define PCIE_PHY_COM_BCR 12 +#define PCIE_PHY_NOCSR_COM_PHY_BCR 13 + +/* MMSS block resets */ +#define CAMSS_MICRO_BCR 0 + #endif diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 67bc2da5d233..83d1926c61e4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -165,13 +165,12 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl); void bpf_register_map_type(struct bpf_map_type_list *tl); struct bpf_prog *bpf_prog_get(u32 ufd); -struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog); void bpf_prog_put(struct bpf_prog *prog); void bpf_prog_put_rcu(struct bpf_prog *prog); struct bpf_map *bpf_map_get_with_uref(u32 ufd); struct bpf_map *__bpf_map_get(struct fd f); -struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref); +void bpf_map_inc(struct bpf_map *map, bool uref); void bpf_map_put_with_uref(struct bpf_map *map); void bpf_map_put(struct bpf_map *map); diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 788c7c49a673..e63d3a513e67 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -435,7 +435,6 @@ struct cgroup_subsys { int (*can_attach)(struct cgroup_taskset *tset); void (*cancel_attach)(struct cgroup_taskset *tset); void (*attach)(struct cgroup_taskset *tset); - void (*post_attach)(void); int (*can_fork)(struct task_struct *task, void **priv_p); void (*cancel_fork)(struct task_struct *task, void *priv); void (*fork)(struct task_struct *task, void *priv); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 8d5915f78935..23026ba6ff25 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -387,7 +387,6 @@ struct clk_divider { #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) extern const struct clk_ops clk_divider_ops; -extern const struct clk_ops clk_divider_ro_ops; unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned int val, const struct clk_div_table *table, diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 85a868ccb493..fea160ee5803 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -137,6 +137,8 @@ static inline void set_mems_allowed(nodemask_t nodemask) task_unlock(current); } +extern void cpuset_post_attach_flush(void); + #else /* !CONFIG_CPUSETS */ static inline bool cpusets_enabled(void) { return false; } @@ -243,6 +245,10 @@ static inline bool read_mems_allowed_retry(unsigned int seq) return false; } +static inline void cpuset_post_attach_flush(void) +{ +} + #endif /* !CONFIG_CPUSETS */ #endif /* _LINUX_CPUSET_H */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index d81746d3b2da..f513dd855cb2 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -592,16 +592,4 @@ static inline struct dentry *d_real(struct dentry *dentry) return dentry; } -static inline struct inode *vfs_select_inode(struct dentry *dentry, - unsigned open_flags) -{ - struct inode *inode = d_inode(dentry); - - if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE)) - inode = dentry->d_op->d_select_inode(dentry, open_flags); - - return inode; -} - - #endif /* __LINUX_DCACHE_H */ diff --git a/include/linux/efi.h b/include/linux/efi.h index 333d0ca6940f..47be3ad7d3e5 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -299,7 +299,7 @@ typedef struct { void *open_protocol_information; void *protocols_per_handle; void *locate_handle_buffer; - efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **); + void *locate_protocol; void *install_multiple_protocol_interfaces; void *uninstall_multiple_protocol_interfaces; void *calculate_crc32; @@ -599,10 +599,6 @@ void efi_native_runtime_setup(void); #define EFI_PROPERTIES_TABLE_GUID \ EFI_GUID( 0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 ) -#define EFI_RNG_PROTOCOL_GUID \ - EFI_GUID(0x3152bca5, 0xeade, 0x433d, \ - 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) - typedef struct { efi_guid_t guid; u64 table; diff --git a/include/linux/hash.h b/include/linux/hash.h index a75b1009d3f7..d0494c399392 100644 --- a/include/linux/hash.h +++ b/include/linux/hash.h @@ -33,28 +33,12 @@ #error Wordsize not 32 or 64 #endif -/* - * The above primes are actively bad for hashing, since they are - * too sparse. The 32-bit one is mostly ok, the 64-bit one causes - * real problems. Besides, the "prime" part is pointless for the - * multiplicative hash. - * - * Although a random odd number will do, it turns out that the golden - * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice - * properties. - * - * These are the negative, (1 - phi) = (phi^2) = (3 - sqrt(5))/2. - * (See Knuth vol 3, section 6.4, exercise 9.) - */ -#define GOLDEN_RATIO_32 0x61C88647 -#define GOLDEN_RATIO_64 0x61C8864680B583EBull - static __always_inline u64 hash_64(u64 val, unsigned int bits) { u64 hash = val; -#if BITS_PER_LONG == 64 - hash = hash * GOLDEN_RATIO_64; +#if defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64 + hash = hash * GOLDEN_RATIO_PRIME_64; #else /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ u64 n = hash; diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index b0eb06423d5e..685c262e0be8 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -96,7 +96,9 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm, struct address_space *mapping, pgoff_t idx, unsigned long address); +#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud); +#endif extern int hugepages_treat_as_movable; extern int sysctl_hugetlb_shm_group; diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h index bd37af71fe0d..ad95957d9189 100644 --- a/include/linux/input/ft5x06_ts.h +++ b/include/linux/input/ft5x06_ts.h @@ -34,11 +34,11 @@ struct fw_upgrade_info { u16 delay_erase_flash; }; -struct ft5x06_psensor_platform_data { - struct input_dev *input_psensor_dev; - struct sensors_classdev ps_cdev; - int tp_psensor_opened; - char tp_psensor_data; /* 0 near, 1 far */ +struct ft5x06_gesture_platform_data { + int gesture_enable_to_set; /* enable/disable gesture */ + int in_pocket; /* whether in pocket mode or not */ + struct device *dev; + struct class *gesture_class; struct ft5x06_ts_data *data; }; @@ -68,7 +68,8 @@ struct ft5x06_ts_platform_data { bool no_force_update; bool i2c_pull_up; bool ignore_id_check; - bool psensor_support; + bool gesture_support; + bool resume_in_workqueue; int (*power_init)(bool); int (*power_on)(bool); }; diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h index 2c14eeca46f0..b288965e8101 100644 --- a/include/linux/mfd/samsung/s2mps11.h +++ b/include/linux/mfd/samsung/s2mps11.h @@ -173,12 +173,10 @@ enum s2mps11_regulators { #define S2MPS11_LDO_VSEL_MASK 0x3F #define S2MPS11_BUCK_VSEL_MASK 0xFF -#define S2MPS11_BUCK9_VSEL_MASK 0x1F #define S2MPS11_ENABLE_MASK (0x03 << S2MPS11_ENABLE_SHIFT) #define S2MPS11_ENABLE_SHIFT 0x06 #define S2MPS11_LDO_N_VOLTAGES (S2MPS11_LDO_VSEL_MASK + 1) #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1) -#define S2MPS11_BUCK9_N_VOLTAGES (S2MPS11_BUCK9_VSEL_MASK + 1) #define S2MPS11_RAMP_DELAY 25000 /* uV/us */ #define S2MPS11_CTRL1_PWRHOLD_MASK BIT(4) diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index 75908dfa8d64..f595275e9d42 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -204,6 +204,7 @@ struct wcd9xxx_core_resource { void *parent; struct device *dev; + struct irq_domain *domain; }; /* diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index a91b67b18a73..0b473cbfa7ef 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -334,17 +334,6 @@ enum { MLX5_CAP_OFF_CMDIF_CSUM = 46, }; -enum { - /* - * Max wqe size for rdma read is 512 bytes, so this - * limits our max_sge_rd as the wqe needs to fit: - * - ctrl segment (16 bytes) - * - rdma segment (16 bytes) - * - scatter elements (16 bytes each) - */ - MLX5_MAX_SGE_RD = (512 - 16 - 16) / 16 -}; - struct mlx5_inbox_hdr { __be16 opcode; u8 rsvd[4]; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 412aa988c6ad..af3efd9157f0 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -792,9 +792,9 @@ int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, enum mlx5_port_status *status); -int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port); -void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, u8 port); -void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu, +int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port); +void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, u8 port); +void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu, u8 port); int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, diff --git a/include/linux/mm.h b/include/linux/mm.h index 57a44fa9ab89..cbe9b794c714 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1097,8 +1097,6 @@ struct zap_details { struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte); -struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr, - pmd_t pmd); int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, unsigned long size); diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h index 54c99d9cb245..873a778d5370 100644 --- a/include/linux/msm_ext_display.h +++ b/include/linux/msm_ext_display.h @@ -133,58 +133,17 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, struct msm_ext_disp_audio_codec_ops *ops); /* + * msm_hdmi_register_audio_codec() - wrapper for hdmi audio codec registration + * @pdev: platform device pointer + * @codec_ops: audio codec operations + */ +int msm_hdmi_register_audio_codec(struct platform_device *pdev, + struct msm_ext_disp_audio_codec_ops *ops); +/* * msm_ext_disp_register_intf() - display interface registration * @init_data: data needed to register the display interface */ int msm_ext_disp_register_intf(struct platform_device *pdev, struct msm_ext_disp_init_data *init_data); -/* TODO: remove all the display specific functions below */ -#ifdef CONFIG_FB_MSM_MDSS_DP_PANEL -int msm_dp_register_audio_codec(struct platform_device *pdev, - struct msm_ext_disp_audio_codec_ops *ops); - -#else -static inline int msm_dp_register_audio_codec(struct platform_device *pdev, - struct msm_ext_disp_audio_codec_ops *ops) { - return 0; -} -#endif /* CONFIG_FB_MSM_MDSS_DP_PANEL */ -#ifdef CONFIG_FB_MSM_MDSS_HDMI_PANEL -/* - * Register for HDMI cable connect or disconnect notification. - * @param handler callback handler for notification - * @return negative value as error otherwise current status of cable - */ -int register_hdmi_cable_notification( - struct ext_disp_cable_notify *handler); - -/* - * Un-register for HDMI cable connect or disconnect notification. - * @param handler callback handler for notification - * @return negative value as error - */ -int unregister_hdmi_cable_notification( - struct ext_disp_cable_notify *handler); - -int msm_hdmi_register_audio_codec(struct platform_device *pdev, - struct msm_ext_disp_audio_codec_ops *ops); - -#else -static inline int register_hdmi_cable_notification( - struct ext_disp_cable_notify *handler) { - return 0; -} - -static inline int unregister_hdmi_cable_notification( - struct ext_disp_cable_notify *handler) { - return 0; -} - -static inline int msm_hdmi_register_audio_codec(struct platform_device *pdev, - struct msm_ext_disp_audio_codec_ops *ops) { - return 0; -} -#endif /* CONFIG_FB_MSM_MDSS_HDMI_PANEL */ - #endif /*_MSM_EXT_DISPLAY_H_*/ diff --git a/include/linux/net.h b/include/linux/net.h index 25ef630f1bd6..0b4ac7da583a 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -245,15 +245,7 @@ do { \ net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__) #define net_info_ratelimited(fmt, ...) \ net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__) -#if defined(CONFIG_DYNAMIC_DEBUG) -#define net_dbg_ratelimited(fmt, ...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \ - net_ratelimit()) \ - __dynamic_pr_debug(&descriptor, fmt, ##__VA_ARGS__); \ -} while (0) -#elif defined(DEBUG) +#if defined(DEBUG) #define net_dbg_ratelimited(fmt, ...) \ net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__) #else diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 56e78254286e..03853d956b41 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -176,6 +176,8 @@ enum power_supply_property { POWER_SUPPLY_PROP_USB_OTG, POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED, POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_STEP_CHARGING_STEP, POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, diff --git a/include/linux/qpnp/qpnp-haptic.h b/include/linux/qpnp/qpnp-haptic.h index 92a66e844f94..95e514a513e2 100644 --- a/include/linux/qpnp/qpnp-haptic.h +++ b/include/linux/qpnp/qpnp-haptic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,12 +10,13 @@ * GNU General Public License for more details. */ #ifndef __QPNP_HAPTIC_H +#define __QPNP_HAPTIC_H /* interface for the other module to play different sequences */ #ifdef CONFIG_QPNP_HAPTIC int qpnp_hap_play_byte(u8 data, bool on); #else -int qpnp_hap_play_byte(u8 data, bool on); +static inline int qpnp_hap_play_byte(u8 data, bool on) { return 0; } diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h new file mode 100644 index 000000000000..22888b0f2ca6 --- /dev/null +++ b/include/media/radio-iris.h @@ -0,0 +1,322 @@ +/* + * + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * This file is based on include/net/bluetooth/hci_core.h + * + * Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + * SOFTWARE IS DISCLAIMED. + */ + +#ifndef __RADIO_IRIS_H +#define __RADIO_IRIS_H + +#include <uapi/media/radio-iris.h> + +#include <linux/skbuff.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/atomic.h> + +struct radio_hci_dev { + char name[8]; + unsigned long flags; + __u16 id; + __u8 bus; + __u8 dev_type; + __u8 dev_name[248]; + __u8 dev_class[3]; + __u8 features[8]; + __u8 commands[64]; + + unsigned int data_block_len; + unsigned long cmd_last_tx; + + struct sk_buff *sent_cmd; + + __u32 req_status; + __u32 req_result; + atomic_t cmd_cnt; + + struct tasklet_struct cmd_task; + struct tasklet_struct rx_task; + struct tasklet_struct tx_task; + + struct sk_buff_head rx_q; + struct sk_buff_head raw_q; + struct sk_buff_head cmd_q; + + struct mutex req_lock; + wait_queue_head_t req_wait_q; + + int (*open)(struct radio_hci_dev *hdev); + int (*close)(struct radio_hci_dev *hdev); + int (*flush)(struct radio_hci_dev *hdev); + int (*send)(struct sk_buff *skb); + void (*destruct)(struct radio_hci_dev *hdev); + void (*notify)(struct radio_hci_dev *hdev, unsigned int evt); + void (*close_smd)(void); +}; + +int radio_hci_register_dev(struct radio_hci_dev *hdev); +int radio_hci_unregister_dev(struct radio_hci_dev *hdev); +int radio_hci_recv_frame(struct sk_buff *skb); +int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen, + void *param); +void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb); + +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) + +#undef FMDBG +#ifdef FM_DEBUG +#define FMDBG(fmt, args...) pr_info("iris_radio: " fmt, ##args) +#else +#define FMDBG(fmt, args...) +#endif + +#undef FMDERR +#define FMDERR(fmt, args...) pr_err("iris_radio: " fmt, ##args) + +/* HCI timeouts */ +#define RADIO_HCI_TIMEOUT (10000) /* 10 seconds */ + +int hci_def_data_read(struct hci_fm_def_data_rd_req *arg, + struct radio_hci_dev *hdev); +int hci_def_data_write(struct hci_fm_def_data_wr_req *arg, + struct radio_hci_dev *hdev); +int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev); +int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev); + +static inline int is_valid_tone(int tone) +{ + if ((tone >= MIN_TX_TONE_VAL) && + (tone <= MAX_TX_TONE_VAL)) + return 1; + else + return 0; +} + +static inline int is_valid_hard_mute(int hard_mute) +{ + if ((hard_mute >= MIN_HARD_MUTE_VAL) && + (hard_mute <= MAX_HARD_MUTE_VAL)) + return 1; + else + return 0; +} + +static inline int is_valid_srch_mode(int srch_mode) +{ + if ((srch_mode >= MIN_SRCH_MODE) && + (srch_mode <= MAX_SRCH_MODE)) + return 1; + else + return 0; +} + +static inline int is_valid_scan_dwell_prd(int scan_dwell_prd) +{ + if ((scan_dwell_prd >= MIN_SCAN_DWELL) && + (scan_dwell_prd <= MAX_SCAN_DWELL)) + return 1; + else + return 0; +} + +static inline int is_valid_sig_th(int sig_th) +{ + if ((sig_th >= MIN_SIG_TH) && + (sig_th <= MAX_SIG_TH)) + return 1; + else + return 0; +} + +static inline int is_valid_pty(int pty) +{ + if ((pty >= MIN_PTY) && + (pty <= MAX_PTY)) + return 1; + else + return 0; +} + +static inline int is_valid_pi(int pi) +{ + if ((pi >= MIN_PI) && + (pi <= MAX_PI)) + return 1; + else + return 0; +} + +static inline int is_valid_srch_station_cnt(int cnt) +{ + if ((cnt >= MIN_SRCH_STATIONS_CNT) && + (cnt <= MAX_SRCH_STATIONS_CNT)) + return 1; + else + return 0; +} + +static inline int is_valid_chan_spacing(int spacing) +{ + if ((spacing >= MIN_CHAN_SPACING) && + (spacing <= MAX_CHAN_SPACING)) + return 1; + else + return 0; +} + +static inline int is_valid_emphasis(int emphasis) +{ + if ((emphasis >= MIN_EMPHASIS) && + (emphasis <= MAX_EMPHASIS)) + return 1; + else + return 0; +} + +static inline int is_valid_rds_std(int rds_std) +{ + if ((rds_std >= MIN_RDS_STD) && + (rds_std <= MAX_RDS_STD)) + return 1; + else + return 0; +} + +static inline int is_valid_antenna(int antenna_type) +{ + if ((antenna_type >= MIN_ANTENNA_VAL) && + (antenna_type <= MAX_ANTENNA_VAL)) + return 1; + else + return 0; +} + +static inline int is_valid_ps_repeat_cnt(int cnt) +{ + if ((cnt >= MIN_TX_PS_REPEAT_CNT) && + (cnt <= MAX_TX_PS_REPEAT_CNT)) + return 1; + else + return 0; +} + +static inline int is_valid_soft_mute(int soft_mute) +{ + if ((soft_mute >= MIN_SOFT_MUTE) && + (soft_mute <= MAX_SOFT_MUTE)) + return 1; + else + return 0; +} + +static inline int is_valid_peek_len(int len) +{ + if ((len >= MIN_PEEK_ACCESS_LEN) && + (len <= MAX_PEEK_ACCESS_LEN)) + return 1; + else + return 0; +} + +static inline int is_valid_reset_cntr(int cntr) +{ + if ((cntr >= MIN_RESET_CNTR) && + (cntr <= MAX_RESET_CNTR)) + return 1; + else + return 0; +} + +static inline int is_valid_hlsi(int hlsi) +{ + if ((hlsi >= MIN_HLSI) && + (hlsi <= MAX_HLSI)) + return 1; + else + return 0; +} + +static inline int is_valid_notch_filter(int filter) +{ + if ((filter >= MIN_NOTCH_FILTER) && + (filter <= MAX_NOTCH_FILTER)) + return 1; + else + return 0; +} + +static inline int is_valid_intf_det_low_th(int th) +{ + if ((th >= MIN_INTF_DET_OUT_LW_TH) && + (th <= MAX_INTF_DET_OUT_LW_TH)) + return 1; + else + return 0; +} + +static inline int is_valid_intf_det_hgh_th(int th) +{ + if ((th >= MIN_INTF_DET_OUT_HG_TH) && + (th <= MAX_INTF_DET_OUT_HG_TH)) + return 1; + else + return 0; +} + +static inline int is_valid_sinr_th(int th) +{ + if ((th >= MIN_SINR_TH) && + (th <= MAX_SINR_TH)) + return 1; + else + return 0; +} + +static inline int is_valid_sinr_samples(int samples_cnt) +{ + if ((samples_cnt >= MIN_SINR_SAMPLES) && + (samples_cnt <= MAX_SINR_SAMPLES)) + return 1; + else + return 0; +} + +static inline int is_valid_fm_state(int state) +{ + if ((state >= 0) && (state < FM_MAX_NO_STATES)) + return 1; + else + return 0; +} + +static inline int is_valid_blend_value(int val) +{ + if ((val >= MIN_BLEND_HI) && (val <= MAX_BLEND_HI)) + return 1; + else + return 0; +} + +#endif + diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 7d250f14d032..4984d372b04b 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -363,7 +363,6 @@ struct vb2_ops { }; struct vb2_buf_ops { - int (*verify_planes_array)(struct vb2_buffer *vb, const void *pb); int (*fill_user_buffer)(struct vb2_buffer *vb, void *pb); int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb, struct vb2_plane *planes); diff --git a/include/net/codel.h b/include/net/codel.h index d168aca115cc..267e70210061 100644 --- a/include/net/codel.h +++ b/include/net/codel.h @@ -162,14 +162,12 @@ struct codel_vars { * struct codel_stats - contains codel shared variables and stats * @maxpacket: largest packet we've seen so far * @drop_count: temp count of dropped packets in dequeue() - * @drop_len: bytes of dropped packets in dequeue() * ecn_mark: number of packets we ECN marked instead of dropping * ce_mark: number of packets CE marked because sojourn time was above ce_threshold */ struct codel_stats { u32 maxpacket; u32 drop_count; - u32 drop_len; u32 ecn_mark; u32 ce_mark; }; @@ -310,7 +308,6 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, vars->rec_inv_sqrt); goto end; } - stats->drop_len += qdisc_pkt_len(skb); qdisc_drop(skb, sch); stats->drop_count++; skb = dequeue_func(vars, sch); @@ -333,7 +330,6 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, if (params->ecn && INET_ECN_set_ce(skb)) { stats->ecn_mark++; } else { - stats->drop_len += qdisc_pkt_len(skb); qdisc_drop(skb, sch); stats->drop_count++; diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index a6cc576fd467..0816c872b689 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -1588,23 +1588,6 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp) } #endif /* CONFIG_IP_VS_NFCT */ -/* Really using conntrack? */ -static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp, - struct sk_buff *skb) -{ -#ifdef CONFIG_IP_VS_NFCT - enum ip_conntrack_info ctinfo; - struct nf_conn *ct; - - if (!(cp->flags & IP_VS_CONN_F_NFCT)) - return false; - ct = nf_ct_get(skb, &ctinfo); - if (ct && !nf_ct_is_untracked(ct)) - return true; -#endif - return false; -} - static inline int ip_vs_dest_conn_overhead(struct ip_vs_dest *dest) { diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 86df0835f6b5..b2a8e6338576 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -396,8 +396,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, struct Qdisc *qdisc); void qdisc_reset(struct Qdisc *qdisc); void qdisc_destroy(struct Qdisc *qdisc); -void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n, - unsigned int len); +void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n); struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, const struct Qdisc_ops *ops); struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, @@ -699,23 +698,6 @@ static inline void qdisc_reset_queue(struct Qdisc *sch) sch->qstats.backlog = 0; } -static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new, - struct Qdisc **pold) -{ - struct Qdisc *old; - - sch_tree_lock(sch); - old = *pold; - *pold = new; - if (old != NULL) { - qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog); - qdisc_reset(old); - } - sch_tree_unlock(sch); - - return old; -} - static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch, struct sk_buff_head *list) { diff --git a/include/rdma/ib.h b/include/rdma/ib.h index a6b93706b0fc..cf8f9e700e48 100644 --- a/include/rdma/ib.h +++ b/include/rdma/ib.h @@ -34,7 +34,6 @@ #define _RDMA_IB_H #include <linux/types.h> -#include <linux/sched.h> struct ib_addr { union { @@ -87,19 +86,4 @@ struct sockaddr_ib { __u64 sib_scope_id; }; -/* - * The IB interfaces that use write() as bi-directional ioctl() are - * fundamentally unsafe, since there are lots of ways to trigger "write()" - * calls from various contexts with elevated privileges. That includes the - * traditional suid executable error message writes, but also various kernel - * interfaces that can write to file descriptors. - * - * This function provides protection for the legacy API by restricting the - * calling context. - */ -static inline bool ib_safe_file_access(struct file *filp) -{ - return filp->f_cred == current_cred() && segment_eq(get_fs(), USER_DS); -} - #endif /* _RDMA_IB_H */ diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 695e33f4d1cf..636ae899c304 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -804,6 +804,7 @@ struct adm_cmd_connect_afe_port_v5 { #define INT_FM_TX 0x3005 #define RT_PROXY_PORT_001_RX 0x2000 #define RT_PROXY_PORT_001_TX 0x2001 +#define DISPLAY_PORT_RX 0x6020 #define AFE_PORT_INVALID 0xFFFF #define SLIMBUS_INVALID AFE_PORT_INVALID @@ -953,6 +954,8 @@ struct adm_cmd_connect_afe_port_v5 { #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_RX 0x4010 /* SLIMbus Tx port on channel 8. */ #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_8_TX 0x4011 +/* AFE Rx port for audio over Display port */ +#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020 /*USB AFE port */ #define AFE_PORT_ID_USB_RX 0x7000 #define AFE_PORT_ID_USB_TX 0x7001 diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e1f4920053ed..2b6e8f8240d9 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -141,7 +141,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */ #define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */ #define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */ -#define SNDRV_PCM_RATE_384000 (1<<13) /* 384000Hz */ +#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */ +#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */ #define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */ #define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */ @@ -154,6 +155,9 @@ struct snd_pcm_ops { SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) #define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\ SNDRV_PCM_RATE_192000) +#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|\ + SNDRV_PCM_RATE_352800|\ + SNDRV_PCM_RATE_384000) #define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt) #define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8) #define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8) diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index 6be903a4c8d0..b252463b72a2 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -173,14 +173,16 @@ enum { IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_6, IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_7, IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_7, - /* IDX 118->122 */ + /* IDX 118->121 */ IDX_SLIMBUS_7_RX, IDX_SLIMBUS_7_TX, IDX_SLIMBUS_8_RX, IDX_SLIMBUS_8_TX, - /* IDX 123-> 124 */ + /* IDX 122-> 123 */ IDX_AFE_PORT_ID_USB_RX, IDX_AFE_PORT_ID_USB_TX, + /* IDX 124 */ + IDX_DISPLAY_PORT_RX, AFE_MAX_PORTS }; diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index 95ca6e841212..b2e3c3b91f72 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -52,24 +52,29 @@ TRACE_EVENT(consume_skb, TRACE_EVENT(print_skb_gso, - TP_PROTO(struct sk_buff *skb), + TP_PROTO(struct sk_buff *skb, __be16 src, __be16 dest), - TP_ARGS(skb), + TP_ARGS(skb, src, dest), TP_STRUCT__entry( __field(void *, skbaddr) __field(int , len) __field(int , data_len) + __field(__be16, src) + __field(__be16, dest) ), TP_fast_assign( __entry->skbaddr = skb; __entry->len = skb->len; __entry->data_len = skb->data_len; + __entry->src = src; + __entry->dest = dest; ), - TP_printk("GSO: skbaddr=%p, len=%d, data_len=%d", - __entry->skbaddr, __entry->len, __entry->data_len) + TP_printk("GSO: skbaddr=%pK, len=%d, data_len=%d, src=%u, dest=%u", + __entry->skbaddr, __entry->len, __entry->data_len, + be16_to_cpu(__entry->src), be16_to_cpu(__entry->dest)) ); TRACE_EVENT(skb_copy_datagram_iovec, diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h index 752f5dc040a5..9cf2394f0bcf 100644 --- a/include/uapi/linux/if.h +++ b/include/uapi/linux/if.h @@ -19,20 +19,14 @@ #ifndef _LINUX_IF_H #define _LINUX_IF_H -#include <linux/libc-compat.h> /* for compatibility with glibc */ #include <linux/types.h> /* for "__kernel_caddr_t" et al */ #include <linux/socket.h> /* for "struct sockaddr" et al */ #include <linux/compiler.h> /* for "__user" et al */ -#if __UAPI_DEF_IF_IFNAMSIZ #define IFNAMSIZ 16 -#endif /* __UAPI_DEF_IF_IFNAMSIZ */ #define IFALIASZ 256 #include <linux/hdlc/ioctl.h> -/* For glibc compatibility. An empty enum does not compile. */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \ - __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 /** * enum net_device_flags - &struct net_device flags * @@ -74,8 +68,6 @@ * @IFF_ECHO: echo sent packets. Volatile. */ enum net_device_flags { -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS IFF_UP = 1<<0, /* sysfs */ IFF_BROADCAST = 1<<1, /* volatile */ IFF_DEBUG = 1<<2, /* sysfs */ @@ -92,17 +84,11 @@ enum net_device_flags { IFF_PORTSEL = 1<<13, /* sysfs */ IFF_AUTOMEDIA = 1<<14, /* sysfs */ IFF_DYNAMIC = 1<<15, /* sysfs */ -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO IFF_LOWER_UP = 1<<16, /* volatile */ IFF_DORMANT = 1<<17, /* volatile */ IFF_ECHO = 1<<18, /* volatile */ -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ }; -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS #define IFF_UP IFF_UP #define IFF_BROADCAST IFF_BROADCAST #define IFF_DEBUG IFF_DEBUG @@ -119,13 +105,9 @@ enum net_device_flags { #define IFF_PORTSEL IFF_PORTSEL #define IFF_AUTOMEDIA IFF_AUTOMEDIA #define IFF_DYNAMIC IFF_DYNAMIC -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ - -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO #define IFF_LOWER_UP IFF_LOWER_UP #define IFF_DORMANT IFF_DORMANT #define IFF_ECHO IFF_ECHO -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) @@ -184,8 +166,6 @@ enum { * being very small might be worth keeping for clean configuration. */ -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_IFMAP struct ifmap { unsigned long mem_start; unsigned long mem_end; @@ -195,7 +175,6 @@ struct ifmap { unsigned char port; /* 3 bytes spare */ }; -#endif /* __UAPI_DEF_IF_IFMAP */ struct if_settings { unsigned int type; /* Type of physical device or protocol */ @@ -221,8 +200,6 @@ struct if_settings { * remainder may be interface specific. */ -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_IFREQ struct ifreq { #define IFHWADDRLEN 6 union @@ -246,7 +223,6 @@ struct ifreq { struct if_settings ifru_settings; } ifr_ifru; }; -#endif /* __UAPI_DEF_IF_IFREQ */ #define ifr_name ifr_ifrn.ifrn_name /* interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ @@ -273,8 +249,6 @@ struct ifreq { * must know all networks accessible). */ -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_IFCONF struct ifconf { int ifc_len; /* size of buffer */ union { @@ -282,8 +256,6 @@ struct ifconf { struct ifreq __user *ifcu_req; } ifc_ifcu; }; -#endif /* __UAPI_DEF_IF_IFCONF */ - #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h index d5e38c73377c..7d024ceb075d 100644 --- a/include/uapi/linux/libc-compat.h +++ b/include/uapi/linux/libc-compat.h @@ -51,40 +51,6 @@ /* We have included glibc headers... */ #if defined(__GLIBC__) -/* Coordinate with glibc net/if.h header. */ -#if defined(_NET_IF_H) - -/* GLIBC headers included first so don't define anything - * that would already be defined. */ - -#define __UAPI_DEF_IF_IFCONF 0 -#define __UAPI_DEF_IF_IFMAP 0 -#define __UAPI_DEF_IF_IFNAMSIZ 0 -#define __UAPI_DEF_IF_IFREQ 0 -/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 -/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ -#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ - -#else /* _NET_IF_H */ - -/* Linux headers included first, and we must define everything - * we need. The expectation is that glibc will check the - * __UAPI_DEF_* defines and adjust appropriately. */ - -#define __UAPI_DEF_IF_IFCONF 1 -#define __UAPI_DEF_IF_IFMAP 1 -#define __UAPI_DEF_IF_IFNAMSIZ 1 -#define __UAPI_DEF_IF_IFREQ 1 -/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 -/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 - -#endif /* _NET_IF_H */ - /* Coordinate with glibc netinet/in.h header. */ #if defined(_NETINET_IN_H) @@ -151,16 +117,6 @@ * that we need. */ #else /* !defined(__GLIBC__) */ -/* Definitions for if.h */ -#define __UAPI_DEF_IF_IFCONF 1 -#define __UAPI_DEF_IF_IFMAP 1 -#define __UAPI_DEF_IF_IFNAMSIZ 1 -#define __UAPI_DEF_IF_IFREQ 1 -/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 -/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 - /* Definitions for in.h */ #define __UAPI_DEF_IN_ADDR 1 #define __UAPI_DEF_IN_IPPROTO 1 diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index 086168e18ca8..c039f1d68a09 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -183,8 +183,7 @@ #define V4L2_DV_BT_CEA_3840X2160P24 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1276, 88, 296, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, \ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ @@ -192,16 +191,14 @@ #define V4L2_DV_BT_CEA_3840X2160P25 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P30 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, \ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ @@ -209,16 +206,14 @@ #define V4L2_DV_BT_CEA_3840X2160P50 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P60 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, \ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ @@ -226,8 +221,7 @@ #define V4L2_DV_BT_CEA_4096X2160P24 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1020, 88, 296, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, \ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ @@ -235,16 +229,14 @@ #define V4L2_DV_BT_CEA_4096X2160P25 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P30 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, \ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ @@ -252,16 +244,14 @@ #define V4L2_DV_BT_CEA_4096X2160P50 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P60 { \ .type = V4L2_DV_BT_656_1120, \ - V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \ - V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \ V4L2_DV_BT_STD_CEA861, \ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild index c04bb724119a..8405472d8674 100644 --- a/include/uapi/media/Kbuild +++ b/include/uapi/media/Kbuild @@ -17,3 +17,5 @@ header-y += msmb_generic_buf_mgr.h header-y += msmb_isp.h header-y += msmb_ispif.h header-y += msmb_pproc.h +header-y += radio-iris.h +header-y += radio-iris-commands.h diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h index 540a96c57e5b..2c7ada5d02cf 100644 --- a/include/uapi/media/msm_cam_sensor.h +++ b/include/uapi/media/msm_cam_sensor.h @@ -34,6 +34,9 @@ #define MAX_NUMBER_OF_STEPS 47 #define MAX_REGULATOR 5 +/*msm_flash_query_data_t query types*/ +#define FLASH_QUERY_CURRENT 1 + #define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */ #define MSM_V4L2_PIX_FMT_META10 v4l2_fourcc('M', 'E', '1', '0') /* META10 */ #define MSM_V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4') @@ -531,6 +534,12 @@ struct msm_flash_cfg_data_t { } cfg; }; +struct msm_flash_query_data_t { + int32_t flags; + int32_t query_type; + int32_t max_avail_curr; +}; + /* sensor init structures and enums */ enum msm_sensor_init_cfg_type_t { CFG_SINIT_PROBE, @@ -586,5 +595,8 @@ struct sensor_init_cfg_data { #define VIDIOC_MSM_OIS_CFG_DOWNLOAD \ _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_ois_cfg_download_data) +#define VIDIOC_MSM_FLASH_QUERY_DATA \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_flash_query_data_t) + #endif diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index 9f933dc7e84f..cdb85170919a 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -18,6 +18,9 @@ #define ISP_META_CHANNEL_BIT (0x10000 << 3) #define ISP_SCRATCH_BUF_BIT (0x10000 << 4) #define ISP_OFFLINE_STATS_BIT (0x10000 << 5) +#define ISP_SVHDR_IN_BIT (0x10000 << 6) /* RDI hw stream for SVHDR */ +#define ISP_SVHDR_OUT_BIT (0x10000 << 7) /* SVHDR output bufq stream*/ + #define ISP_STATS_STREAM_BIT 0x80000000 struct msm_vfe_cfg_cmd_list; @@ -324,7 +327,9 @@ enum msm_vfe_axi_stream_update_type { UPDATE_STREAM_ADD_BUFQ, UPDATE_STREAM_REMOVE_BUFQ, UPDATE_STREAM_SW_FRAME_DROP, + UPDATE_STREAM_REQUEST_FRAMES_VER2, }; +#define UPDATE_STREAM_REQUEST_FRAMES_VER2 UPDATE_STREAM_REQUEST_FRAMES_VER2 enum msm_vfe_iommu_type { IOMMU_ATTACH, @@ -347,6 +352,13 @@ struct msm_vfe_axi_stream_cfg_update_info { struct msm_isp_sw_framskip sw_skip_info; }; +struct msm_vfe_axi_stream_cfg_update_info_req_frm { + uint32_t stream_handle; + uint32_t user_stream_id; + uint32_t frame_id; + uint32_t buf_index; +}; + struct msm_vfe_axi_halt_cmd { uint32_t stop_camif; uint32_t overflow_detected; @@ -365,8 +377,15 @@ struct msm_vfe_axi_restart_cmd { struct msm_vfe_axi_stream_update_cmd { uint32_t num_streams; enum msm_vfe_axi_stream_update_type update_type; - struct msm_vfe_axi_stream_cfg_update_info + /* + * For backward compatibility, ensure 1st member of any struct + * in union below is uint32_t stream_handle. + */ + union { + struct msm_vfe_axi_stream_cfg_update_info update_info[MSM_ISP_STATS_MAX]; + struct msm_vfe_axi_stream_cfg_update_info_req_frm req_frm_ver2; + }; }; struct msm_vfe_smmu_attach_cmd { @@ -808,82 +827,133 @@ struct msm_isp_ahb_clk_cfg { #define V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('B', 'A', '1', '4') /* 14 GRGR.BGBG.*/ #define V4L2_PIX_FMT_SRGGB14 v4l2_fourcc('R', 'G', '1', '4') /* 14 RGRG.GBGB.*/ +enum msm_isp_ioctl_cmd_code { + MSM_VFE_REG_CFG = BASE_VIDIOC_PRIVATE, + MSM_ISP_REQUEST_BUF, + MSM_ISP_ENQUEUE_BUF, + MSM_ISP_RELEASE_BUF, + MSM_ISP_REQUEST_STREAM, + MSM_ISP_CFG_STREAM, + MSM_ISP_RELEASE_STREAM, + MSM_ISP_INPUT_CFG, + MSM_ISP_SET_SRC_STATE, + MSM_ISP_REQUEST_STATS_STREAM, + MSM_ISP_CFG_STATS_STREAM, + MSM_ISP_RELEASE_STATS_STREAM, + MSM_ISP_REG_UPDATE_CMD, + MSM_ISP_UPDATE_STREAM, + MSM_VFE_REG_LIST_CFG, + MSM_ISP_SMMU_ATTACH, + MSM_ISP_UPDATE_STATS_STREAM, + MSM_ISP_AXI_HALT, + MSM_ISP_AXI_RESET, + MSM_ISP_AXI_RESTART, + MSM_ISP_FETCH_ENG_START, + MSM_ISP_DEQUEUE_BUF, + MSM_ISP_SET_DUAL_HW_MASTER_SLAVE, + MSM_ISP_MAP_BUF_START_FE, + MSM_ISP_UNMAP_BUF, +}; + #define VIDIOC_MSM_VFE_REG_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2) + _IOWR('V', MSM_VFE_REG_CFG, \ + struct msm_vfe_cfg_cmd2) #define VIDIOC_MSM_ISP_REQUEST_BUF \ - _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct msm_isp_buf_request) + _IOWR('V', MSM_ISP_REQUEST_BUF, \ + struct msm_isp_buf_request) #define VIDIOC_MSM_ISP_ENQUEUE_BUF \ - _IOWR('V', BASE_VIDIOC_PRIVATE+2, struct msm_isp_qbuf_info) + _IOWR('V', MSM_ISP_ENQUEUE_BUF, \ + struct msm_isp_qbuf_info) #define VIDIOC_MSM_ISP_RELEASE_BUF \ - _IOWR('V', BASE_VIDIOC_PRIVATE+3, struct msm_isp_buf_request) + _IOWR('V', MSM_ISP_RELEASE_BUF, \ + struct msm_isp_buf_request) #define VIDIOC_MSM_ISP_REQUEST_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+4, struct msm_vfe_axi_stream_request_cmd) + _IOWR('V', MSM_ISP_REQUEST_STREAM, \ + struct msm_vfe_axi_stream_request_cmd) #define VIDIOC_MSM_ISP_CFG_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+5, struct msm_vfe_axi_stream_cfg_cmd) + _IOWR('V', MSM_ISP_CFG_STREAM, \ + struct msm_vfe_axi_stream_cfg_cmd) #define VIDIOC_MSM_ISP_RELEASE_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+6, struct msm_vfe_axi_stream_release_cmd) + _IOWR('V', MSM_ISP_RELEASE_STREAM, \ + struct msm_vfe_axi_stream_release_cmd) #define VIDIOC_MSM_ISP_INPUT_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE+7, struct msm_vfe_input_cfg) + _IOWR('V', MSM_ISP_INPUT_CFG, \ + struct msm_vfe_input_cfg) #define VIDIOC_MSM_ISP_SET_SRC_STATE \ - _IOWR('V', BASE_VIDIOC_PRIVATE+8, struct msm_vfe_axi_src_state) + _IOWR('V', MSM_ISP_SET_SRC_STATE, \ + struct msm_vfe_axi_src_state) #define VIDIOC_MSM_ISP_REQUEST_STATS_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+9, \ - struct msm_vfe_stats_stream_request_cmd) + _IOWR('V', MSM_ISP_REQUEST_STATS_STREAM, \ + struct msm_vfe_stats_stream_request_cmd) #define VIDIOC_MSM_ISP_CFG_STATS_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+10, struct msm_vfe_stats_stream_cfg_cmd) + _IOWR('V', MSM_ISP_CFG_STATS_STREAM, \ + struct msm_vfe_stats_stream_cfg_cmd) #define VIDIOC_MSM_ISP_RELEASE_STATS_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+11, \ - struct msm_vfe_stats_stream_release_cmd) + _IOWR('V', MSM_ISP_RELEASE_STATS_STREAM, \ + struct msm_vfe_stats_stream_release_cmd) #define VIDIOC_MSM_ISP_REG_UPDATE_CMD \ - _IOWR('V', BASE_VIDIOC_PRIVATE+12, enum msm_vfe_input_src) + _IOWR('V', MSM_ISP_REG_UPDATE_CMD, \ + enum msm_vfe_input_src) #define VIDIOC_MSM_ISP_UPDATE_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+13, struct msm_vfe_axi_stream_update_cmd) + _IOWR('V', MSM_ISP_UPDATE_STREAM, \ + struct msm_vfe_axi_stream_update_cmd) #define VIDIOC_MSM_VFE_REG_LIST_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE+14, struct msm_vfe_cfg_cmd_list) + _IOWR('V', MSM_VFE_REG_LIST_CFG, \ + struct msm_vfe_cfg_cmd_list) #define VIDIOC_MSM_ISP_SMMU_ATTACH \ - _IOWR('V', BASE_VIDIOC_PRIVATE+15, struct msm_vfe_smmu_attach_cmd) + _IOWR('V', MSM_ISP_SMMU_ATTACH, \ + struct msm_vfe_smmu_attach_cmd) #define VIDIOC_MSM_ISP_UPDATE_STATS_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE+16, struct msm_vfe_axi_stream_update_cmd) + _IOWR('V', MSM_ISP_UPDATE_STATS_STREAM, \ + struct msm_vfe_axi_stream_update_cmd) #define VIDIOC_MSM_ISP_AXI_HALT \ - _IOWR('V', BASE_VIDIOC_PRIVATE+17, struct msm_vfe_axi_halt_cmd) + _IOWR('V', MSM_ISP_AXI_HALT, \ + struct msm_vfe_axi_halt_cmd) #define VIDIOC_MSM_ISP_AXI_RESET \ - _IOWR('V', BASE_VIDIOC_PRIVATE+18, struct msm_vfe_axi_reset_cmd) + _IOWR('V', MSM_ISP_AXI_RESET, \ + struct msm_vfe_axi_reset_cmd) #define VIDIOC_MSM_ISP_AXI_RESTART \ - _IOWR('V', BASE_VIDIOC_PRIVATE+19, struct msm_vfe_axi_restart_cmd) + _IOWR('V', MSM_ISP_AXI_RESTART, \ + struct msm_vfe_axi_restart_cmd) #define VIDIOC_MSM_ISP_FETCH_ENG_START \ - _IOWR('V', BASE_VIDIOC_PRIVATE+20, struct msm_vfe_fetch_eng_start) + _IOWR('V', MSM_ISP_FETCH_ENG_START, \ + struct msm_vfe_fetch_eng_start) #define VIDIOC_MSM_ISP_DEQUEUE_BUF \ - _IOWR('V', BASE_VIDIOC_PRIVATE+21, struct msm_isp_qbuf_info) + _IOWR('V', MSM_ISP_DEQUEUE_BUF, \ + struct msm_isp_qbuf_info) #define VIDIOC_MSM_ISP_SET_DUAL_HW_MASTER_SLAVE \ - _IOWR('V', BASE_VIDIOC_PRIVATE+22, struct msm_isp_set_dual_hw_ms_cmd) + _IOWR('V', MSM_ISP_SET_DUAL_HW_MASTER_SLAVE, \ + struct msm_isp_set_dual_hw_ms_cmd) #define VIDIOC_MSM_ISP_MAP_BUF_START_FE \ - _IOWR('V', BASE_VIDIOC_PRIVATE+23, struct msm_vfe_fetch_eng_start) + _IOWR('V', MSM_ISP_MAP_BUF_START_FE, \ + struct msm_vfe_fetch_eng_start) #define VIDIOC_MSM_ISP_UNMAP_BUF \ - _IOWR('V', BASE_VIDIOC_PRIVATE+24, struct msm_isp_unmap_buf_req) + _IOWR('V', MSM_ISP_UNMAP_BUF, \ + struct msm_isp_unmap_buf_req) #define VIDIOC_MSM_ISP_AHB_CLK_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE+25, struct msm_isp_ahb_clk_cfg) diff --git a/include/uapi/media/radio-iris-commands.h b/include/uapi/media/radio-iris-commands.h new file mode 100644 index 000000000000..b9dce3dc6872 --- /dev/null +++ b/include/uapi/media/radio-iris-commands.h @@ -0,0 +1,108 @@ +#ifndef __UAPI_RADIO_IRIS_COMMANDS_H +#define __UAPI_RADIO_IRIS_COMMANDS_H + +enum v4l2_cid_private_iris_t { + V4L2_CID_PRIVATE_IRIS_SRCHMODE = (0x08000000 + 1), + V4L2_CID_PRIVATE_IRIS_SCANDWELL, + V4L2_CID_PRIVATE_IRIS_SRCHON, + V4L2_CID_PRIVATE_IRIS_STATE, + V4L2_CID_PRIVATE_IRIS_TRANSMIT_MODE, + V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK, + V4L2_CID_PRIVATE_IRIS_REGION, + V4L2_CID_PRIVATE_IRIS_SIGNAL_TH, + V4L2_CID_PRIVATE_IRIS_SRCH_PTY, + V4L2_CID_PRIVATE_IRIS_SRCH_PI, + V4L2_CID_PRIVATE_IRIS_SRCH_CNT, + V4L2_CID_PRIVATE_IRIS_EMPHASIS, + V4L2_CID_PRIVATE_IRIS_RDS_STD, + V4L2_CID_PRIVATE_IRIS_SPACING, + V4L2_CID_PRIVATE_IRIS_RDSON, + V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC, + V4L2_CID_PRIVATE_IRIS_LP_MODE, + V4L2_CID_PRIVATE_IRIS_ANTENNA, + V4L2_CID_PRIVATE_IRIS_RDSD_BUF, + V4L2_CID_PRIVATE_IRIS_PSALL, /*0x8000014*/ + + /*v4l2 Tx controls*/ + V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT, + V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME, + V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT, + V4L2_CID_PRIVATE_IRIS_IOVERC, + V4L2_CID_PRIVATE_IRIS_INTDET, + V4L2_CID_PRIVATE_IRIS_MPX_DCC, + V4L2_CID_PRIVATE_IRIS_AF_JUMP, + V4L2_CID_PRIVATE_IRIS_RSSI_DELTA, + V4L2_CID_PRIVATE_IRIS_HLSI, /*0x800001d*/ + + /*Diagnostic commands*/ + V4L2_CID_PRIVATE_IRIS_SOFT_MUTE, + V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR, + V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN, + V4L2_CID_PRIVATE_IRIS_RIVA_PEEK, + V4L2_CID_PRIVATE_IRIS_RIVA_POKE, + V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR, + V4L2_CID_PRIVATE_IRIS_SSBI_PEEK, + V4L2_CID_PRIVATE_IRIS_SSBI_POKE, + V4L2_CID_PRIVATE_IRIS_TX_TONE, + V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS, + V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER, /* 0x8000028 */ + V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH, /* TAVARUA specific command */ + V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION, + V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM, /* TAVARUA specific command */ + V4L2_CID_PRIVATE_IRIS_GET_SINR, + V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, + V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, + V4L2_CID_PRIVATE_SINR_THRESHOLD, + V4L2_CID_PRIVATE_SINR_SAMPLES, + V4L2_CID_PRIVATE_SPUR_FREQ, + V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI, + V4L2_CID_PRIVATE_SPUR_SELECTION, + V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE, + V4L2_CID_PRIVATE_VALID_CHANNEL, + V4L2_CID_PRIVATE_AF_RMSSI_TH, + V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES, + V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH, + V4L2_CID_PRIVATE_SRCHALGOTYPE, + V4L2_CID_PRIVATE_CF0TH12, + V4L2_CID_PRIVATE_SINRFIRSTSTAGE, + V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE, + V4L2_CID_PRIVATE_RXREPEATCOUNT, + V4L2_CID_PRIVATE_IRIS_RSSI_TH, + V4L2_CID_PRIVATE_IRIS_AF_JUMP_RSSI_TH, + V4L2_CID_PRIVATE_BLEND_SINRHI, + V4L2_CID_PRIVATE_BLEND_RMSSIHI, + + /*using private CIDs under userclass*/ + V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928, + V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT, + V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION, + V4L2_CID_PRIVATE_IRIS_SET_SPURTABLE = 0x0098092D, + V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL = 0x0098092E, +}; + +enum iris_evt_t { + IRIS_EVT_RADIO_READY, + IRIS_EVT_TUNE_SUCC, + IRIS_EVT_SEEK_COMPLETE, + IRIS_EVT_SCAN_NEXT, + IRIS_EVT_NEW_RAW_RDS, + IRIS_EVT_NEW_RT_RDS, + IRIS_EVT_NEW_PS_RDS, + IRIS_EVT_ERROR, + IRIS_EVT_BELOW_TH, + IRIS_EVT_ABOVE_TH, + IRIS_EVT_STEREO, + IRIS_EVT_MONO, + IRIS_EVT_RDS_AVAIL, + IRIS_EVT_RDS_NOT_AVAIL, + IRIS_EVT_NEW_SRCH_LIST, + IRIS_EVT_NEW_AF_LIST, + IRIS_EVT_TXRDSDAT, + IRIS_EVT_TXRDSDONE, + IRIS_EVT_RADIO_DISABLED, + IRIS_EVT_NEW_ODA, + IRIS_EVT_NEW_RT_PLUS, + IRIS_EVT_NEW_ERT, + IRIS_EVT_SPUR_TBL, +}; +#endif diff --git a/include/uapi/media/radio-iris.h b/include/uapi/media/radio-iris.h new file mode 100644 index 000000000000..015016ccfbbc --- /dev/null +++ b/include/uapi/media/radio-iris.h @@ -0,0 +1,813 @@ +#ifndef __UAPI_RADIO_IRIS_H +#define __UAPI_RADIO_IRIS_H + +#include <linux/types.h> +#include <media/radio-iris-commands.h> + +#define MIN_TX_TONE_VAL 0x00 +#define MAX_TX_TONE_VAL 0x07 +#define MIN_HARD_MUTE_VAL 0x00 +#define MAX_HARD_MUTE_VAL 0x03 +#define MIN_SRCH_MODE 0x00 +#define MAX_SRCH_MODE 0x09 +#define MIN_SCAN_DWELL 0x00 +#define MAX_SCAN_DWELL 0x0F +#define MIN_SIG_TH 0x00 +#define MAX_SIG_TH 0x03 +#define MIN_PTY 0X00 +#define MAX_PTY 0x1F +#define MIN_PI 0x0000 +#define MAX_PI 0xFFFF +#define MIN_SRCH_STATIONS_CNT 0x00 +#define MAX_SRCH_STATIONS_CNT 0x14 +#define MIN_CHAN_SPACING 0x00 +#define MAX_CHAN_SPACING 0x02 +#define MIN_EMPHASIS 0x00 +#define MAX_EMPHASIS 0x01 +#define MIN_RDS_STD 0x00 +#define MAX_RDS_STD 0x02 +#define MIN_ANTENNA_VAL 0x00 +#define MAX_ANTENNA_VAL 0x01 +#define MIN_TX_PS_REPEAT_CNT 0x01 +#define MAX_TX_PS_REPEAT_CNT 0x0F +#define MIN_SOFT_MUTE 0x00 +#define MAX_SOFT_MUTE 0x01 +#define MIN_PEEK_ACCESS_LEN 0x01 +#define MAX_PEEK_ACCESS_LEN 0xF9 +#define MIN_RESET_CNTR 0x00 +#define MAX_RESET_CNTR 0x01 +#define MIN_HLSI 0x00 +#define MAX_HLSI 0x02 +#define MIN_NOTCH_FILTER 0x00 +#define MAX_NOTCH_FILTER 0x02 +#define MIN_INTF_DET_OUT_LW_TH 0x00 +#define MAX_INTF_DET_OUT_LW_TH 0xFF +#define MIN_INTF_DET_OUT_HG_TH 0x00 +#define MAX_INTF_DET_OUT_HG_TH 0xFF +#define MIN_SINR_TH -128 +#define MAX_SINR_TH 127 +#define MIN_SINR_SAMPLES 0x01 +#define MAX_SINR_SAMPLES 0xFF +#define MIN_BLEND_HI -128 +#define MAX_BLEND_HI 127 + + +/* ---- HCI Packet structures ---- */ +#define RADIO_HCI_COMMAND_HDR_SIZE sizeof(struct radio_hci_command_hdr) +#define RADIO_HCI_EVENT_HDR_SIZE sizeof(struct radio_hci_event_hdr) + +/* HCI data types */ +#define RADIO_HCI_COMMAND_PKT 0x11 +#define RADIO_HCI_EVENT_PKT 0x14 +/*HCI reponce packets*/ +#define MAX_RIVA_PEEK_RSP_SIZE 251 +/* default data access */ +#define DEFAULT_DATA_OFFSET 2 +#define DEFAULT_DATA_SIZE 249 +/* Power levels are 0-7, but SOC will expect values from 0-255 + * So the each level step size will be 255/7 = 36 + */ +#define FM_TX_PWR_LVL_STEP_SIZE 36 +#define FM_TX_PWR_LVL_0 0 /* Lowest power lvl that can be set for Tx */ +#define FM_TX_PWR_LVL_MAX 7 /* Max power lvl for Tx */ +#define FM_TX_PHY_CFG_MODE 0x3c +#define FM_TX_PHY_CFG_LEN 0x10 +#define FM_TX_PWR_GAIN_OFFSET 14 +/**RDS CONFIG MODE**/ +#define FM_RDS_CNFG_MODE 0x0f +#define FM_RDS_CNFG_LEN 0x10 +#define AF_RMSSI_TH_LSB_OFFSET 10 +#define AF_RMSSI_TH_MSB_OFFSET 11 +#define AF_RMSSI_SAMPLES_OFFSET 15 +/**RX CONFIG MODE**/ +#define FM_RX_CONFG_MODE 0x15 +#define FM_RX_CNFG_LEN 0x20 +#define GD_CH_RMSSI_TH_OFFSET 12 +#define MAX_GD_CH_RMSSI_TH 127 +#define SRCH_ALGO_TYPE_OFFSET 25 +#define SINRFIRSTSTAGE_OFFSET 26 +#define RMSSIFIRSTSTAGE_OFFSET 27 +#define CF0TH12_BYTE1_OFFSET 8 +#define CF0TH12_BYTE2_OFFSET 9 +#define CF0TH12_BYTE3_OFFSET 10 +#define CF0TH12_BYTE4_OFFSET 11 +#define MAX_SINR_FIRSTSTAGE 127 +#define MAX_RMSSI_FIRSTSTAGE 127 +#define RDS_PS0_XFR_MODE 0x01 +#define RDS_PS0_LEN 6 +#define RX_REPEATE_BYTE_OFFSET 5 +#define FM_SPUR_TBL_SIZE 240 +#define SPUR_DATA_LEN 16 +#define ENTRIES_EACH_CMD 15 +#define SPUR_DATA_INDEX 2 +#define FM_AF_LIST_MAX_SIZE 200 +/* Each AF frequency consist of sizeof(int) bytes */ +#define AF_LIST_MAX (FM_AF_LIST_MAX_SIZE / 4) + +#define MAX_BLEND_INDEX 49 + +#define TUNE_PARAM 16 +#define FM_RDS_3A_GRP (0x40) +struct radio_hci_command_hdr { + __le16 opcode; /* OCF & OGF */ + __u8 plen; +} __packed; + +struct radio_hci_event_hdr { + __u8 evt; + __u8 plen; +} __packed; + +/* Opcode OCF */ +/* HCI recv control commands opcode */ +#define HCI_OCF_FM_ENABLE_RECV_REQ 0x0001 +#define HCI_OCF_FM_DISABLE_RECV_REQ 0x0002 +#define HCI_OCF_FM_GET_RECV_CONF_REQ 0x0003 +#define HCI_OCF_FM_SET_RECV_CONF_REQ 0x0004 +#define HCI_OCF_FM_SET_MUTE_MODE_REQ 0x0005 +#define HCI_OCF_FM_SET_STEREO_MODE_REQ 0x0006 +#define HCI_OCF_FM_SET_ANTENNA 0x0007 +#define HCI_OCF_FM_SET_SIGNAL_THRESHOLD 0x0008 +#define HCI_OCF_FM_GET_SIGNAL_THRESHOLD 0x0009 +#define HCI_OCF_FM_GET_STATION_PARAM_REQ 0x000A +#define HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ 0x000B +#define HCI_OCF_FM_GET_RADIO_TEXT_REQ 0x000C +#define HCI_OCF_FM_GET_AF_LIST_REQ 0x000D +#define HCI_OCF_FM_SEARCH_STATIONS 0x000E +#define HCI_OCF_FM_SEARCH_RDS_STATIONS 0x000F +#define HCI_OCF_FM_SEARCH_STATIONS_LIST 0x0010 +#define HCI_OCF_FM_CANCEL_SEARCH 0x0011 +#define HCI_OCF_FM_RDS_GRP 0x0012 +#define HCI_OCF_FM_RDS_GRP_PROCESS 0x0013 +#define HCI_OCF_FM_EN_WAN_AVD_CTRL 0x0014 +#define HCI_OCF_FM_EN_NOTCH_CTRL 0x0015 +#define HCI_OCF_FM_SET_EVENT_MASK 0x0016 +#define HCI_OCF_FM_SET_CH_DET_THRESHOLD 0x0017 +#define HCI_OCF_FM_GET_CH_DET_THRESHOLD 0x0018 +#define HCI_OCF_FM_SET_BLND_TBL 0x001B +#define HCI_OCF_FM_GET_BLND_TBL 0x001C +/* HCI trans control commans opcode*/ +#define HCI_OCF_FM_ENABLE_TRANS_REQ 0x0001 +#define HCI_OCF_FM_DISABLE_TRANS_REQ 0x0002 +#define HCI_OCF_FM_GET_TRANS_CONF_REQ 0x0003 +#define HCI_OCF_FM_SET_TRANS_CONF_REQ 0x0004 +#define HCI_OCF_FM_RDS_RT_REQ 0x0008 +#define HCI_OCF_FM_RDS_PS_REQ 0x0009 + + +/* HCI common control commands opcode */ +#define HCI_OCF_FM_TUNE_STATION_REQ 0x0001 +#define HCI_OCF_FM_DEFAULT_DATA_READ 0x0002 +#define HCI_OCF_FM_DEFAULT_DATA_WRITE 0x0003 +#define HCI_OCF_FM_RESET 0x0004 +#define HCI_OCF_FM_GET_FEATURE_LIST 0x0005 +#define HCI_OCF_FM_DO_CALIBRATION 0x0006 +#define HCI_OCF_FM_SET_CALIBRATION 0x0007 +#define HCI_OCF_FM_SET_SPUR_TABLE 0x0008 +#define HCI_OCF_FM_GET_SPUR_TABLE 0x0009 + +/*HCI Status parameters commands*/ +#define HCI_OCF_FM_READ_GRP_COUNTERS 0x0001 + +/*HCI Diagnostic commands*/ +#define HCI_OCF_FM_PEEK_DATA 0x0002 +#define HCI_OCF_FM_POKE_DATA 0x0003 +#define HCI_OCF_FM_SSBI_PEEK_REG 0x0004 +#define HCI_OCF_FM_SSBI_POKE_REG 0x0005 +#define HCI_OCF_FM_STATION_DBG_PARAM 0x0007 +#define HCI_FM_SET_INTERNAL_TONE_GENRATOR 0x0008 + +/* Opcode OGF */ +#define HCI_OGF_FM_RECV_CTRL_CMD_REQ 0x0013 +#define HCI_OGF_FM_TRANS_CTRL_CMD_REQ 0x0014 +#define HCI_OGF_FM_COMMON_CTRL_CMD_REQ 0x0015 +#define HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ 0x0016 +#define HCI_OGF_FM_TEST_CMD_REQ 0x0017 +#define HCI_OGF_FM_DIAGNOSTIC_CMD_REQ 0x003F + +/* Command opcode pack/unpack */ +#define hci_opcode_pack(ogf, ocf) ((__u16) ((ocf & 0x03ff)|(ogf << 10))) +#define hci_opcode_ogf(op) (op >> 10) +#define hci_opcode_ocf(op) (op & 0x03ff) +#define hci_recv_ctrl_cmd_op_pack(ocf) \ + ((__u16) hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ, ocf)) +#define hci_trans_ctrl_cmd_op_pack(ocf) \ + ((__u16) hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ, ocf)) +#define hci_common_cmd_op_pack(ocf) \ + ((__u16) hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ, ocf)) +#define hci_status_param_op_pack(ocf) \ + ((__u16) hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ, ocf)) +#define hci_diagnostic_cmd_op_pack(ocf) \ + ((__u16) hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ, ocf)) + + +/* HCI commands with no arguments*/ +#define HCI_FM_ENABLE_RECV_CMD 1 +#define HCI_FM_DISABLE_RECV_CMD 2 +#define HCI_FM_GET_RECV_CONF_CMD 3 +#define HCI_FM_GET_STATION_PARAM_CMD 4 +#define HCI_FM_GET_SIGNAL_TH_CMD 5 +#define HCI_FM_GET_PROGRAM_SERVICE_CMD 6 +#define HCI_FM_GET_RADIO_TEXT_CMD 7 +#define HCI_FM_GET_AF_LIST_CMD 8 +#define HCI_FM_CANCEL_SEARCH_CMD 9 +#define HCI_FM_RESET_CMD 10 +#define HCI_FM_GET_FEATURES_CMD 11 +#define HCI_FM_STATION_DBG_PARAM_CMD 12 +#define HCI_FM_ENABLE_TRANS_CMD 13 +#define HCI_FM_DISABLE_TRANS_CMD 14 +#define HCI_FM_GET_TX_CONFIG 15 +#define HCI_FM_GET_DET_CH_TH_CMD 16 +#define HCI_FM_GET_BLND_TBL_CMD 17 + +/* Defines for FM TX*/ +#define TX_PS_DATA_LENGTH 108 +#define TX_RT_DATA_LENGTH 64 +#define PS_STRING_LEN 9 + +/* ----- HCI Command request ----- */ +struct hci_fm_recv_conf_req { + __u8 emphasis; + __u8 ch_spacing; + __u8 rds_std; + __u8 hlsi; + __u32 band_low_limit; + __u32 band_high_limit; +} __packed; + +/* ----- HCI Command request ----- */ +struct hci_fm_trans_conf_req_struct { + __u8 emphasis; + __u8 rds_std; + __u32 band_low_limit; + __u32 band_high_limit; +} __packed; + + +/* ----- HCI Command request ----- */ +struct hci_fm_tx_ps { + __u8 ps_control; + __u16 pi; + __u8 pty; + __u8 ps_repeatcount; + __u8 ps_num; + __u8 ps_data[TX_PS_DATA_LENGTH]; +} __packed; + +struct hci_fm_tx_rt { + __u8 rt_control; + __u16 pi; + __u8 pty; + __u8 rt_len; + __u8 rt_data[TX_RT_DATA_LENGTH]; +} __packed; + +struct hci_fm_mute_mode_req { + __u8 hard_mute; + __u8 soft_mute; +} __packed; + +struct hci_fm_stereo_mode_req { + __u8 stereo_mode; + __u8 sig_blend; + __u8 intf_blend; + __u8 most_switch; +} __packed; + +struct hci_fm_search_station_req { + __u8 srch_mode; + __u8 scan_time; + __u8 srch_dir; +} __packed; + +struct hci_fm_search_rds_station_req { + struct hci_fm_search_station_req srch_station; + __u8 srch_pty; + __u16 srch_pi; +} __packed; + +struct hci_fm_search_station_list_req { + __u8 srch_list_mode; + __u8 srch_list_dir; + __u32 srch_list_max; + __u8 srch_pty; +} __packed; + +struct hci_fm_rds_grp_req { + __u32 rds_grp_enable_mask; + __u32 rds_buf_size; + __u8 en_rds_change_filter; +} __packed; + +struct hci_fm_en_avd_ctrl_req { + __u8 no_freqs; + __u8 freq_index; + __u8 lo_shft; + __u16 freq_min; + __u16 freq_max; +} __packed; + +struct hci_fm_def_data_rd_req { + __u8 mode; + __u8 length; + __u8 param_len; + __u8 param; +} __packed; + +struct hci_fm_def_data_wr_req { + __u8 mode; + __u8 length; + __u8 data[DEFAULT_DATA_SIZE]; +} __packed; + +struct hci_fm_riva_data { + __u8 subopcode; + __u32 start_addr; + __u8 length; +} __packed; + +struct hci_fm_riva_poke { + struct hci_fm_riva_data cmd_params; + __u8 data[MAX_RIVA_PEEK_RSP_SIZE]; +} __packed; + +struct hci_fm_ssbi_req { + __u16 start_addr; + __u8 data; +} __packed; +struct hci_fm_ssbi_peek { + __u16 start_address; +} __packed; + +struct hci_fm_ch_det_threshold { + char sinr; + __u8 sinr_samples; + __u8 low_th; + __u8 high_th; + +} __packed; + +struct hci_fm_blend_table { + __u8 ucBlendType; + __u8 ucBlendRampRateUp; + __u8 ucBlendDebounceNumSampleUp; + __u8 ucBlendDebounceIdxUp; + __u8 ucBlendSinrIdxSkipStep; + __u8 scBlendSinrHi; + __u8 scBlendRmssiHi; + __u8 ucBlendIndexHi; + __u8 ucBlendIndex[MAX_BLEND_INDEX]; +} __packed; + +/*HCI events*/ +#define HCI_EV_TUNE_STATUS 0x01 +#define HCI_EV_RDS_LOCK_STATUS 0x02 +#define HCI_EV_STEREO_STATUS 0x03 +#define HCI_EV_SERVICE_AVAILABLE 0x04 +#define HCI_EV_SEARCH_PROGRESS 0x05 +#define HCI_EV_SEARCH_RDS_PROGRESS 0x06 +#define HCI_EV_SEARCH_LIST_PROGRESS 0x07 +#define HCI_EV_RDS_RX_DATA 0x08 +#define HCI_EV_PROGRAM_SERVICE 0x09 +#define HCI_EV_RADIO_TEXT 0x0A +#define HCI_EV_FM_AF_LIST 0x0B +#define HCI_EV_TX_RDS_GRP_AVBLE 0x0C +#define HCI_EV_TX_RDS_GRP_COMPL 0x0D +#define HCI_EV_TX_RDS_CONT_GRP_COMPL 0x0E +#define HCI_EV_CMD_COMPLETE 0x0F +#define HCI_EV_CMD_STATUS 0x10 +#define HCI_EV_TUNE_COMPLETE 0x11 +#define HCI_EV_SEARCH_COMPLETE 0x12 +#define HCI_EV_SEARCH_RDS_COMPLETE 0x13 +#define HCI_EV_SEARCH_LIST_COMPLETE 0x14 + +#define HCI_REQ_DONE 0 +#define HCI_REQ_PEND 1 +#define HCI_REQ_CANCELED 2 +#define HCI_REQ_STATUS 3 + +#define MAX_RAW_RDS_GRPS 21 + +#define RDSGRP_DATA_OFFSET 0x1 + +/*RT PLUS*/ +#define DUMMY_CLASS 0 +#define RT_PLUS_LEN_1_TAG 3 +#define RT_ERT_FLAG_BIT 5 + +/*TAG1*/ +#define TAG1_MSB_OFFSET 3 +#define TAG1_MSB_MASK 7 +#define TAG1_LSB_OFFSET 5 +#define TAG1_POS_MSB_MASK 31 +#define TAG1_POS_MSB_OFFSET 1 +#define TAG1_POS_LSB_OFFSET 7 +#define TAG1_LEN_OFFSET 1 +#define TAG1_LEN_MASK 63 + +/*TAG2*/ +#define TAG2_MSB_OFFSET 5 +#define TAG2_MSB_MASK 1 +#define TAG2_LSB_OFFSET 3 +#define TAG2_POS_MSB_MASK 7 +#define TAG2_POS_MSB_OFFSET 3 +#define TAG2_POS_LSB_OFFSET 5 +#define TAG2_LEN_MASK 31 + +#define AGT_MASK 31 +/*Extract 5 left most bits of lsb of 2nd block*/ +#define AGT(x) (x & AGT_MASK) +/*16 bits of 4th block*/ +#define AID(lsb, msb) ((msb << 8) | (lsb)) +/*Extract 5 right most bits of msb of 2nd block*/ +#define GTC(blk2msb) (blk2msb >> 3) + +#define GRP_3A 0x6 +#define RT_PLUS_AID 0x4bd7 + +/*ERT*/ +#define ERT_AID 0x6552 +#define CARRIAGE_RETURN 0x000D +#define MAX_ERT_SEGMENT 31 +#define ERT_FORMAT_DIR_BIT 1 + +#define EXTRACT_BIT(data, bit_pos) ((data & (1 << bit_pos)) >> bit_pos) + +struct hci_ev_tune_status { + __u8 sub_event; + __le32 station_freq; + __u8 serv_avble; + char rssi; + __u8 stereo_prg; + __u8 rds_sync_status; + __u8 mute_mode; + char sinr; + __u8 intf_det_th; +} __packed; + +struct rds_blk_data { + __u8 rdsMsb; + __u8 rdsLsb; + __u8 blockStatus; +} __packed; + +struct rds_grp_data { + struct rds_blk_data rdsBlk[4]; +} __packed; + +struct hci_ev_rds_rx_data { + __u8 num_rds_grps; + struct rds_grp_data rds_grp_data[MAX_RAW_RDS_GRPS]; +} __packed; + +struct hci_ev_prg_service { + __le16 pi_prg_id; + __u8 pty_prg_type; + __u8 ta_prg_code_type; + __u8 ta_ann_code_flag; + __u8 ms_switch_code_flag; + __u8 dec_id_ctrl_code_flag; + __u8 ps_num; + __u8 prg_service_name[119]; +} __packed; + +struct hci_ev_radio_text { + __le16 pi_prg_id; + __u8 pty_prg_type; + __u8 ta_prg_code_type; + __u8 txt_ab_flag; + __u8 radio_txt[64]; +} __packed; + +struct hci_ev_af_list { + __le32 tune_freq; + __le16 pi_code; + __u8 af_size; + __u8 af_list[FM_AF_LIST_MAX_SIZE]; +} __packed; + +struct hci_ev_cmd_complete { + __u8 num_hci_cmd_pkts; + __le16 cmd_opcode; +} __packed; + +struct hci_ev_cmd_status { + __u8 status; + __u8 num_hci_cmd_pkts; + __le16 status_opcode; +} __packed; + +struct hci_ev_srch_st { + __le32 station_freq; + __u8 rds_cap; + __u8 pty; + __le16 status_opcode; +} __packed; + +struct hci_ev_rel_freq { + __u8 rel_freq_msb; + __u8 rel_freq_lsb; + +} __packed; +struct hci_ev_srch_list_compl { + __u8 num_stations_found; + struct hci_ev_rel_freq rel_freq[20]; +} __packed; + +/* ----- HCI Event Response ----- */ +struct hci_fm_conf_rsp { + __u8 status; + struct hci_fm_recv_conf_req recv_conf_rsp; +} __packed; + +struct hci_fm_get_trans_conf_rsp { + __u8 status; + struct hci_fm_trans_conf_req_struct trans_conf_rsp; +} __packed; +struct hci_fm_sig_threshold_rsp { + __u8 status; + __u8 sig_threshold; +} __packed; + +struct hci_fm_station_rsp { + struct hci_ev_tune_status station_rsp; +} __packed; + +struct hci_fm_prgm_srv_rsp { + __u8 status; + struct hci_ev_prg_service prg_srv; +} __packed; + +struct hci_fm_radio_txt_rsp { + __u8 status; + struct hci_ev_radio_text rd_txt; +} __packed; + +struct hci_fm_af_list_rsp { + __u8 status; + struct hci_ev_af_list rd_txt; +} __packed; + +struct hci_fm_data_rd_rsp { + __u8 status; + __u8 ret_data_len; + __u8 data[DEFAULT_DATA_SIZE]; +} __packed; + +struct hci_fm_feature_list_rsp { + __u8 status; + __u8 feature_mask; +} __packed; + +struct hci_fm_dbg_param_rsp { + __u8 status; + __u8 blend; + __u8 soft_mute; + __u8 inf_blend; + __u8 inf_soft_mute; + __u8 pilot_pil; + __u8 io_verc; + __u8 in_det_out; +} __packed; + +#define CLKSPURID_INDEX0 0 +#define CLKSPURID_INDEX1 5 +#define CLKSPURID_INDEX2 10 +#define CLKSPURID_INDEX3 15 +#define CLKSPURID_INDEX4 20 +#define CLKSPURID_INDEX5 25 + +#define MAX_SPUR_FREQ_LIMIT 30 +#define CKK_SPUR 0x3B +#define SPUR_DATA_SIZE 0x4 +#define SPUR_ENTRIES_PER_ID 0x5 + +#define COMPUTE_SPUR(val) ((((val) - (76000)) / (50))) +#define GET_FREQ(val, bit) ((bit == 1) ? ((val) >> 8) : ((val) & 0xFF)) +#define GET_SPUR_ENTRY_LEVEL(val) ((val) / (5)) + +struct hci_fm_spur_data { + __u32 freq[MAX_SPUR_FREQ_LIMIT]; + __s8 rmssi[MAX_SPUR_FREQ_LIMIT]; + __u8 enable[MAX_SPUR_FREQ_LIMIT]; +} __packed; + + +/* HCI dev events */ +#define RADIO_HCI_DEV_REG 1 +#define RADIO_HCI_DEV_WRITE 2 + +/* FM RDS */ +#define RDS_PTYPE 2 +#define RDS_PID_LOWER 1 +#define RDS_PID_HIGHER 0 +#define RDS_OFFSET 5 +#define RDS_PS_LENGTH_OFFSET 7 +#define RDS_STRING 8 +#define RDS_PS_DATA_OFFSET 8 +#define RDS_CONFIG_OFFSET 3 +#define RDS_AF_JUMP_OFFSET 4 +#define PI_CODE_OFFSET 4 +#define AF_SIZE_OFFSET 6 +#define AF_LIST_OFFSET 7 +#define RT_A_B_FLAG_OFFSET 4 +/*FM states*/ + +enum radio_state_t { + FM_OFF, + FM_RECV, + FM_TRANS, + FM_RESET, + FM_CALIB, + FM_TURNING_OFF, + FM_RECV_TURNING_ON, + FM_TRANS_TURNING_ON, + FM_MAX_NO_STATES, +}; + +enum emphasis_type { + FM_RX_EMP75 = 0x0, + FM_RX_EMP50 = 0x1 +}; + +enum channel_space_type { + FM_RX_SPACE_200KHZ = 0x0, + FM_RX_SPACE_100KHZ = 0x1, + FM_RX_SPACE_50KHZ = 0x2 +}; + +enum high_low_injection { + AUTO_HI_LO_INJECTION = 0x0, + LOW_SIDE_INJECTION = 0x1, + HIGH_SIDE_INJECTION = 0x2 +}; + +enum fm_rds_type { + FM_RX_RDBS_SYSTEM = 0x0, + FM_RX_RDS_SYSTEM = 0x1 +}; + +enum iris_region_t { + IRIS_REGION_US, + IRIS_REGION_EU, + IRIS_REGION_JAPAN, + IRIS_REGION_JAPAN_WIDE, + IRIS_REGION_OTHER +}; + +#define STD_BUF_SIZE (256) + +enum iris_buf_t { + IRIS_BUF_SRCH_LIST, + IRIS_BUF_EVENTS, + IRIS_BUF_RT_RDS, + IRIS_BUF_PS_RDS, + IRIS_BUF_RAW_RDS, + IRIS_BUF_AF_LIST, + IRIS_BUF_PEEK, + IRIS_BUF_SSBI_PEEK, + IRIS_BUF_RDS_CNTRS, + IRIS_BUF_RD_DEFAULT, + IRIS_BUF_CAL_DATA, + IRIS_BUF_RT_PLUS, + IRIS_BUF_ERT, + IRIS_BUF_SPUR, + IRIS_BUF_MAX, +}; + +enum iris_xfr_t { + IRIS_XFR_SYNC, + IRIS_XFR_ERROR, + IRIS_XFR_SRCH_LIST, + IRIS_XFR_RT_RDS, + IRIS_XFR_PS_RDS, + IRIS_XFR_AF_LIST, + IRIS_XFR_MAX +}; + +/* Search options */ +enum search_t { + SEEK, + SCAN, + SCAN_FOR_STRONG, + SCAN_FOR_WEAK, + RDS_SEEK_PTY, + RDS_SCAN_PTY, + RDS_SEEK_PI, + RDS_AF_JUMP, +}; + +enum spur_entry_levels { + ENTRY_0, + ENTRY_1, + ENTRY_2, + ENTRY_3, + ENTRY_4, + ENTRY_5, +}; + +/* Band limits */ +#define REGION_US_EU_BAND_LOW 87500 +#define REGION_US_EU_BAND_HIGH 108000 +#define REGION_JAPAN_STANDARD_BAND_LOW 76000 +#define REGION_JAPAN_STANDARD_BAND_HIGH 90000 +#define REGION_JAPAN_WIDE_BAND_LOW 90000 +#define REGION_JAPAN_WIDE_BAND_HIGH 108000 + +#define SRCH_MODE 0x07 +#define SRCH_DIR 0x08 /* 0-up 1-down */ +#define SCAN_DWELL 0x70 +#define SRCH_ON 0x80 + +/* I/O Control */ +#define IOC_HRD_MUTE 0x03 +#define IOC_SFT_MUTE 0x01 +#define IOC_MON_STR 0x01 +#define IOC_SIG_BLND 0x01 +#define IOC_INTF_BLND 0x01 +#define IOC_ANTENNA 0x01 + +/* RDS Control */ +#define RDS_ON 0x01 +#define RDS_BUF_SZ 100 + +/* constants */ +#define RDS_BLOCKS_NUM (4) +#define BYTES_PER_BLOCK (3) +#define MAX_PS_LENGTH (108) +#define MAX_RT_LENGTH (64) +#define RDS_GRP_CNTR_LEN (36) +#define RX_RT_DATA_LENGTH (63) +/* Search direction */ +#define SRCH_DIR_UP (0) +#define SRCH_DIR_DOWN (1) + +/*Search RDS stations*/ +#define SEARCH_RDS_STNS_MODE_OFFSET 4 + +/*Search Station list */ +#define PARAMS_PER_STATION 0x08 +#define STN_NUM_OFFSET 0x01 +#define STN_FREQ_OFFSET 0x02 +#define KHZ_TO_MHZ 1000 +#define GET_MSB(x)((x >> 8) & 0xFF) +#define GET_LSB(x)((x) & 0xFF) + +/* control options */ +#define CTRL_ON (1) +#define CTRL_OFF (0) + +/*Diagnostic commands*/ + +#define RIVA_PEEK_OPCODE 0x0D +#define RIVA_POKE_OPCODE 0x0C + +#define PEEK_DATA_OFSET 0x1 +#define RIVA_PEEK_PARAM 0x6 +#define RIVA_PEEK_LEN_OFSET 0x6 +#define SSBI_PEEK_LEN 0x01 +/*Calibration data*/ +#define PROCS_CALIB_MODE 1 +#define PROCS_CALIB_SIZE 23 +#define DC_CALIB_MODE 2 +#define DC_CALIB_SIZE 48 +#define RSB_CALIB_MODE 3 +#define RSB_CALIB_SIZE 4 +#define CALIB_DATA_OFSET 2 +#define CALIB_MODE_OFSET 1 +#define MAX_CALIB_SIZE 75 + +/* Channel validity */ +#define INVALID_CHANNEL (0) +#define VALID_CHANNEL (1) + +struct hci_fm_set_cal_req_proc { + __u8 mode; + /*Max process calibration data size*/ + __u8 data[PROCS_CALIB_SIZE]; +} __packed; + +struct hci_fm_set_cal_req_dc { + __u8 mode; + /*Max DC calibration data size*/ + __u8 data[DC_CALIB_SIZE]; +} __packed; + +struct hci_cc_do_calibration_rsp { + __u8 status; + __u8 mode; + __u8 data[MAX_CALIB_SIZE]; +} __packed; + +struct hci_fm_set_spur_table_req { + __u8 mode; + __u8 no_of_freqs_entries; + __u8 spur_data[FM_SPUR_TBL_SIZE]; +} __packed; +/* Low Power mode*/ +#define SIG_LEVEL_INTR (1 << 0) +#define RDS_SYNC_INTR (1 << 1) +#define AUDIO_CTRL_INTR (1 << 2) +#define AF_JUMP_ENABLE (1 << 4) + +#endif diff --git a/include/xen/page.h b/include/xen/page.h index 9dc46cb8a0fd..96294ac93755 100644 --- a/include/xen/page.h +++ b/include/xen/page.h @@ -15,9 +15,9 @@ */ #define xen_pfn_to_page(xen_pfn) \ - (pfn_to_page((unsigned long)(xen_pfn) >> (PAGE_SHIFT - XEN_PAGE_SHIFT))) + ((pfn_to_page(((unsigned long)(xen_pfn) << XEN_PAGE_SHIFT) >> PAGE_SHIFT))) #define page_to_xen_pfn(page) \ - ((page_to_pfn(page)) << (PAGE_SHIFT - XEN_PAGE_SHIFT)) + (((page_to_pfn(page)) << PAGE_SHIFT) >> XEN_PAGE_SHIFT) #define XEN_PFN_PER_PAGE (PAGE_SIZE / XEN_PAGE_SIZE) diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index d1a7646f79c5..5a8a797d50b7 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -31,10 +31,10 @@ static void *bpf_any_get(void *raw, enum bpf_type type) { switch (type) { case BPF_TYPE_PROG: - raw = bpf_prog_inc(raw); + atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt); break; case BPF_TYPE_MAP: - raw = bpf_map_inc(raw, true); + bpf_map_inc(raw, true); break; default: WARN_ON_ONCE(1); @@ -277,8 +277,7 @@ static void *bpf_obj_do_get(const struct filename *pathname, goto out; raw = bpf_any_get(inode->i_private, *type); - if (!IS_ERR(raw)) - touch_atime(&path); + touch_atime(&path); path_put(&path); return raw; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4e32cc94edd9..3b39550d8485 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -181,18 +181,11 @@ struct bpf_map *__bpf_map_get(struct fd f) return f.file->private_data; } -/* prog's and map's refcnt limit */ -#define BPF_MAX_REFCNT 32768 - -struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) +void bpf_map_inc(struct bpf_map *map, bool uref) { - if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { - atomic_dec(&map->refcnt); - return ERR_PTR(-EBUSY); - } + atomic_inc(&map->refcnt); if (uref) atomic_inc(&map->usercnt); - return map; } struct bpf_map *bpf_map_get_with_uref(u32 ufd) @@ -204,7 +197,7 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd) if (IS_ERR(map)) return map; - map = bpf_map_inc(map, true); + bpf_map_inc(map, true); fdput(f); return map; @@ -587,15 +580,6 @@ static struct bpf_prog *__bpf_prog_get(struct fd f) return f.file->private_data; } -struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) -{ - if (atomic_inc_return(&prog->aux->refcnt) > BPF_MAX_REFCNT) { - atomic_dec(&prog->aux->refcnt); - return ERR_PTR(-EBUSY); - } - return prog; -} - /* called by sockets/tracing/seccomp before attaching program to an event * pairs with bpf_prog_put() */ @@ -608,7 +592,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd) if (IS_ERR(prog)) return prog; - prog = bpf_prog_inc(prog); + atomic_inc(&prog->aux->refcnt); fdput(f); return prog; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 2cbfba78d3db..2e7f7ab739e4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -239,6 +239,15 @@ static const char * const reg_type_str[] = { [CONST_IMM] = "imm", }; +static const struct { + int map_type; + int func_id; +} func_limit[] = { + {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call}, + {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read}, + {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output}, +}; + static void print_verifier_state(struct verifier_env *env) { enum bpf_reg_type t; @@ -889,44 +898,24 @@ static int check_func_arg(struct verifier_env *env, u32 regno, static int check_map_func_compatibility(struct bpf_map *map, int func_id) { + bool bool_map, bool_func; + int i; + if (!map) return 0; - /* We need a two way check, first is from map perspective ... */ - switch (map->map_type) { - case BPF_MAP_TYPE_PROG_ARRAY: - if (func_id != BPF_FUNC_tail_call) - goto error; - break; - case BPF_MAP_TYPE_PERF_EVENT_ARRAY: - if (func_id != BPF_FUNC_perf_event_read && - func_id != BPF_FUNC_perf_event_output) - goto error; - break; - default: - break; - } - - /* ... and second from the function itself. */ - switch (func_id) { - case BPF_FUNC_tail_call: - if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY) - goto error; - break; - case BPF_FUNC_perf_event_read: - case BPF_FUNC_perf_event_output: - if (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) - goto error; - break; - default: - break; + for (i = 0; i < ARRAY_SIZE(func_limit); i++) { + bool_map = (map->map_type == func_limit[i].map_type); + bool_func = (func_id == func_limit[i].func_id); + /* only when map & func pair match it can continue. + * don't allow any other map type to be passed into + * the special func; + */ + if (bool_func && bool_map != bool_func) + return -EINVAL; } return 0; -error: - verbose("cannot pass map_type %d into func %d\n", - map->map_type, func_id); - return -EINVAL; } static int check_call(struct verifier_env *env, int func_id) @@ -1359,7 +1348,6 @@ static int check_ld_abs(struct verifier_env *env, struct bpf_insn *insn) } if (insn->dst_reg != BPF_REG_0 || insn->off != 0 || - BPF_SIZE(insn->code) == BPF_DW || (mode == BPF_ABS && insn->src_reg != BPF_REG_0)) { verbose("BPF_LD_ABS uses reserved fields\n"); return -EINVAL; @@ -2015,6 +2003,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) if (IS_ERR(map)) { verbose("fd %d is not pointing to valid bpf_map\n", insn->imm); + fdput(f); return PTR_ERR(map); } @@ -2034,18 +2023,15 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) return -E2BIG; } + /* remember this map */ + env->used_maps[env->used_map_cnt++] = map; + /* hold the map. If the program is rejected by verifier, * the map will be released by release_maps() or it * will be used by the valid program until it's unloaded * and all maps are released in free_bpf_prog_info() */ - map = bpf_map_inc(map, false); - if (IS_ERR(map)) { - fdput(f); - return PTR_ERR(map); - } - env->used_maps[env->used_map_cnt++] = map; - + bpf_map_inc(map, false); fdput(f); next_insn: insn++; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9d03abef6676..e8d71110ed2a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2776,10 +2776,9 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off, bool threadgroup) { struct task_struct *tsk; - struct cgroup_subsys *ss; struct cgroup *cgrp; pid_t pid; - int ssid, ret; + int ret; if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0) return -EINVAL; @@ -2827,10 +2826,8 @@ out_unlock_rcu: rcu_read_unlock(); out_unlock_threadgroup: percpu_up_write(&cgroup_threadgroup_rwsem); - for_each_subsys(ss, ssid) - if (ss->post_attach) - ss->post_attach(); cgroup_kn_unlock(of->kn); + cpuset_post_attach_flush(); return ret ?: nbytes; } @@ -4747,15 +4744,14 @@ static void css_free_work_fn(struct work_struct *work) if (ss) { /* css free path */ - struct cgroup_subsys_state *parent = css->parent; int id = css->id; + if (css->parent) + css_put(css->parent); + ss->css_free(css); cgroup_idr_remove(&ss->css_idr, id); cgroup_put(cgrp); - - if (parent) - css_put(parent); } else { /* cgroup free path */ atomic_dec(&cgrp->root->nr_cgrps); diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 92c34fe1b2b9..69d25607d41b 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -57,6 +57,7 @@ #include <asm/uaccess.h> #include <linux/atomic.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <linux/cgroup.h> #include <linux/wait.h> @@ -1017,7 +1018,7 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, } } -static void cpuset_post_attach(void) +void cpuset_post_attach_flush(void) { flush_workqueue(cpuset_migrate_mm_wq); } @@ -2110,7 +2111,6 @@ struct cgroup_subsys cpuset_cgrp_subsys = { .allow_attach = cpuset_allow_attach, .cancel_attach = cpuset_cancel_attach, .attach = cpuset_attach, - .post_attach = cpuset_post_attach, .bind = cpuset_bind, .legacy_cftypes = files, .early_init = 1, diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 014b69528194..adfdc0536117 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -347,7 +347,6 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, bool truncated) { struct ring_buffer *rb = handle->rb; - bool wakeup = truncated; unsigned long aux_head; u64 flags = 0; @@ -376,16 +375,9 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, aux_head = rb->user_page->aux_head = local_read(&rb->aux_head); if (aux_head - local_read(&rb->aux_wakeup) >= rb->aux_watermark) { - wakeup = true; - local_add(rb->aux_watermark, &rb->aux_wakeup); - } - - if (wakeup) { - if (truncated) - handle->event->pending_disable = 1; perf_output_wakeup(handle); + local_add(rb->aux_watermark, &rb->aux_wakeup); } - handle->event = NULL; local_set(&rb->aux_nest, 0); diff --git a/kernel/futex.c b/kernel/futex.c index 9d8163afd87c..461c72b2dac2 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1244,20 +1244,10 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this, if (unlikely(should_fail_futex(true))) ret = -EFAULT; - if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) { + if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) ret = -EFAULT; - } else if (curval != uval) { - /* - * If a unconditional UNLOCK_PI operation (user space did not - * try the TID->0 transition) raced with a waiter setting the - * FUTEX_WAITERS flag between get_user() and locking the hash - * bucket lock, retry the operation. - */ - if ((FUTEX_TID_MASK & curval) == uval) - ret = -EAGAIN; - else - ret = -EINVAL; - } + else if (curval != uval) + ret = -EINVAL; if (ret) { raw_spin_unlock(&pi_state->pi_mutex.wait_lock); return ret; @@ -1484,8 +1474,8 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1, if (likely(&hb1->chain != &hb2->chain)) { plist_del(&q->list, &hb1->chain); hb_waiters_dec(hb1); - hb_waiters_inc(hb2); plist_add(&q->list, &hb2->chain); + hb_waiters_inc(hb2); q->lock_ptr = &hb2->lock; } get_futex_key_refs(key2); @@ -2548,15 +2538,6 @@ retry: if (ret == -EFAULT) goto pi_faulted; /* - * A unconditional UNLOCK_PI op raced against a waiter - * setting the FUTEX_WAITERS bit. Try again. - */ - if (ret == -EAGAIN) { - spin_unlock(&hb->lock); - put_futex_key(&key); - goto retry; - } - /* * wake_futex_pi has detected invalid state. Tell user * space. */ diff --git a/kernel/locking/mcs_spinlock.h b/kernel/locking/mcs_spinlock.h index c835270f0c2f..5b9102a47ea5 100644 --- a/kernel/locking/mcs_spinlock.h +++ b/kernel/locking/mcs_spinlock.h @@ -67,13 +67,7 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node) node->locked = 0; node->next = NULL; - /* - * We rely on the full barrier with global transitivity implied by the - * below xchg() to order the initialization stores above against any - * observation of @node. And to provide the ACQUIRE ordering associated - * with a LOCK primitive. - */ - prev = xchg(lock, node); + prev = xchg_acquire(lock, node); if (likely(prev == NULL)) { /* * Lock acquired, don't need to set node->locked to 1. Threads diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 0551c219c40e..fb42418507ae 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/debug_locks.h> #include <linux/osq_lock.h> +#include <linux/delay.h> /* * In the DEBUG case we are using the "NULL fastpath" for mutexes, @@ -378,6 +379,17 @@ static bool mutex_optimistic_spin(struct mutex *lock, * values at the cost of a few extra spins. */ cpu_relax_lowlatency(); + + /* + * On arm systems, we must slow down the waiter's repeated + * aquisition of spin_mlock and atomics on the lock count, or + * we risk starving out a thread attempting to release the + * mutex. The mutex slowpath release must take spin lock + * wait_lock. This spin lock can share a monitor with the + * other waiter atomics in the mutex data structure, so must + * take care to rate limit the waiters. + */ + udelay(1); } osq_unlock(&lock->osq); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a1626bdf8729..ae54c5bfac1d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7979,7 +7979,7 @@ void set_curr_task(int cpu, struct task_struct *p) /* task_group_lock serializes the addition/removal of task groups */ static DEFINE_SPINLOCK(task_group_lock); -static void sched_free_group(struct task_group *tg) +static void free_sched_group(struct task_group *tg) { free_fair_sched_group(tg); free_rt_sched_group(tg); @@ -8005,7 +8005,7 @@ struct task_group *sched_create_group(struct task_group *parent) return tg; err: - sched_free_group(tg); + free_sched_group(tg); return ERR_PTR(-ENOMEM); } @@ -8025,16 +8025,17 @@ void sched_online_group(struct task_group *tg, struct task_group *parent) } /* rcu callback to free various structures associated with a task group */ -static void sched_free_group_rcu(struct rcu_head *rhp) +static void free_sched_group_rcu(struct rcu_head *rhp) { /* now it should be safe to free those cfs_rqs */ - sched_free_group(container_of(rhp, struct task_group, rcu)); + free_sched_group(container_of(rhp, struct task_group, rcu)); } +/* Destroy runqueue etc associated with a task group */ void sched_destroy_group(struct task_group *tg) { /* wait for possible concurrent references to cfs_rqs complete */ - call_rcu(&tg->rcu, sched_free_group_rcu); + call_rcu(&tg->rcu, free_sched_group_rcu); } void sched_offline_group(struct task_group *tg) @@ -8495,26 +8496,31 @@ cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) if (IS_ERR(tg)) return ERR_PTR(-ENOMEM); - sched_online_group(tg, parent); - return &tg->css; } -static void cpu_cgroup_css_released(struct cgroup_subsys_state *css) +static int cpu_cgroup_css_online(struct cgroup_subsys_state *css) { struct task_group *tg = css_tg(css); + struct task_group *parent = css_tg(css->parent); - sched_offline_group(tg); + if (parent) + sched_online_group(tg, parent); + return 0; } static void cpu_cgroup_css_free(struct cgroup_subsys_state *css) { struct task_group *tg = css_tg(css); - /* - * Relies on the RCU grace period between css_released() and this. - */ - sched_free_group(tg); + sched_destroy_group(tg); +} + +static void cpu_cgroup_css_offline(struct cgroup_subsys_state *css) +{ + struct task_group *tg = css_tg(css); + + sched_offline_group(tg); } static void cpu_cgroup_fork(struct task_struct *task, void *private) @@ -8881,8 +8887,9 @@ static struct cftype cpu_files[] = { struct cgroup_subsys cpu_cgrp_subsys = { .css_alloc = cpu_cgroup_css_alloc, - .css_released = cpu_cgroup_css_released, .css_free = cpu_cgroup_css_free, + .css_online = cpu_cgroup_css_online, + .css_offline = cpu_cgroup_css_offline, .fork = cpu_cgroup_fork, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 26960e49bb8c..fda3b6e1b3a0 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -2108,13 +2108,8 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) trace_create_file("filter", 0644, file->dir, file, &ftrace_event_filter_fops); - /* - * Only event directories that can be enabled should have - * triggers. - */ - if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) - trace_create_file("trigger", 0644, file->dir, file, - &event_trigger_fops); + trace_create_file("trigger", 0644, file->dir, file, + &event_trigger_fops); trace_create_file("format", 0444, file->dir, call, &ftrace_event_format_fops); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 316b316c7528..ef84d9874d03 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -652,35 +652,6 @@ static void set_work_pool_and_clear_pending(struct work_struct *work, */ smp_wmb(); set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0); - /* - * The following mb guarantees that previous clear of a PENDING bit - * will not be reordered with any speculative LOADS or STORES from - * work->current_func, which is executed afterwards. This possible - * reordering can lead to a missed execution on attempt to qeueue - * the same @work. E.g. consider this case: - * - * CPU#0 CPU#1 - * ---------------------------- -------------------------------- - * - * 1 STORE event_indicated - * 2 queue_work_on() { - * 3 test_and_set_bit(PENDING) - * 4 } set_..._and_clear_pending() { - * 5 set_work_data() # clear bit - * 6 smp_mb() - * 7 work->current_func() { - * 8 LOAD event_indicated - * } - * - * Without an explicit full barrier speculative LOAD on line 8 can - * be executed before CPU#0 does STORE on line 1. If that happens, - * CPU#0 observes the PENDING bit is still set and new execution of - * a @work is not queued in a hope, that CPU#1 will eventually - * finish the queued @work. Meanwhile CPU#1 does not see - * event_indicated is set, because speculative LOAD was executed - * before actual STORE. - */ - smp_mb(); } static void clear_work_data(struct work_struct *work) @@ -4476,17 +4447,6 @@ static void rebind_workers(struct worker_pool *pool) pool->attrs->cpumask) < 0); spin_lock_irq(&pool->lock); - - /* - * XXX: CPU hotplug notifiers are weird and can call DOWN_FAILED - * w/o preceding DOWN_PREPARE. Work around it. CPU hotplug is - * being reworked and this can go away in time. - */ - if (!(pool->flags & POOL_DISASSOCIATED)) { - spin_unlock_irq(&pool->lock); - return; - } - pool->flags &= ~POOL_DISASSOCIATED; for_each_pool_worker(worker, pool) { diff --git a/lib/assoc_array.c b/lib/assoc_array.c index 59fd7c0b119c..03dd576e6773 100644 --- a/lib/assoc_array.c +++ b/lib/assoc_array.c @@ -524,9 +524,7 @@ static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit, free_slot = i; continue; } - if (assoc_array_ptr_is_leaf(ptr) && - ops->compare_object(assoc_array_ptr_to_leaf(ptr), - index_key)) { + if (ops->compare_object(assoc_array_ptr_to_leaf(ptr), index_key)) { pr_devel("replace in slot %d\n", i); edit->leaf_p = &node->slots[i]; edit->dead_leaf = node->slots[i]; diff --git a/lib/extable.c b/lib/extable.c index 0be02ad561e9..4cac81ec225e 100644 --- a/lib/extable.c +++ b/lib/extable.c @@ -14,37 +14,7 @@ #include <linux/sort.h> #include <asm/uaccess.h> -#ifndef ARCH_HAS_RELATIVE_EXTABLE -#define ex_to_insn(x) ((x)->insn) -#else -static inline unsigned long ex_to_insn(const struct exception_table_entry *x) -{ - return (unsigned long)&x->insn + x->insn; -} -#endif - #ifndef ARCH_HAS_SORT_EXTABLE -#ifndef ARCH_HAS_RELATIVE_EXTABLE -#define swap_ex NULL -#else -static void swap_ex(void *a, void *b, int size) -{ - struct exception_table_entry *x = a, *y = b, tmp; - int delta = b - a; - - tmp = *x; - x->insn = y->insn + delta; - y->insn = tmp.insn - delta; - -#ifdef swap_ex_entry_fixup - swap_ex_entry_fixup(x, y, tmp, delta); -#else - x->fixup = y->fixup + delta; - y->fixup = tmp.fixup - delta; -#endif -} -#endif /* ARCH_HAS_RELATIVE_EXTABLE */ - /* * The exception table needs to be sorted so that the binary * search that we use to find entries in it works properly. @@ -56,9 +26,9 @@ static int cmp_ex(const void *a, const void *b) const struct exception_table_entry *x = a, *y = b; /* avoid overflow */ - if (ex_to_insn(x) > ex_to_insn(y)) + if (x->insn > y->insn) return 1; - if (ex_to_insn(x) < ex_to_insn(y)) + if (x->insn < y->insn) return -1; return 0; } @@ -67,7 +37,7 @@ void sort_extable(struct exception_table_entry *start, struct exception_table_entry *finish) { sort(start, finish - start, sizeof(struct exception_table_entry), - cmp_ex, swap_ex); + cmp_ex, NULL); } #ifdef CONFIG_MODULES @@ -78,15 +48,13 @@ void sort_extable(struct exception_table_entry *start, void trim_init_extable(struct module *m) { /*trim the beginning*/ - while (m->num_exentries && - within_module_init(ex_to_insn(&m->extable[0]), m)) { + while (m->num_exentries && within_module_init(m->extable[0].insn, m)) { m->extable++; m->num_exentries--; } /*trim the end*/ while (m->num_exentries && - within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]), - m)) + within_module_init(m->extable[m->num_exentries-1].insn, m)) m->num_exentries--; } #endif /* CONFIG_MODULES */ @@ -113,13 +81,13 @@ search_extable(const struct exception_table_entry *first, * careful, the distance between value and insn * can be larger than MAX_LONG: */ - if (ex_to_insn(mid) < value) + if (mid->insn < value) first = mid + 1; - else if (ex_to_insn(mid) > value) + else if (mid->insn > value) last = mid - 1; else return mid; - } - return NULL; + } + return NULL; } #endif diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h index 0710a62ad2f6..abcecdc2d0f2 100644 --- a/lib/lz4/lz4defs.h +++ b/lib/lz4/lz4defs.h @@ -11,7 +11,8 @@ /* * Detects 64 bits mode */ -#if defined(CONFIG_64BIT) +#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) \ + || defined(__ppc64__) || defined(__LP64__)) #define LZ4_ARCH64 1 #else #define LZ4_ARCH64 0 @@ -34,10 +35,6 @@ typedef struct _U64_S { u64 v; } U64_S; #define PUT4(s, d) (A32(d) = A32(s)) #define PUT8(s, d) (A64(d) = A64(s)) - -#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ - (d = s - A16(p)) - #define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ do { \ A16(p) = v; \ @@ -54,13 +51,10 @@ typedef struct _U64_S { u64 v; } U64_S; #define PUT8(s, d) \ put_unaligned(get_unaligned((const u64 *) s), (u64 *) d) -#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ - (d = s - get_unaligned_le16(p)) - -#define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ - do { \ - put_unaligned_le16(v, (u16 *)(p)); \ - p += 2; \ +#define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ + do { \ + put_unaligned(v, (u16 *)(p)); \ + p += 2; \ } while (0) #endif @@ -146,6 +140,9 @@ typedef struct _U64_S { u64 v; } U64_S; #endif +#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ + (d = s - get_unaligned_le16(p)) + #define LZ4_WILDCOPY(s, d, e) \ do { \ LZ4_COPYPACKET(s, d); \ diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index e00ff00e861c..3db76b8c1115 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -128,23 +128,6 @@ leave: } EXPORT_SYMBOL_GPL(mpi_read_from_buffer); -static int count_lzeros(MPI a) -{ - mpi_limb_t alimb; - int i, lzeros = 0; - - for (i = a->nlimbs - 1; i >= 0; i--) { - alimb = a->d[i]; - if (alimb == 0) { - lzeros += sizeof(mpi_limb_t); - } else { - lzeros += count_leading_zeros(alimb) / 8; - break; - } - } - return lzeros; -} - /** * mpi_read_buffer() - read MPI to a bufer provided by user (msb first) * @@ -163,7 +146,7 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, uint8_t *p; mpi_limb_t alimb; unsigned int n = mpi_get_size(a); - int i, lzeros; + int i, lzeros = 0; if (buf_len < n || !buf || !nbytes) return -EINVAL; @@ -171,7 +154,14 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, if (sign) *sign = a->sign; - lzeros = count_lzeros(a); + p = (void *)&a->d[a->nlimbs] - 1; + + for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) { + if (!*p) + lzeros++; + else + break; + } p = buf; *nbytes = n - lzeros; @@ -353,7 +343,7 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, u8 *p, *p2; mpi_limb_t alimb, alimb2; unsigned int n = mpi_get_size(a); - int i, x, y = 0, lzeros, buf_len; + int i, x, y = 0, lzeros = 0, buf_len; if (!nbytes || *nbytes < n) return -EINVAL; @@ -361,7 +351,14 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, if (sign) *sign = a->sign; - lzeros = count_lzeros(a); + p = (void *)&a->d[a->nlimbs] - 1; + + for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) { + if (!*p) + lzeros++; + else + break; + } *nbytes = n - lzeros; buf_len = sgl->length; diff --git a/lib/test-string_helpers.c b/lib/test-string_helpers.c index 25b5cbfb7615..98866a770770 100644 --- a/lib/test-string_helpers.c +++ b/lib/test-string_helpers.c @@ -327,67 +327,36 @@ out: } #define string_get_size_maxbuf 16 -#define test_string_get_size_one(size, blk_size, exp_result10, exp_result2) \ +#define test_string_get_size_one(size, blk_size, units, exp_result) \ do { \ - BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf); \ - BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf); \ - __test_string_get_size((size), (blk_size), (exp_result10), \ - (exp_result2)); \ + BUILD_BUG_ON(sizeof(exp_result) >= string_get_size_maxbuf); \ + __test_string_get_size((size), (blk_size), (units), \ + (exp_result)); \ } while (0) -static __init void test_string_get_size_check(const char *units, - const char *exp, - char *res, - const u64 size, - const u64 blk_size) -{ - if (!memcmp(res, exp, strlen(exp) + 1)) - return; - - res[string_get_size_maxbuf - 1] = '\0'; - - pr_warn("Test 'test_string_get_size' failed!\n"); - pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n", - size, blk_size, units); - pr_warn("expected: '%s', got '%s'\n", exp, res); -} - static __init void __test_string_get_size(const u64 size, const u64 blk_size, - const char *exp_result10, - const char *exp_result2) + const enum string_size_units units, + const char *exp_result) { - char buf10[string_get_size_maxbuf]; - char buf2[string_get_size_maxbuf]; - - string_get_size(size, blk_size, STRING_UNITS_10, buf10, sizeof(buf10)); - string_get_size(size, blk_size, STRING_UNITS_2, buf2, sizeof(buf2)); + char buf[string_get_size_maxbuf]; - test_string_get_size_check("STRING_UNITS_10", exp_result10, buf10, - size, blk_size); + string_get_size(size, blk_size, units, buf, sizeof(buf)); + if (!memcmp(buf, exp_result, strlen(exp_result) + 1)) + return; - test_string_get_size_check("STRING_UNITS_2", exp_result2, buf2, - size, blk_size); + buf[sizeof(buf) - 1] = '\0'; + pr_warn("Test 'test_string_get_size_one' failed!\n"); + pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %d\n", + size, blk_size, units); + pr_warn("expected: '%s', got '%s'\n", exp_result, buf); } static __init void test_string_get_size(void) { - /* small values */ - test_string_get_size_one(0, 512, "0 B", "0 B"); - test_string_get_size_one(1, 512, "512 B", "512 B"); - test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB"); - - /* normal values */ - test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB"); - test_string_get_size_one(500118192, 512, "256 GB", "238 GiB"); - test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB"); - - /* weird block sizes */ - test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB"); - - /* huge values */ - test_string_get_size_one(U64_MAX, 4096, "75.6 ZB", "64.0 ZiB"); - test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB"); + test_string_get_size_one(16384, 512, STRING_UNITS_2, "8.00 MiB"); + test_string_get_size_one(8192, 4096, STRING_UNITS_10, "32.7 MB"); + test_string_get_size_one(1, 512, STRING_UNITS_10, "512 B"); } static int __init test_string_helpers_init(void) diff --git a/mm/compaction.c b/mm/compaction.c index 7f9e60489d67..e0d4a58bcee4 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -905,8 +905,16 @@ isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn, pfn = isolate_migratepages_block(cc, pfn, block_end_pfn, ISOLATE_UNEVICTABLE); - if (!pfn) + /* + * In case of fatal failure, release everything that might + * have been isolated in the previous iteration, and signal + * the failure back to caller. + */ + if (!pfn) { + putback_movable_pages(&cc->migratepages); + cc->nr_migratepages = 0; break; + } if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) break; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 530e6427f823..62fe06bb7d04 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2134,9 +2134,10 @@ int khugepaged_enter_vma_merge(struct vm_area_struct *vma, * page fault if needed. */ return 0; - if (vma->vm_ops || (vm_flags & VM_NO_THP)) + if (vma->vm_ops) /* khugepaged not yet working on file or special mappings */ return 0; + VM_BUG_ON_VMA(vm_flags & VM_NO_THP, vma); hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK; hend = vma->vm_end & HPAGE_PMD_MASK; if (hstart < hend) @@ -2497,7 +2498,8 @@ static bool hugepage_vma_check(struct vm_area_struct *vma) return false; if (is_vma_temporary_stack(vma)) return false; - return !(vma->vm_flags & VM_NO_THP); + VM_BUG_ON_VMA(vma->vm_flags & VM_NO_THP, vma); + return true; } static void collapse_huge_page(struct mm_struct *mm, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d1f6dc5a715d..7535ef32a75b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -196,7 +196,6 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg); /* "mc" and its members are protected by cgroup_mutex */ static struct move_charge_struct { spinlock_t lock; /* for from, to */ - struct mm_struct *mm; struct mem_cgroup *from; struct mem_cgroup *to; unsigned long flags; @@ -4801,8 +4800,6 @@ static void __mem_cgroup_clear_mc(void) static void mem_cgroup_clear_mc(void) { - struct mm_struct *mm = mc.mm; - /* * we must clear moving_task before waking up waiters at the end of * task migration. @@ -4812,10 +4809,7 @@ static void mem_cgroup_clear_mc(void) spin_lock(&mc.lock); mc.from = NULL; mc.to = NULL; - mc.mm = NULL; spin_unlock(&mc.lock); - - mmput(mm); } static int mem_cgroup_can_attach(struct cgroup_taskset *tset) @@ -4872,7 +4866,6 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset) VM_BUG_ON(mc.moved_swap); spin_lock(&mc.lock); - mc.mm = mm; mc.from = from; mc.to = memcg; mc.flags = move_flags; @@ -4882,9 +4875,8 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset) ret = mem_cgroup_precharge_mc(mm); if (ret) mem_cgroup_clear_mc(); - } else { - mmput(mm); } + mmput(mm); return ret; } @@ -4998,11 +4990,11 @@ put: /* get_mctgt_type() gets the page */ return ret; } -static void mem_cgroup_move_charge(void) +static void mem_cgroup_move_charge(struct mm_struct *mm) { struct mm_walk mem_cgroup_move_charge_walk = { .pmd_entry = mem_cgroup_move_charge_pte_range, - .mm = mc.mm, + .mm = mm, }; lru_add_drain_all(); @@ -5014,7 +5006,7 @@ static void mem_cgroup_move_charge(void) atomic_inc(&mc.from->moving_account); synchronize_rcu(); retry: - if (unlikely(!down_read_trylock(&mc.mm->mmap_sem))) { + if (unlikely(!down_read_trylock(&mm->mmap_sem))) { /* * Someone who are holding the mmap_sem might be waiting in * waitq. So we cancel all extra charges, wake up all waiters, @@ -5031,16 +5023,23 @@ retry: * additional charge, the page walk just aborts. */ walk_page_range(0, ~0UL, &mem_cgroup_move_charge_walk); - up_read(&mc.mm->mmap_sem); + up_read(&mm->mmap_sem); atomic_dec(&mc.from->moving_account); } -static void mem_cgroup_move_task(void) +static void mem_cgroup_move_task(struct cgroup_taskset *tset) { - if (mc.to) { - mem_cgroup_move_charge(); - mem_cgroup_clear_mc(); + struct cgroup_subsys_state *css; + struct task_struct *p = cgroup_taskset_first(tset, &css); + struct mm_struct *mm = get_task_mm(p); + + if (mm) { + if (mc.to) + mem_cgroup_move_charge(mm); + mmput(mm); } + if (mc.to) + mem_cgroup_clear_mc(); } #else /* !CONFIG_MMU */ static int mem_cgroup_can_attach(struct cgroup_taskset *tset) @@ -5054,7 +5053,7 @@ static int mem_cgroup_allow_attach(struct cgroup_taskset *tset) static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset) { } -static void mem_cgroup_move_task(void) +static void mem_cgroup_move_task(struct cgroup_taskset *tset) { } #endif @@ -5270,7 +5269,6 @@ struct cgroup_subsys memory_cgrp_subsys = { .cancel_attach = mem_cgroup_cancel_attach, .attach = mem_cgroup_move_task, .allow_attach = mem_cgroup_allow_attach, - .post_attach = mem_cgroup_move_task, .bind = mem_cgroup_bind, .dfl_cftypes = memory_files, .legacy_cftypes = mem_cgroup_legacy_files, diff --git a/mm/memory.c b/mm/memory.c index b536e3d60fc7..6098837a4e5e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -797,46 +797,6 @@ out: return pfn_to_page(pfn); } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr, - pmd_t pmd) -{ - unsigned long pfn = pmd_pfn(pmd); - - /* - * There is no pmd_special() but there may be special pmds, e.g. - * in a direct-access (dax) mapping, so let's just replicate the - * !HAVE_PTE_SPECIAL case from vm_normal_page() here. - */ - if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) { - if (vma->vm_flags & VM_MIXEDMAP) { - if (!pfn_valid(pfn)) - return NULL; - goto out; - } else { - unsigned long off; - off = (addr - vma->vm_start) >> PAGE_SHIFT; - if (pfn == vma->vm_pgoff + off) - return NULL; - if (!is_cow_mapping(vma->vm_flags)) - return NULL; - } - } - - if (is_zero_pfn(pfn)) - return NULL; - if (unlikely(pfn > highest_memmap_pfn)) - return NULL; - - /* - * NOTE! We still have PageReserved() pages in the page tables. - * eg. VDSO mappings can cause them to exist. - */ -out: - return pfn_to_page(pfn); -} -#endif - /* * copy one vm_area from one task to the other. Assumes the page tables * already present in the new task to be cleared in the whole range diff --git a/mm/migrate.c b/mm/migrate.c index 3db1b0277eb4..cd1e63062459 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -963,13 +963,7 @@ out: dec_zone_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); /* Soft-offlined page shouldn't go through lru cache list */ - if (reason == MR_MEMORY_FAILURE && rc == MIGRATEPAGE_SUCCESS) { - /* - * With this release, we free successfully migrated - * page and set PG_HWPoison on just freed page - * intentionally. Although it's rather weird, it's how - * HWPoison flag works at the moment. - */ + if (reason == MR_MEMORY_FAILURE) { put_page(page); if (!test_set_page_hwpoison(page)) num_poisoned_pages_inc(); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 8bf8e06a56a6..112c0bebfff3 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1899,8 +1899,7 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb) if (gdtc->dirty > gdtc->bg_thresh) return true; - if (wb_stat(wb, WB_RECLAIMABLE) > - wb_calc_thresh(gdtc->wb, gdtc->bg_thresh)) + if (wb_stat(wb, WB_RECLAIMABLE) > __wb_calc_thresh(gdtc)) return true; if (mdtc) { @@ -1914,8 +1913,7 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb) if (mdtc->dirty > mdtc->bg_thresh) return true; - if (wb_stat(wb, WB_RECLAIMABLE) > - wb_calc_thresh(mdtc->wb, mdtc->bg_thresh)) + if (wb_stat(wb, WB_RECLAIMABLE) > __wb_calc_thresh(mdtc)) return true; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c8a31783c2d6..ffcb2b56f6c1 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6294,7 +6294,7 @@ int __meminit init_per_zone_wmark_min(void) setup_per_zone_inactive_ratio(); return 0; } -core_initcall(init_per_zone_wmark_min) +module_init(init_per_zone_wmark_min) /* * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so diff --git a/mm/slub.c b/mm/slub.c index fdc0721ebc31..2d5bbea0f0e8 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2832,7 +2832,6 @@ struct detached_freelist { void *tail; void *freelist; int cnt; - struct kmem_cache *s; }; /* @@ -2847,9 +2846,8 @@ struct detached_freelist { * synchronization primitive. Look ahead in the array is limited due * to performance reasons. */ -static inline -int build_detached_freelist(struct kmem_cache *s, size_t size, - void **p, struct detached_freelist *df) +static int build_detached_freelist(struct kmem_cache *s, size_t size, + void **p, struct detached_freelist *df) { size_t first_skipped_index = 0; int lookahead = 3; @@ -2865,11 +2863,8 @@ int build_detached_freelist(struct kmem_cache *s, size_t size, if (!object) return 0; - /* Support for memcg, compiler can optimize this out */ - df->s = cache_from_obj(s, object); - /* Start new detached freelist */ - set_freepointer(df->s, object, NULL); + set_freepointer(s, object, NULL); df->page = virt_to_head_page(object); df->tail = object; df->freelist = object; @@ -2884,7 +2879,7 @@ int build_detached_freelist(struct kmem_cache *s, size_t size, /* df->page is always set at this point */ if (df->page == virt_to_head_page(object)) { /* Opportunity build freelist */ - set_freepointer(df->s, object, df->freelist); + set_freepointer(s, object, df->freelist); df->freelist = object; df->cnt++; p[size] = NULL; /* mark object processed */ @@ -2903,20 +2898,25 @@ int build_detached_freelist(struct kmem_cache *s, size_t size, return first_skipped_index; } + /* Note that interrupts must be enabled when calling this function. */ -void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) +void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p) { if (WARN_ON(!size)) return; do { struct detached_freelist df; + struct kmem_cache *s; + + /* Support for memcg */ + s = cache_from_obj(orig_s, p[size - 1]); size = build_detached_freelist(s, size, p, &df); if (unlikely(!df.page)) continue; - slab_free(df.s, df.page, df.freelist, df.tail, df.cnt,_RET_IP_); + slab_free(s, df.page, df.freelist, df.tail, df.cnt, _RET_IP_); } while (likely(size)); } EXPORT_SYMBOL(kmem_cache_free_bulk); diff --git a/mm/vmscan.c b/mm/vmscan.c index d5c3ef60a71e..73f5cec91063 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2683,7 +2683,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc) sc->gfp_mask |= __GFP_HIGHMEM; for_each_zone_zonelist_nodemask(zone, z, zonelist, - gfp_zone(sc->gfp_mask), sc->nodemask) { + requested_highidx, sc->nodemask) { enum zone_type classzone_idx; if (!populated_zone(zone)) diff --git a/mm/zbud.c b/mm/zbud.c index 04359b845ead..09ab957e2b10 100644 --- a/mm/zbud.c +++ b/mm/zbud.c @@ -357,6 +357,7 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp, struct zbud_header *zhdr = NULL; enum buddy bud; struct page *page; + unsigned long flags; int found = 0; if (!size || (gfp & __GFP_HIGHMEM)) @@ -364,7 +365,7 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp, if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE) return -ENOSPC; chunks = size_to_chunks(size); - spin_lock_bh(&pool->lock); + spin_lock_irqsave(&pool->lock, flags); /* First, try to find an unbuddied zbud page. */ zhdr = NULL; @@ -383,11 +384,11 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp, } /* Couldn't find unbuddied zbud page, create new one */ - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); page = alloc_page(gfp); if (!page) return -ENOMEM; - spin_lock_bh(&pool->lock); + spin_lock_irqsave(&pool->lock, flags); pool->pages_nr++; zhdr = init_zbud_page(page); bud = FIRST; @@ -415,7 +416,7 @@ found: *handle = encode_handle(zhdr, bud); if ((gfp & __GFP_ZERO) && found) memset((void *)*handle, 0, size); - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); return 0; } @@ -434,8 +435,9 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle) { struct zbud_header *zhdr; int freechunks; + unsigned long flags; - spin_lock_bh(&pool->lock); + spin_lock_irqsave(&pool->lock, flags); zhdr = handle_to_zbud_header(handle); /* If first buddy, handle will be page aligned */ @@ -446,7 +448,7 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle) if (zhdr->under_reclaim) { /* zbud page is under reclaim, reclaim will free */ - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); return; } @@ -464,7 +466,7 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle) list_add(&zhdr->buddy, &pool->unbuddied[freechunks]); } - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); } #define list_tail_entry(ptr, type, member) \ @@ -509,12 +511,13 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries) { int i, ret, freechunks; struct zbud_header *zhdr; + unsigned long flags; unsigned long first_handle = 0, last_handle = 0; - spin_lock_bh(&pool->lock); + spin_lock_irqsave(&pool->lock, flags); if (!pool->ops || !pool->ops->evict || list_empty(&pool->lru) || retries == 0) { - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); return -EINVAL; } for (i = 0; i < retries; i++) { @@ -533,7 +536,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries) first_handle = encode_handle(zhdr, FIRST); if (zhdr->last_chunks) last_handle = encode_handle(zhdr, LAST); - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); /* Issue the eviction callback(s) */ if (first_handle) { @@ -547,7 +550,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries) goto next; } next: - spin_lock_bh(&pool->lock); + spin_lock_irqsave(&pool->lock, flags); zhdr->under_reclaim = false; if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) { /* @@ -556,7 +559,7 @@ next: */ free_zbud_page(zhdr); pool->pages_nr--; - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); return 0; } else if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0) { @@ -571,7 +574,7 @@ next: /* add to beginning of LRU */ list_add(&zhdr->lru, &pool->lru); } - spin_unlock_bh(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); return -EAGAIN; } diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index c1ea19478119..fc083996e40a 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1732,13 +1732,10 @@ static struct page *isolate_source_page(struct size_class *class) static unsigned long zs_can_compact(struct size_class *class) { unsigned long obj_wasted; - unsigned long obj_allocated = zs_stat_get(class, OBJ_ALLOCATED); - unsigned long obj_used = zs_stat_get(class, OBJ_USED); - if (obj_allocated <= obj_used) - return 0; + obj_wasted = zs_stat_get(class, OBJ_ALLOCATED) - + zs_stat_get(class, OBJ_USED); - obj_wasted = obj_allocated - obj_used; obj_wasted /= get_maxobj_per_zspage(class->size, class->pages_per_zspage); diff --git a/mm/zswap.c b/mm/zswap.c index 340261946fda..bf14508afd64 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -170,8 +170,6 @@ static struct zswap_tree *zswap_trees[MAX_SWAPFILES]; static LIST_HEAD(zswap_pools); /* protects zswap_pools list modification */ static DEFINE_SPINLOCK(zswap_pools_lock); -/* pool counter to provide unique names to zpool */ -static atomic_t zswap_pools_count = ATOMIC_INIT(0); /* used by param callback function */ static bool zswap_init_started; @@ -567,7 +565,6 @@ static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor) static struct zswap_pool *zswap_pool_create(char *type, char *compressor) { struct zswap_pool *pool; - char name[38]; /* 'zswap' + 32 char (max) num + \0 */ gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM; pool = kzalloc(sizeof(*pool), GFP_KERNEL); @@ -576,10 +573,7 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor) return NULL; } - /* unique name for each pool specifically required by zsmalloc */ - snprintf(name, 38, "zswap%x", atomic_inc_return(&zswap_pools_count)); - - pool->zpool = zpool_create_pool(type, name, gfp, &zswap_zpool_ops); + pool->zpool = zpool_create_pool(type, "zswap", gfp, &zswap_zpool_ops); if (!pool->zpool) { pr_err("%s zpool not available\n", type); goto error; diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 5f19133c5530..a49c705fb86b 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -553,7 +553,6 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv, * be sent to * @bat_priv: the bat priv with all the soft interface information * @ip_dst: ipv4 to look up in the DHT - * @vid: VLAN identifier * * An originator O is selected if and only if its DHT_ID value is one of three * closest values (from the LEFT, with wrap around if needed) then the hash @@ -562,8 +561,7 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv, * Returns the candidate array of size BATADV_DAT_CANDIDATE_NUM. */ static struct batadv_dat_candidate * -batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst, - unsigned short vid) +batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst) { int select; batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key; @@ -579,7 +577,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst, return NULL; dat.ip = ip_dst; - dat.vid = vid; + dat.vid = 0; ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat, BATADV_DAT_ADDR_MAX); @@ -599,7 +597,6 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst, * @bat_priv: the bat priv with all the soft interface information * @skb: payload to send * @ip: the DHT key - * @vid: VLAN identifier * @packet_subtype: unicast4addr packet subtype to use * * This function copies the skb with pskb_copy() and is sent as unicast packet @@ -610,7 +607,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst, */ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, struct sk_buff *skb, __be32 ip, - unsigned short vid, int packet_subtype) + int packet_subtype) { int i; bool ret = false; @@ -619,7 +616,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, struct sk_buff *tmp_skb; struct batadv_dat_candidate *cand; - cand = batadv_dat_select_candidates(bat_priv, ip, vid); + cand = batadv_dat_select_candidates(bat_priv, ip); if (!cand) goto out; @@ -1007,7 +1004,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, ret = true; } else { /* Send the request to the DHT */ - ret = batadv_dat_send_data(bat_priv, skb, ip_dst, vid, + ret = batadv_dat_send_data(bat_priv, skb, ip_dst, BATADV_P_DAT_DHT_GET); } out: @@ -1135,8 +1132,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, /* Send the ARP reply to the candidates for both the IP addresses that * the node obtained from the ARP reply */ - batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT); - batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT); + batadv_dat_send_data(bat_priv, skb, ip_src, BATADV_P_DAT_DHT_PUT); + batadv_dat_send_data(bat_priv, skb, ip_dst, BATADV_P_DAT_DHT_PUT); } /** diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index d8a2f33e60e5..3207667e69de 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -104,15 +104,6 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, neigh_node = NULL; spin_lock_bh(&orig_node->neigh_list_lock); - /* curr_router used earlier may not be the current orig_ifinfo->router - * anymore because it was dereferenced outside of the neigh_list_lock - * protected region. After the new best neighbor has replace the current - * best neighbor the reference counter needs to decrease. Consequently, - * the code needs to ensure the curr_router variable contains a pointer - * to the replaced best neighbor. - */ - curr_router = rcu_dereference_protected(orig_ifinfo->router, true); - rcu_assign_pointer(orig_ifinfo->router, neigh_node); spin_unlock_bh(&orig_node->neigh_list_lock); batadv_orig_ifinfo_free_ref(orig_ifinfo); diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 0e0c3b8ed927..f664324805eb 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -630,9 +630,6 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, if (pending) { hlist_del(&forw_packet->list); - if (!forw_packet->own) - atomic_inc(&bat_priv->bcast_queue_left); - batadv_forw_packet_free(forw_packet); } } @@ -660,9 +657,6 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, if (pending) { hlist_del(&forw_packet->list); - if (!forw_packet->own) - atomic_inc(&bat_priv->batman_queue_left); - batadv_forw_packet_free(forw_packet); } } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 720f1a5b81ac..ac4d08de5df4 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -407,17 +407,11 @@ void batadv_interface_rx(struct net_device *soft_iface, */ nf_reset(skb); - if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) - goto dropped; - vid = batadv_get_vid(skb, 0); ethhdr = eth_hdr(skb); switch (ntohs(ethhdr->h_proto)) { case ETH_P_8021Q: - if (!pskb_may_pull(skb, VLAN_ETH_HLEN)) - goto dropped; - vhdr = (struct vlan_ethhdr *)skb->data; if (vhdr->h_vlan_encapsulated_proto != ethertype) @@ -429,6 +423,8 @@ void batadv_interface_rx(struct net_device *soft_iface, } /* skb->dev & skb->pkt_type are set here */ + if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) + goto dropped; skb->protocol = eth_type_trans(skb, soft_iface); /* should not be necessary anymore as we use skb_pull_rcsum() diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 60a3dbfca8a1..263b4de4de57 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -21,19 +21,18 @@ #include <asm/uaccess.h> #include "br_private.h" +/* called with RTNL */ static int get_bridge_ifindices(struct net *net, int *indices, int num) { struct net_device *dev; int i = 0; - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { + for_each_netdev(net, dev) { if (i >= num) break; if (dev->priv_flags & IFF_EBRIDGE) indices[i++] = dev->ifindex; } - rcu_read_unlock(); return i; } diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index ea9893743a0f..03661d97463c 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1270,7 +1270,6 @@ static int br_ip4_multicast_query(struct net_bridge *br, struct br_ip saddr; unsigned long max_delay; unsigned long now = jiffies; - unsigned int offset = skb_transport_offset(skb); __be32 group; int err = 0; @@ -1281,14 +1280,14 @@ static int br_ip4_multicast_query(struct net_bridge *br, group = ih->group; - if (skb->len == offset + sizeof(*ih)) { + if (skb->len == sizeof(*ih)) { max_delay = ih->code * (HZ / IGMP_TIMER_SCALE); if (!max_delay) { max_delay = 10 * HZ; group = 0; } - } else if (skb->len >= offset + sizeof(*ih3)) { + } else if (skb->len >= sizeof(*ih3)) { ih3 = igmpv3_query_hdr(skb); if (ih3->nsrcs) goto out; @@ -1349,7 +1348,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, struct br_ip saddr; unsigned long max_delay; unsigned long now = jiffies; - unsigned int offset = skb_transport_offset(skb); const struct in6_addr *group = NULL; bool is_general_query; int err = 0; @@ -1359,8 +1357,8 @@ static int br_ip6_multicast_query(struct net_bridge *br, (port && port->state == BR_STATE_DISABLED)) goto out; - if (skb->len == offset + sizeof(*mld)) { - if (!pskb_may_pull(skb, offset + sizeof(*mld))) { + if (skb->len == sizeof(*mld)) { + if (!pskb_may_pull(skb, sizeof(*mld))) { err = -EINVAL; goto out; } @@ -1369,7 +1367,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, if (max_delay) group = &mld->mld_mca; } else { - if (!pskb_may_pull(skb, offset + sizeof(*mld2q))) { + if (!pskb_may_pull(skb, sizeof(*mld2q))) { err = -EINVAL; goto out; } diff --git a/net/core/dev.c b/net/core/dev.c index 95b832edc303..a299c3956daa 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -137,6 +137,8 @@ #include <linux/errqueue.h> #include <linux/hrtimer.h> #include <linux/netfilter_ingress.h> +#include <linux/tcp.h> +#include <net/tcp.h> #include "net-sysfs.h" @@ -2773,7 +2775,10 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device if (netif_needs_gso(skb, features)) { struct sk_buff *segs; - trace_print_skb_gso(skb); + __be16 src_port = tcp_hdr(skb)->source; + __be16 dest_port = tcp_hdr(skb)->dest; + + trace_print_skb_gso(skb, src_port, dest_port); segs = skb_gso_segment(skb, features); if (IS_ERR(segs)) { goto out_kfree_skb; @@ -4142,6 +4147,7 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) unsigned long diffs; NAPI_GRO_CB(p)->flush = 0; + NAPI_GRO_CB(p)->flush_id = 0; if (hash != skb_get_hash_raw(p)) { NAPI_GRO_CB(p)->same_flow = 0; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 87b91ffbdec3..ca966f7de351 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1175,16 +1175,14 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev) { - struct rtnl_link_ifmap map; - - memset(&map, 0, sizeof(map)); - map.mem_start = dev->mem_start; - map.mem_end = dev->mem_end; - map.base_addr = dev->base_addr; - map.irq = dev->irq; - map.dma = dev->dma; - map.port = dev->if_port; - + struct rtnl_link_ifmap map = { + .mem_start = dev->mem_start, + .mem_end = dev->mem_end, + .base_addr = dev->base_addr, + .irq = dev->irq, + .dma = dev->dma, + .port = dev->if_port, + }; if (nla_put(skb, IFLA_MAP, sizeof(map), &map)) return -EMSGSIZE; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 38467f386b14..732be5afa6ce 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4444,16 +4444,15 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci) __skb_push(skb, offset); err = __vlan_insert_tag(skb, skb->vlan_proto, skb_vlan_tag_get(skb)); - if (err) { - __skb_pull(skb, offset); + if (err) return err; - } - skb->protocol = skb->vlan_proto; skb->mac_len += VLAN_HLEN; - - skb_postpush_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN); __skb_pull(skb, offset); + + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->csum = csum_add(skb->csum, csum_partial(skb->data + + (2 * ETH_ALEN), VLAN_HLEN, 0)); } __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci); return 0; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index b1dc096d22f8..607a14f20d88 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1034,13 +1034,10 @@ source_ok: if (!fld.daddr) { fld.daddr = fld.saddr; + err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); - err = -EINVAL; dev_out = init_net.loopback_dev; - if (!dev_out->dn_ptr) - goto out; - err = -EADDRNOTAVAIL; dev_hold(dev_out); if (!fld.daddr) { fld.daddr = @@ -1113,8 +1110,6 @@ source_ok: if (dev_out == NULL) goto out; dn_db = rcu_dereference_raw(dev_out->dn_ptr); - if (!dn_db) - goto e_inval; /* Possible improvement - check all devices for local addr */ if (dn_dev_islocal(dev_out, fld.daddr)) { dev_put(dev_out); @@ -1156,8 +1151,6 @@ select_source: dev_put(dev_out); dev_out = init_net.loopback_dev; dev_hold(dev_out); - if (!dev_out->dn_ptr) - goto e_inval; fld.flowidn_oif = dev_out->ifindex; if (res.fi) dn_fib_info_put(res.fi); diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index fae41583d0e9..008d034fcf8f 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -2176,7 +2176,6 @@ static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info, { union rr_control_msg ctl; - ipc_router_reset_conn(rport_ptr); memset(&ctl, 0, sizeof(ctl)); ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER; ctl.srv.service = server->name.service; @@ -2207,6 +2206,7 @@ static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info, server = rport_ptr->server; rport_ptr->server = NULL; mutex_unlock(&rport_ptr->rport_lock_lhb2); + ipc_router_reset_conn(rport_ptr); if (server) { cleanup_rmt_server(xprt_info, rport_ptr, server); @@ -2361,13 +2361,13 @@ static void ipc_router_reset_conn(struct msm_ipc_router_remote_port *rport_ptr) list_for_each_entry_safe(conn_info, tmp_conn_info, &rport_ptr->conn_info_list, list) { port_ptr = ipc_router_get_port_ref(conn_info->port_id); - if (!port_ptr) - continue; - mutex_lock(&port_ptr->port_lock_lhc3); - port_ptr->conn_status = CONNECTION_RESET; - mutex_unlock(&port_ptr->port_lock_lhc3); - wake_up(&port_ptr->port_rx_wait_q); - kref_put(&port_ptr->ref, ipc_router_release_port); + if (port_ptr) { + mutex_lock(&port_ptr->port_lock_lhc3); + port_ptr->conn_status = CONNECTION_RESET; + mutex_unlock(&port_ptr->port_lock_lhc3); + wake_up(&port_ptr->port_rx_wait_q); + kref_put(&port_ptr->ref, ipc_router_release_port); + } list_del(&conn_info->list); kfree(conn_info); @@ -2651,6 +2651,7 @@ static int process_rmv_client_msg(struct msm_ipc_router_xprt_info *xprt_info, server = rport_ptr->server; rport_ptr->server = NULL; mutex_unlock(&rport_ptr->rport_lock_lhb2); + ipc_router_reset_conn(rport_ptr); down_write(&server_list_lock_lha2); if (server) cleanup_rmt_server(NULL, rport_ptr, server); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a243ef1d7aa0..c600403137b7 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1345,6 +1345,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, for (p = *head; p; p = p->next) { struct iphdr *iph2; + u16 flush_id; if (!NAPI_GRO_CB(p)->same_flow) continue; @@ -1368,14 +1369,24 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, (iph->tos ^ iph2->tos) | ((iph->frag_off ^ iph2->frag_off) & htons(IP_DF)); - /* Save the IP ID check to be included later when we get to - * the transport layer so only the inner most IP ID is checked. - * This is because some GSO/TSO implementations do not - * correctly increment the IP ID for the outer hdrs. - */ - NAPI_GRO_CB(p)->flush_id = - ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id); NAPI_GRO_CB(p)->flush |= flush; + + /* We must save the offset as it is possible to have multiple + * flows using the same protocol and address pairs so we + * need to wait until we can validate this is part of the + * same flow with a 5-tuple or better to avoid unnecessary + * collisions between flows. We can support one of two + * possible scenarios, either a fixed value with DF bit set + * or an incrementing value with DF either set or unset. + * In the case of a fixed value we will end up losing the + * data that the IP ID was a fixed value, however per RFC + * 6864 in such a case the actual value of the IP ID is + * meant to be ignored anyway. + */ + flush_id = (u16)(id - ntohs(iph2->id)); + if (flush_id || !(iph2->frag_off & htons(IP_DF))) + NAPI_GRO_CB(p)->flush_id |= flush_id ^ + NAPI_GRO_CB(p)->count; } NAPI_GRO_CB(skb)->flush |= flush; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 98c754e61024..f97ae9d93ee9 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -905,11 +905,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) if (ifa->ifa_flags & IFA_F_SECONDARY) { prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); if (!prim) { - /* if the device has been deleted, we don't perform - * address promotion - */ - if (!in_dev->dead) - pr_warn("%s: bug: prim == NULL\n", __func__); + pr_warn("%s: bug: prim == NULL\n", __func__); return; } if (iprim && iprim != prim) { diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 2b68418c7198..d97268e8ff10 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -975,8 +975,6 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) val = 65535 - 40; if (type == RTAX_MTU && val > 65535 - 15) val = 65535 - 15; - if (type == RTAX_HOPLIMIT && val > 255) - val = 255; if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) return -EINVAL; fi->fib_metrics[type - 1] = val; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 7dc962b89fa1..614521437e30 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -180,7 +180,6 @@ static __be16 tnl_flags_to_gre_flags(__be16 tflags) return flags; } -/* Fills in tpi and returns header length to be pulled. */ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, bool *csum_err) { @@ -240,7 +239,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, return -EINVAL; } } - return hdr_len; + return iptunnel_pull_header(skb, hdr_len, tpi->proto); } static void ipgre_err(struct sk_buff *skb, u32 info, @@ -343,7 +342,7 @@ static void gre_err(struct sk_buff *skb, u32 info) struct tnl_ptk_info tpi; bool csum_err = false; - if (parse_gre_header(skb, &tpi, &csum_err) < 0) { + if (parse_gre_header(skb, &tpi, &csum_err)) { if (!csum_err) /* ignore csum errors. */ return; } @@ -421,7 +420,6 @@ static int gre_rcv(struct sk_buff *skb) { struct tnl_ptk_info tpi; bool csum_err = false; - int hdr_len; #ifdef CONFIG_NET_IPGRE_BROADCAST if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { @@ -431,10 +429,7 @@ static int gre_rcv(struct sk_buff *skb) } #endif - hdr_len = parse_gre_header(skb, &tpi, &csum_err); - if (hdr_len < 0) - goto drop; - if (iptunnel_pull_header(skb, hdr_len, tpi.proto) < 0) + if (parse_gre_header(skb, &tpi, &csum_err) < 0) goto drop; if (ipgre_rcv(skb, &tpi) == PACKET_RCVD) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index fb54659320d8..79a957ea6545 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2047,18 +2047,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res, */ if (fi && res->prefixlen < 4) fi = NULL; - } else if ((type == RTN_LOCAL) && (orig_oif != 0) && - (orig_oif != dev_out->ifindex)) { - /* For local routes that require a particular output interface - * we do not want to cache the result. Caching the result - * causes incorrect behaviour when there are multiple source - * addresses on the interface, the end result being that if the - * intended recipient is waiting on that interface for the - * packet he won't receive it because it will be delivered on - * the loopback interface and the IP_PKTINFO ipi_ifindex will - * be set to the loopback interface as well. - */ - fi = NULL; } fnhe = NULL; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0dd207cd1f38..9f069bd9de46 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2625,10 +2625,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) */ if (unlikely((NET_IP_ALIGN && ((unsigned long)skb->data & 3)) || skb_headroom(skb) >= 0xFFFF)) { - struct sk_buff *nskb; - - skb_mstamp_get(&skb->skb_mstamp); - nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); + struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER, + GFP_ATOMIC); err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : -ENOBUFS; } else { diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index eeca943f12dc..f542438c70ce 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -238,9 +238,6 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, /* flush if Traffic Class fields are different */ NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); NAPI_GRO_CB(p)->flush |= flush; - - /* Clear flush_id, there's really no concept of ID in IPv6. */ - NAPI_GRO_CB(p)->flush_id = 0; } NAPI_GRO_CB(skb)->flush |= flush; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index a234552a7e3d..45f5ae51de65 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -496,8 +496,10 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, IP6CB(head)->flags |= IP6SKB_FRAGMENTED; /* Yes, and fold redundant checksum back. 8) */ - skb_postpush_rcsum(head, skb_network_header(head), - skb_network_header_len(head)); + if (head->ip_summed == CHECKSUM_COMPLETE) + head->csum = csum_partial(skb_network_header(head), + skb_network_header_len(head), + head->csum); rcu_read_lock(); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 161cdc072547..01d7ee57d937 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1721,8 +1721,6 @@ static int ip6_convert_metrics(struct mx6_config *mxc, } else { val = nla_get_u32(nla); } - if (type == RTAX_HOPLIMIT && val > 255) - val = 255; if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) goto err; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index bb8edb9ef506..8dab4e569571 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -626,7 +626,6 @@ static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb) if (llc->cmsg_flags & LLC_CMSG_PKTINFO) { struct llc_pktinfo info; - memset(&info, 0, sizeof(info)); info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex; llc_pdu_decode_dsap(skb, &info.lpi_sap); llc_pdu_decode_da(skb, info.lpi_mac); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bcb0a1b64556..7a2b7915093b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1750,7 +1750,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ret = dev_alloc_name(ndev, ndev->name); if (ret < 0) { - ieee80211_if_free(ndev); + free_netdev(ndev); return ret; } @@ -1836,7 +1836,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ret = register_netdevice(ndev); if (ret) { - ieee80211_if_free(ndev); + free_netdev(ndev); return ret; } } diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 4da560005b0e..f57b4dcdb233 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1757,34 +1757,15 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int cp = pp->conn_in_get(ipvs, af, skb, &iph); conn_reuse_mode = sysctl_conn_reuse_mode(ipvs); - if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) { - bool uses_ct = false, resched = false; - - if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest && - unlikely(!atomic_read(&cp->dest->weight))) { - resched = true; - uses_ct = ip_vs_conn_uses_conntrack(cp, skb); - } else if (is_new_conn_expected(cp, conn_reuse_mode)) { - uses_ct = ip_vs_conn_uses_conntrack(cp, skb); - if (!atomic_read(&cp->n_control)) { - resched = true; - } else { - /* Do not reschedule controlling connection - * that uses conntrack while it is still - * referenced by controlled connection(s). - */ - resched = !uses_ct; - } - } - - if (resched) { - if (!atomic_read(&cp->n_control)) - ip_vs_conn_expire_now(cp); - __ip_vs_conn_put(cp); - if (uses_ct) - return NF_DROP; - cp = NULL; - } + if (conn_reuse_mode && !iph.fragoffs && + is_new_conn(skb, &iph) && cp && + ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest && + unlikely(!atomic_read(&cp->dest->weight))) || + unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) { + if (!atomic_read(&cp->n_control)) + ip_vs_conn_expire_now(cp); + __ip_vs_conn_put(cp); + cp = NULL; } if (unlikely(!cp)) { diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c index 0a6eb5c0d9e9..1b8d594e493a 100644 --- a/net/netfilter/ipvs/ip_vs_pe_sip.c +++ b/net/netfilter/ipvs/ip_vs_pe_sip.c @@ -70,10 +70,10 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) const char *dptr; int retc; - retc = ip_vs_fill_iph_skb(p->af, skb, false, &iph); + ip_vs_fill_iph_skb(p->af, skb, false, &iph); /* Only useful with UDP */ - if (!retc || iph.protocol != IPPROTO_UDP) + if (iph.protocol != IPPROTO_UDP) return -EINVAL; /* todo: IPv6 fragments: * I think this only should be done for the first fragment. /HS @@ -88,7 +88,7 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) dptr = skb->data + dataoff; datalen = skb->len - dataoff; - if (get_callid(dptr, 0, datalen, &matchoff, &matchlen)) + if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen)) return -EINVAL; /* N.B: pe_data is only set on success, diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 86a3c6f0c871..3cb3cb831591 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1757,7 +1757,6 @@ void nf_conntrack_init_end(void) int nf_conntrack_init_net(struct net *net) { - static atomic64_t unique_id; int ret = -ENOMEM; int cpu; @@ -1780,8 +1779,7 @@ int nf_conntrack_init_net(struct net *net) if (!net->ct.stat) goto err_pcpu_lists; - net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%llu", - (u64)atomic64_inc_return(&unique_id)); + net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net); if (!net->ct.slabname) goto err_slabname; diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index e2e7d54f9bb1..dca5cacc51f0 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1175,6 +1175,38 @@ static void iface_stat_update(struct net_device *net_dev, bool stash_only) spin_unlock_bh(&iface_stat_list_lock); } +/* Guarantied to return a net_device that has a name */ +static void get_dev_and_dir(const struct sk_buff *skb, + struct xt_action_param *par, + enum ifs_tx_rx *direction, + const struct net_device **el_dev) +{ + BUG_ON(!direction || !el_dev); + + if (par->in) { + *el_dev = par->in; + *direction = IFS_RX; + } else if (par->out) { + *el_dev = par->out; + *direction = IFS_TX; + } else { + pr_err("qtaguid[%d]: %s(): no par->in/out?!!\n", + par->hooknum, __func__); + BUG(); + } + if (unlikely(!(*el_dev)->name)) { + pr_err("qtaguid[%d]: %s(): no dev->name?!!\n", + par->hooknum, __func__); + BUG(); + } + if (skb->dev && *el_dev != skb->dev) { + MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs par->%s=%p %s\n", + par->hooknum, skb->dev, skb->dev->name, + *direction == IFS_RX ? "in" : "out", *el_dev, + (*el_dev)->name); + } +} + /* * Update stats for the specified interface from the skb. * Do nothing if the entry @@ -1186,50 +1218,27 @@ static void iface_stat_update_from_skb(const struct sk_buff *skb, { struct iface_stat *entry; const struct net_device *el_dev; - enum ifs_tx_rx direction = par->in ? IFS_RX : IFS_TX; + enum ifs_tx_rx direction; int bytes = skb->len; int proto; - if (!skb->dev) { - MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum); - el_dev = par->in ? : par->out; - } else { - const struct net_device *other_dev; - el_dev = skb->dev; - other_dev = par->in ? : par->out; - if (el_dev != other_dev) { - MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs " - "par->(in/out)=%p %s\n", - par->hooknum, el_dev, el_dev->name, other_dev, - other_dev->name); - } - } - - if (unlikely(!el_dev)) { - pr_err_ratelimited("qtaguid[%d]: %s(): no par->in/out?!!\n", - par->hooknum, __func__); - BUG(); - } else if (unlikely(!el_dev->name)) { - pr_err_ratelimited("qtaguid[%d]: %s(): no dev->name?!!\n", - par->hooknum, __func__); - BUG(); - } else { - proto = ipx_proto(skb, par); - MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n", - par->hooknum, el_dev->name, el_dev->type, - par->family, proto); - } + get_dev_and_dir(skb, par, &direction, &el_dev); + proto = ipx_proto(skb, par); + MT_DEBUG("qtaguid[%d]: iface_stat: %s(%s): " + "type=%d fam=%d proto=%d dir=%d\n", + par->hooknum, __func__, el_dev->name, el_dev->type, + par->family, proto, direction); spin_lock_bh(&iface_stat_list_lock); entry = get_iface_entry(el_dev->name); if (entry == NULL) { - IF_DEBUG("qtaguid: iface_stat: %s(%s): not tracked\n", - __func__, el_dev->name); + IF_DEBUG("qtaguid[%d]: iface_stat: %s(%s): not tracked\n", + par->hooknum, __func__, el_dev->name); spin_unlock_bh(&iface_stat_list_lock); return; } - IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__, + IF_DEBUG("qtaguid[%d]: %s(%s): entry=%p\n", par->hooknum, __func__, el_dev->name, entry); data_counters_update(&entry->totals_via_skb, 0, direction, proto, @@ -1294,14 +1303,14 @@ static void if_tag_stat_update(const char *ifname, uid_t uid, spin_lock_bh(&iface_stat_list_lock); iface_entry = get_iface_entry(ifname); if (!iface_entry) { - pr_err_ratelimited("qtaguid: iface_stat: stat_update() " + pr_err_ratelimited("qtaguid: tag_stat: stat_update() " "%s not found\n", ifname); spin_unlock_bh(&iface_stat_list_lock); return; } /* It is ok to process data when an iface_entry is inactive */ - MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n", + MT_DEBUG("qtaguid: tag_stat: stat_update() dev=%s entry=%p\n", ifname, iface_entry); /* @@ -1318,7 +1327,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid, tag = combine_atag_with_uid(acct_tag, uid); uid_tag = make_tag_from_uid(uid); } - MT_DEBUG("qtaguid: iface_stat: stat_update(): " + MT_DEBUG("qtaguid: tag_stat: stat_update(): " " looking for tag=0x%llx (uid=%u) in ife=%p\n", tag, get_uid_from_tag(tag), iface_entry); /* Loop over tag list under this interface for {acct_tag,uid_tag} */ @@ -1578,8 +1587,8 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb, struct sock *sk; unsigned int hook_mask = (1 << par->hooknum); - MT_DEBUG("qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb, - par->hooknum, par->family); + MT_DEBUG("qtaguid[%d]: find_sk(skb=%p) family=%d\n", + par->hooknum, skb, par->family); /* * Let's not abuse the the xt_socket_get*_sk(), or else it will @@ -1600,8 +1609,8 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb, } if (sk) { - MT_DEBUG("qtaguid: %p->sk_proto=%u " - "->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state); + MT_DEBUG("qtaguid[%d]: %p->sk_proto=%u->sk_state=%d\n", + par->hooknum, sk, sk->sk_protocol, sk->sk_state); /* * When in TCP_TIME_WAIT the sk is not a "struct sock" but * "struct inet_timewait_sock" which is missing fields. @@ -1619,37 +1628,19 @@ static void account_for_uid(const struct sk_buff *skb, struct xt_action_param *par) { const struct net_device *el_dev; + enum ifs_tx_rx direction; + int proto; - if (!skb->dev) { - MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum); - el_dev = par->in ? : par->out; - } else { - const struct net_device *other_dev; - el_dev = skb->dev; - other_dev = par->in ? : par->out; - if (el_dev != other_dev) { - MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs " - "par->(in/out)=%p %s\n", - par->hooknum, el_dev, el_dev->name, other_dev, - other_dev->name); - } - } - - if (unlikely(!el_dev)) { - pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum); - } else if (unlikely(!el_dev->name)) { - pr_info("qtaguid[%d]: no dev->name?!!\n", par->hooknum); - } else { - int proto = ipx_proto(skb, par); - MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n", - par->hooknum, el_dev->name, el_dev->type, - par->family, proto); + get_dev_and_dir(skb, par, &direction, &el_dev); + proto = ipx_proto(skb, par); + MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d dir=%d\n", + par->hooknum, el_dev->name, el_dev->type, + par->family, proto, direction); - if_tag_stat_update(el_dev->name, uid, - skb->sk ? skb->sk : alternate_sk, - par->in ? IFS_RX : IFS_TX, - proto, skb->len); - } + if_tag_stat_update(el_dev->name, uid, + skb->sk ? skb->sk : alternate_sk, + direction, + proto, skb->len); } static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) @@ -1661,6 +1652,11 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) kuid_t sock_uid; bool res; bool set_sk_callback_lock = false; + /* + * TODO: unhack how to force just accounting. + * For now we only do tag stats when the uid-owner is not requested + */ + bool do_tag_stat = !(info->match & XT_QTAGUID_UID); if (unlikely(module_passive)) return (info->match ^ info->invert) == 0; @@ -1734,12 +1730,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) * couldn't find the owner, so for now we just count them * against the system. */ - /* - * TODO: unhack how to force just accounting. - * For now we only do iface stats when the uid-owner is not - * requested. - */ - if (!(info->match & XT_QTAGUID_UID)) + if (do_tag_stat) account_for_uid(skb, sk, 0, par); MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n", par->hooknum, @@ -1754,18 +1745,15 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) filp = sk->sk_socket->file; if (filp == NULL) { MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum); - account_for_uid(skb, sk, 0, par); + if (do_tag_stat) + account_for_uid(skb, sk, 0, par); res = ((info->match ^ info->invert) & (XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0; atomic64_inc(&qtu_events.match_no_sk_file); goto put_sock_ret_res; } sock_uid = filp->f_cred->fsuid; - /* - * TODO: unhack how to force just accounting. - * For now we only do iface stats when the uid-owner is not requested - */ - if (!(info->match & XT_QTAGUID_UID)) + if (do_tag_stat) account_for_uid(skb, sk, from_kuid(&init_user_ns, sock_uid), par); /* @@ -1946,7 +1934,7 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) ); f_count = atomic_long_read( &sock_tag_entry->socket->file->f_count); - seq_printf(m, "sock=%p tag=0x%llx (uid=%u) pid=%u " + seq_printf(m, "sock=%pK tag=0x%llx (uid=%u) pid=%u " "f_count=%lu\n", sock_tag_entry->sk, sock_tag_entry->tag, uid, diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c index 99592ae56d9b..90604d8a8b4f 100644 --- a/net/netfilter/xt_quota2.c +++ b/net/netfilter/xt_quota2.c @@ -16,14 +16,15 @@ #include <linux/proc_fs.h> #include <linux/skbuff.h> #include <linux/spinlock.h> +#include <linux/workqueue.h> #include <asm/atomic.h> #include <net/netlink.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_quota2.h> -#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -#include <linux/netfilter_ipv4/ipt_ULOG.h> -#endif + +#define QUOTA2_SYSFS_WORK_MAX_SIZE 64 +#define QUOTA2_SYSFS_NUM_ENVP 3 /** * @lock: lock to protect quota writers from each other @@ -35,17 +36,16 @@ struct xt_quota_counter { atomic_t ref; char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)]; struct proc_dir_entry *procfs_entry; + char last_iface[QUOTA2_SYSFS_WORK_MAX_SIZE]; + char last_prefix[QUOTA2_SYSFS_WORK_MAX_SIZE]; + struct work_struct work; }; -#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -/* Harald's favorite number +1 :D From ipt_ULOG.C */ -static int qlog_nl_event = 112; -module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(event_num, - "Event number for NETLINK_NFLOG message. 0 disables log." - "111 is what ipt_ULOG uses."); -static struct sock *nflognl; -#endif +#define to_quota_counter(x) container_of(x, struct xt_quota_counter, work) + +static struct class *quota_class; +static struct device *quota_device; +static struct kobject *quota_kobj; static LIST_HEAD(counter_list); static DEFINE_SPINLOCK(counter_list_lock); @@ -56,68 +56,39 @@ static kuid_t quota_list_uid = KUIDT_INIT(0); static kgid_t quota_list_gid = KGIDT_INIT(0); module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR); -#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -static void quota2_log(unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, +static void quota2_work(struct work_struct *work) +{ + char alert_msg[QUOTA2_SYSFS_WORK_MAX_SIZE]; + char iface_name[QUOTA2_SYSFS_WORK_MAX_SIZE]; + char *envp[QUOTA2_SYSFS_NUM_ENVP] = {alert_msg, iface_name, NULL}; + struct xt_quota_counter *counter = to_quota_counter(work); + + snprintf(alert_msg, sizeof(alert_msg), "ALERT_NAME=%s", counter->name); + snprintf(iface_name, sizeof(iface_name), "INTERFACE=%s", + counter->last_iface); + + kobject_uevent_env(quota_kobj, KOBJ_CHANGE, envp); +} + +static void quota2_log(const struct net_device *in, const struct net_device *out, + struct xt_quota_counter *q, const char *prefix) { - ulog_packet_msg_t *pm; - struct sk_buff *log_skb; - size_t size; - struct nlmsghdr *nlh; - - if (!qlog_nl_event) + if (!prefix) return; - size = NLMSG_SPACE(sizeof(*pm)); - size = max(size, (size_t)NLMSG_GOODSIZE); - log_skb = alloc_skb(size, GFP_ATOMIC); - if (!log_skb) { - pr_err("xt_quota2: cannot alloc skb for logging\n"); - return; - } + strlcpy(q->last_prefix, prefix, QUOTA2_SYSFS_WORK_MAX_SIZE); - nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event, - sizeof(*pm), 0); - if (!nlh) { - pr_err("xt_quota2: nlmsg_put failed\n"); - kfree_skb(log_skb); - return; - } - pm = nlmsg_data(nlh); - if (skb->tstamp.tv64 == 0) - __net_timestamp((struct sk_buff *)skb); - pm->data_len = 0; - pm->hook = hooknum; - if (prefix != NULL) - strlcpy(pm->prefix, prefix, sizeof(pm->prefix)); - else - *(pm->prefix) = '\0'; if (in) - strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name)); - else - pm->indev_name[0] = '\0'; - - if (out) - strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); + strlcpy(q->last_iface, in->name, QUOTA2_SYSFS_WORK_MAX_SIZE); + else if (out) + strlcpy(q->last_iface, out->name, QUOTA2_SYSFS_WORK_MAX_SIZE); else - pm->outdev_name[0] = '\0'; + strlcpy(q->last_iface, "UNKNOWN", QUOTA2_SYSFS_WORK_MAX_SIZE); - NETLINK_CB(log_skb).dst_group = 1; - pr_debug("throwing 1 packets to netlink group 1\n"); - netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC); -} -#else -static void quota2_log(unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const char *prefix) -{ + schedule_work(&q->work); } -#endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */ static ssize_t quota_proc_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) @@ -174,6 +145,9 @@ q2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon) INIT_LIST_HEAD(&e->list); atomic_set(&e->ref, 1); strlcpy(e->name, q->name, sizeof(e->name)); + strlcpy(e->last_prefix, "UNSET", sizeof(e->last_prefix)); + strlcpy(e->last_iface, "UNSET", sizeof(e->last_iface)); + INIT_WORK(&e->work, quota2_work); } return e; } @@ -307,11 +281,7 @@ quota_mt2(const struct sk_buff *skb, struct xt_action_param *par) } else { /* We are transitioning, log that fact. */ if (e->quota) { - quota2_log(par->hooknum, - skb, - par->in, - par->out, - q->name); + quota2_log(par->in, par->out, e, q->name); } /* we do not allow even small packets from now on */ e->quota = 0; @@ -349,11 +319,25 @@ static int __init quota_mt2_init(void) int ret; pr_debug("xt_quota2: init()"); -#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG - nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL); - if (!nflognl) - return -ENOMEM; -#endif + quota_class = class_create(THIS_MODULE, "xt_quota2"); + ret = PTR_ERR(quota_class); + if (IS_ERR(quota_class)) { + pr_err("xt_quota2: couldn't create class"); + class_destroy(quota_class); + return ret; + } + + quota_device = device_create(quota_class, NULL, MKDEV(0, 0), NULL, + "counters"); + ret = PTR_ERR(quota_device); + if (IS_ERR(quota_device)) { + pr_err("xt_quota2: couldn't create device"); + device_destroy(quota_class, MKDEV(0, 0)); + class_destroy(quota_class); + return ret; + } + + quota_kobj = "a_device->kobj; proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net); if (proc_xt_quota == NULL) @@ -370,6 +354,8 @@ static void __exit quota_mt2_exit(void) { xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg)); remove_proc_entry("xt_quota", init_net.proc_net); + device_destroy(quota_class, MKDEV(0, 0)); + class_destroy(quota_class); } module_init(quota_mt2_init); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 992b35fb8615..59651af8cc27 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1305,7 +1305,7 @@ static int netlink_release(struct socket *sock) skb_queue_purge(&sk->sk_write_queue); - if (nlk->portid && nlk->bound) { + if (nlk->portid) { struct netlink_notify n = { .net = sock_net(sk), .protocol = sk->sk_protocol, diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 7cb8184ac165..c88d0f2d3e01 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -158,7 +158,9 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, new_mpls_lse = (__be32 *)skb_mpls_header(skb); *new_mpls_lse = mpls->mpls_lse; - skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN); + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->csum = csum_add(skb->csum, csum_partial(new_mpls_lse, + MPLS_HLEN, 0)); hdr = eth_hdr(skb); hdr->h_proto = mpls->mpls_ethertype; @@ -278,7 +280,7 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key, ether_addr_copy_masked(eth_hdr(skb)->h_dest, key->eth_dst, mask->eth_dst); - skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); + ovs_skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); ether_addr_copy(flow_key->eth.src, eth_hdr(skb)->h_source); ether_addr_copy(flow_key->eth.dst, eth_hdr(skb)->h_dest); @@ -461,7 +463,7 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key, mask_ipv6_addr(saddr, key->ipv6_src, mask->ipv6_src, masked); if (unlikely(memcmp(saddr, masked, sizeof(masked)))) { - set_ipv6_addr(skb, flow_key->ip.proto, saddr, masked, + set_ipv6_addr(skb, key->ipv6_proto, saddr, masked, true); memcpy(&flow_key->ipv6.addr.src, masked, sizeof(flow_key->ipv6.addr.src)); @@ -483,7 +485,7 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key, NULL, &flags) != NEXTHDR_ROUTING); - set_ipv6_addr(skb, flow_key->ip.proto, daddr, masked, + set_ipv6_addr(skb, key->ipv6_proto, daddr, masked, recalc_csum); memcpy(&flow_key->ipv6.addr.dst, masked, sizeof(flow_key->ipv6.addr.dst)); @@ -637,7 +639,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk, struct sk_buff *sk /* Reconstruct the MAC header. */ skb_push(skb, data->l2_len); memcpy(skb->data, &data->l2_data, data->l2_len); - skb_postpush_rcsum(skb, skb->data, data->l2_len); + ovs_skb_postpush_rcsum(skb, skb->data, data->l2_len); skb_reset_mac_header(skb); ovs_vport_send(vport, skb); diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 76fcaf1fd2a9..6b0190b987ec 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -58,7 +58,7 @@ static void netdev_port_receive(struct sk_buff *skb) return; skb_push(skb, ETH_HLEN); - skb_postpush_rcsum(skb, skb->data, ETH_HLEN); + ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); ovs_vport_receive(vport, skb, skb_tunnel_info(skb)); return; error: diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 6e2b62f9d595..8ea3a96980ac 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -184,6 +184,13 @@ static inline struct vport *vport_from_priv(void *priv) int ovs_vport_receive(struct vport *, struct sk_buff *, const struct ip_tunnel_info *); +static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, + const void *start, unsigned int len) +{ + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->csum = csum_add(skb->csum, csum_partial(start, len, 0)); +} + static inline const char *ovs_vport_name(struct vport *vport) { return vport->dev->name; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9cc7b512b472..da1ae0e13cb5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3436,7 +3436,6 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) i->ifindex = mreq->mr_ifindex; i->alen = mreq->mr_alen; memcpy(i->addr, mreq->mr_address, i->alen); - memset(i->addr + i->alen, 0, sizeof(i->addr) - i->alen); i->count = 1; i->next = po->mclist; po->mclist = i; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index b855352167b1..34967c19da85 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -744,15 +744,14 @@ static u32 qdisc_alloc_handle(struct net_device *dev) return 0; } -void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n, - unsigned int len) +void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) { const struct Qdisc_class_ops *cops; unsigned long cl; u32 parentid; int drops; - if (n == 0 && len == 0) + if (n == 0) return; drops = max_t(int, n, 0); rcu_read_lock(); @@ -775,12 +774,11 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n, cops->put(sch, cl); } sch->q.qlen -= n; - sch->qstats.backlog -= len; __qdisc_qstats_drop(sch, drops); } rcu_read_unlock(); } -EXPORT_SYMBOL(qdisc_tree_reduce_backlog); +EXPORT_SYMBOL(qdisc_tree_decrease_qlen); static void notify_and_destroy(struct net *net, struct sk_buff *skb, struct nlmsghdr *n, u32 clid, diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index baafddf229ce..c538d9e4a8f6 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1624,8 +1624,13 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, new->reshape_fail = cbq_reshape_fail; #endif } + sch_tree_lock(sch); + *old = cl->q; + cl->q = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); - *old = qdisc_replace(sch, new, &cl->q); return 0; } @@ -1909,7 +1914,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg) { struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl = (struct cbq_class *)arg; - unsigned int qlen, backlog; + unsigned int qlen; if (cl->filters || cl->children || cl == &q->link) return -EBUSY; @@ -1917,9 +1922,8 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg) sch_tree_lock(sch); qlen = cl->q->q.qlen; - backlog = cl->q->qstats.backlog; qdisc_reset(cl->q); - qdisc_tree_reduce_backlog(cl->q, qlen, backlog); + qdisc_tree_decrease_qlen(cl->q, qlen); if (cl->next_alive) cbq_deactivate_class(cl); diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 0a08c860eee4..5ffb8b8337c7 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx) choke_zap_tail_holes(q); qdisc_qstats_backlog_dec(sch, skb); - qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); qdisc_drop(skb, sch); + qdisc_tree_decrease_qlen(sch, 1); --sch->q.qlen; } @@ -456,7 +456,6 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) old = q->tab; if (old) { unsigned int oqlen = sch->q.qlen, tail = 0; - unsigned dropped = 0; while (q->head != q->tail) { struct sk_buff *skb = q->tab[q->head]; @@ -468,12 +467,11 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) ntab[tail++] = skb; continue; } - dropped += qdisc_pkt_len(skb); qdisc_qstats_backlog_dec(sch, skb); --sch->q.qlen; qdisc_drop(skb, sch); } - qdisc_tree_reduce_backlog(sch, oqlen - sch->q.qlen, dropped); + qdisc_tree_decrease_qlen(sch, oqlen - sch->q.qlen); q->head = 0; q->tail = tail; } diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index 9b7e2980ee5c..535007d5f0b5 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -79,13 +79,12 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue); - /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, + /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, * or HTB crashes. Defer it for next round. */ if (q->stats.drop_count && sch->q.qlen) { - qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); + qdisc_tree_decrease_qlen(sch, q->stats.drop_count); q->stats.drop_count = 0; - q->stats.drop_len = 0; } if (skb) qdisc_bstats_update(sch, skb); @@ -117,7 +116,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt) { struct codel_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_CODEL_MAX + 1]; - unsigned int qlen, dropped = 0; + unsigned int qlen; int err; if (!opt) @@ -157,11 +156,10 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt) while (sch->q.qlen > sch->limit) { struct sk_buff *skb = __skb_dequeue(&sch->q); - dropped += qdisc_pkt_len(skb); qdisc_qstats_backlog_dec(sch, skb); qdisc_drop(skb, sch); } - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index d6e3ad43cecb..f26bdea875c1 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -53,10 +53,9 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid) static void drr_purge_queue(struct drr_class *cl) { unsigned int len = cl->qdisc->q.qlen; - unsigned int backlog = cl->qdisc->qstats.backlog; qdisc_reset(cl->qdisc); - qdisc_tree_reduce_backlog(cl->qdisc, len, backlog); + qdisc_tree_decrease_qlen(cl->qdisc, len); } static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = { @@ -227,7 +226,11 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg, new = &noop_qdisc; } - *old = qdisc_replace(sch, new, &cl->qdisc); + sch_tree_lock(sch); + drr_purge_queue(cl); + *old = cl->qdisc; + cl->qdisc = new; + sch_tree_unlock(sch); return 0; } diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index d0dff0cd8186..f357f34d02d2 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -73,7 +73,13 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, new = &noop_qdisc; } - *old = qdisc_replace(sch, new, &p->q); + sch_tree_lock(sch); + *old = p->q; + p->q = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); + return 0; } @@ -258,7 +264,6 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch) return err; } - qdisc_qstats_backlog_inc(sch, skb); sch->q.qlen++; return NET_XMIT_SUCCESS; @@ -281,7 +286,6 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) return NULL; qdisc_bstats_update(sch, skb); - qdisc_qstats_backlog_dec(sch, skb); sch->q.qlen--; index = skb->tc_index & (p->indices - 1); @@ -397,7 +401,6 @@ static void dsmark_reset(struct Qdisc *sch) pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); qdisc_reset(p->q); - sch->qstats.backlog = 0; sch->q.qlen = 0; } diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 3c6a47d66a04..109b2322778f 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -662,7 +662,6 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) struct fq_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_FQ_MAX + 1]; int err, drop_count = 0; - unsigned drop_len = 0; u32 fq_log; if (!opt) @@ -737,11 +736,10 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) if (!skb) break; - drop_len += qdisc_pkt_len(skb); kfree_skb(skb); drop_count++; } - qdisc_tree_reduce_backlog(sch, drop_count, drop_len); + qdisc_tree_decrease_qlen(sch, drop_count); sch_tree_unlock(sch); return err; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index d3fc8f9dd3d4..4c834e93dafb 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -175,7 +175,7 @@ static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch) static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct fq_codel_sched_data *q = qdisc_priv(sch); - unsigned int idx, prev_backlog; + unsigned int idx; struct fq_codel_flow *flow; int uninitialized_var(ret); @@ -203,7 +203,6 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (++sch->q.qlen <= sch->limit) return NET_XMIT_SUCCESS; - prev_backlog = sch->qstats.backlog; q->drop_overlimit++; /* Return Congestion Notification only if we dropped a packet * from this flow. @@ -212,7 +211,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) return NET_XMIT_CN; /* As we dropped a packet, better let upper stack know this */ - qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog); + qdisc_tree_decrease_qlen(sch, 1); return NET_XMIT_SUCCESS; } @@ -242,7 +241,6 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch) struct fq_codel_flow *flow; struct list_head *head; u32 prev_drop_count, prev_ecn_mark; - unsigned int prev_backlog; begin: head = &q->new_flows; @@ -261,7 +259,6 @@ begin: prev_drop_count = q->cstats.drop_count; prev_ecn_mark = q->cstats.ecn_mark; - prev_backlog = sch->qstats.backlog; skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats, dequeue); @@ -279,14 +276,12 @@ begin: } qdisc_bstats_update(sch, skb); flow->deficit -= qdisc_pkt_len(skb); - /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, + /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, * or HTB crashes. Defer it for next round. */ if (q->cstats.drop_count && sch->q.qlen) { - qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, - q->cstats.drop_len); + qdisc_tree_decrease_qlen(sch, q->cstats.drop_count); q->cstats.drop_count = 0; - q->cstats.drop_len = 0; } return skb; } @@ -377,13 +372,11 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) while (sch->q.qlen > sch->limit) { struct sk_buff *skb = fq_codel_dequeue(sch); - q->cstats.drop_len += qdisc_pkt_len(skb); kfree_skb(skb); q->cstats.drop_count++; } - qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len); + qdisc_tree_decrease_qlen(sch, q->cstats.drop_count); q->cstats.drop_count = 0; - q->cstats.drop_len = 0; sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index aa4725038f94..16bc83b2842a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -159,15 +159,12 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, if (validate) skb = validate_xmit_skb_list(skb, dev); - if (likely(skb)) { + if (skb) { HARD_TX_LOCK(dev, txq, smp_processor_id()); if (!netif_xmit_frozen_or_stopped(txq)) skb = dev_hard_start_xmit(skb, dev, txq, &ret); HARD_TX_UNLOCK(dev, txq); - } else { - spin_lock(root_lock); - return qdisc_qlen(q); } spin_lock(root_lock); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index d783d7cc3348..b7ebe2c87586 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -895,10 +895,9 @@ static void hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl) { unsigned int len = cl->qdisc->q.qlen; - unsigned int backlog = cl->qdisc->qstats.backlog; qdisc_reset(cl->qdisc); - qdisc_tree_reduce_backlog(cl->qdisc, len, backlog); + qdisc_tree_decrease_qlen(cl->qdisc, len); } static void @@ -1216,7 +1215,11 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, new = &noop_qdisc; } - *old = qdisc_replace(sch, new, &cl->qdisc); + sch_tree_lock(sch); + hfsc_purge_queue(sch, cl); + *old = cl->qdisc; + cl->qdisc = new; + sch_tree_unlock(sch); return 0; } diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 13d6f83ec491..86b04e31e60b 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -382,7 +382,6 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch) struct hhf_sched_data *q = qdisc_priv(sch); enum wdrr_bucket_idx idx; struct wdrr_bucket *bucket; - unsigned int prev_backlog; idx = hhf_classify(skb, sch); @@ -410,7 +409,6 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (++sch->q.qlen <= sch->limit) return NET_XMIT_SUCCESS; - prev_backlog = sch->qstats.backlog; q->drop_overlimit++; /* Return Congestion Notification only if we dropped a packet from this * bucket. @@ -419,7 +417,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch) return NET_XMIT_CN; /* As we dropped a packet, better let upper stack know this. */ - qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog); + qdisc_tree_decrease_qlen(sch, 1); return NET_XMIT_SUCCESS; } @@ -529,7 +527,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt) { struct hhf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_HHF_MAX + 1]; - unsigned int qlen, prev_backlog; + unsigned int qlen; int err; u64 non_hh_quantum; u32 new_quantum = q->quantum; @@ -579,14 +577,12 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt) } qlen = sch->q.qlen; - prev_backlog = sch->qstats.backlog; while (sch->q.qlen > sch->limit) { struct sk_buff *skb = hhf_dequeue(sch); kfree_skb(skb); } - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, - prev_backlog - sch->qstats.backlog); + qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 87b02ed3d5f2..15ccd7f8fb2a 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -600,7 +600,6 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) htb_activate(q, cl); } - qdisc_qstats_backlog_inc(sch, skb); sch->q.qlen++; return NET_XMIT_SUCCESS; } @@ -890,7 +889,6 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) ok: qdisc_bstats_update(sch, skb); qdisc_unthrottled(sch); - qdisc_qstats_backlog_dec(sch, skb); sch->q.qlen--; return skb; } @@ -957,7 +955,6 @@ static unsigned int htb_drop(struct Qdisc *sch) unsigned int len; if (cl->un.leaf.q->ops->drop && (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { - sch->qstats.backlog -= len; sch->q.qlen--; if (!cl->un.leaf.q->q.qlen) htb_deactivate(q, cl); @@ -987,12 +984,12 @@ static void htb_reset(struct Qdisc *sch) } cl->prio_activity = 0; cl->cmode = HTB_CAN_SEND; + } } qdisc_watchdog_cancel(&q->watchdog); __skb_queue_purge(&q->direct_queue); sch->q.qlen = 0; - sch->qstats.backlog = 0; memset(q->hlevel, 0, sizeof(q->hlevel)); memset(q->row_mask, 0, sizeof(q->row_mask)); for (i = 0; i < TC_HTB_NUMPRIO; i++) @@ -1166,7 +1163,14 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, cl->common.classid)) == NULL) return -ENOBUFS; - *old = qdisc_replace(sch, new, &cl->un.leaf.q); + sch_tree_lock(sch); + *old = cl->un.leaf.q; + cl->un.leaf.q = new; + if (*old != NULL) { + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + } + sch_tree_unlock(sch); return 0; } @@ -1268,6 +1272,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) { struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)arg; + unsigned int qlen; struct Qdisc *new_q = NULL; int last_child = 0; @@ -1287,11 +1292,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) sch_tree_lock(sch); if (!cl->level) { - unsigned int qlen = cl->un.leaf.q->q.qlen; - unsigned int backlog = cl->un.leaf.q->qstats.backlog; - + qlen = cl->un.leaf.q->q.qlen; qdisc_reset(cl->un.leaf.q); - qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog); + qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); } /* delete from hash and active; remainder in destroy_class */ @@ -1425,11 +1428,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, sch_tree_lock(sch); if (parent && !parent->level) { unsigned int qlen = parent->un.leaf.q->q.qlen; - unsigned int backlog = parent->un.leaf.q->qstats.backlog; /* turn parent into inner node */ qdisc_reset(parent->un.leaf.q); - qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog); + qdisc_tree_decrease_qlen(parent->un.leaf.q, qlen); qdisc_destroy(parent->un.leaf.q); if (parent->prio_activity) htb_deactivate(q, parent); diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index bcdd54bb101c..4e904ca0af9d 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -218,8 +218,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) if (q->queues[i] != &noop_qdisc) { struct Qdisc *child = q->queues[i]; q->queues[i] = &noop_qdisc; - qdisc_tree_reduce_backlog(child, child->q.qlen, - child->qstats.backlog); + qdisc_tree_decrease_qlen(child, child->q.qlen); qdisc_destroy(child); } } @@ -239,9 +238,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) q->queues[i] = child; if (old != &noop_qdisc) { - qdisc_tree_reduce_backlog(old, - old->q.qlen, - old->qstats.backlog); + qdisc_tree_decrease_qlen(old, + old->q.qlen); qdisc_destroy(old); } sch_tree_unlock(sch); @@ -305,7 +303,13 @@ static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (new == NULL) new = &noop_qdisc; - *old = qdisc_replace(sch, new, &q->queues[band]); + sch_tree_lock(sch); + *old = q->queues[band]; + q->queues[band] = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); + return 0; } diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 4befe97a9034..5abd1d9de989 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -395,25 +395,6 @@ static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) sch->q.qlen++; } -/* netem can't properly corrupt a megapacket (like we get from GSO), so instead - * when we statistically choose to corrupt one, we instead segment it, returning - * the first packet to be corrupted, and re-enqueue the remaining frames - */ -static struct sk_buff *netem_segment(struct sk_buff *skb, struct Qdisc *sch) -{ - struct sk_buff *segs; - netdev_features_t features = netif_skb_features(skb); - - segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); - - if (IS_ERR_OR_NULL(segs)) { - qdisc_reshape_fail(skb, sch); - return NULL; - } - consume_skb(skb); - return segs; -} - /* * Insert one skb into qdisc. * Note: parent depends on return value to account for queue length. @@ -426,11 +407,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) /* We don't fill cb now as skb_unshare() may invalidate it */ struct netem_skb_cb *cb; struct sk_buff *skb2; - struct sk_buff *segs = NULL; - unsigned int len = 0, last_len, prev_len = qdisc_pkt_len(skb); - int nb = 0; int count = 1; - int rc = NET_XMIT_SUCCESS; /* Random duplication */ if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) @@ -476,23 +453,10 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) * do it now in software before we mangle it. */ if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { - if (skb_is_gso(skb)) { - segs = netem_segment(skb, sch); - if (!segs) - return NET_XMIT_DROP; - } else { - segs = skb; - } - - skb = segs; - segs = segs->next; - if (!(skb = skb_unshare(skb, GFP_ATOMIC)) || (skb->ip_summed == CHECKSUM_PARTIAL && - skb_checksum_help(skb))) { - rc = qdisc_drop(skb, sch); - goto finish_segs; - } + skb_checksum_help(skb))) + return qdisc_drop(skb, sch); skb->data[prandom_u32() % skb_headlen(skb)] ^= 1<<(prandom_u32() % 8); @@ -552,27 +516,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) sch->qstats.requeues++; } -finish_segs: - if (segs) { - while (segs) { - skb2 = segs->next; - segs->next = NULL; - qdisc_skb_cb(segs)->pkt_len = segs->len; - last_len = segs->len; - rc = qdisc_enqueue(segs, sch); - if (rc != NET_XMIT_SUCCESS) { - if (net_xmit_drop_count(rc)) - qdisc_qstats_drop(sch); - } else { - nb++; - len += last_len; - } - segs = skb2; - } - sch->q.qlen += nb; - if (nb > 1) - qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len); - } return NET_XMIT_SUCCESS; } @@ -655,8 +598,7 @@ deliver: if (unlikely(err != NET_XMIT_SUCCESS)) { if (net_xmit_drop_count(err)) { qdisc_qstats_drop(sch); - qdisc_tree_reduce_backlog(sch, 1, - qdisc_pkt_len(skb)); + qdisc_tree_decrease_qlen(sch, 1); } } goto tfifo_dequeue; @@ -1095,7 +1037,15 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, { struct netem_sched_data *q = qdisc_priv(sch); - *old = qdisc_replace(sch, new, &q->qdisc); + sch_tree_lock(sch); + *old = q->qdisc; + q->qdisc = new; + if (*old) { + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + } + sch_tree_unlock(sch); + return 0; } diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index 71ae3b9629f9..b783a446d884 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -183,7 +183,7 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt) { struct pie_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_PIE_MAX + 1]; - unsigned int qlen, dropped = 0; + unsigned int qlen; int err; if (!opt) @@ -232,11 +232,10 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt) while (sch->q.qlen > sch->limit) { struct sk_buff *skb = __skb_dequeue(&sch->q); - dropped += qdisc_pkt_len(skb); qdisc_qstats_backlog_dec(sch, skb); qdisc_drop(skb, sch); } - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 0d4630b155fe..59ef2daf652c 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -205,7 +205,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) struct Qdisc *child = q->queues[i]; q->queues[i] = &noop_qdisc; if (child != &noop_qdisc) { - qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog); + qdisc_tree_decrease_qlen(child, child->q.qlen); qdisc_destroy(child); } } @@ -224,9 +224,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) q->queues[i] = child; if (old != &noop_qdisc) { - qdisc_tree_reduce_backlog(old, - old->q.qlen, - old->qstats.backlog); + qdisc_tree_decrease_qlen(old, + old->q.qlen); qdisc_destroy(old); } sch_tree_unlock(sch); @@ -291,7 +290,13 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (new == NULL) new = &noop_qdisc; - *old = qdisc_replace(sch, new, &q->queues[band]); + sch_tree_lock(sch); + *old = q->queues[band]; + q->queues[band] = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); + return 0; } diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 8d2d8d953432..3dc3a6e56052 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -220,10 +220,9 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid) static void qfq_purge_queue(struct qfq_class *cl) { unsigned int len = cl->qdisc->q.qlen; - unsigned int backlog = cl->qdisc->qstats.backlog; qdisc_reset(cl->qdisc); - qdisc_tree_reduce_backlog(cl->qdisc, len, backlog); + qdisc_tree_decrease_qlen(cl->qdisc, len); } static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = { @@ -618,7 +617,11 @@ static int qfq_graft_class(struct Qdisc *sch, unsigned long arg, new = &noop_qdisc; } - *old = qdisc_replace(sch, new, &cl->qdisc); + sch_tree_lock(sch); + qfq_purge_queue(cl); + *old = cl->qdisc; + cl->qdisc = new; + sch_tree_unlock(sch); return 0; } diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 8c0508c0e287..6c0534cc7758 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -210,8 +210,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) q->flags = ctl->flags; q->limit = ctl->limit; if (child) { - qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, - q->qdisc->qstats.backlog); + qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(q->qdisc); q->qdisc = child; } @@ -314,7 +313,12 @@ static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (new == NULL) new = &noop_qdisc; - *old = qdisc_replace(sch, new, &q->qdisc); + sch_tree_lock(sch); + *old = q->qdisc; + q->qdisc = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); return 0; } diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index c69611640fa5..5bbb6332ec57 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -510,8 +510,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt) sch_tree_lock(sch); - qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, - q->qdisc->qstats.backlog); + qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(q->qdisc); q->qdisc = child; @@ -607,7 +606,12 @@ static int sfb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (new == NULL) new = &noop_qdisc; - *old = qdisc_replace(sch, new, &q->qdisc); + sch_tree_lock(sch); + *old = q->qdisc; + q->qdisc = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); return 0; } diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 498f0a2cb47f..3abab534eb5c 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -346,7 +346,7 @@ static int sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct sfq_sched_data *q = qdisc_priv(sch); - unsigned int hash, dropped; + unsigned int hash; sfq_index x, qlen; struct sfq_slot *slot; int uninitialized_var(ret); @@ -461,7 +461,7 @@ enqueue: return NET_XMIT_SUCCESS; qlen = slot->qlen; - dropped = sfq_drop(sch); + sfq_drop(sch); /* Return Congestion Notification only if we dropped a packet * from this flow. */ @@ -469,7 +469,7 @@ enqueue: return NET_XMIT_CN; /* As we dropped a packet, better let upper stack know this */ - qdisc_tree_reduce_backlog(sch, 1, dropped); + qdisc_tree_decrease_qlen(sch, 1); return NET_XMIT_SUCCESS; } @@ -537,7 +537,6 @@ static void sfq_rehash(struct Qdisc *sch) struct sfq_slot *slot; struct sk_buff_head list; int dropped = 0; - unsigned int drop_len = 0; __skb_queue_head_init(&list); @@ -566,7 +565,6 @@ static void sfq_rehash(struct Qdisc *sch) if (x >= SFQ_MAX_FLOWS) { drop: qdisc_qstats_backlog_dec(sch, skb); - drop_len += qdisc_pkt_len(skb); kfree_skb(skb); dropped++; continue; @@ -596,7 +594,7 @@ drop: } } sch->q.qlen -= dropped; - qdisc_tree_reduce_backlog(sch, dropped, drop_len); + qdisc_tree_decrease_qlen(sch, dropped); } static void sfq_perturbation(unsigned long arg) @@ -620,7 +618,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) struct sfq_sched_data *q = qdisc_priv(sch); struct tc_sfq_qopt *ctl = nla_data(opt); struct tc_sfq_qopt_v1 *ctl_v1 = NULL; - unsigned int qlen, dropped = 0; + unsigned int qlen; struct red_parms *p = NULL; if (opt->nla_len < nla_attr_size(sizeof(*ctl))) @@ -669,8 +667,8 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) qlen = sch->q.qlen; while (sch->q.qlen > q->limit) - dropped += sfq_drop(sch); - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + sfq_drop(sch); + qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); del_timer(&q->perturb_timer); if (q->perturb_period) { diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index c2fbde742f37..a4afde14e865 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -160,7 +160,6 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch) struct tbf_sched_data *q = qdisc_priv(sch); struct sk_buff *segs, *nskb; netdev_features_t features = netif_skb_features(skb); - unsigned int len = 0, prev_len = qdisc_pkt_len(skb); int ret, nb; segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); @@ -173,7 +172,6 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch) nskb = segs->next; segs->next = NULL; qdisc_skb_cb(segs)->pkt_len = segs->len; - len += segs->len; ret = qdisc_enqueue(segs, q->qdisc); if (ret != NET_XMIT_SUCCESS) { if (net_xmit_drop_count(ret)) @@ -185,7 +183,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch) } sch->q.qlen += nb; if (nb > 1) - qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len); + qdisc_tree_decrease_qlen(sch, 1 - nb); consume_skb(skb); return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP; } @@ -401,8 +399,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt) sch_tree_lock(sch); if (child) { - qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, - q->qdisc->qstats.backlog); + qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(q->qdisc); q->qdisc = child; } @@ -505,7 +502,13 @@ static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (new == NULL) new = &noop_qdisc; - *old = qdisc_replace(sch, new, &q->qdisc); + sch_tree_lock(sch); + *old = q->qdisc; + q->qdisc = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); + return 0; } diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 63fb5ee212cf..21e20353178e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1182,14 +1182,14 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) } crq->q.reader = 0; + crq->item = cache_get(h); crq->buf = buf; crq->len = 0; crq->readers = 0; spin_lock(&queue_lock); - if (test_bit(CACHE_PENDING, &h->flags)) { - crq->item = cache_get(h); + if (test_bit(CACHE_PENDING, &h->flags)) list_add_tail(&crq->q.list, &detail->queue); - } else + else /* Lost a race, no longer PENDING, so don't enqueue */ ret = -EAGAIN; spin_unlock(&queue_lock); diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 9b5bd6d142dc..7fd1220fbfa0 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1794,8 +1794,27 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, else if (sk->sk_shutdown & RCV_SHUTDOWN) err = 0; - if (copied > 0) + if (copied > 0) { + /* We only do these additional bookkeeping/notification steps + * if we actually copied something out of the queue pair + * instead of just peeking ahead. + */ + + if (!(flags & MSG_PEEK)) { + /* If the other side has shutdown for sending and there + * is nothing more to read, then modify the socket + * state. + */ + if (vsk->peer_shutdown & SEND_SHUTDOWN) { + if (vsock_stream_has_data(vsk) <= 0) { + sk->sk_state = SS_UNCONNECTED; + sock_set_flag(sk, SOCK_DONE); + sk->sk_state_change(sk); + } + } + } err = copied; + } out_wait: finish_wait(sk_sleep(sk), &wait); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3c7615c78cd2..913843530213 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -13226,7 +13226,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, struct wireless_dev *wdev; struct cfg80211_beacon_registration *reg, *tmp; - if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC) + if (state != NETLINK_URELEASE) return NOTIFY_DONE; rcu_read_lock(); diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index 997ff7b2509b..7ecd04c21360 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c @@ -277,7 +277,6 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, memset(&theirs, 0, sizeof(theirs)); memcpy(new, ours, sizeof(*new)); - memset(dte, 0, sizeof(*dte)); len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); if (len < 0) diff --git a/samples/bpf/trace_output_kern.c b/samples/bpf/trace_output_kern.c index 9b96f4fb8cea..8d8d1ec429eb 100644 --- a/samples/bpf/trace_output_kern.c +++ b/samples/bpf/trace_output_kern.c @@ -18,6 +18,7 @@ int bpf_prog1(struct pt_regs *ctx) u64 cookie; } data; + memset(&data, 0, sizeof(data)); data.pid = bpf_get_current_pid_tgid(); data.cookie = 0x12345678; diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index dd243d2abd87..0b7dc2fd7bac 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -267,8 +267,10 @@ int conf_read_simple(const char *name, int def) if (in) goto load; sym_add_change_count(1); - if (!sym_defconfig_list) + if (!sym_defconfig_list) { + sym_calc_value(modules_sym); return 1; + } for_all_defaults(sym_defconfig_list, prop) { if (expr_calc_value(prop->visible.expr) == no || @@ -401,6 +403,7 @@ setsym: } free(line); fclose(in); + sym_calc_value(modules_sym); return 0; } @@ -411,12 +414,8 @@ int conf_read(const char *name) sym_set_change_count(0); - if (conf_read_simple(name, S_DEF_USER)) { - sym_calc_value(modules_sym); + if (conf_read_simple(name, S_DEF_USER)) return 1; - } - - sym_calc_value(modules_sym); for_all_symbols(i, sym) { sym_calc_value(sym); @@ -847,7 +846,6 @@ static int conf_split_config(void) name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); - sym_calc_value(modules_sym); if (chdir("include/config")) return 1; diff --git a/scripts/sortextable.c b/scripts/sortextable.c index a2c0d620ca80..c2423d913b46 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -266,9 +266,9 @@ do_file(char const *const fname) break; } /* end switch */ if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 - || (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) + || r2(&ehdr->e_type) != ET_EXEC || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { - fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname); + fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); fail_file(); } @@ -282,13 +282,12 @@ do_file(char const *const fname) case EM_386: case EM_X86_64: case EM_S390: - case EM_AARCH64: - case EM_PARISC: custom_sort = sort_relative_table; break; case EM_ARCOMPACT: case EM_ARCV2: case EM_ARM: + case EM_AARCH64: case EM_MICROBLAZE: case EM_MIPS: case EM_XTENSA: @@ -305,7 +304,7 @@ do_file(char const *const fname) if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { fprintf(stderr, - "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); + "unrecognized ET_EXEC file: %s\n", fname); fail_file(); } do32(ehdr, fname, custom_sort); @@ -315,7 +314,7 @@ do_file(char const *const fname) if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { fprintf(stderr, - "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); + "unrecognized ET_EXEC file: %s\n", fname); fail_file(); } do64(ghdr, fname, custom_sort); diff --git a/sound/core/timer.c b/sound/core/timer.c index b982d1b089bd..a3f547badd38 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1247,6 +1247,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, tu->tstamp = *tstamp; if ((tu->filter & (1 << event)) == 0 || !tu->tread) return; + memset(&r1, 0, sizeof(r1)); r1.event = event; r1.tstamp = *tstamp; r1.val = resolution; @@ -1281,6 +1282,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, } if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { + memset(&r1, 0, sizeof(r1)); r1.event = SNDRV_TIMER_EVENT_RESOLUTION; r1.tstamp = tstamp; r1.val = resolution; @@ -1746,6 +1748,7 @@ static int snd_timer_user_params(struct file *file, if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { struct snd_timer_tread tread; + memset(&tread, 0, sizeof(tread)); tread.event = SNDRV_TIMER_EVENT_EARLY; tread.tstamp.tv_sec = 0; tread.tstamp.tv_nsec = 0; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 367dbf0d285e..5c4fa8eba1d0 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -843,7 +843,7 @@ static hda_nid_t path_power_update(struct hda_codec *codec, bool allow_powerdown) { hda_nid_t nid, changed = 0; - int i, state, power; + int i, state; for (i = 0; i < path->depth; i++) { nid = path->path[i]; @@ -855,9 +855,7 @@ static hda_nid_t path_power_update(struct hda_codec *codec, state = AC_PWRST_D0; else state = AC_PWRST_D3; - power = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0); - if (power != (state | (state << 4))) { + if (!snd_hda_check_power_state(codec, nid, state)) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, state); changed = nid; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 411630e9c034..2ff692dd2c5f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2207,9 +2207,6 @@ static const struct pci_device_id azx_ids[] = { /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, - /* Broxton-T */ - { PCI_DEVICE(0x8086, 0x1a98), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 9739fce9e032..64e0d1d81ca5 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -141,6 +141,14 @@ static int reconfig_codec(struct hda_codec *codec) err = snd_hda_codec_configure(codec); if (err < 0) goto error; + /* rebuild PCMs */ + err = snd_hda_codec_build_pcms(codec); + if (err < 0) + goto error; + /* rebuild mixers */ + err = snd_hda_codec_build_controls(codec); + if (err < 0) + goto error; err = snd_card_register(codec->card); error: snd_hda_power_down(codec); diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 80bbadc83721..a47e8ae0eb30 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -361,7 +361,6 @@ static int cs_parse_auto_config(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; int err; - int i; err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) @@ -371,19 +370,6 @@ static int cs_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - /* keep the ADCs powered up when it's dynamically switchable */ - if (spec->gen.dyn_adc_switch) { - unsigned int done = 0; - for (i = 0; i < spec->gen.input_mux.num_items; i++) { - int idx = spec->gen.dyn_adc_idx[i]; - if (done & (1 << idx)) - continue; - snd_hda_gen_fix_pin_power(codec, - spec->gen.adc_nids[idx]); - done |= 1 << idx; - } - } - return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4918ffa5ba68..1402ba954b3d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5449,7 +5449,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13), - SND_PCI_QUIRK(0x1028, 0x0669, "Dell Optiplex 9020m", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -5584,7 +5583,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x504a, "ThinkPad X260", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), @@ -6426,7 +6424,6 @@ enum { ALC668_FIXUP_DELL_DISABLE_AAMIX, ALC668_FIXUP_DELL_XPS13, ALC662_FIXUP_ASUS_Nx50, - ALC668_FIXUP_ASUS_Nx51, }; static const struct hda_fixup alc662_fixups[] = { @@ -6673,15 +6670,6 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC662_FIXUP_BASS_1A }, - [ALC668_FIXUP_ASUS_Nx51] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - {0x1a, 0x90170151}, /* bass speaker */ - {} - }, - .chained = true, - .chain_id = ALC662_FIXUP_BASS_CHMAP, - }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6704,14 +6692,11 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), - SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), - SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), - SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51), SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index d7e71f309299..c5194f5b150a 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1341,6 +1341,5 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id) } pcxhr_msg_thread(mgr); - mutex_unlock(&mgr->lock); return IRQ_HANDLED; } diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c index 241410c60b97..dee66f231ceb 100755..100644 --- a/sound/soc/codecs/msm_hdmi_codec_rx.c +++ b/sound/soc/codecs/msm_hdmi_codec_rx.c @@ -19,115 +19,208 @@ #include <sound/soc.h> #include <linux/msm_ext_display.h> -#define MSM_HDMI_PCM_RATES SNDRV_PCM_RATE_48000 +#define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000 -static int msm_hdmi_audio_codec_return_value; +static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"}; -struct msm_hdmi_audio_codec_rx_data { - struct platform_device *hdmi_core_pdev; - struct msm_ext_disp_audio_codec_ops hdmi_ops; +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text); + +struct msm_ext_disp_audio_codec_rx_data { + struct platform_device *ext_disp_core_pdev; + struct msm_ext_disp_audio_codec_ops ext_disp_ops; + int cable_status; }; -static int msm_hdmi_edid_ctl_info(struct snd_kcontrol *kcontrol, +static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; struct msm_ext_disp_audio_edid_blk edid_blk; int rc; codec_data = snd_soc_codec_get_drvdata(codec); - if (!codec_data->hdmi_ops.get_audio_edid_blk) { - pr_debug("%s: get_audio_edid_blk() is NULL\n", __func__); + if (!codec_data) { + dev_err(codec->dev, "%s: codec_data is NULL\n", __func__); + return -EINVAL; + } + + if (!codec_data->ext_disp_ops.get_audio_edid_blk) { + dev_dbg(codec->dev, "%s: get_audio_edid_blk() is NULL\n", + __func__); uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = 0; return 0; } - rc = codec_data->hdmi_ops.get_audio_edid_blk( - codec_data->hdmi_core_pdev, - &edid_blk); + rc = codec_data->ext_disp_ops.get_audio_edid_blk( + codec_data->ext_disp_core_pdev, &edid_blk); + if (!IS_ERR_VALUE(rc)) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = edid_blk.audio_data_blk_size + edid_blk.spk_alloc_data_blk_size; } + dev_dbg(codec->dev, "%s: count: %d\n", __func__, uinfo->count); + return rc; } -static int msm_hdmi_edid_get(struct snd_kcontrol *kcontrol, +static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; struct msm_ext_disp_audio_edid_blk edid_blk; int rc; codec_data = snd_soc_codec_get_drvdata(codec); - - if (!codec_data->hdmi_ops.get_audio_edid_blk) + if (!codec_data || !codec_data->ext_disp_ops.get_audio_edid_blk) { + dev_err(codec->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n", + __func__); return -EINVAL; + } - rc = codec_data->hdmi_ops.get_audio_edid_blk( - codec_data->hdmi_core_pdev, &edid_blk); - + rc = codec_data->ext_disp_ops.get_audio_edid_blk( + codec_data->ext_disp_core_pdev, &edid_blk); if (!IS_ERR_VALUE(rc)) { memcpy(ucontrol->value.bytes.data, - edid_blk.audio_data_blk, - edid_blk.audio_data_blk_size); + edid_blk.audio_data_blk, + edid_blk.audio_data_blk_size); memcpy((ucontrol->value.bytes.data + - edid_blk.audio_data_blk_size), - edid_blk.spk_alloc_data_blk, - edid_blk.spk_alloc_data_blk_size); + edid_blk.audio_data_blk_size), + edid_blk.spk_alloc_data_blk, + edid_blk.spk_alloc_data_blk_size); + + dev_dbg(codec->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n", + __func__, edid_blk.audio_data_blk_size, + edid_blk.spk_alloc_data_blk_size); } return rc; } -static const struct snd_kcontrol_new msm_hdmi_codec_rx_controls[] = { +static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + enum msm_ext_disp_cable_state cable_state; + enum msm_ext_disp_type disp_type; + int rc; + + codec_data = snd_soc_codec_get_drvdata(codec); + if (!codec_data || + !codec_data->ext_disp_ops.get_audio_edid_blk || + !codec_data->ext_disp_ops.get_intf_id) { + dev_err(codec->dev, "%s: codec_data, get_audio_edid_blk() or get_intf_id is NULL\n", + __func__); + return -EINVAL; + } + + cable_state = codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 1); + if (IS_ERR_VALUE(cable_state)) { + dev_err(codec->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n", + __func__, cable_state); + rc = cable_state; + goto done; + } + + codec_data->cable_status = cable_state; + if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) { + dev_err(codec->dev, "%s: Display cable disconnected\n", + __func__); + ucontrol->value.integer.value[0] = 0; + rc = 0; + goto done; + } + + disp_type = codec_data->ext_disp_ops.get_intf_id( + codec_data->ext_disp_core_pdev); + if (!IS_ERR_VALUE(disp_type)) { + switch (disp_type) { + case EXT_DISPLAY_TYPE_DP: + ucontrol->value.integer.value[0] = 2; + rc = 0; + break; + case EXT_DISPLAY_TYPE_HDMI: + ucontrol->value.integer.value[0] = 1; + rc = 0; + break; + default: + rc = -EINVAL; + dev_err(codec->dev, "%s: Invalid disp_type:%d\n", + __func__, disp_type); + goto done; + } + dev_dbg(codec->dev, "%s: Display type: %d\n", + __func__, disp_type); + } else { + dev_err(codec->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n", + __func__, disp_type); + rc = disp_type; + } + +done: + return rc; +} + +static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "HDMI EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + }, { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "HDMI EDID", - .info = msm_hdmi_edid_ctl_info, - .get = msm_hdmi_edid_get, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Display Port EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, }, + SOC_ENUM_EXT("External Display Type", ext_disp_audio_type, + msm_ext_disp_audio_type_get, NULL), }; -static int msm_hdmi_audio_codec_rx_dai_startup( +static int msm_ext_disp_audio_codec_rx_dai_startup( struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret = 0; - struct msm_hdmi_audio_codec_rx_data *codec_data = + struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->codec->dev); - if (!codec_data->hdmi_ops.cable_status) { - dev_err(dai->dev, "%s() cable_status is null\n", __func__); + if (!codec_data || !codec_data->ext_disp_ops.cable_status) { + dev_err(dai->dev, "%s() codec_data or cable_status is null\n", + __func__); return -EINVAL; } - msm_hdmi_audio_codec_return_value = - codec_data->hdmi_ops.cable_status( - codec_data->hdmi_core_pdev, 1); - if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) { + codec_data->cable_status = + codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 1); + if (IS_ERR_VALUE(codec_data->cable_status)) { dev_err(dai->dev, - "%s() HDMI core is not ready (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); - ret = msm_hdmi_audio_codec_return_value; - } else if (!msm_hdmi_audio_codec_return_value) { + "%s() ext disp core is not ready (ret val = %d)\n", + __func__, codec_data->cable_status); + ret = codec_data->cable_status; + } else if (!codec_data->cable_status) { dev_err(dai->dev, - "%s() HDMI cable is not connected (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); + "%s() ext disp cable is not connected (ret val = %d)\n", + __func__, codec_data->cable_status); ret = -ENODEV; } return ret; } -static int msm_hdmi_audio_codec_rx_dai_hw_params( +static int msm_ext_disp_audio_codec_rx_dai_hw_params( struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -139,23 +232,24 @@ static int msm_hdmi_audio_codec_rx_dai_hw_params( int rc = 0; struct msm_ext_disp_audio_setup_params audio_setup_params = {0}; - struct msm_hdmi_audio_codec_rx_data *codec_data = + struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->codec->dev); - if (!codec_data->hdmi_ops.audio_info_setup) { - dev_err(dai->dev, "%s() audio_info_setup is null\n", __func__); + if (!codec_data || !codec_data->ext_disp_ops.audio_info_setup) { + dev_err(dai->dev, "%s: codec_data or audio_info_setup is null\n", + __func__); return -EINVAL; } - if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) { + if (IS_ERR_VALUE(codec_data->cable_status)) { dev_err_ratelimited(dai->dev, - "%s() HDMI core is not ready (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); - return msm_hdmi_audio_codec_return_value; - } else if (!msm_hdmi_audio_codec_return_value) { + "%s() ext disp core is not ready (ret val = %d)\n", + __func__, codec_data->cable_status); + return codec_data->cable_status; + } else if (!codec_data->cable_status) { dev_err_ratelimited(dai->dev, - "%s() HDMI cable is not connected (ret val = %d)\n", - __func__, msm_hdmi_audio_codec_return_value); + "%s() ext disp cable is not connected (ret val = %d)\n", + __func__, codec_data->cable_status); return -ENODEV; } @@ -204,54 +298,49 @@ static int msm_hdmi_audio_codec_rx_dai_hw_params( audio_setup_params.level_shift = level_shift; audio_setup_params.down_mix = down_mix; - rc = codec_data->hdmi_ops.audio_info_setup( - codec_data->hdmi_core_pdev, &audio_setup_params); + rc = codec_data->ext_disp_ops.audio_info_setup( + codec_data->ext_disp_core_pdev, &audio_setup_params); if (IS_ERR_VALUE(rc)) { dev_err_ratelimited(dai->dev, - "%s() HDMI core is not ready, rc: %d\n", + "%s() ext disp core is not ready, rc: %d\n", __func__, rc); } return rc; } -static void msm_hdmi_audio_codec_rx_dai_shutdown( +static void msm_ext_disp_audio_codec_rx_dai_shutdown( struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int rc; - struct msm_hdmi_audio_codec_rx_data *codec_data = + struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->codec->dev); - if (!codec_data->hdmi_ops.cable_status) { - dev_err(dai->dev, "%s() cable_status is null\n", __func__); + if (!codec_data || !codec_data->ext_disp_ops.cable_status) { + dev_err(dai->dev, "%s: codec data or cable_status is null\n", + __func__); return; } - rc = codec_data->hdmi_ops.cable_status( - codec_data->hdmi_core_pdev, 0); + rc = codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 0); if (IS_ERR_VALUE(rc)) { dev_err(dai->dev, - "%s() HDMI core had problems releasing HDMI audio flag\n", + "%s: ext disp core had problems releasing audio flag\n", __func__); } return; } -static struct snd_soc_dai_ops msm_hdmi_audio_codec_rx_dai_ops = { - .startup = msm_hdmi_audio_codec_rx_dai_startup, - .hw_params = msm_hdmi_audio_codec_rx_dai_hw_params, - .shutdown = msm_hdmi_audio_codec_rx_dai_shutdown -}; - -static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) +static int msm_ext_disp_audio_codec_rx_probe(struct snd_soc_codec *codec) { - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; struct device_node *of_node_parent = NULL; - codec_data = kzalloc(sizeof(struct msm_hdmi_audio_codec_rx_data), + codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data), GFP_KERNEL); if (!codec_data) { @@ -268,16 +357,16 @@ static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) return -ENODEV; } - codec_data->hdmi_core_pdev = of_find_device_by_node(of_node_parent); - if (!codec_data->hdmi_core_pdev) { + codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent); + if (!codec_data->ext_disp_core_pdev) { dev_err(codec->dev, "%s(): can't get parent pdev\n", __func__); kfree(codec_data); return -ENODEV; } - if (msm_hdmi_register_audio_codec(codec_data->hdmi_core_pdev, - &codec_data->hdmi_ops)) { - dev_err(codec->dev, "%s(): can't register with hdmi core", + if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev, + &codec_data->ext_disp_ops)) { + dev_err(codec->dev, "%s(): can't register with ext disp core", __func__); kfree(codec_data); return -ENODEV; @@ -285,15 +374,15 @@ static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) dev_set_drvdata(codec->dev, codec_data); - dev_dbg(codec->dev, "%s(): registerd %s with HDMI core\n", + dev_dbg(codec->dev, "%s(): registered %s with ext disp core\n", __func__, codec->component.name); return 0; } -static int msm_hdmi_audio_codec_rx_remove(struct snd_soc_codec *codec) +static int msm_ext_disp_audio_codec_rx_remove(struct snd_soc_codec *codec) { - struct msm_hdmi_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_codec_rx_data *codec_data; codec_data = dev_get_drvdata(codec->dev); kfree(codec_data); @@ -301,7 +390,13 @@ static int msm_hdmi_audio_codec_rx_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_dai_driver msm_hdmi_audio_codec_rx_dais[] = { +static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = { + .startup = msm_ext_disp_audio_codec_rx_dai_startup, + .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params, + .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown +}; + +static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = { { .name = "msm_hdmi_audio_codec_rx_dai", .playback = { @@ -310,66 +405,89 @@ static struct snd_soc_dai_driver msm_hdmi_audio_codec_rx_dais[] = { .channels_max = 8, .rate_min = 48000, .rate_max = 48000, - .rates = MSM_HDMI_PCM_RATES, + .rates = MSM_EXT_DISP_PCM_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &msm_hdmi_audio_codec_rx_dai_ops, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, + { + .name = "msm_dp_audio_codec_rx_dai", + .playback = { + .stream_name = "Display Port Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 48000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, }, }; -static struct snd_soc_codec_driver msm_hdmi_audio_codec_rx_soc_driver = { - .probe = msm_hdmi_audio_codec_rx_probe, - .remove = msm_hdmi_audio_codec_rx_remove, - .controls = msm_hdmi_codec_rx_controls, - .num_controls = ARRAY_SIZE(msm_hdmi_codec_rx_controls), +static struct snd_soc_codec_driver msm_ext_disp_audio_codec_rx_soc_driver = { + .probe = msm_ext_disp_audio_codec_rx_probe, + .remove = msm_ext_disp_audio_codec_rx_remove, + .controls = msm_ext_disp_codec_rx_controls, + .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls), }; -static int msm_hdmi_audio_codec_rx_plat_probe( +static int msm_ext_disp_audio_codec_rx_plat_probe( struct platform_device *pdev) { dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__, dev_name(&pdev->dev)); return snd_soc_register_codec(&pdev->dev, - &msm_hdmi_audio_codec_rx_soc_driver, - msm_hdmi_audio_codec_rx_dais, - ARRAY_SIZE(msm_hdmi_audio_codec_rx_dais)); + &msm_ext_disp_audio_codec_rx_soc_driver, + msm_ext_disp_audio_codec_rx_dais, + ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais)); } -static int msm_hdmi_audio_codec_rx_plat_remove( +static int msm_ext_disp_audio_codec_rx_plat_remove( struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; } -static const struct of_device_id msm_hdmi_audio_codec_rx_dt_match[] = { - { .compatible = "qcom,msm-hdmi-audio-codec-rx", }, +static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = { + { .compatible = "qcom,msm-ext-disp-audio-codec-rx", }, {} }; -MODULE_DEVICE_TABLE(of, msm_hdmi_codec_dt_match); +MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match); -static struct platform_driver msm_hdmi_audio_codec_rx_driver = { +static struct platform_driver msm_ext_disp_audio_codec_rx_driver = { .driver = { - .name = "msm-hdmi-audio-codec-rx", + .name = "msm-ext-disp-audio-codec-rx", .owner = THIS_MODULE, - .of_match_table = msm_hdmi_audio_codec_rx_dt_match, + .of_match_table = msm_ext_disp_audio_codec_rx_dt_match, }, - .probe = msm_hdmi_audio_codec_rx_plat_probe, - .remove = msm_hdmi_audio_codec_rx_plat_remove, + .probe = msm_ext_disp_audio_codec_rx_plat_probe, + .remove = msm_ext_disp_audio_codec_rx_plat_remove, }; -static int __init msm_hdmi_audio_codec_rx_init(void) +static int __init msm_ext_disp_audio_codec_rx_init(void) { - return platform_driver_register(&msm_hdmi_audio_codec_rx_driver); + int rc; + + rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver); + if (rc) { + pr_err("%s: failed to register ext disp codec driver err:%d\n", + __func__, rc); + } + + return rc; } -module_init(msm_hdmi_audio_codec_rx_init); +module_init(msm_ext_disp_audio_codec_rx_init); -static void __exit msm_hdmi_audio_codec_rx_exit(void) +static void __exit msm_ext_disp_audio_codec_rx_exit(void) { - platform_driver_unregister(&msm_hdmi_audio_codec_rx_driver); + platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver); } -module_exit(msm_hdmi_audio_codec_rx_exit); +module_exit(msm_ext_disp_audio_codec_rx_exit); -MODULE_DESCRIPTION("MSM HDMI CODEC driver"); +MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index b1c8bb39cdf1..f2beb1aa5763 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -359,7 +359,7 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv, /* Interface data select */ static const char * const rt5640_data_select[] = { - "Normal", "Swap", "left copy to right", "right copy to left"}; + "Normal", "left copy to right", "right copy to left", "Swap"}; static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 243f42633989..3deb8babeabb 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -442,39 +442,39 @@ #define RT5640_IF1_DAC_SEL_MASK (0x3 << 14) #define RT5640_IF1_DAC_SEL_SFT 14 #define RT5640_IF1_DAC_SEL_NOR (0x0 << 14) -#define RT5640_IF1_DAC_SEL_SWAP (0x1 << 14) -#define RT5640_IF1_DAC_SEL_L2R (0x2 << 14) -#define RT5640_IF1_DAC_SEL_R2L (0x3 << 14) +#define RT5640_IF1_DAC_SEL_L2R (0x1 << 14) +#define RT5640_IF1_DAC_SEL_R2L (0x2 << 14) +#define RT5640_IF1_DAC_SEL_SWAP (0x3 << 14) #define RT5640_IF1_ADC_SEL_MASK (0x3 << 12) #define RT5640_IF1_ADC_SEL_SFT 12 #define RT5640_IF1_ADC_SEL_NOR (0x0 << 12) -#define RT5640_IF1_ADC_SEL_SWAP (0x1 << 12) -#define RT5640_IF1_ADC_SEL_L2R (0x2 << 12) -#define RT5640_IF1_ADC_SEL_R2L (0x3 << 12) +#define RT5640_IF1_ADC_SEL_L2R (0x1 << 12) +#define RT5640_IF1_ADC_SEL_R2L (0x2 << 12) +#define RT5640_IF1_ADC_SEL_SWAP (0x3 << 12) #define RT5640_IF2_DAC_SEL_MASK (0x3 << 10) #define RT5640_IF2_DAC_SEL_SFT 10 #define RT5640_IF2_DAC_SEL_NOR (0x0 << 10) -#define RT5640_IF2_DAC_SEL_SWAP (0x1 << 10) -#define RT5640_IF2_DAC_SEL_L2R (0x2 << 10) -#define RT5640_IF2_DAC_SEL_R2L (0x3 << 10) +#define RT5640_IF2_DAC_SEL_L2R (0x1 << 10) +#define RT5640_IF2_DAC_SEL_R2L (0x2 << 10) +#define RT5640_IF2_DAC_SEL_SWAP (0x3 << 10) #define RT5640_IF2_ADC_SEL_MASK (0x3 << 8) #define RT5640_IF2_ADC_SEL_SFT 8 #define RT5640_IF2_ADC_SEL_NOR (0x0 << 8) -#define RT5640_IF2_ADC_SEL_SWAP (0x1 << 8) -#define RT5640_IF2_ADC_SEL_L2R (0x2 << 8) -#define RT5640_IF2_ADC_SEL_R2L (0x3 << 8) +#define RT5640_IF2_ADC_SEL_L2R (0x1 << 8) +#define RT5640_IF2_ADC_SEL_R2L (0x2 << 8) +#define RT5640_IF2_ADC_SEL_SWAP (0x3 << 8) #define RT5640_IF3_DAC_SEL_MASK (0x3 << 6) #define RT5640_IF3_DAC_SEL_SFT 6 #define RT5640_IF3_DAC_SEL_NOR (0x0 << 6) -#define RT5640_IF3_DAC_SEL_SWAP (0x1 << 6) -#define RT5640_IF3_DAC_SEL_L2R (0x2 << 6) -#define RT5640_IF3_DAC_SEL_R2L (0x3 << 6) +#define RT5640_IF3_DAC_SEL_L2R (0x1 << 6) +#define RT5640_IF3_DAC_SEL_R2L (0x2 << 6) +#define RT5640_IF3_DAC_SEL_SWAP (0x3 << 6) #define RT5640_IF3_ADC_SEL_MASK (0x3 << 4) #define RT5640_IF3_ADC_SEL_SFT 4 #define RT5640_IF3_ADC_SEL_NOR (0x0 << 4) -#define RT5640_IF3_ADC_SEL_SWAP (0x1 << 4) -#define RT5640_IF3_ADC_SEL_L2R (0x2 << 4) -#define RT5640_IF3_ADC_SEL_R2L (0x3 << 4) +#define RT5640_IF3_ADC_SEL_L2R (0x1 << 4) +#define RT5640_IF3_ADC_SEL_R2L (0x2 << 4) +#define RT5640_IF3_ADC_SEL_SWAP (0x3 << 4) /* REC Left Mixer Control 1 (0x3b) */ #define RT5640_G_HP_L_RM_L_MASK (0x7 << 13) diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 080c78e88e10..e619d5651b09 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -352,11 +352,6 @@ static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) regcache_cache_only(ssm4567->regmap, !enable); if (enable) { - ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, - 0x00); - if (ret) - return ret; - ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_POWER_CTRL, SSM4567_POWER_SPWDN, 0x00); diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 60a7ad1b01c2..5b6af14e1d94 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1545,6 +1545,13 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) mbhc->btn_press_intr = false; if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, + false); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, + false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, + 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); } else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) { wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED); diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 50a023013fa8..84e5c09494c6 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -2905,6 +2905,56 @@ out: return ret; } +static u32 tavil_get_dmic_sample_rate(struct snd_soc_codec *codec, + unsigned int dmic, + struct wcd9xxx_pdata *pdata) +{ + u8 tx_stream_fs; + u8 adc_mux_index = 0, adc_mux_sel = 0; + bool dec_found = false; + u16 adc_mux_ctl_reg, tx_fs_reg; + u32 dmic_fs; + + while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) { + if (adc_mux_index < 4) { + adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + (adc_mux_index * 2); + } else if (adc_mux_index < WCD934X_INVALID_ADC_MUX) { + adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_index - 4; + } else if (adc_mux_index == WCD934X_INVALID_ADC_MUX) { + ++adc_mux_index; + continue; + } + adc_mux_sel = ((snd_soc_read(codec, adc_mux_ctl_reg) & + 0xF8) >> 3) - 1; + + if (adc_mux_sel == dmic) { + dec_found = true; + break; + } + + ++adc_mux_index; + } + + if (dec_found && adc_mux_index <= 8) { + tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index); + tx_stream_fs = snd_soc_read(codec, tx_fs_reg) & 0x0F; + if (tx_stream_fs <= 4) { + if (pdata->dmic_sample_rate <= + WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ) + dmic_fs = pdata->dmic_sample_rate; + else + dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ; + } else + dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + } else { + dmic_fs = pdata->dmic_sample_rate; + } + + return dmic_fs; +} + static u8 tavil_get_dmic_clk_val(struct snd_soc_codec *codec, u32 mclk_rate, u32 dmic_clk_rate) { @@ -2988,6 +3038,7 @@ static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w, s32 *dmic_clk_cnt; u8 dmic_rate_val, dmic_rate_shift = 1; unsigned int dmic; + u32 dmic_sample_rate; int ret; char *wname; @@ -3030,10 +3081,12 @@ static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + dmic_sample_rate = tavil_get_dmic_sample_rate(codec, dmic, + pdata); dmic_rate_val = tavil_get_dmic_clk_val(codec, pdata->mclk_rate, - pdata->dmic_sample_rate); + dmic_sample_rate); (*dmic_clk_cnt)++; if (*dmic_clk_cnt == 1) { @@ -6289,7 +6342,7 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { {WCD934X_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, {WCD934X_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12}, {WCD934X_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08}, - {WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x1F, 0x03}, + {WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x1F, 0x09}, }; static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = { @@ -6306,13 +6359,6 @@ static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = { {WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, - {WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, - {WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, {WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x01, 0x01}, {WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01}, {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80}, @@ -6816,14 +6862,6 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec) for (i = 0; i < COMPANDER_MAX; i++) tavil->comp_enabled[i] = 0; - dev_dbg(codec->dev, "%s: MCLK Rate = %x\n", __func__, - control->mclk_rate); - if (control->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ) - snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG, - 0x03, 0x00); - else if (control->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) - snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG, - 0x03, 0x01); tavil_codec_init_reg(codec); tavil_enable_sido_buck(codec); @@ -7480,6 +7518,16 @@ static int tavil_probe(struct platform_device *pdev) tavil->wcd_ext_clk = wcd_ext_clk; set_bit(AUDIO_NOMINAL, &tavil->status_mask); /* Update codec register default values */ + dev_dbg(&pdev->dev, "%s: MCLK Rate = %x\n", __func__, + tavil->wcd9xxx->mclk_rate); + if (tavil->wcd9xxx->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ) + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x00); + else if (tavil->wcd9xxx->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x01); tavil_update_reg_defaults(tavil); __tavil_enable_efuse_sensing(tavil); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 0171810803a9..b97b73dc4191 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -90,6 +90,7 @@ struct wsa881x_priv { bool comp_enable; bool boost_enable; bool visense_enable; + u8 pa_gain; struct swr_port port[WSA881X_MAX_SWR_PORTS]; int pd_gpio; struct wsa881x_tz_priv tz_pdata; @@ -134,6 +135,47 @@ static unsigned int devnum; static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec, bool enable); +static const char * const wsa_pa_gain_text[] = { + "G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB", + "G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", + "G_0_DB" +}; + +static const struct soc_enum wsa_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text); + +static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wsa881x->pa_gain; + + dev_dbg(codec->dev, "%s: PA gain = 0x%x\n", __func__, wsa881x->pa_gain); + + return 0; +} + +static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + wsa881x->pa_gain = ucontrol->value.integer.value[0]; + + return 0; +} + +static const struct snd_kcontrol_new wsa_analog_gain_controls[] = { + SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum, + wsa_pa_gain_get, wsa_pa_gain_put), +}; + static int codec_debug_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -775,6 +817,7 @@ static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + int min_gain, max_gain; dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event); switch (event) { @@ -786,15 +829,32 @@ static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w, swr_slvdev_datapath_control(wsa881x->swr_slave, wsa881x->swr_slave->dev_num, true); + /* Set register mode if compander is not enabled */ + if (!wsa881x->comp_enable) + snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, + 0x08, 0x08); + else + snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, + 0x08, 0x00); + break; case SND_SOC_DAPM_POST_PMU: if (!wsa881x->comp_enable) { + max_gain = wsa881x->pa_gain; + /* + * Gain has to set incrementally in 4 steps + * as per HW sequence + */ + if (max_gain > G_4P5DB) + min_gain = G_0DB; + else + min_gain = max_gain + 3; /* * 1ms delay is needed before change in gain * as per HW requirement. */ usleep_range(1000, 1010); - wsa881x_ramp_pa_gain(codec, G_13P5DB, G_18DB, 1000); + wsa881x_ramp_pa_gain(codec, min_gain, max_gain, 1000); } if (wsa881x->visense_enable) { wsa881x_visense_txfe_ctrl(codec, ENABLE, @@ -987,6 +1047,8 @@ static int wsa881x_probe(struct snd_soc_codec *codec) wsa881x->tz_pdata.codec = codec; wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read; wsa881x_init_thermal(&wsa881x->tz_pdata); + snd_soc_add_codec_controls(codec, wsa_analog_gain_controls, + ARRAY_SIZE(wsa_analog_gain_controls)); INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work); return 0; } diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index 85fa45ff400f..4cb62a6b3e7d 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -25,7 +25,7 @@ static struct snd_soc_dai_ops msm_fe_dai_ops = {}; /* Conventional and unconventional sample rate supported */ static unsigned int supported_sample_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, - 88200, 96000, 176400, 192000 + 88200, 96000, 176400, 192000, 352800, 384000 }; static struct snd_pcm_hw_constraint_list constraints_sample_rates = { @@ -92,7 +92,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia1 Playback", .aif_name = "MM_DL1", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -100,12 +100,12 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia1 Capture", .aif_name = "MM_UL1", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE| @@ -123,7 +123,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia2 Playback", .aif_name = "MM_DL2", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -131,12 +131,12 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia2 Capture", .aif_name = "MM_UL2", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -206,7 +206,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia3 Playback", .aif_name = "MM_DL3", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -214,12 +214,12 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 6, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia3 Capture", .aif_name = "MM_UL3", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), @@ -236,7 +236,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia4 Playback", .aif_name = "MM_DL4", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -244,7 +244,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -255,7 +255,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia5 Playback", .aif_name = "MM_DL5", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -263,7 +263,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia5 Capture", @@ -286,7 +286,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia6 Playback", .aif_name = "MM_DL6", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -294,7 +294,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia6 Capture", @@ -317,7 +317,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia7 Playback", .aif_name = "MM_DL7", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -325,7 +325,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -336,7 +336,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia8 Playback", .aif_name = "MM_DL8", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -344,7 +344,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia8 Capture", @@ -368,13 +368,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS0_HOSTLESS Playback", .aif_name = "SLIM0_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS0_HOSTLESS Capture", @@ -386,7 +386,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SLIMBUS0_HOSTLESS", @@ -396,13 +396,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS1_HOSTLESS Playback", .aif_name = "SLIM1_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS1_HOSTLESS Capture", @@ -423,13 +423,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS3_HOSTLESS Playback", .aif_name = "SLIM3_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS3_HOSTLESS Capture", @@ -450,13 +450,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS4_HOSTLESS Playback", .aif_name = "SLIM4_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS4_HOSTLESS Capture", @@ -477,13 +477,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS6_HOSTLESS Playback", .aif_name = "SLIM6_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SLIMBUS6_HOSTLESS", @@ -493,24 +493,24 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "SLIMBUS8_HOSTLESS Playback", .aif_name = "SLIM8_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "SLIMBUS8_HOSTLESS Capture", .aif_name = "SLIM8_UL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SLIMBUS8_HOSTLESS", @@ -747,13 +747,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Primary MI2S_RX Hostless Playback", .aif_name = "PRI_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "PRI_MI2S_RX_HOSTLESS", @@ -779,13 +779,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Secondary MI2S_RX Hostless Playback", .aif_name = "SEC_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "SEC_MI2S_RX_HOSTLESS", @@ -811,13 +811,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Tertiary MI2S_RX Hostless Playback", .aif_name = "TERT_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "TERT_MI2S_RX_HOSTLESS", @@ -843,13 +843,13 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "Quaternary MI2S_RX Hostless Playback", .aif_name = "QUAT_MI2S_DL_HL", - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_dai_ops, .name = "QUAT_MI2S_RX_HOSTLESS", @@ -2016,7 +2016,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia9 Playback", .aif_name = "MM_DL9", - .rates = (SNDRV_PCM_RATE_8000_192000| + .rates = (SNDRV_PCM_RATE_8000_384000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2024,7 +2024,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .capture = { .stream_name = "MultiMedia9 Capture", @@ -2216,7 +2216,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia10 Playback", .aif_name = "MM_DL10", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2224,7 +2224,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2235,7 +2235,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia11 Playback", .aif_name = "MM_DL11", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2243,7 +2243,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2254,7 +2254,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia12 Playback", .aif_name = "MM_DL12", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2262,7 +2262,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2273,7 +2273,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia13 Playback", .aif_name = "MM_DL13", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2281,7 +2281,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2292,7 +2292,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia14 Playback", .aif_name = "MM_DL14", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2300,7 +2300,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2311,7 +2311,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia15 Playback", .aif_name = "MM_DL15", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2319,7 +2319,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, @@ -2330,7 +2330,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .playback = { .stream_name = "MultiMedia16 Playback", .aif_name = "MM_DL16", - .rates = (SNDRV_PCM_RATE_8000_192000 | + .rates = (SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | @@ -2338,7 +2338,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_fe_Multimedia_dai_ops, .compress_new = snd_soc_new_compress, diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index b0948acf8a71..523cd1ce4140 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -101,6 +101,12 @@ struct dev_config { u32 channels; }; +enum { + HDMI_RX_IDX = 0, + DP_RX_IDX, + EXT_DISP_RX_IDX_MAX, +}; + struct msm_wsa881x_dev_info { struct device_node *of_node; u32 index; @@ -147,6 +153,13 @@ static struct dev_config slim_tx_cfg[] = { [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; + +/* Default configuration of external display BE */ +static struct dev_config ext_disp_rx_cfg[] = { + [HDMI_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [DP_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + static struct dev_config usb_rx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, @@ -159,12 +172,6 @@ static struct dev_config usb_tx_cfg = { .channels = 1, }; -static struct dev_config hdmi_rx_cfg = { - .sample_rate = SAMPLING_RATE_48KHZ, - .bit_format = SNDRV_PCM_FORMAT_S16_LE, - .channels = 2, -}; - static struct dev_config proxy_rx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, @@ -178,6 +185,7 @@ static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", "Eight"}; static const char *const vi_feed_ch_text[] = {"One", "Two"}; static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"}; static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_88P2", "KHZ_96", "KHZ_176P4", @@ -190,8 +198,8 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", "KHZ_22P05", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_96", "KHZ_192"}; -static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", - "KHZ_192"}; +static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); @@ -202,7 +210,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); -static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_chs, ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); @@ -210,7 +218,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); -static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); @@ -219,7 +227,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); -static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_sample_rate, hdmi_rx_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate, + ext_disp_sample_rate_text); static struct platform_device *spdev; @@ -999,15 +1008,33 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } -static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol) { + int idx; - switch (hdmi_rx_cfg.bit_format) { - case SNDRV_PCM_FORMAT_S24_3LE: - ucontrol->value.integer.value[0] = 2; - break; + if (strnstr(kcontrol->id.name, "HDMI_RX", sizeof("HDMI_RX"))) + idx = HDMI_RX_IDX; + else if (strnstr(kcontrol->id.name, "Display Port RX", + sizeof("Display Port RX"))) + idx = DP_RX_IDX; + else { + pr_err("%s: unsupported BE: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} +static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_disp_rx_cfg[idx].bit_format) { case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -1018,66 +1045,79 @@ static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol, break; } - pr_debug("%s: hdmi_rx_cfg = %d, ucontrol value = %ld\n", - __func__, hdmi_rx_cfg.bit_format, + pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_disp_rx_cfg[idx].bit_format, ucontrol->value.integer.value[0]); - return 0; } -static int hdmi_rx_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + switch (ucontrol->value.integer.value[0]) { - case 2: - hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; - break; case 1: - hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE; break; case 0: default: - hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE; break; } - pr_debug("%s: hdmi_rx_cfg.bit_format = %d, ucontrol value = %ld\n", - __func__, hdmi_rx_cfg.bit_format, + pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_disp_rx_cfg[idx].bit_format, ucontrol->value.integer.value[0]); return 0; } -static int hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, - hdmi_rx_cfg.channels); - ucontrol->value.integer.value[0] = hdmi_rx_cfg.channels - 2; + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.integer.value[0] = + ext_disp_rx_cfg[idx].channels - 2; + + pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].channels); return 0; } -static int hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - hdmi_rx_cfg.channels = ucontrol->value.integer.value[0] + 2; - if (hdmi_rx_cfg.channels > 8) { - pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n", - __func__, hdmi_rx_cfg.channels); - hdmi_rx_cfg.channels = 8; - } - pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, - hdmi_rx_cfg.channels); + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ext_disp_rx_cfg[idx].channels = + ucontrol->value.integer.value[0] + 2; + pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].channels); return 1; } -static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int sample_rate_val = 0; + int sample_rate_val; + int idx = ext_disp_get_port_idx(kcontrol); - switch (hdmi_rx_cfg.sample_rate) { + if (idx < 0) + return idx; + + switch (ext_disp_rx_cfg[idx].sample_rate) { case SAMPLING_RATE_192KHZ: sample_rate_val = 2; break; @@ -1093,33 +1133,36 @@ static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, } ucontrol->value.integer.value[0] = sample_rate_val; - pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__, - hdmi_rx_cfg.sample_rate); + pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].sample_rate); return 0; } -static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - pr_debug("%s: ucontrol value = %ld\n", __func__, - ucontrol->value.integer.value[0]); + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; switch (ucontrol->value.integer.value[0]) { case 2: - hdmi_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ; break; case 1: - hdmi_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ; break; case 0: default: - hdmi_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ; + break; } - pr_debug("%s: hdmi_rx_cfg.sample_rate = %d\n", __func__, - hdmi_rx_cfg.sample_rate); - + pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], idx, + ext_disp_rx_cfg[idx].sample_rate); return 0; } @@ -1162,8 +1205,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_ch_get, usb_audio_rx_ch_put), SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, usb_audio_tx_ch_get, usb_audio_tx_ch_put), - SOC_ENUM_EXT("HDMI_RX Channels", hdmi_rx_chs, - hdmi_rx_ch_get, hdmi_rx_ch_put), + SOC_ENUM_EXT("HDMI_RX Channels", ext_disp_rx_chs, + ext_disp_rx_ch_get, ext_disp_rx_ch_put), + SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs, + ext_disp_rx_ch_get, ext_disp_rx_ch_put), SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs, proxy_rx_ch_get, proxy_rx_ch_put), SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format, @@ -1178,8 +1223,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_format_get, usb_audio_rx_format_put), SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, usb_audio_tx_format_get, usb_audio_tx_format_put), - SOC_ENUM_EXT("HDMI_RX Bit Format", hdmi_rx_format, - hdmi_rx_format_get, hdmi_rx_format_put), + SOC_ENUM_EXT("HDMI_RX Bit Format", ext_disp_rx_format, + ext_disp_rx_format_get, ext_disp_rx_format_put), + SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format, + ext_disp_rx_format_get, ext_disp_rx_format_put), SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate, @@ -1199,9 +1246,12 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, usb_audio_tx_sample_rate_get, usb_audio_tx_sample_rate_put), - SOC_ENUM_EXT("HDMI_RX SampleRate", hdmi_rx_sample_rate, - hdmi_rx_sample_rate_get, - hdmi_rx_sample_rate_put), + SOC_ENUM_EXT("HDMI_RX SampleRate", ext_disp_rx_sample_rate, + ext_disp_rx_sample_rate_get, + ext_disp_rx_sample_rate_put), + SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate, + ext_disp_rx_sample_rate_get, + ext_disp_rx_sample_rate_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -1324,6 +1374,26 @@ static int msm_slim_get_ch_from_beid(int32_t be_id) return ch_id; } +static int msm_ext_disp_get_idx_from_beid(int32_t be_id) +{ + int idx; + + switch (be_id) { + case MSM_BACKEND_DAI_HDMI_RX: + idx = HDMI_RX_IDX; + break; + case MSM_BACKEND_DAI_DISPLAY_PORT_RX: + idx = DP_RX_IDX; + break; + default: + pr_err("%s: Incorrect ext_disp be_id %d\n", __func__, be_id); + idx = -EINVAL; + break; + } + + return idx; +} + static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -1333,9 +1403,9 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); int rc = 0; + int idx; void *config = NULL; struct snd_soc_codec *codec = NULL; - int ch_num; pr_debug("%s: format = %d, rate = %d\n", __func__, params_format(params), params_rate(params)); @@ -1347,20 +1417,20 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, case MSM_BACKEND_DAI_SLIMBUS_3_RX: case MSM_BACKEND_DAI_SLIMBUS_4_RX: case MSM_BACKEND_DAI_SLIMBUS_6_RX: - ch_num = msm_slim_get_ch_from_beid(dai_link->be_id); + idx = msm_slim_get_ch_from_beid(dai_link->be_id); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - slim_rx_cfg[ch_num].bit_format); - rate->min = rate->max = slim_rx_cfg[ch_num].sample_rate; - channels->min = channels->max = slim_rx_cfg[ch_num].channels; + slim_rx_cfg[idx].bit_format); + rate->min = rate->max = slim_rx_cfg[idx].sample_rate; + channels->min = channels->max = slim_rx_cfg[idx].channels; break; case MSM_BACKEND_DAI_SLIMBUS_0_TX: case MSM_BACKEND_DAI_SLIMBUS_3_TX: - ch_num = msm_slim_get_ch_from_beid(dai_link->be_id); + idx = msm_slim_get_ch_from_beid(dai_link->be_id); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - slim_tx_cfg[ch_num].bit_format); - rate->min = rate->max = slim_tx_cfg[ch_num].sample_rate; - channels->min = channels->max = slim_tx_cfg[ch_num].channels; + slim_tx_cfg[idx].bit_format); + rate->min = rate->max = slim_tx_cfg[idx].sample_rate; + channels->min = channels->max = slim_tx_cfg[idx].channels; break; case MSM_BACKEND_DAI_SLIMBUS_1_TX: @@ -1435,10 +1505,19 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, break; case MSM_BACKEND_DAI_HDMI_RX: + case MSM_BACKEND_DAI_DISPLAY_PORT_RX: + idx = msm_ext_disp_get_idx_from_beid(dai_link->be_id); + if (IS_ERR_VALUE(idx)) { + pr_err("%s: Incorrect ext disp idx %d\n", + __func__, idx); + rc = idx; + goto done; + } + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - hdmi_rx_cfg.bit_format); - rate->min = rate->max = hdmi_rx_cfg.sample_rate; - channels->min = channels->max = hdmi_rx_cfg.channels; + ext_disp_rx_cfg[idx].bit_format); + rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate; + channels->min = channels->max = ext_disp_rx_cfg[idx].channels; break; case MSM_BACKEND_DAI_AFE_PCM_RX: @@ -1450,7 +1529,9 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = SAMPLING_RATE_48KHZ; break; } - return 0; + +done: + return rc; } static bool msm_swap_gnd_mic(struct snd_soc_codec *codec) @@ -3293,14 +3374,14 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { }, }; -static struct snd_soc_dai_link hdmi_be_dai_link[] = { +static struct snd_soc_dai_link ext_disp_be_dai_link[] = { /* HDMI BACK END DAI Link */ { .name = LPASS_BE_HDMI, .stream_name = "HDMI Playback", .cpu_dai_name = "msm-dai-q6-hdmi.8", .platform_name = "msm-pcm-routing", - .codec_name = "msm-hdmi-audio-codec-rx", + .codec_name = "msm-ext-disp-audio-codec-rx", .codec_dai_name = "msm_hdmi_audio_codec_rx_dai", .no_pcm = 1, .dpcm_playback = 1, @@ -3309,6 +3390,21 @@ static struct snd_soc_dai_link hdmi_be_dai_link[] = { .ignore_pmdown_time = 1, .ignore_suspend = 1, }, + /* DISP PORT BACK END DAI Link */ + { + .name = LPASS_BE_DISPLAY_PORT, + .stream_name = "Display Port Playback", + .cpu_dai_name = "msm-dai-q6-dp.24608", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-ext-disp-audio-codec-rx", + .codec_dai_name = "msm_dp_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, }; static struct snd_soc_dai_link msm_tasha_dai_links[ @@ -3317,7 +3413,7 @@ static struct snd_soc_dai_link msm_tasha_dai_links[ ARRAY_SIZE(msm_common_be_dai_links) + ARRAY_SIZE(msm_tasha_be_dai_links) + ARRAY_SIZE(msm_wcn_be_dai_links) + - ARRAY_SIZE(hdmi_be_dai_link)]; + ARRAY_SIZE(ext_disp_be_dai_link)]; static struct snd_soc_dai_link msm_tavil_dai_links[ ARRAY_SIZE(msm_common_dai_links) + @@ -3325,7 +3421,7 @@ static struct snd_soc_dai_link msm_tavil_dai_links[ ARRAY_SIZE(msm_common_be_dai_links) + ARRAY_SIZE(msm_tavil_be_dai_links) + ARRAY_SIZE(msm_wcn_be_dai_links) + - ARRAY_SIZE(hdmi_be_dai_link)]; + ARRAY_SIZE(ext_disp_be_dai_link)]; static int msm_snd_card_late_probe(struct snd_soc_card *card) { @@ -3725,14 +3821,15 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) total_links += ARRAY_SIZE(msm_wcn_be_dai_links); } - if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { - dev_dbg(dev, "%s(): HDMI support present\n", __func__); + if (of_property_read_bool(dev->of_node, + "qcom,ext-disp-audio-rx")) { + dev_dbg(dev, "%s(): External display audio support present\n", + __func__); memcpy(msm_tasha_dai_links + total_links, - hdmi_be_dai_link, - sizeof(hdmi_be_dai_link)); - total_links += ARRAY_SIZE(hdmi_be_dai_link); + ext_disp_be_dai_link, + sizeof(ext_disp_be_dai_link)); + total_links += ARRAY_SIZE(ext_disp_be_dai_link); } - dailink = msm_tasha_dai_links; } else if (!strcmp(match->data, "tavil_codec")) { card = &snd_soc_card_tavil_msm; @@ -3762,14 +3859,15 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) total_links += ARRAY_SIZE(msm_wcn_be_dai_links); } - if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { - dev_dbg(dev, "%s(): HDMI support present\n", __func__); + if (of_property_read_bool(dev->of_node, + "qcom,ext-disp-audio-rx")) { + dev_dbg(dev, "%s(): ext disp audio support present\n", + __func__); memcpy(msm_tavil_dai_links + total_links, - hdmi_be_dai_link, - sizeof(hdmi_be_dai_link)); - total_links += ARRAY_SIZE(hdmi_be_dai_link); + ext_disp_be_dai_link, + sizeof(ext_disp_be_dai_link)); + total_links += ARRAY_SIZE(ext_disp_be_dai_link); } - dailink = msm_tavil_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; @@ -3786,7 +3884,6 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) dailink = msm_stub_dai_links; total_links = len_2; } - dev_dbg(dev, "%s(): No hdmi audio support\n", __func__); if (card) { card->dai_link = dailink; diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c index 9c57adb863d4..69a9e14c47de 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -32,53 +32,82 @@ enum { STATUS_MAX }; -struct msm_hdmi_ca { +struct msm_ext_disp_ca { bool set_ca; u32 ca; }; -static struct msm_hdmi_ca hdmi_ca = { false, 0x0 }; - struct msm_dai_q6_hdmi_dai_data { DECLARE_BITMAP(status_mask, STATUS_MAX); u32 rate; u32 channels; + struct msm_ext_disp_ca ca; union afe_port_config port_config; }; -static int msm_dai_q6_hdmi_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_dai_q6_ext_disp_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; int value = ucontrol->value.integer.value[0]; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + dai_data->port_config.hdmi_multi_ch.datatype = value; pr_debug("%s: value = %d\n", __func__, value); + return 0; } -static int msm_dai_q6_hdmi_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_dai_q6_ext_disp_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + ucontrol->value.integer.value[0] = dai_data->port_config.hdmi_multi_ch.datatype; + pr_debug("%s: value = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; } -static int msm_dai_q6_hdmi_ca_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_dai_q6_ext_disp_ca_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - hdmi_ca.ca = ucontrol->value.integer.value[0]; - hdmi_ca.set_ca = true; + struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + + dai_data->ca.ca = ucontrol->value.integer.value[0]; + dai_data->ca.set_ca = true; + pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca); return 0; } -static int msm_dai_q6_hdmi_ca_get(struct snd_kcontrol *kcontrol, +static int msm_dai_q6_ext_disp_ca_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = hdmi_ca.ca; + struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: dai_data is NULL\n", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = dai_data->ca.ca; + pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca); return 0; } @@ -97,12 +126,22 @@ static const struct soc_enum hdmi_config_enum[] = { static const struct snd_kcontrol_new hdmi_config_controls[] = { SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0], - msm_dai_q6_hdmi_format_get, - msm_dai_q6_hdmi_format_put), + msm_dai_q6_ext_disp_format_get, + msm_dai_q6_ext_disp_format_put), SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0, HDMI_RX_CA_MAX, 0, 1, - msm_dai_q6_hdmi_ca_get, - msm_dai_q6_hdmi_ca_put), + msm_dai_q6_ext_disp_ca_get, + msm_dai_q6_ext_disp_ca_put), +}; + +static const struct snd_kcontrol_new display_port_config_controls[] = { + SOC_ENUM_EXT("Display Port RX Format", hdmi_config_enum[0], + msm_dai_q6_ext_disp_format_get, + msm_dai_q6_ext_disp_format_put), + SOC_SINGLE_MULTI_EXT("Display Port RX CA", SND_SOC_NOPM, 0, + HDMI_RX_CA_MAX, 0, 1, + msm_dai_q6_ext_disp_ca_get, + msm_dai_q6_ext_disp_ca_put), }; /* Current implementation assumes hw_param is called once @@ -200,9 +239,9 @@ static int msm_dai_q6_hdmi_prepare(struct snd_pcm_substream *substream, struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev); int rc = 0; - if (hdmi_ca.set_ca) + if (dai_data->ca.set_ca) dai_data->port_config.hdmi_multi_ch.channel_allocation = - hdmi_ca.ca; + dai_data->ca.ca; if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { rc = afe_port_start(dai->id, &dai_data->port_config, @@ -236,8 +275,8 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai) struct snd_soc_dapm_route intercon; struct snd_soc_dapm_context *dapm; - if (!dai) { - pr_err("%s: dai not found\n", __func__); + if (!dai || !dai->driver) { + pr_err("%s: dai or dai->driver is NULL\n", __func__); return -EINVAL; } dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data), @@ -252,19 +291,33 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai) msm_dai_q6_hdmi_set_dai_id(dai); - kcontrol = &hdmi_config_controls[0]; - - rc = snd_ctl_add(dai->component->card->snd_card, - snd_ctl_new1(kcontrol, dai_data)); - - kcontrol = &hdmi_config_controls[1]; - - rc = snd_ctl_add(dai->component->card->snd_card, - snd_ctl_new1(kcontrol, dai_data)); + if (dai->driver->id == HDMI_RX) { + kcontrol = &hdmi_config_controls[0]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + + kcontrol = &hdmi_config_controls[1]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + } else if (dai->driver->id == DISPLAY_PORT_RX) { + kcontrol = &display_port_config_controls[0]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + + kcontrol = &display_port_config_controls[1]; + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(kcontrol, dai_data)); + } else { + dev_err(dai->dev, "%s: Invalid id:%d\n", + __func__, dai->driver->id); + kfree(dai_data); + dev_set_drvdata(dai->dev, NULL); + return -EINVAL; + } dapm = snd_soc_component_get_dapm(dai->component); memset(&intercon, 0 , sizeof(intercon)); - if (!rc && dai && dai->driver) { + if (!rc) { if (dai->driver->playback.stream_name && dai->driver->playback.aif_name) { dev_dbg(dai->dev, "%s add route for widget %s", @@ -325,8 +378,8 @@ static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .channels_min = 2, .channels_max = 8, - .rate_max = 192000, - .rate_min = 48000, + .rate_max = 192000, + .rate_min = 48000, }, .ops = &msm_dai_q6_hdmi_ops, .id = HDMI_RX, @@ -334,6 +387,27 @@ static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = { .remove = msm_dai_q6_hdmi_dai_remove, }; +static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = { + { + .playback = { + .stream_name = "Display Port Playback", + .aif_name = "DISPLAY_PORT", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 8, + .rate_max = 192000, + .rate_min = 48000, + }, + .ops = &msm_dai_q6_hdmi_ops, + .id = DISPLAY_PORT_RX, + .probe = msm_dai_q6_hdmi_dai_probe, + .remove = msm_dai_q6_hdmi_dai_remove, + }, +}; + static const struct snd_soc_component_driver msm_dai_hdmi_q6_component = { .name = "msm-dai-q6-hdmi", }; @@ -362,6 +436,12 @@ static int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev) &msm_dai_hdmi_q6_component, &msm_dai_q6_hdmi_hdmi_rx_dai, 1); break; + case DISPLAY_PORT_RX: + rc = snd_soc_register_component(&pdev->dev, + &msm_dai_hdmi_q6_component, + &msm_dai_q6_display_port_rx_dai[0], + ARRAY_SIZE(msm_dai_q6_display_port_rx_dai)); + break; default: dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id); rc = -ENODEV; diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 51ebd039d96b..a898532643ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -37,6 +37,10 @@ #define CHANNEL_STATUS_MASK 0x4 #define AFE_API_VERSION_CLOCK_SET 1 +#define DAI_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + enum { ENC_FMT_NONE, ENC_FMT_SBC = ASM_MEDIA_FMT_SBC, @@ -2808,15 +2812,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus Playback", .aif_name = "SLIMBUS_0_RX", - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_0_RX, @@ -2827,15 +2828,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus1 Playback", .aif_name = "SLIMBUS_1_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_1_RX, @@ -2846,15 +2844,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus2 Playback", .aif_name = "SLIMBUS_2_RX", - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_2_RX, @@ -2865,15 +2860,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus3 Playback", .aif_name = "SLIMBUS_3_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_3_RX, @@ -2884,15 +2876,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus4 Playback", .aif_name = "SLIMBUS_4_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_4_RX, @@ -2903,15 +2892,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus6 Playback", .aif_name = "SLIMBUS_6_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_6_RX, @@ -2922,15 +2908,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus5 Playback", .aif_name = "SLIMBUS_5_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_5_RX, @@ -2941,15 +2924,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus7 Playback", .aif_name = "SLIMBUS_7_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_7_RX, @@ -2960,15 +2940,12 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai[] = { .playback = { .stream_name = "Slimbus8 Playback", .aif_name = "SLIMBUS_8_RX", - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_8000_384000, + .formats = DAI_FORMATS_S16_S24_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, }, .ops = &msm_dai_q6_ops, .id = SLIMBUS_8_RX, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 695f57b30322..aea60f1fa044 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -99,7 +99,8 @@ struct msm_pcm_route_bdai_pp_params { static struct msm_pcm_route_bdai_pp_params msm_bedais_pp_params[MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX] = { - {HDMI_RX, 0, 0, 0} + {HDMI_RX, 0, 0, 0}, + {DISPLAY_PORT_RX, 0, 0, 0}, }; static int msm_routing_send_device_pp_params(int port_id, int copp_idx); @@ -448,6 +449,7 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { { SLIMBUS_8_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX}, { AFE_PORT_ID_USB_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX}, { AFE_PORT_ID_USB_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX}, + { DISPLAY_PORT_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT}, }; /* Track ASM playback & capture sessions of DAI */ @@ -2932,6 +2934,58 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; + +static const struct snd_kcontrol_new display_port_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + /* incall music delivery mixer */ static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, @@ -5583,6 +5637,12 @@ static const struct snd_kcontrol_new hdmi_rx_port_mixer_controls[] = { msm_routing_put_port_mixer), }; +static const struct snd_kcontrol_new display_port_rx_port_mixer_controls[] = { + SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), +}; + static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, @@ -7435,6 +7495,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0), + SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT", "Display Port Playback", + 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback", 0, 0, 0, 0), @@ -7709,6 +7771,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { slimbus_7_rx_mixer_controls, ARRAY_SIZE(slimbus_7_rx_mixer_controls)), SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0, hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)), + SND_SOC_DAPM_MIXER("DISPLAY_PORT Mixer", SND_SOC_NOPM, 0, 0, + display_port_mixer_controls, ARRAY_SIZE(display_port_mixer_controls)), SND_SOC_DAPM_MIXER("SPDIF_RX Audio Mixer", SND_SOC_NOPM, 0, 0, spdif_rx_mixer_controls, ARRAY_SIZE(spdif_rx_mixer_controls)), SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -7923,6 +7987,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer", SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls, ARRAY_SIZE(hdmi_rx_port_mixer_controls)), + SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Port Mixer", + SND_SOC_NOPM, 0, 0, display_port_rx_port_mixer_controls, + ARRAY_SIZE(display_port_rx_port_mixer_controls)), SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer", SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls, ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)), @@ -8114,6 +8181,24 @@ static const struct snd_soc_dapm_route intercon[] = { {"HDMI Mixer", "MultiMedia16", "MM_DL16"}, {"HDMI", NULL, "HDMI Mixer"}, + {"DISPLAY_PORT Mixer", "MultiMedia1", "MM_DL1"}, + {"DISPLAY_PORT Mixer", "MultiMedia2", "MM_DL2"}, + {"DISPLAY_PORT Mixer", "MultiMedia3", "MM_DL3"}, + {"DISPLAY_PORT Mixer", "MultiMedia4", "MM_DL4"}, + {"DISPLAY_PORT Mixer", "MultiMedia5", "MM_DL5"}, + {"DISPLAY_PORT Mixer", "MultiMedia6", "MM_DL6"}, + {"DISPLAY_PORT Mixer", "MultiMedia7", "MM_DL7"}, + {"DISPLAY_PORT Mixer", "MultiMedia8", "MM_DL8"}, + {"DISPLAY_PORT Mixer", "MultiMedia9", "MM_DL9"}, + {"DISPLAY_PORT Mixer", "MultiMedia10", "MM_DL10"}, + {"DISPLAY_PORT Mixer", "MultiMedia11", "MM_DL11"}, + {"DISPLAY_PORT Mixer", "MultiMedia12", "MM_DL12"}, + {"DISPLAY_PORT Mixer", "MultiMedia13", "MM_DL13"}, + {"DISPLAY_PORT Mixer", "MultiMedia14", "MM_DL14"}, + {"DISPLAY_PORT Mixer", "MultiMedia15", "MM_DL15"}, + {"DISPLAY_PORT Mixer", "MultiMedia16", "MM_DL16"}, + {"DISPLAY_PORT", NULL, "DISPLAY_PORT Mixer"}, + {"SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"SPDIF_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, {"SPDIF_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -9517,6 +9602,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, {"HDMI", NULL, "HDMI_RX Port Mixer"}, + {"DISPLAY_PORT_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, + {"DISPLAY_PORT", NULL, "DISPLAY_PORT_RX Port Mixer"}, + {"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, {"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"}, @@ -9571,6 +9659,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"BE_OUT", NULL, "SLIMBUS_8_RX"}, {"BE_OUT", NULL, "USB_AUDIO_RX"}, {"BE_OUT", NULL, "HDMI"}, + {"BE_OUT", NULL, "DISPLAY_PORT"}, {"BE_OUT", NULL, "SPDIF_RX"}, {"BE_OUT", NULL, "MI2S_RX"}, {"BE_OUT", NULL, "QUAT_MI2S_RX"}, @@ -9886,7 +9975,7 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx) pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx); - if (port_id != HDMI_RX) { + if (port_id != HDMI_RX && port_id != DISPLAY_PORT_RX) { pr_err("%s: Device pp params on invalid port %d\n", __func__, port_id); return -EINVAL; @@ -9959,7 +10048,7 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) { port_id = msm_bedais[be_idx].port_id; - if (port_id == HDMI_RX) + if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX) break; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 009eebede28a..d8cec53c0d9e 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -18,6 +18,7 @@ #define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX" #define LPASS_BE_SLIMBUS_0_TX "SLIMBUS_0_TX" #define LPASS_BE_HDMI "HDMI" +#define LPASS_BE_DISPLAY_PORT "DISPLAY_PORT" #define LPASS_BE_INT_BT_SCO_RX "INT_BT_SCO_RX" #define LPASS_BE_INT_BT_SCO_TX "INT_BT_SCO_TX" #define LPASS_BE_INT_BT_A2DP_RX "INT_BT_A2DP_RX" @@ -311,6 +312,7 @@ enum { MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_BACKEND_DAI_USB_RX, MSM_BACKEND_DAI_USB_TX, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_BACKEND_DAI_MAX, }; @@ -339,7 +341,7 @@ enum { #define RELEASE_LOCK 0 #define ACQUIRE_LOCK 1 -#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX 1 +#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX 2 #define HDMI_RX_ID 0x8001 #define ADM_PP_PARAM_MUTE_ID 0 #define ADM_PP_PARAM_MUTE_BIT 1 diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index 16c7ef4c0bf5..f6a687611f8a 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -423,6 +423,7 @@ int afe_get_port_type(u16 port_id) case SECONDARY_I2S_RX: case MI2S_RX: case HDMI_RX: + case DISPLAY_PORT_RX: case AFE_PORT_ID_SPDIF_RX: case SLIMBUS_0_RX: case SLIMBUS_1_RX: @@ -574,6 +575,7 @@ int afe_sizeof_cfg_cmd(u16 port_id) ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg); break; case HDMI_RX: + case DISPLAY_PORT_RX: ret_size = SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg); break; @@ -2897,6 +2899,7 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case HDMI_RX: + case DISPLAY_PORT_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; case VOICE_PLAYBACK_TX: @@ -3073,6 +3076,7 @@ int afe_get_port_index(u16 port_id) case MI2S_RX: return IDX_MI2S_RX; case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; + case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; @@ -3352,6 +3356,7 @@ int afe_open(u16 port_id, cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case HDMI_RX: + case DISPLAY_PORT_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; case SLIMBUS_0_RX: @@ -4809,6 +4814,7 @@ int afe_validate_port(u16 port_id) case MI2S_RX: case MI2S_TX: case HDMI_RX: + case DISPLAY_PORT_RX: case AFE_PORT_ID_SPDIF_RX: case RSVD_2: case RSVD_3: @@ -5591,6 +5597,12 @@ int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi) goto done; } index = q6audio_get_port_index(port); + if (index < 0) { + pr_err("%s: invalid port 0x%x, index %d\n", + __func__, port, index); + ret = -EINVAL; + goto done; + } th_vi->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); th_vi->hdr.pkt_size = sizeof(*th_vi); diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c index 56dc6b58a646..a737a27cc327 100644 --- a/sound/soc/msm/qdsp6v2/q6audio-v2.c +++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c @@ -37,6 +37,7 @@ int q6audio_get_port_index(u16 port_id) case MI2S_RX: return IDX_MI2S_RX; case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; + case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; @@ -246,6 +247,8 @@ int q6audio_get_port_id(u16 port_id) case MI2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX; case MI2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX; case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX; + case DISPLAY_PORT_RX: + return AFE_PORT_ID_HDMI_OVER_DP_RX; case AFE_PORT_ID_SPDIF_RX: return AFE_PORT_ID_SPDIF_RX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; @@ -573,6 +576,7 @@ int q6audio_validate_port(u16 port_id) case MI2S_RX: case MI2S_TX: case HDMI_RX: + case DISPLAY_PORT_RX: case RSVD_2: case RSVD_3: case DIGI_MIC_TX: diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c index 084f7df9d243..b242a8fe6017 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.c +++ b/sound/soc/msm/qdsp6v2/q6voice.c @@ -48,6 +48,7 @@ struct cvd_version_table cvd_version_table_mapping[CVD_INT_VERSION_MAX] = { {CVD_VERSION_0_0, CVD_INT_VERSION_0_0}, {CVD_VERSION_2_1, CVD_INT_VERSION_2_1}, {CVD_VERSION_2_2, CVD_INT_VERSION_2_2}, + {CVD_VERSION_2_3, CVD_INT_VERSION_2_3}, }; static struct common_data common; diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h index d230bf097eb9..3b3e728f88f2 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.h +++ b/sound/soc/msm/qdsp6v2/q6voice.h @@ -41,12 +41,14 @@ #define CVD_VERSION_0_0 "0.0" #define CVD_VERSION_2_1 "2.1" #define CVD_VERSION_2_2 "2.2" +#define CVD_VERSION_2_3 "2.3" #define CVD_INT_VERSION_DEFAULT 0 #define CVD_INT_VERSION_0_0 1 #define CVD_INT_VERSION_2_1 2 #define CVD_INT_VERSION_2_2 3 -#define CVD_INT_VERSION_LAST CVD_INT_VERSION_2_2 +#define CVD_INT_VERSION_2_3 4 +#define CVD_INT_VERSION_LAST CVD_INT_VERSION_2_3 #define CVD_INT_VERSION_MAX (CVD_INT_VERSION_LAST + 1) struct cvd_version_table { diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index b6ab3fc5789e..df65c5b494b1 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -709,7 +709,7 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #endif int s3c_i2sv2_register_component(struct device *dev, int id, - const struct snd_soc_component_driver *cmp_drv, + struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv) { struct snd_soc_dai_ops *ops = (struct snd_soc_dai_ops *)dai_drv->ops; diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index d0684145ed1f..90abab364b49 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -101,7 +101,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, * soc core. */ extern int s3c_i2sv2_register_component(struct device *dev, int id, - const struct snd_soc_component_driver *cmp_drv, + struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index fd847be299eb..94806ad6437b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2204,13 +2204,6 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, int count = 0; char *state = "not set"; - /* card won't be set for the dummy component, as a spot fix - * we're checking for that case specifically here but in future - * we will ensure that the dummy component looks like others. - */ - if (!cmpnt->card) - return 0; - list_for_each_entry(w, &cmpnt->card->widgets, list) { if (w->dapm != dapm) continue; diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index b2dd69055927..c48d8c8d9766 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -201,7 +201,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; uinfo->value.integer.min = 0; - if (mc->min < 0 && (uinfo->type == SNDRV_CTL_ELEM_TYPE_INTEGER)) + if (uinfo->type == SNDRV_CTL_ELEM_TYPE_INTEGER) uinfo->value.integer.max = platform_max - mc->min; else uinfo->value.integer.max = platform_max; @@ -224,14 +224,12 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - snd_soc_info_volsw(kcontrol, uinfo); /* Max represents the number of levels in an SX control not the - * maximum value, so add the minimum value back on + * maximum value. + * uinfo->value.integer.max is set to number of levels + * in snd_soc_info_volsw_sx. No further adjustment is necessary. */ - uinfo->value.integer.max += mc->min; return 0; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index db11ecf0b74d..001fb4dc0722 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1138,11 +1138,8 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */ case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ - case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ - case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */ case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ - case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ return true; } diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 94c051773fd9..fa0206cc14c6 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -1007,8 +1007,8 @@ static int uaudio_qmi_plat_probe(struct platform_device *pdev) } uaudio_qdev->domain = iommu_domain_alloc(msm_iommu_get_bus(&pdev->dev)); - if (!uaudio_qdev) { - dev_err(&pdev->dev, "failed to callocate iommu domin\n"); + if (!uaudio_qdev->domain) { + dev_err(&pdev->dev, "failed to callocate iommu domain\n"); return -ENODEV; } diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 88cccea3ca99..0144b3d1bb77 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -1164,11 +1164,11 @@ process_filter(struct event_format *event, struct filter_arg **parg, current_op = current_exp; ret = collapse_tree(current_op, parg, error_str); - /* collapse_tree() may free current_op, and updates parg accordingly */ - current_op = NULL; if (ret < 0) goto fail; + *parg = current_op; + free(token); return 0; diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 90c3558c2c12..4e074a660826 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -62,14 +62,6 @@ OPTIONS --scale:: scale/normalize counter values --d:: ---detailed:: - print more detailed statistics, can be specified up to 3 times - - -d: detailed events, L1 and LLC data cache - -d -d: more detailed events, dTLB and iTLB events - -d -d -d: very detailed events, adding prefetch events - -r:: --repeat=<n>:: repeat command and print average + stddev (max: 100). 0 means forever. diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 3900386a3629..81def6c3f24b 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2059,12 +2059,10 @@ skip_annotation: * * See hist_browser__show_entry. */ - if (sort__has_sym && browser->selection->sym) { - nr_options += add_script_opt(browser, - &actions[nr_options], - &options[nr_options], - NULL, browser->selection->sym); - } + nr_options += add_script_opt(browser, + &actions[nr_options], + &options[nr_options], + NULL, browser->selection->sym); } nr_options += add_script_opt(browser, &actions[nr_options], &options[nr_options], NULL, NULL); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 956187bf1a85..8b10621b415c 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -274,7 +274,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool, strcpy(execname, ""); /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n", + n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", &event->mmap2.start, &event->mmap2.len, prot, &event->mmap2.pgoff, &event->mmap2.maj, &event->mmap2.min, diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b4b96120fc3b..d1392194a9a9 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1211,12 +1211,12 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, */ if (cpus != evlist->cpus) { cpu_map__put(evlist->cpus); - evlist->cpus = cpu_map__get(cpus); + evlist->cpus = cpus; } if (threads != evlist->threads) { thread_map__put(evlist->threads); - evlist->threads = thread_map__get(threads); + evlist->threads = threads; } perf_evlist__propagate_maps(evlist); diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 9227c2f076c3..97f963a3dcb9 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1127,7 +1127,7 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", ret); - if (pt->synth_opts.last_branch) + if (pt->synth_opts.callchain) intel_pt_reset_last_branch_rb(ptq); return ret; diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index a7b9022b5c8f..ea6064696fe4 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -86,8 +86,6 @@ static void kvm_timer_inject_irq_work(struct work_struct *work) vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired); vcpu->arch.timer_cpu.armed = false; - WARN_ON(!kvm_timer_should_fire(vcpu)); - /* * If the vcpu is blocked we want to wake it up so that it will see * the timer has expired when entering the guest. @@ -95,46 +93,10 @@ static void kvm_timer_inject_irq_work(struct work_struct *work) kvm_vcpu_kick(vcpu); } -static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu) -{ - cycle_t cval, now; - - cval = vcpu->arch.timer_cpu.cntv_cval; - now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; - - if (now < cval) { - u64 ns; - - ns = cyclecounter_cyc2ns(timecounter->cc, - cval - now, - timecounter->mask, - &timecounter->frac); - return ns; - } - - return 0; -} - static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt) { struct arch_timer_cpu *timer; - struct kvm_vcpu *vcpu; - u64 ns; - timer = container_of(hrt, struct arch_timer_cpu, timer); - vcpu = container_of(timer, struct kvm_vcpu, arch.timer_cpu); - - /* - * Check that the timer has really expired from the guest's - * PoV (NTP on the host may have forced it to expire - * early). If we should have slept longer, restart it. - */ - ns = kvm_timer_compute_delta(vcpu); - if (unlikely(ns)) { - hrtimer_forward_now(hrt, ns_to_ktime(ns)); - return HRTIMER_RESTART; - } - queue_work(wqueue, &timer->expired); return HRTIMER_NORESTART; } @@ -208,6 +170,8 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu) void kvm_timer_schedule(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; + u64 ns; + cycle_t cval, now; BUG_ON(timer_is_armed(timer)); @@ -227,7 +191,14 @@ void kvm_timer_schedule(struct kvm_vcpu *vcpu) return; /* The timer has not yet expired, schedule a background timer */ - timer_arm(timer, kvm_timer_compute_delta(vcpu)); + cval = timer->cntv_cval; + now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; + + ns = cyclecounter_cyc2ns(timecounter->cc, + cval - now, + timecounter->mask, + &timecounter->frac); + timer_arm(timer, ns); } void kvm_timer_unschedule(struct kvm_vcpu *vcpu) |
