diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 56e752040a19f44b50a1d8949ba06615c67b63c5..35d3573210c615e266e3d21e2186c947a2efa3f5 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -28,6 +28,10 @@ $(warning Forcing kernel header generation only for '$(TARGET_KERNEL_HEADER_ARCH KERNEL_HEADER_ARCH := $(TARGET_KERNEL_HEADER_ARCH) endif +ifeq ($(shell echo $(KERNEL_DEFCONFIG) | grep vendor),) +KERNEL_DEFCONFIG := vendor/$(KERNEL_DEFCONFIG) +endif + KERNEL_HEADER_DEFCONFIG := $(strip $(KERNEL_HEADER_DEFCONFIG)) ifeq ($(KERNEL_HEADER_DEFCONFIG),) KERNEL_HEADER_DEFCONFIG := $(KERNEL_DEFCONFIG) diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 68dde5605044ec4930355f5f381c40a1063a97a8..f0e27cad2427ca9e4de8fb39332178dff1a42680 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -163,6 +163,9 @@ compatible = "qcom,sm6150-idp" compatible = "qcom,sm6150p-idp" compatible = "qcom,sm6150p" compatible = "qcom,sm6150p-qrd" +compatible = "qcom,sa6155-adp-star" +compatible = "qcom,sa6155p-adp-star" +compatible = "qcom,sa6155p" compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-iot" compatible = "qcom,qcs403-iot" diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index efb9510595e53d61dda9ba397955008618098587..837c33cd07481189a9a9dcfaf590703ff29f4890 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -76,9 +76,15 @@ mhi channel node properties: - mhi,ee Usage: required Value type: - Definition: Channel execution enviornment as defined by enum MHI_EE - 1 = Bootloader stage - 2 = AMSS mode + Definition: Channel execution enviornment (EE) mask as defined by enum + mhi_ch_ee_mask + BIT(0) = Channel supported in PBL EE + BIT(1) = Channel supported in SBL EE + BIT(2) = Channel supported in AMSS EE + BIT(3) = Channel supported in RDDM EE + BIT(4) = Channel supported in WFW EE + BIT(5) = Channel supported in PTHRU EE + BIT(6) = Channel supported in EDL EE - mhi,pollcfg Usage: optional @@ -223,7 +229,7 @@ mhi_controller { mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@1 { @@ -234,7 +240,7 @@ mhi_controller { mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_event@0 { diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt index 9eaaeb35829ae47f7eb92e4a22e78bf2e24e7d3a..0c2aefae84147daded09800f889ccd5f18d5c519 100644 --- a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt @@ -2,8 +2,11 @@ Qualcomm Technologies, Inc. Display Clock & Reset Controller Binding -------------------------------------------------------------------- Required properties : -- compatible : Shall contain "qcom,dispcc-sm8150" or "qcom,dispcc-sm8150-v2" or - "qcom,dispcc-sm6150". +- compatible : Shall contain one of the following: + "qcom,dispcc-sm8150", + "qcom,dispcc-sm8150-v2", + "qcom,dispcc-sm6150", + "qcom,dispcc-sdmmagpie". - reg : Shall contain base register location and length. - reg-names: Address name. Must be "cc_base". - vdd_mm-supply: phandle to the MM_CX rail that needs to be voted on behalf diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt index c0532804724107d0013d25f064e393e956d5ab95..a500819ceb31e4f1c3dbf881dd41c5dbfbd24cb7 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt @@ -5,7 +5,8 @@ Required properties : - compatible : shall contain one of the following: "qcom,gpucc-sm8150", "qcom,gpucc-sdmshrike", - "qcom,gpucc-sm6150". + "qcom,gpucc-sm6150", + "qcom,gpucc-sdmmagpie". - reg : shall contain base register offset and size. - reg-names: names of registers listed in the same order as in the reg property. diff --git a/Documentation/devicetree/bindings/clock/qcom,npucc.txt b/Documentation/devicetree/bindings/clock/qcom,npucc.txt index a5310ee9df231981911750665a2f463eda69493c..d5e4ed6f0f9db09de77b0b6ee9b3918670d353f7 100644 --- a/Documentation/devicetree/bindings/clock/qcom,npucc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,npucc.txt @@ -2,7 +2,8 @@ Qualcomm Technologies, Inc. NPU Clock & Reset Controller Binding ---------------------------------------------------------------- Required properties : -- compatible : must contain "qcom,npucc-sm8150" or "qcom,npucc-sm8150-v2". +- compatible : must contain "qcom,npucc-sm8150" or "qcom,npucc-sm8150-v2" + or "qcom,npucc-sdmmagpie". - reg : shall contain base register location and length. - reg-names: names of registers listed in the same order as in the reg property. diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.txt b/Documentation/devicetree/bindings/clock/qcom,videocc.txt index 1c7dfcd9027041ed2e9c7f2281e48b688e9a3c03..38dd889acdef4c0c689ca492709c9c5eceae5c89 100644 --- a/Documentation/devicetree/bindings/clock/qcom,videocc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,videocc.txt @@ -2,10 +2,10 @@ Qualcomm Technologies, Inc. Video Clock & Reset Controller Bindings Required properties: - compatible: shall contain "qcom,videocc-sm8150" or "qcom,videocc-sm8150-v2" or - "qcom,videocc-sm6150". + "qcom,videocc-sm6150", "qcom,videocc-sdmmagpie". - reg: shall contain base register location and length. - reg-names: names of registers listed in the same order as in the reg property. -- vdd_mm-supply: the logic rail supply. +- vdd_-supply: the logic rail supply which could be either MM or CX. - clock-names: Shall contain "cfg_ahb_clk" - clocks: phandle + clock reference to the GCC AHB clock. - #clock-cells: shall contain 1. diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index 20f26fbce8756c6692969532c7cf8629f7c53a35..cd091b99e4e0057734e925d948944f64f3e43de6 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -12,6 +12,8 @@ Required properties: * "qcom,scm-msm8690" for MSM8690 platforms * "qcom,scm-msm8996" for MSM8996 platforms * "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc) + * "android,firmware" for firmware image + * "android,vbmeta" for setting system properties for verified boot. - clocks: One to three clocks may be required based on compatible. * No clock required for "qcom,scm-msm8996" * Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960" @@ -28,3 +30,26 @@ Example for MSM8916: clock-names = "core", "bus", "iface"; }; }; + +Example for SM6150: + +firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt index 747e0b601da22d1b21d7f57be5e883ef4df9158e..645052c048d2a0fc0a1c27de06a876a16340934a 100644 --- a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt +++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt @@ -2,7 +2,7 @@ Qualcomm Technologies, Inc. GPU powerlevels Powerlevels are defined in sets by qcom,gpu-pwrlevels. Multiple sets (bins) can be defined within qcom,gpu-pwrelvel-bins. Each powerlevel defines a -voltage, bus, and bandwitdh level. +voltage, bus, bandwidth level, and a DVM value. - qcom,gpu-pwrlevel-bins: Contains one or more qcom,gpu-pwrlevels sets @@ -28,3 +28,8 @@ Properties: settings) - qcom,bus-min Minimum bus level to set for the power level - qcom,bus-max maximum bus level to set for the power level +- qcom,dvm-val: Value that is used as a register setting for + the ACD power feature. It helps determine the + threshold for when ACD activates. 0xFFFFFFFF + is the default value, and the setting where + ACD will never activate. diff --git a/Documentation/devicetree/bindings/input/qti-haptics.txt b/Documentation/devicetree/bindings/input/qti-haptics.txt index 2c4f4f02ae349af256a6a23dd4f5c60b260503ab..b3daa49fe443cc27e272351a92e9a9569a28140d 100644 --- a/Documentation/devicetree/bindings/input/qti-haptics.txt +++ b/Documentation/devicetree/bindings/input/qti-haptics.txt @@ -130,6 +130,15 @@ waveforms/effects: [5:1]: waveform amplitude [0]: reserved. +- qcom,wf-vmax-mv + Usage: optional + Value type: + Definition: Specifies the maximum allowed output voltage in millivolts + for this effect. Value specified here will be rounded + off to the closest multiple of 116 mV. Allowed values: + 0 to 3596. If this is not specified, the value defined in + "qcom,vmax-mv" will be applied. + - qcom,wf-play-rate-us Usage: optional Value type: diff --git a/Documentation/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt similarity index 75% rename from Documentation/input/touchscreen/himax.txt rename to Documentation/devicetree/bindings/input/touchscreen/himax.txt index 37ddc6749b2499d30de12460055e9cb1f74fe2ea..4b1743430fba12df6d49d8965db41902452fb728 100644 --- a/Documentation/input/touchscreen/himax.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt @@ -26,3 +26,21 @@ Optional properties: - himax,3v3-gpio : gpio acting as 3.3 v supply. - himax,report_type : Multi-touch protocol type. Default 0. 0 for protocol A, 1 for protocol B. + +Example: + i2c@884000 { + status = "okay"; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <89 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + himax,panel-coords = <0 1080 0 2160>; + himax,display-coords = <0 1080 0 2160>; + himax,irq-gpio = <&tlmm 89 0x00>; + himax,rst-gpio = <&tlmm 88 0x00>; + report_type = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 04faf3cf51eabd1240e44364e4774a10f8795f81..c8ad1b304dc5a3f866127c5a5cac2c848783834b 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -117,12 +117,26 @@ conditions. Some hardware may not have full support for atos debugging in tandem with other features like power collapse. +-qcom,opt-out-tbu-halting: + Allow certain TBUs to opt-out from being halted for the + ATOS operation to proceed. Halting certain TBUs would cause + considerable impact to the system such as deadlocks on demand. + Such TBUs can be opted out to be halted from software. + - qcom,deferred-regulator-disable-delay : The time delay for deferred regulator disable in ms. In case of unmap call, regulator is enabled/disabled. This may introduce additional delay. For clients who do not detach, it's not possible to keep regulator vote while smmu is attached. Type is . +- qcom,min-iova-align: + Some hardware revision might have the deep prefetch bug where + invalid entries in the prefetch window would cause improper + permissions to be cached for the valid entries in this window. + Enable the workaround on such hardware by aligning the start + and end of all mapped buffers to prefetch size boundary, which + is defined by ARM_SMMU_MIN_IOVA_ALIGN. + - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified diff --git a/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt b/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt new file mode 100644 index 0000000000000000000000000000000000000000..c53c3a065822a0ac605abbd7f66f660fdf7d3a83 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt @@ -0,0 +1,55 @@ +NXP LED segment driver devicetree bindings + +Required properties: + + - compatible : "nxp,pca9956b" for PCA9956b + - nxp,mode1 : MODE1 register + - nxp,mode2 : MODE2 register + - nxp,ledout0~5 : LED output state registers + - nxp,defaultiref : LED output gain control default value + +LED sub-node properties: + - reg: number of LED line, 0 to 24 + - label: (optional) name of LED + - linux,default-trigger : (optional) + +Example: +pca9956b { + /* I2C version */ + reg = <0x7d>; + + /* nxp-ledseg properties */ + + compatible = "nxp,pca9956b"; + + pinctrl-names = "default"; + pinctrl-0 = <&pca9956b_pins>; + + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xaa>; + pca9956b,ledout1 = <0xaa>; + pca9956b,ledout2 = <0xaa>; + pca9956b,ledout3 = <0xff>; + pca9956b,ledout4 = <0xff>; + pca9956b,ledout5 = <0xff>; + pca9956b,defaultiref = <0x2f>; + + out0@0 { + label = "ledsec1_b"; + reg = <0x0>; + }; + + out1@1 { + label = "ledsec1_g"; + reg = <0x1>; + }; + + out5@5 { + label = "ledsec1_g"; + reg = <0x5>; + linux,default_trigger = "heartbeat"; + }; +}; diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 169f848b534d77ba2afd7d271123e2404648e909..8728a1bdbc6a212a667894d6cc6ae772b97a37aa 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -24,11 +24,11 @@ Optional properties: 128, 192. Unit is uS. - qcom,short-circuit-det : Boolean property which enables short circuit fault detection. - qcom,open-circuit-det : Boolean property which enables open circuit fault detection. -- qcom,vph-droop-det : Boolean property which enables VPH droop detection. -- qcom,vph-droop-hys-mv : Integer property to specify VPH droop hysteresis. It is only used if - qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75. - Unit is mV. -- qcom,vph-droop-thresh-mv : Integer property to specify VPH droop threshold. It is only used if +- qcom,vph-droop-det : Boolean property which enables VPH droop detection. +- qcom,vph-droop-hysteresis-mv : Integer property to specify VPH droop hysteresis. It is only used if + qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75. + Unit is mV. +- qcom,vph-droop-threshold-mv : Integer property to specify VPH droop threshold. It is only used if qcom,vph-droop-det is specified. Valid values are 2500 to 3200 with step size of 100. Unit is mV. - qcom,vph-droop-debounce-us : Integer property to specify VPH droop debounce time. It is only used diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt index 33865b225231af411d5e7e4f2063120257d562ca..249dd04cc6e26088b9ac2947b6a8600322af3f2a 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt @@ -14,7 +14,7 @@ First Level Node - CSIPHY device Usage: required Value type: Definition: Should be "qcom,csiphy-v1.0", - "qcom,csiphy-v1.1", "qcom,csiphy". + "qcom,csiphy-v1.1", "qcom,csiphy-v2.0", "qcom,csiphy". - cell-index: csiphy hardware core index Usage: required diff --git a/Documentation/devicetree/bindings/net/dsa/qca8k.txt b/Documentation/devicetree/bindings/net/dsa/qca8k.txt index 9c67ee4890d749af16ea27997e235f5f12594cb1..bbcb255c3150230978fba796b320a71c206ddbad 100644 --- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt +++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt @@ -2,7 +2,10 @@ Required properties: -- compatible: should be "qca,qca8337" +- compatible: should be one of: + "qca,qca8334" + "qca,qca8337" + - #size-cells: must be 0 - #address-cells: must be 1 @@ -14,6 +17,20 @@ port and PHY id, each subnode describing a port needs to have a valid phandle referencing the internal PHY connected to it. The CPU port of this switch is always port 0. +A CPU port node has the following optional node: + +- fixed-link : Fixed-link subnode describing a link to a non-MDIO + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. + +For QCA8K the 'fixed-link' sub-node supports only the following properties: + +- 'speed' (integer, mandatory), to indicate the link speed. Accepted + values are 10, 100 and 1000 +- 'full-duplex' (boolean, optional), to indicate that full duplex is + used. When absent, half duplex is assumed. + Example: @@ -53,6 +70,10 @@ Example: label = "cpu"; ethernet = <&gmac1>; phy-mode = "rgmii"; + fixed-link { + speed = 1000; + full-duplex; + }; }; port@1 { diff --git a/Documentation/devicetree/bindings/net/meson-dwmac.txt b/Documentation/devicetree/bindings/net/meson-dwmac.txt index 354dd9896bb54bbe9cbcb7da56a659d5846f80b3..910187ebf1ce281e05c5e658b877ed6857bb0804 100644 --- a/Documentation/devicetree/bindings/net/meson-dwmac.txt +++ b/Documentation/devicetree/bindings/net/meson-dwmac.txt @@ -10,6 +10,7 @@ Required properties on all platforms: - "amlogic,meson6-dwmac" - "amlogic,meson8b-dwmac" - "amlogic,meson-gxbb-dwmac" + - "amlogic,meson-axg-dwmac" Additionally "snps,dwmac" and any applicable more detailed version number described in net/stmmac.txt should be used. diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt index 2392557ede2777a2463e76f77e78be4ddadbd607..df77d394edc024586ace6be0616cbfc9db054199 100644 --- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt @@ -3,8 +3,10 @@ Required properties for the root node: - compatible: one of "amlogic,meson8-cbus-pinctrl" "amlogic,meson8b-cbus-pinctrl" + "amlogic,meson8m2-cbus-pinctrl" "amlogic,meson8-aobus-pinctrl" "amlogic,meson8b-aobus-pinctrl" + "amlogic,meson8m2-aobus-pinctrl" "amlogic,meson-gxbb-periphs-pinctrl" "amlogic,meson-gxbb-aobus-pinctrl" "amlogic,meson-gxl-periphs-pinctrl" diff --git a/Documentation/devicetree/bindings/platform/msm/msm_demux.txt b/Documentation/devicetree/bindings/platform/msm/msm_demux.txt new file mode 100644 index 0000000000000000000000000000000000000000..c192a43d58f94418fa78a96569ff0d54793db15c --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/msm_demux.txt @@ -0,0 +1,13 @@ +* Demux + +Demux is responsible for demuxing the transport stream contents +to respective elementary streams + +Required properties: +- compatible : Should be "qcom,demux" + +Example: + + demux { + compatible = "qcom,demux"; + }; diff --git a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt new file mode 100644 index 0000000000000000000000000000000000000000..70377b4a9551bb43a3cd367fde1f492ba111dea9 --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt @@ -0,0 +1,83 @@ +* TSPP ( QTI Transport Stream Packet Processor ) + +Hardware driver for QTI TSIF 12seg wrapper core, which consists of a TSPP, a +BAM (Bus access manager, used for DMA) and two TSIF inputs. + +The TSPP driver is responsible for: + - TSPP/TSIF hardware configuration (using SPS driver to configure BAM hardware) + - TSIF GPIO/Clocks configuration + - Memory resource management + - Handling TSIF/TSPP interrupts and BAM events + - TSPP Power management + +Required properties: +- compatible : Should be "qcom,msm_tspp" +- reg : Specifies the base physical addresses and sizes of TSIF, TSPP & BAM registers. +- reg-names : Specifies the register names of TSIF, TSPP & BAM base registers. +- interrupts : Specifies the interrupts associated with TSIF 12 seg core. +- interrupt-names: Specifies interrupt names for TSIF, TSPP & BAM interrupts. +- clock-names: Specifies the clock names used for interface & reference clocks. +- clocks: GCC_TSIF_AHB_CLK clock for interface clock & GCC_TSIF_REF_CLK clock for reference clock. +- qcom, msm_bus,name: Should be "tsif" +- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling +- qcom, msm_bus,num_paths: The paths for source and destination ports +- qcom, msm_bus,vectors: Vectors for bus topology. +- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active. +- qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation. +- iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + +Example: + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x20 0x0f>; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt index e6158732517a62aa1b742db634711c83f9347761..91d9047f193d044857e2b8557848af90093e8c1b 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt @@ -351,6 +351,13 @@ First Level Node - FG Gen4 device property "qcom,slope-limit-temp-threshold" to make dynamic slope limit adjustment functional. +- qcom,rapid-soc-dec-en + Usage: optional + Value type: + Definition: A boolean property that when defined enables rapid SOC + decrease when the battery SOC is low but not converging to + zero with battery voltage dropping rapidly below Vcutoff. + ========================================================== Second Level Nodes - Peripherals managed by FG Gen4 driver ========================================================== diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt index abbb9816cf9849749ef3ec1eb3ea3b7d8b6121c3..528c285a936147c1d6d4aebb48c6d75b0524dfa4 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt @@ -36,6 +36,33 @@ Charger specific properties: connected to AUX. Set this flag to indicate the thermistor doesn't exist. +- qcom,parallel-mode + Usage: optional + Value type: + Definition: Specifies parallel charging mode. If not specified, MID-MID + option is selected by default. + +- qcom,stacked-batfet + Usage: optional + Value type: + Definition: boolean flag. Specifies if parallel charger has stacked BATFET + configuration. + In stacked batfet the main and parallel charger's batfet are + stacked one after the other and thus all the charge current + (FCC) flows through main. In a non-stacked configuration each + charger controls the charge current (FCC) separately. + +- qcom,die-temp-threshold-degc + Usage: optional + Value type: + Definition: Specifies DIE temp threshold beyond which h/w starts mitigation. + If not sepcified, 90 degrees centigrade is used. + +- qcom,hw-die-temp-mitigation + Usage: optional + Value type: bool + Definition: Boolean property to enable h/w controlled die temp mitigation. + ================================================ Second Level Nodes - SMB1355 Charger Peripherals ================================================ diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt index ddd90e134a1664c58822120fe3f74a50ec3b2534..d01f25a190c1a416d1e6700e290d1934e995cd0c 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt @@ -40,6 +40,17 @@ device module in Qualcomm Technologies, Inc. PMIC chips. channels. This property is required if any LPG channels support LUT mode. +- qcom,sync-channel-ids: + Usage: optional + Value type: + Definition: The hardware IDs of the LPG channel that required be + grouped together. These channels will share the same LUT + ramping configuration so that they will be enabled with a + synchronized pattern. If the LUT ramping configuration + differs for the channels grouped for synchronization, + configuration of the first channel will be applied for + all others. + Subnode is optional if LUT mode is not required, it's required if any LPG channels expected to be supported in LUT mode. @@ -114,6 +125,7 @@ Example: #pwm-cells = <2>; qcom,lut-patterns = <0 14 28 42 56 70 84 100 100 84 70 56 42 28 14 0>; + qcom,sync-channel-ids = <3 4 5>; lpg@3 { qcom,lpg-chan-id = <3>; qcom,ramp-step-ms = <200>; diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt index 54a3f2c80e3acd085a48782881dcac9bcbf318a0..90ca0b70d55526b2879221a8acf55ccf979d0c31 100644 --- a/Documentation/devicetree/bindings/regulator/fan53555.txt +++ b/Documentation/devicetree/bindings/regulator/fan53555.txt @@ -1,7 +1,8 @@ Binding for Fairchild FAN53555 regulators Required properties: - - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" + - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" or + "halo,hl7509" - reg: I2C address Optional properties: @@ -10,6 +11,10 @@ Optional properties: voltage. The other one is used for the runtime voltage setting Possible values are either <0> or <1> - vin-supply: regulator supplying the vin pin + - fcs,disable-suspend: Boolean flag which specifies if suspend voltage + configuration should be avoided. If this property is present, + then the voltage selector register defined by + fcs,suspend-voltage-selector should not be modified at runtime. Example: @@ -21,3 +26,12 @@ Example: vin-supply = <&parent_reg>; fcs,suspend-voltage-selector = <1>; }; + + regulator@60 { + compatible = "halo,hl7509"; + regulator-name = "hl7509"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1230000>; + fcs,suspend-voltage-selector = <1>; + fcs,disable-suspend; + }; diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 5c93e5666634ebc8166ef3b9d0977cbbee5aa120..c661c71aee3b343a75d3e7c78b3cc1f5457d51a9 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -43,6 +43,12 @@ Optional properties: Ex. "base", "domain-addr", "sw-reset", "hw-ctrl-addr". - qcom,no-status-check-on-disable: Do not poll the status bit when GDSC is disabled. + - qcom,skip-disable: Boolean flag indicating that the GDSC must not be + physically disabled upon a software disable request. + Instead, the GDSC will be disabled by the always-on + processor (AOP) upon entering system sleep. The AOP + will also perform a special reset sequence for the GDSC + upon resuming from system sleep. - qcom,disallow-clear: Presence denotes the periph & core memory will not be cleared, unless the required subsystem does not invoke the api which will allow clearing the bits. diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt index 20e87c4164d272e1828fb47b0847a737fbfc98e5..8d582798fddfe0346fb9043380a4459e35743b76 100644 --- a/Documentation/devicetree/bindings/sound/wcd_codec.txt +++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt @@ -550,6 +550,14 @@ Tanggu Codec Required properties: - compatible: "qcom,wcd937x-codec"; + - qcom,rx_swr_ch_map: mapping of swr rx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,tx_swr_ch_map: mapping of swr tx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. - qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio configuration. If this property is not defined, it is expected to atleast define "qcom,cdc-reset-gpio" property. @@ -585,6 +593,17 @@ Optional properties: Example: wcd937x_codec: wcd937x-codec { compatible = "qcom,wcd937x-codec"; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x3 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; qcom,wcd-rst-gpio-node = <&wcd937x_rst_gpio>; qcom,rx-slave = <&wcd937x_rx_slave>; diff --git a/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt b/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt index ba92e093b1343650f037e3ab64c7e70a1b6a6fe1..41822f28acd68545067f6052340fe9bd53a61054 100644 --- a/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt +++ b/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt @@ -22,6 +22,9 @@ Required properties: which the swr-devid is <0x0 0x032000> where 0x03 represents device Unique_ID, 0x20 represents Part_Id1 and 0x00 represents part_Id2. +Optional properties: +- mipi-sdw-clock-stop-mode0-supported : should be set to 1 if all + the slaves under the master supports clock stop mode 0 Example: @@ -46,4 +49,5 @@ swr0: swr_master { compatible = "qcom,wsa881x"; reg = <0x00 0x042000>; }; + mipi-sdw-clock-stop-mode0-supported = <0>; }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ea764a49c6bcbc3b494c7b7cd53963c690714c58..0753f394367ac50d1aea32ca7ba172bd9f2bc1aa 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -28,6 +28,7 @@ amstaos AMS-Taos Inc. android Google Inc. analogix Analogix Semiconductor, Inc. andestech Andes Technology Corporation +android Google apm Applied Micro Circuits Corporation (APM) aptina Aptina Imaging arasan Arasan Chip Systems @@ -136,6 +137,7 @@ grinn Grinn grmn Garmin Limited gumstix Gumstix, Inc. gw Gateworks Corporation +halo Halo Microelectronics Co., Ltd. hannstar HannStar Display Corporation haoyu Haoyu Microelectronic Co. Ltd. hardkernel Hardkernel Co., Ltd @@ -329,7 +331,7 @@ summit Summit microelectronics sunchip Shenzhen Sunchip Technology Co., Ltd SUNW Sun Microsystems, Inc swir Sierra Wireless -syna Synaptics Inc. +synaptics Synaptics Inc. synology Synology, Inc. tbs TBS Technologies tcg Trusted Computing Group diff --git a/Documentation/vfio-mediated-device.txt b/Documentation/vfio-mediated-device.txt index 1b395034653205b5a6c127488053daced91075d6..c3f69bcaf96e1f9caaae06fbcdc0cafde22bbf0b 100644 --- a/Documentation/vfio-mediated-device.txt +++ b/Documentation/vfio-mediated-device.txt @@ -145,6 +145,11 @@ The functions in the mdev_parent_ops structure are as follows: * create: allocate basic resources in a driver for a mediated device * remove: free resources in a driver when a mediated device is destroyed +(Note that mdev-core provides no implicit serialization of create/remove +callbacks per mdev parent device, per mdev type, or any other categorization. +Vendor drivers are expected to be fully asynchronous in this respect or +provide their own internal resource protection.) + The callbacks in the mdev_parent_ops structure are as follows: * open: open callback of mediated device diff --git a/Makefile b/Makefile index 55c8e72948c3301afeeda83534eb6d35f303e7bb..c8312bec46750c35396fd9d37f000cd31f288e70 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 56 +SUBLEVEL = 62 EXTRAVERSION = NAME = Petit Gorille @@ -667,6 +667,7 @@ KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context) +KBUILD_CFLAGS += $(call cc-disable-warning, attribute-alias) ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += $(call cc-option,-Oz,-Os) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 75a5c35a2067d05c10746138470249dfd6ba4e6a..a48976dc9bcd0ad8638aadfd927e0480f3816c3e 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1183,13 +1183,10 @@ SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru) SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, struct rusage32 __user *, ur) { - unsigned int status = 0; struct rusage r; - long err = kernel_wait4(pid, &status, options, &r); + long err = kernel_wait4(pid, ustatus, options, &r); if (err <= 0) return err; - if (put_user(status, ustatus)) - return -EFAULT; if (!ur) return err; if (put_tv32(&ur->ru_utime, &r.ru_utime)) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 4383313b064a0439a74a8b8184d210d0d9160a12..5c8caf85c35054722402d86f58033820d3de7640 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -408,7 +408,7 @@ config ARC_HAS_DIV_REM config ARC_HAS_ACCL_REGS bool "Reg Pair ACCL:ACCH (FPU and/or MPY > 6)" - default n + default y help Depending on the configuration, CPU can contain accumulator reg-pair (also referred to as r58:r59). These can also be used by gcc as GPR so diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index ec7c849a5c8e9887fbd60acf176f194cc0c4ba03..a8242362e55199e550f4da319f1f5f2bd33f23c2 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index 63d3cf69e0b02efe45fca035649951836fc1e948..ef3c31cd77378c0fcfed9f4e97a05ba1460c5410 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index f613ecac14a750e6008dc817d3a06727a4631989..1757ac9cecbc10fb189673d23a76ad5137e9ed9f 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/haps_hs_defconfig b/arch/arc/configs/haps_hs_defconfig index db04ea4dd2d97237b843fd4b90706f2e0c8ef6d9..aa8240a92b60791b8f63fd18230813bb972a019a 100644 --- a/arch/arc/configs/haps_hs_defconfig +++ b/arch/arc/configs/haps_hs_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set diff --git a/arch/arc/configs/haps_hs_smp_defconfig b/arch/arc/configs/haps_hs_smp_defconfig index 3507be2af6fe3684f4acca6de7009903da82b97e..bc5a24ea6cf7b704a5fb5a9688d5d6724ab1013f 100644 --- a/arch/arc/configs/haps_hs_smp_defconfig +++ b/arch/arc/configs/haps_hs_smp_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/hsdk_defconfig b/arch/arc/configs/hsdk_defconfig index 7b8f8faf8a24315d3379d189cab69506539e04a8..762b1fcd93dc1c3a503de3776833de726b05bc8b 100644 --- a/arch/arc/configs/hsdk_defconfig +++ b/arch/arc/configs/hsdk_defconfig @@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/nsim_700_defconfig b/arch/arc/configs/nsim_700_defconfig index 6dff83a238b8591ba08f889e7d7013734ff587db..b1a78222699c69f10342d96c2c112e37ef9a2640 100644 --- a/arch/arc/configs/nsim_700_defconfig +++ b/arch/arc/configs/nsim_700_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsim_hs_defconfig b/arch/arc/configs/nsim_hs_defconfig index 31ee51b987e7c5b97c2f044794f9d1c5b4eea73e..217d7ea3c9569078bc539cd45927b41fcbe2b3a2 100644 --- a/arch/arc/configs/nsim_hs_defconfig +++ b/arch/arc/configs/nsim_hs_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsim_hs_smp_defconfig b/arch/arc/configs/nsim_hs_smp_defconfig index 8d3b1f67cae421c423e55c2622b5a78ea3d67794..e733e4f1a3208f4310a77ec44dde042a239a821a 100644 --- a/arch/arc/configs/nsim_hs_smp_defconfig +++ b/arch/arc/configs/nsim_hs_smp_defconfig @@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsimosci_defconfig b/arch/arc/configs/nsimosci_defconfig index 6168ce2ac2efdd869705a8a75e78f7f9b9c55af4..14377b8234f79baa62a5145fe0ba9d40af1bca1f 100644 --- a/arch/arc/configs/nsimosci_defconfig +++ b/arch/arc/configs/nsimosci_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsimosci_hs_defconfig b/arch/arc/configs/nsimosci_hs_defconfig index a70bdeb2b3fd03bdefd10388e69cd8e5b120ac0f..7e61c923a3cdd1227fdf2d391b479b67f566c57b 100644 --- a/arch/arc/configs/nsimosci_hs_defconfig +++ b/arch/arc/configs/nsimosci_hs_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig index ef96406c446e823d4706e5c84b6ac0626d4b5812..299fbe8003b28ed738c35bafa6863e13c7f745cb 100644 --- a/arch/arc/configs/nsimosci_hs_smp_defconfig +++ b/arch/arc/configs/nsimosci_hs_smp_defconfig @@ -9,7 +9,6 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/" CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set CONFIG_KPROBES=y diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 109baa06831cecc38cf1d9f11ba447a31c0c4b14..09ddddf71cc5049a570d11a5114ccec945df56ad 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -105,7 +105,7 @@ typedef pte_t * pgtable_t; #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) /* Default Permissions for stack/heaps pages (Non Executable) */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE) +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define WANT_PAGE_VIRTUAL 1 diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 08fe33830d4b17337757d548399c897aa240de36..77676e18da698b22aad76d609db662e7661fd50b 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -379,7 +379,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, /* Decode a PTE containing swap "identifier "into constituents */ #define __swp_type(pte_lookalike) (((pte_lookalike).val) & 0x1f) -#define __swp_offset(pte_lookalike) ((pte_lookalike).val << 13) +#define __swp_offset(pte_lookalike) ((pte_lookalike).val >> 13) /* NOPs, to keep generic kernel happy */ #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) diff --git a/arch/arc/plat-hsdk/Kconfig b/arch/arc/plat-hsdk/Kconfig index 19ab3cf98f0f34904b8431a6d4cf36642066c513..fcc9a9e27e9cb6696c333d93a9cda99a0ebfc5a8 100644 --- a/arch/arc/plat-hsdk/Kconfig +++ b/arch/arc/plat-hsdk/Kconfig @@ -7,5 +7,7 @@ menuconfig ARC_SOC_HSDK bool "ARC HS Development Kit SOC" + depends on ISA_ARCV2 + select ARC_HAS_ACCL_REGS select CLK_HSDK select RESET_HSDK diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi index 42ea246e71cb4e207d2e451da2df4d7ce465856f..fec1241b858ff96f316cd5988f3cbb8ba778fb62 100644 --- a/arch/arm/boot/dts/emev2.dtsi +++ b/arch/arm/boot/dts/emev2.dtsi @@ -31,13 +31,13 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; clock-frequency = <533000000>; }; - cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; @@ -57,6 +57,7 @@ compatible = "arm,cortex-a9-pmu"; interrupts = , ; + interrupt-affinity = <&cpu0>, <&cpu1>; }; clocks@e0110000 { diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 4ea5c5a16c57eed5235fc0f7365ce1a9d5e005f5..5fc24d4c2d5d4cbdc0dfce67440aefd5b5a4d8de 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -22,7 +22,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; @@ -30,7 +30,7 @@ power-domains = <&pd_a2sl>; next-level-cache = <&L2>; }; - cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; @@ -89,6 +89,7 @@ compatible = "arm,cortex-a9-pmu"; interrupts = , ; + interrupt-affinity = <&cpu0>, <&cpu1>; }; cmt1: timer@e6138000 { diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi index bd1a82e8fffee706d8f8030bb01c209fe23b8521..fe501d32d05925aee2e2aab9b0f7f9c05e87714c 100644 --- a/arch/arm/boot/dts/stih407-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi @@ -52,7 +52,7 @@ st,syscfg = <&syscfg_sbc>; reg = <0x0961f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09610000 0x6000>; @@ -376,7 +376,7 @@ st,syscfg = <&syscfg_front>; reg = <0x0920f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09200000 0x10000>; @@ -936,7 +936,7 @@ st,syscfg = <&syscfg_front>; reg = <0x0921f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09210000 0x10000>; @@ -969,7 +969,7 @@ st,syscfg = <&syscfg_rear>; reg = <0x0922f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09220000 0x6000>; @@ -1164,7 +1164,7 @@ st,syscfg = <&syscfg_flash>; reg = <0x0923f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09230000 0x3000>; diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig deleted file mode 120000 index 03b88505560a94d015f119e6e0c281bf4921186c..0000000000000000000000000000000000000000 --- a/arch/arm/configs/qcs405-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405-perf_defconfig \ No newline at end of file diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig deleted file mode 120000 index 372fd3e54d888c039678b077724b27f28e68fa29..0000000000000000000000000000000000000000 --- a/arch/arm/configs/qcs405_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405_defconfig \ No newline at end of file diff --git a/arch/arm/configs/vendor/qcs405-perf_defconfig b/arch/arm/configs/vendor/qcs405-perf_defconfig index 1de5a83d0f23149b596dc6de41288d1d11ca47af..66231a7ceddd81521a776082e4a6f413fb558eeb 100644 --- a/arch/arm/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm/configs/vendor/qcs405-perf_defconfig @@ -181,12 +181,10 @@ CONFIG_NET_CLS_ACT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_DEBUGFS is not set +CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y @@ -226,7 +224,7 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y -CONFIG_KS8851=y +CONFIG_AT803X_PHY=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -266,6 +264,7 @@ CONFIG_I2C_CHARDEV=y CONFIG_SPI=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y diff --git a/arch/arm/configs/vendor/qcs405_defconfig b/arch/arm/configs/vendor/qcs405_defconfig index d8a0f5407420ca9f19b6c6ed23bcf6c5a3392e29..1448d2995939c59d1abd3580c3d314906bc339f8 100644 --- a/arch/arm/configs/vendor/qcs405_defconfig +++ b/arch/arm/configs/vendor/qcs405_defconfig @@ -186,12 +186,10 @@ CONFIG_NET_CLS_ACT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_DEBUGFS is not set +CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y @@ -276,6 +274,7 @@ CONFIG_SPI_DEBUG=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index ff61ff4057d416b8b2b875a5212811631fb80066..62a973069bf6933a74e12b14ca247b513658a250 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -133,6 +133,7 @@ CONFIG_BRIDGE_EBT_SNAT=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_QRTR=y CONFIG_BT=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y @@ -257,8 +258,10 @@ CONFIG_STAGING=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y +CONFIG_GSI_REGISTER_VERSION_2=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y @@ -269,7 +272,9 @@ CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QTI_RPMH_API=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 7d08a7eae535f21ddc4aa777ac5174ef80f0d527..dd30efc0b96400c0cb83e1defd34615172e45ed2 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -133,6 +133,7 @@ CONFIG_BRIDGE_EBT_SNAT=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_QRTR=y CONFIG_CFG80211=y CONFIG_RFKILL=y CONFIG_DMA_CMA=y @@ -247,8 +248,10 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_GSI_REGISTER_VERSION_2=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y @@ -259,8 +262,10 @@ CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_MSM_BOOT_STATS=y +CONFIG_QTI_RPMH_API=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_STM=y diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8f973e3b7348e4aaac5bc15c9497d87e8d543790..65572e14306c877403a93860164b64204e58b064 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -302,4 +302,16 @@ static inline bool kvm_arm_harden_branch_predictor(void) return false; } +#define KVM_SSBD_UNKNOWN -1 +#define KVM_SSBD_FORCE_DISABLE 0 +#define KVM_SSBD_KERNEL 1 +#define KVM_SSBD_FORCE_ENABLE 2 +#define KVM_SSBD_MITIGATED 3 + +static inline int kvm_arm_have_ssbd(void) +{ + /* No way to detect it yet, pretend it is not there. */ + return KVM_SSBD_UNKNOWN; +} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 08cd720eae0110e354d7055b8a8841ffc81a7075..8a098e65f5f857bb35b64b70677dd0261ba9beeb 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -28,6 +28,13 @@ */ #define kern_hyp_va(kva) (kva) +/* Contrary to arm64, there is no need to generate a PC-relative address */ +#define hyp_symbol_addr(s) \ + ({ \ + typeof(s) *addr = &(s); \ + addr; \ + }) + /* * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation levels. */ @@ -247,6 +254,11 @@ static inline int kvm_map_vectors(void) return 0; } +static inline int hyp_map_aux_data(void) +{ + return 0; +} + #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 323a4df59a6c0ec6657b42b714b161a6d3729cca..ece2d1d43724b88c8bde71db75606677ca749731 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -718,7 +718,7 @@ static inline void emit_a32_arsh_r64(const u8 dst[], const u8 src[], bool dstk, } /* dst = dst >> src */ -static inline void emit_a32_lsr_r64(const u8 dst[], const u8 src[], bool dstk, +static inline void emit_a32_rsh_r64(const u8 dst[], const u8 src[], bool dstk, bool sstk, struct jit_ctx *ctx) { const u8 *tmp = bpf2a32[TMP_REG_1]; const u8 *tmp2 = bpf2a32[TMP_REG_2]; @@ -734,7 +734,7 @@ static inline void emit_a32_lsr_r64(const u8 dst[], const u8 src[], bool dstk, emit(ARM_LDR_I(rm, ARM_SP, STACK_VAR(dst_hi)), ctx); } - /* Do LSH operation */ + /* Do RSH operation */ emit(ARM_RSB_I(ARM_IP, rt, 32), ctx); emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_LSR, rt), ctx); @@ -784,7 +784,7 @@ static inline void emit_a32_lsh_i64(const u8 dst[], bool dstk, } /* dst = dst >> val */ -static inline void emit_a32_lsr_i64(const u8 dst[], bool dstk, +static inline void emit_a32_rsh_i64(const u8 dst[], bool dstk, const u32 val, struct jit_ctx *ctx) { const u8 *tmp = bpf2a32[TMP_REG_1]; const u8 *tmp2 = bpf2a32[TMP_REG_2]; @@ -1340,7 +1340,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) case BPF_ALU64 | BPF_RSH | BPF_K: if (unlikely(imm > 63)) return -EINVAL; - emit_a32_lsr_i64(dst, dstk, imm, ctx); + emit_a32_rsh_i64(dst, dstk, imm, ctx); break; /* dst = dst << src */ case BPF_ALU64 | BPF_LSH | BPF_X: @@ -1348,7 +1348,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* dst = dst >> src */ case BPF_ALU64 | BPF_RSH | BPF_X: - emit_a32_lsr_r64(dst, src, dstk, sstk, ctx); + emit_a32_rsh_r64(dst, src, dstk, sstk, ctx); break; /* dst = dst >> src (signed) */ case BPF_ALU64 | BPF_ARSH | BPF_X: diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 2987cc075111213b49b3a9b2947eda0163e772c7..2bf868632f9cdc62854ec9c9a591790d105f2f31 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -38,8 +38,8 @@ sm8150-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2. sm8150-rumi-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-qrd-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-qrd-dvt-overlay.dtbo-base := sm8150-v2.dtb sm8150p-v2.dtb -sa8155-adp-star-overlay.dtbo-base := sa8155.dtb -sa8155p-adp-star-overlay.dtbo-base := sa8155p.dtb +sa8155-adp-star-overlay.dtbo-base := sa8155.dtb sa8155-v2.dtb +sa8155p-adp-star-overlay.dtbo-base := sa8155p.dtb sa8155p-v2.dtb sm8150-sdx50m-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-mtp-2.5k-panel-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb @@ -51,6 +51,8 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-qrd.dtb \ sa8155-adp-star.dtb \ sa8155p-adp-star.dtb \ + sa8155-v2-adp-star.dtb \ + sa8155p-v2-adp-star.dtb \ sm8150-v2-rumi.dtb \ sm8150-v2-mtp.dtb \ sm8150-v2-cdp.dtb \ @@ -85,7 +87,10 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm6150p-qrd-overlay.dtbo \ sm6150p-idp-overlay.dtbo \ sm6150-external-codec-idp-overlay.dtbo \ - sm6150-usbc-idp-overlay.dtbo + sm6150-usbc-idp-overlay.dtbo \ + sm6150-cmd-mode-display-idp-overlay.dtbo \ + sa6155-adp-star-overlay.dtbo \ + sa6155p-adp-star-overlay.dtbo sm6150-rumi-overlay.dtbo-base := sm6150.dtb sm6150-qrd-overlay.dtbo-base := sm6150.dtb @@ -94,6 +99,9 @@ sm6150p-qrd-overlay.dtbo-base := sm6150p.dtb sm6150p-idp-overlay.dtbo-base := sm6150p.dtb sm6150-external-codec-idp-overlay.dtbo-base := sm6150.dtb sm6150-usbc-idp-overlay.dtbo-base := sm6150.dtb +sm6150-cmd-mode-display-idp-overlay.dtbo-base := sm6150.dtb +sa6155-adp-star-overlay.dtbo-base := sa6155.dtb +sa6155p-adp-star-overlay.dtbo-base := sa6155p.dtb else dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ sm6150-qrd.dtb \ @@ -101,7 +109,11 @@ dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ sm6150p-qrd.dtb \ sm6150p-idp.dtb \ sm6150-external-codec-idp.dtb \ - sm6150-usbc-idp.dtb + sm6150-usbc-idp.dtb \ + sm6150-cmd-mode-display-idp.dtb \ + sa6155-adp-star.dtb \ + sa6155p-adp-star.dtb + endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi index e065f002395fa3ac1fa67fd6c9f9915ad1acbd80..817b26fe1da26b35f952135e12f85b08c02336d8 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi @@ -43,6 +43,8 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; qcom,mdss-dsi-display-timings { timing@0 { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..97556699dadf09e2b14b5cafdcdd3937ecbf37c3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi @@ -0,0 +1,176 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_td4328_truly_cmd: qcom,mdss_dsi_td4328_truly_cmd { + qcom,mdss-dsi-panel-name = + "td4328 cmd mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 00 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E C7 C7 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 2B + 02 2B + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 50 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 29 01 00 00 00 00 02 B0 00 + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..12827c80a583c5a5c4d5c43a2733aec848ac82cf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi @@ -0,0 +1,172 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_td4328_truly_video: qcom,mdss_dsi_td4328_truly_video { + qcom,mdss-dsi-panel-name = + "td4328 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 31 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E DB DB 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 40 + 02 40 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 90 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi index 22a8d112a783b6ebc59f2c1810adc4d04d6feef7..83efb69d45836e7bda2a791a0e52404d313ded44 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -qcom,alium_860_89032_0000_3600mah_averaged_masterslave_jun15th2018 { - /* #Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Jun15th2018*/ +qcom,alium_860_89032_0000_3600mah_averaged_masterslave_aug6th2018 { + /* #Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Aug6th2018*/ qcom,max-voltage-uv = <4350000>; qcom,fastchg-current-ma = <5400>; qcom,jeita-fcc-ranges = <0 100 2500000 @@ -28,29 +28,29 @@ qcom,alium_860_89032_0000_3600mah_averaged_masterslave_jun15th2018 { qcom,battery-beta = <4250>; qcom,therm-room-temp = <100000>; qcom,fg-cc-cv-threshold-mv = <4340>; - qcom,battery-type = "alium_860_89032_0000_3600mah_jun15th2018"; + qcom,battery-type = "alium_860_89032_0000_3600mah_aug6th2018"; qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; qcom,therm-center-offset = <0x70>; qcom,therm-pull-up = <100>; qcom,rslow-normal-coeffs = <0xa4 0x01 0x24 0x13>; - qcom,rslow-low-coeffs = <0xa7 0xd5 0x0e 0x13>; - qcom,checksum = <0xCDFB>; - qcom,gui-version = "PM8150GUI - 1.0.0.7"; + qcom,rslow-low-coeffs = <0xa4 0x01 0x24 0x13>; + qcom,checksum = <0x99F7>; + qcom,gui-version = "PM855GUI - 1.0.0.10"; qcom,fg-profile-data = [ - 09 00 B5 EA - 3F CC 33 AA - E7 C2 00 00 - 13 BC 83 8A - 03 80 D1 92 - AB 9D 47 80 + 09 00 BD EA + 40 CC E8 BC + DD C3 00 00 + B0 C5 72 92 + F3 87 C8 A2 + E6 9C E2 87 18 00 A4 01 24 13 47 FD A9 F2 CE 07 - 32 00 A6 00 - EF F5 CB FD - 11 0D 4A 23 - 60 2A C1 23 - 6F 42 F8 43 + 32 00 0E E3 + 06 ED 2E EA + 83 FD 5B 14 + B8 1C 75 3A + 5C 42 CA 3A 40 00 3A 00 40 00 48 00 3B 00 34 00 diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi index 3f224c133e6599f707fa353fd4f2e9fd0dc9f7df..f6eafeea4ee20d73411936590b0c4f4d0296a0c9 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi @@ -23,6 +23,7 @@ qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; + qcom,disable-atos; #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -70,6 +71,7 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; + qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; #address-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi index ed019eac9d88e37dc6f4fc6c4380129f8c354ba6..ba808d0fbb4e032060dee6f4c5b57e41531169d1 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi @@ -23,7 +23,6 @@ qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -71,7 +70,6 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; @@ -321,6 +319,7 @@ <0x15182238 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1c00 0x400>; + qcom,opt-out-tbu-halting; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>; clock-names = "gcc_aggre_noc_pcie_tbu_clk"; @@ -343,7 +342,7 @@ reg = <0x151a5000 0x1000>, <0x15182240 0x8>; reg-names = "base", "status-reg"; - qcom,stream-id-range = <0x1c00 0x400>; + qcom,stream-id-range = <0x2000 0x400>; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; qcom,msm-bus,name = "mnoc_sf_0_tbu"; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index 688fac432a73378957c587e5071ad3d0d2ab56a2..b2c9ab8a43022ea901d1cd8a61dee467011a7e11 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -23,8 +23,8 @@ qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; qcom,disable-atos; + qcom,min-iova-align; #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -72,8 +72,8 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; qcom,disable-atos; + qcom,min-iova-align; #global-interrupts = <1>; #size-cells = <1>; #address-cells = <1>; @@ -323,6 +323,7 @@ <0x15182238 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1c00 0x400>; + qcom,opt-out-tbu-halting; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>; clock-names = "gcc_aggre_noc_pcie_tbu_clk"; @@ -345,7 +346,7 @@ reg = <0x151A5000 0x1000>, <0x15182240 0x8>; reg-names = "base", "status-reg"; - qcom,stream-id-range = <0x1c00 0x400>; + qcom,stream-id-range = <0x2000 0x400>; /* No GDSC */ qcom,msm-bus,name = "apps_smmu"; qcom,msm-bus,num-cases = <2>; @@ -385,6 +386,23 @@ }; &kgsl_smmu { - qcom,actlr = <0x0 0x407 0x303>; + qcom,actlr = + /* All CBs of GFX: +15 deep PF */ + <0x0 0x407 0x303>; +}; + +&apps_smmu { + qcom,actlr = + /* SIDs 0x1460 - 0x1463 of NPU: +3 deep PF */ + <0x1460 0x3 0x103>, + + /* SIDs 0x1464 - 0x1465 of NPU: +3 deep PF */ + <0x1464 0x1 0x103>, + + /* SIDs 0x2060 - 0x2063 of NPU: +3 deep PF */ + <0x2060 0x3 0x103>, + + /* SIDs 0x2064 - 0x2065 of NPU: +3 deep PF */ + <0x2064 0x1 0x103>; }; diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi index 361394d60d0a23b859e8316a2887a5bdf4861504..bf4e90043c635c9418f4933a6e225c47d3255fb9 100644 --- a/arch/arm64/boot/dts/qcom/pm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -91,7 +91,7 @@ vbat_sns { reg = ; - label = "vph_pwr"; + label = "vbat_sns"; qcom,pre-scaling = <1 3>; }; @@ -408,6 +408,8 @@ qcom,qg-iterm-ma = <100>; qcom,hold-soc-while-full; qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,pmic-revid = <&pm6150_revid>; io-channels = <&pm6150_vadc ADC_BAT_THERM_PU2>, <&pm6150_vadc ADC_BAT_ID_PU2>; @@ -430,9 +432,9 @@ "qg-good-ocv"; }; - qcom,qg-sdam@b500 { + qcom,qg-sdam@b600 { status = "okay"; - reg = <0xb500 0x100>; + reg = <0xb600 0x100>; }; }; @@ -474,7 +476,7 @@ clocks = <&clock_rpmh RPMH_CXO_CLK>; clock-names = "xo"; assigned-clocks = <&pm6150_clkdiv 1>; - assigned-clock-rates = <9600000>; + assigned-clock-rates = <19200000>; }; pm6150_gpios: pinctrl@c000 { diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi index 9b0ad6f380ed9a4354179819e2de78be9c076e69..94ee3ec63c7f7a8b03ce630d9cf8dbeaf371e330 100644 --- a/arch/arm64/boot/dts/qcom/pm8150b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi @@ -479,7 +479,7 @@ <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hap-sc-irq", "hap-play-irq"; qcom,actuator-type = "lra"; - qcom,vmax-mv = <3600>; + qcom,vmax-mv = <3400>; qcom,play-rate-us = <6667>; qcom,lra-resonance-sig-shape = "sine"; qcom,lra-auto-resonance-mode = "qwd"; @@ -488,38 +488,54 @@ wf_0 { /* CLICK */ qcom,effect-id = <0>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [3e 3e 3e]; qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [01 00 00 00]; + qcom,lra-auto-resonance-disable; }; wf_1 { /* DOUBLE CLICK */ qcom,effect-id = <1>; - qcom,wf-pattern = [7e 7e 02 02 02 02 7e 7e]; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e 02 02 02 02 02 02]; qcom,wf-play-rate-us = <7143>; + qcom,wf-repeat-count = <2>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; }; wf_2 { /* TICK */ qcom,effect-id = <2>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e]; qcom,wf-play-rate-us = <4000>; + qcom,lra-auto-resonance-disable; }; wf_3 { /* THUD */ qcom,effect-id = <3>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e 7e]; - qcom,wf-play-rate-us = <5714>; + qcom,wf-play-rate-us = <6667>; + qcom,lra-auto-resonance-disable; }; wf_4 { /* POP */ qcom,effect-id = <4>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e]; qcom,wf-play-rate-us = <5000>; + qcom,lra-auto-resonance-disable; }; wf_5 { /* HEAVY CLICK */ qcom,effect-id = <5>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e 7e]; qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [03 00 00 00]; + qcom,lra-auto-resonance-disable; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts index fc6b265c4dada301b6dcb17b14b30122960211fc..e40e24350d7c654978578d7d4d5e2b53720aded6 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "qcs403.dtsi" -#include "qcs405-nowcd-audio-overlay.dtsi" +#include "qcs405-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS403 RCM IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs403.dtsi b/arch/arm64/boot/dts/qcom/qcs403.dtsi index 0934e29939acaca5a0982205dfbe1cf23c7f7515..ddb57f3dd44dd708e5f66466d544ee6ab8777d0c 100644 --- a/arch/arm64/boot/dts/qcom/qcs403.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs403.dtsi @@ -20,8 +20,6 @@ }; &soc { - /delete-node/ qcom,msm-geni-ir; - /delete-node/ qcom,msm-cpufreq; msm_cpufreq: qcom,msm-cpufreq { diff --git a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi index bd0c17f9acb6dbfe56b1b9c1411686ee3e19d2f1..2a9453224eb0b4eecc5bf5408b94660b8b6f6f55 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi @@ -60,6 +60,7 @@ qcom,mi2s-audio-intf = <1>; qcom,auxpcm-audio-intf = <1>; qcom,spdif-audio-intf = <1>; + qcom,wcn-btfm = <1>; qcom,msm-mi2s-master = <1>, <0>, <1>, <1>, <1>; qcom,ep92-name = "ep92.3-0064"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi index e32a117768da1554e664e141427ff068c994be47..1ad579c963cb396eb7f51e9258704f54578e3025 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi @@ -30,6 +30,7 @@ qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,audio-routing = + "RX_BIAS", "MCLK", "AMIC3", "MIC BIAS3", "AMIC4", "MIC BIAS4", "MIC BIAS3", "Analog Mic3", diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi index 9138ebf733e7c3d0a24ab9be9b1bc3a36cb07806..76b39a57b791b2c07752b720db1f5c944ee989e0 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi @@ -33,6 +33,7 @@ qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,audio-routing = + "RX_BIAS", "MCLK", "AMIC3", "MIC BIAS3", "AMIC4", "MIC BIAS4", "MIC BIAS3", "Analog Mic3", diff --git a/include/dt-bindings/clock/qcom,cpucc-sm6150.h b/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi similarity index 50% rename from include/dt-bindings/clock/qcom,cpucc-sm6150.h rename to arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi index 2a60ef821775cd94836656452ed92cb6bca6cfd5..95bbcd2ee7936c859d563af33bef699c27f0decf 100644 --- a/include/dt-bindings/clock/qcom,cpucc-sm6150.h +++ b/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi @@ -11,22 +11,25 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_CPU_CC_SM6150_H -#define _DT_BINDINGS_CLK_QCOM_CPU_CC_SM6150_H +#include "qcs405-pinctrl.dtsi" -#define PWRCL_CLK 0 -#define PERFCL_CLK 1 -#define L3_CLK 2 -#define L3_CLUSTER0_VOTE_CLK 3 -#define L3_CLUSTER1_VOTE_CLK 4 -#define CPU0_PWRCL_CLK 5 -#define CPU1_PWRCL_CLK 6 -#define CPU2_PWRCL_CLK 7 -#define CPU3_PWRCL_CLK 8 -#define CPU4_PWRCL_CLK 9 -#define CPU5_PWRCL_CLK 10 -#define CPU6_PERFCL_CLK 11 -#define CPU7_PERFCL_CLK 12 -#define L3_MISC_VOTE_CLK 13 +&soc { + qcom,msm-geni-ir@740000 { + compatible = "qcom,msm-geni-ir"; + reg-names = "base"; + reg = <0x740000 0x1000>; -#endif + interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "geni-ir-core-irq"; + + clocks = <&clock_gcc GCC_GENI_IR_H_CLK>, + <&clock_gcc GCC_GENI_IR_S_CLK>; + clock-names = "iface_clk", "serial_clk"; + + pinctrl-names = "default"; + pinctrl-0 = <&ir_in_default>; + + resets = <&clock_gcc GCC_GENI_IR_BCR>; + reset-names = "geni_reset"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts index 1ff864c6fea74c7535d95b9c4f24aa2ec0bb1b1a..2f034a8360f8cc9ea7e917459342c622e667b27c 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 SPI IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts index 01426fac70786858f25e2cdfb14019148a366f36..9ec18758df4dd289c25e4bad9b9310330a275716 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts @@ -14,7 +14,8 @@ /dts-v1/; #include "qcs405.dtsi" -#include "qcs405-nowcd-audio-overlay.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" #include "qcs405-pinctrl.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts index 41e7bb1d2457e5fa51eb59d1ac9bfae77c6320e5..bbfce94ca0d88eb357268c2ee9aa7dbd342bad22 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 DSI IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts index 2cb3dbb03341ce90651b627e6cd32ca9eb1798a1..695e0500101dd6e7e8c92bf1d1833880eda290b6 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 RGB IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts index a7e4149f43736691ebb20430ec2ceb07aeb0bc4a..edd9d4d86dd0aa7a8f678ffeaa952685c23d61ba 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-csra1-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 CSRA1 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts index b3b723b422b8beb6e882997335172725c5e6d682..ceac14d652d365a7bd5e653cd897b4dfc3eb56f5 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-csra6-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 CSRA6 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts index ea43b030be69d0e4099bc5570a69ce26a0c1828b..ef26d1ae76d7fb7bd18a9eacdbfde15aaa509924 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-amic-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 AMIC IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi b/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..332e805923a926c9595f4c228d9a73aa41568654 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&i2c_2 { + status = "ok"; + qcom,clk-freq-out = <100000>; + + /* PCA9956B LED Drivers */ + nxp-ledseg-i2c@65 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x65>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + out0@0 { + label = "ledsec5_b"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec5_g"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec5_r"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec6_b"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec6_g"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec6_r"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec7_b"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec7_g"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec7_r"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec8_b"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec8_g"; + reg = <0xA>; + }; + out11@11 { + label = "ledsec8_r"; + reg = <0xB>; + }; + out12@12 { + label = "ledsec1_b"; + reg = <0xC>; + }; + out13@13 { + label = "ledsec1_g"; + reg = <0xD>; + }; + out14@14 { + label = "ledsec1_r"; + reg = <0xE>; + }; + out15@15 { + label = "ledsec2_b"; + reg = <0xF>; + }; + out16@16 { + label = "ledsec2_g"; + reg = <0x10>; + }; + out17@17 { + label = "ledsec2_r"; + reg = <0x11>; + }; + out18@18 { + label = "ledsec3_b"; + reg = <0x12>; + }; + out19@19 { + label = "ledsec3_g"; + reg = <0x13>; + }; + out20@20 { + label = "ledsec3_r"; + reg = <0x14>; + }; + out21@21 { + label = "ledsec4_b"; + reg = <0x15>; + }; + out22@22 { + label = "ledsec4_g"; + reg = <0x16>; + }; + out23@23 { + label = "ledsec4_r"; + reg = <0x17>; + }; + }; + + nxp-ledseg-i2c@69 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x69>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + out0@0 { + label = "ledsec9_b"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec9_g"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec9_r"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec10_b"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec10_g"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec10_r"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec11_b"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec11_g"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec11_r"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec12_b"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec12_g"; + reg = <0xA>; + }; + out11@11 { + label = "ledsec12_r"; + reg = <0xB>; + }; + out12@12 { + label = "ledsec13_b"; + reg = <0xC>; + }; + out13@13 { + label = "ledsec13_g"; + reg = <0xD>; + }; + out14@14 { + label = "ledsec13_r"; + reg = <0xE>; + }; + out15@15 { + label = "ledsec14_b"; + reg = <0xF>; + }; + out16@16 { + label = "ledsec14_g"; + reg = <0x10>; + }; + out17@17 { + label = "ledsec14_r"; + reg = <0x11>; + }; + out18@18 { + label = "ledsec15_b"; + reg = <0x12>; + }; + out19@19 { + label = "ledsec15_g"; + reg = <0x13>; + }; + out20@20 { + label = "ledsec15_r"; + reg = <0x14>; + }; + out21@21 { + label = "ledsec16_b"; + reg = <0x15>; + }; + out22@22 { + label = "ledsec16_g"; + reg = <0x16>; + }; + out23@23 { + label = "ledsec16_r"; + reg = <0x17>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi index 5cc5c5e532a2d8b071f308c236da1da6f6080a51..cd961550d9808ccd24318a629a9fe599b634d341 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi @@ -1160,6 +1160,21 @@ }; }; }; + + pca9956b_reset_gpio: pca9956b_reset_gpio { + mux { + pins = "gpio95"; + function = "gpio"; + }; + + config { + pins = "gpio95"; + drive-strength = <2>; + bias-pull-up; + output-high; + }; + }; + sec_mi2s_sck { sec_mi2s_sck_sleep: sec_mi2s_sck_sleep { mux { diff --git a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi index 89b2374a45d26558dd0bc1f4779fb69c495c902e..ca736f3c65dd0eabc8dfe94e3c9da341c83b2d35 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi @@ -62,8 +62,7 @@ mx_cdev: mx-cdev-lvl { compatible = "qcom,regulator-cooling-device"; regulator-cdev-supply = <&pms405_s1_level>; - regulator-levels = - ; #cooling-cells = <2>; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi index b1d41ae2355b0c8f1b2e8d9ab522c716362b524c..1a6ca3013bd61c2fe760f8616b7c28d8d1510bd1 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi @@ -33,6 +33,7 @@ qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,audio-routing = + "RX_BIAS", "MCLK", "AMIC3", "MIC BIAS3", "AMIC4", "MIC BIAS4", "MIC BIAS3", "Analog Mic3", diff --git a/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi index 7f08ec94ef83db4d363c747819aa8838c77ab514..cbcfc52bea807e069ede2042cd17fa3233e5d20e 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi @@ -33,7 +33,7 @@ <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, <8 SPKR_R_VI 0x3>; qcom,swr-num-dev = <2>; - + qcom,swr_master_id = <1>; wsa881x_0211: wsa881x@20170211 { compatible = "qcom,wsa881x"; reg = <0x0 0x20170211>; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 77f460faa5a78bcffde2734c272334149fb0b474..73dc28b6e96a48bdbe2524b1add691c62d4d44b6 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -88,6 +88,14 @@ size = <0 0x7000000>; }; + mdf_mem: mdf_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + qseecom_mem: qseecom_region { compatible = "shared-dma-pool"; reusable; @@ -279,6 +287,11 @@ reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + qcom,mpm2-sleep-counter@4a3000 { compatible = "qcom,mpm2-sleep-counter"; reg = <0x4a3000 0x1000>; @@ -732,6 +745,37 @@ }; }; + qcom,msm-mdf-mem { + compatible = "qcom,msm-mdf-mem-region"; + qcom,msm-mdf-mem-data-size = <0x200000>; + memory-region = <&mdf_mem>; + }; + + qcom,msm-mdf { + compatible = "qcom,msm-mdf"; + + qcom,msm_mdf_cb1 { + compatible = "qcom,msm-mdf-cb"; + label = "adsp"; + qcom,smmu-enabled; + }; + + qcom,msm_mdf_cb2 { + compatible = "qcom,msm-mdf-cb"; + label = "dsps"; + }; + + qcom,msm_mdf_cb3 { + compatible = "qcom,msm-mdf-cb"; + label = "modem"; + }; + + qcom,msm_mdf_cb4 { + compatible = "qcom,msm-mdf-cb"; + label = "cdsp"; + }; + }; + rpm-glink { compatible = "qcom,glink-rpm"; interrupts = ; @@ -1402,23 +1446,29 @@ extcon = <&usb3_extcon>; }; -&soc { - qcom,msm-geni-ir@740000 { - compatible = "qcom,msm-geni-ir"; - reg-names = "base"; - reg = <0x740000 0x1000>; - - interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "geni-ir-core-irq"; - - clocks = <&clock_gcc GCC_GENI_IR_H_CLK>, - <&clock_gcc GCC_GENI_IR_S_CLK>; - clock-names = "iface_clk", "serial_clk"; - - pinctrl-names = "default"; - pinctrl-0 = <&ir_in_default>; +#include "qcs405-led-pca9956.dtsi" - resets = <&clock_gcc GCC_GENI_IR_BCR>; - reset-names = "geni_reset"; +&soc { + i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b6000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 96 0>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_2_active &pca9956b_reset_gpio>; + pinctrl-1 = <&i2c_2_sleep>; + status = "ok"; }; }; diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3b1801077f762acfea17539d2eab2ecb8247c3b5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi @@ -0,0 +1,1040 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,mlp356477_2800mah { + /* mlp356477_2800mah_averaged_MasterSlave_Mar13th2018 */ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <4200>; + qcom,batt-id-kohm = <82>; + qcom,battery-beta = <4250>; + qcom,battery-therm-kohm = <100>; + qcom,battery-type = + "mlp356477_2800mah_averaged_MasterSlave_Mar13th2018"; + qcom,qg-batt-profile-ver = <100>; + + qcom,jeita-fcc-ranges = <0 150 560000 + 151 450 4200000 + 451 550 2380000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + + /* COOL = 15 DegC, WARM = 45 DegC */ + qcom,jeita-soft-thresholds = <0x4621 0x20b8>; + /* COLD = 0 DegC, HOT = 55 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x181d>; + + qcom,fcc1-temp-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-data = <2715 2788 2861 2898 2908>; + }; + + qcom,fcc2-temp-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-data = <2864 2846 2860 2868 2865 2865>; + }; + + qcom,pc-temp-v1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <43494 43682 43812 43865 43879>, + <43243 43420 43582 43645 43659>, + <42984 43174 43350 43418 43434>, + <42737 42940 43115 43191 43208>, + <42506 42710 42878 42958 42978>, + <42287 42479 42641 42722 42746>, + <42087 42250 42407 42489 42514>, + <41903 42027 42175 42255 42281>, + <41709 41807 41948 42023 42050>, + <41489 41592 41723 41794 41822>, + <41265 41381 41502 41568 41596>, + <41069 41176 41286 41348 41374>, + <40898 40982 41074 41131 41155>, + <40720 40799 40871 40921 40942>, + <40501 40613 40673 40716 40735>, + <40269 40405 40482 40518 40534>, + <40088 40193 40295 40329 40343>, + <39955 40022 40116 40148 40162>, + <39834 39894 39952 39975 39988>, + <39708 39765 39807 39818 39827>, + <39583 39577 39645 39659 39667>, + <39447 39345 39420 39461 39475>, + <39277 39148 39173 39221 39239>, + <39089 38991 38991 39014 39028>, + <38930 38860 38851 38860 38868>, + <38794 38758 38733 38728 38732>, + <38683 38676 38628 38611 38612>, + <38607 38602 38535 38507 38505>, + <38548 38529 38451 38414 38409>, + <38501 38462 38373 38327 38317>, + <38466 38407 38305 38251 38234>, + <38437 38360 38245 38182 38160>, + <38405 38317 38193 38121 38092>, + <38366 38277 38147 38067 38030>, + <38329 38240 38109 38022 37980>, + <38300 38203 38069 37977 37929>, + <38273 38170 38027 37921 37863>, + <38236 38130 37980 37857 37784>, + <38162 38057 37912 37781 37700>, + <38062 37946 37816 37690 37609>, + <37947 37830 37704 37585 37507>, + <37801 37713 37578 37463 37382>, + <37644 37575 37436 37322 37239>, + <37473 37394 37270 37162 37082>, + <37320 37251 37129 37032 36959>, + <37220 37161 37058 36960 36899>, + <37185 37129 37033 36942 36880>, + <37156 37103 37014 36927 36865>, + <37120 37070 36988 36902 36835>, + <37014 36957 36885 36755 36652>, + <36682 36593 36544 36398 36287>, + <36204 36109 36077 35921 35807>, + <35597 35486 35476 35307 35181>, + <34771 34630 34656 34460 34321>, + <33460 33262 33379 33128 32955>, + <30000 30000 30000 30000 30000>; + }; + + qcom,pc-temp-v2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <43865 43850 43830 43805 43740 43725>, + <43432 43429 43514 43528 43481 43467>, + <43037 43064 43219 43264 43228 43216>, + <42685 42767 42948 43012 42983 42973>, + <42369 42526 42700 42773 42744 42738>, + <42075 42296 42458 42537 42509 42505>, + <41776 42059 42213 42303 42277 42272>, + <41517 41822 41972 42071 42047 42041>, + <41353 41571 41739 41843 41820 41814>, + <41239 41298 41515 41619 41595 41589>, + <41095 41069 41297 41398 41374 41368>, + <40895 40928 41088 41181 41158 41151>, + <40650 40808 40884 40967 40946 40938>, + <40329 40611 40677 40763 40742 40734>, + <39941 40284 40461 40566 40541 40534>, + <39654 39989 40259 40373 40348 40342>, + <39456 39811 40087 40180 40164 40158>, + <39278 39662 39920 39993 39985 39980>, + <39086 39459 39722 39821 39814 39808>, + <38900 39184 39492 39664 39651 39646>, + <38740 38924 39264 39483 39469 39466>, + <38598 38721 39048 39237 39230 39230>, + <38480 38546 38846 38982 38986 38989>, + <38386 38403 38678 38799 38809 38813>, + <38308 38282 38535 38654 38669 38674>, + <38240 38189 38406 38530 38547 38552>, + <38182 38125 38286 38419 38438 38442>, + <38127 38075 38179 38320 38341 38343>, + <38076 38030 38090 38229 38250 38250>, + <38028 37992 38012 38144 38166 38164>, + <37978 37955 37949 38066 38089 38086>, + <37927 37916 37900 37993 38019 38016>, + <37875 37875 37857 37925 37953 37949>, + <37820 37832 37817 37860 37884 37875>, + <37763 37788 37781 37801 37812 37795>, + <37699 37738 37740 37738 37728 37702>, + <37630 37680 37688 37671 37625 37587>, + <37555 37613 37625 37600 37519 37469>, + <37475 37537 37552 37525 37430 37374>, + <37392 37448 37465 37446 37352 37292>, + <37308 37349 37363 37353 37263 37200>, + <37222 37237 37238 37238 37151 37088>, + <37133 37114 37101 37106 37022 36960>, + <37035 36989 36957 36952 36870 36813>, + <36935 36875 36859 36862 36807 36758>, + <36817 36792 36792 36828 36785 36734>, + <36752 36754 36762 36812 36769 36719>, + <36667 36707 36710 36780 36736 36687>, + <36541 36633 36613 36721 36656 36581>, + <36342 36472 36411 36517 36379 36276>, + <36024 36149 36031 36113 35946 35829>, + <35575 35650 35485 35584 35386 35258>, + <34953 34964 34771 34884 34643 34500>, + <34073 34007 33739 33902 33598 33440>, + <32647 32474 32144 32393 32025 31829>, + <30018 28051 26513 28737 27554 26991>; + }; + + qcom,pc-temp-z1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <14442 13243 12339 11979 11839>, + <14411 13218 12328 11916 11773>, + <14392 13199 12294 11893 11756>, + <14384 13180 12273 11879 11745>, + <14381 13174 12263 11870 11738>, + <14377 13179 12257 11863 11735>, + <14369 13182 12253 11858 11731>, + <14358 13175 12250 11851 11726>, + <14349 13158 12248 11847 11722>, + <14339 13146 12242 11845 11720>, + <14332 13143 12237 11845 11719>, + <14327 13144 12237 11844 11718>, + <14321 13142 12238 11840 11716>, + <14313 13135 12234 11837 11715>, + <14306 13128 12222 11835 11714>, + <14299 13120 12215 11834 11714>, + <14293 13113 12211 11833 11713>, + <14293 13111 12203 11830 11714>, + <14297 13119 12202 11828 11715>, + <14304 13129 12210 11831 11716>, + <14312 13133 12215 11837 11718>, + <14318 13130 12221 11841 11721>, + <14319 13125 12230 11843 11726>, + <14320 13135 12234 11846 11730>, + <14324 13151 12236 11852 11734>, + <14340 13158 12238 11860 11737>, + <14358 13165 12247 11865 11741>, + <14373 13167 12258 11870 11747>, + <14389 13165 12260 11873 11752>, + <14394 13167 12258 11877 11757>, + <14373 13169 12256 11880 11760>, + <14334 13168 12253 11886 11764>, + <14321 13167 12247 11892 11768>, + <14348 13170 12248 11897 11772>, + <14378 13177 12260 11901 11778>, + <14371 13182 12271 11905 11783>, + <14343 13188 12277 11910 11788>, + <14331 13194 12283 11917 11792>, + <14346 13205 12290 11924 11797>, + <14369 13219 12300 11931 11803>, + <14389 13228 12307 11937 11809>, + <14412 13237 12311 11941 11815>, + <14410 13245 12315 11945 11820>, + <14367 13259 12315 11949 11823>, + <14429 13239 12311 11954 11824>, + <14440 13243 12333 11959 11830>, + <14452 13241 12320 11961 11828>, + <14443 13243 12329 11964 11831>, + <14484 13241 12332 11968 11836>, + <14448 13263 12343 11977 11845>, + <14473 13293 12346 11988 11856>, + <14501 13300 12357 12000 11864>, + <14521 13333 12374 12015 11879>, + <14603 13373 12420 12034 11897>, + <14603 13373 12420 12034 11897>, + <14603 13373 12420 12034 11897>; + }; + + qcom,pc-temp-z2-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <9070 11213 10264 10349 10299>, + <9403 10211 10276 10386 10313>, + <9826 10116 10342 10430 10322>, + <9983 10114 10362 10447 10350>, + <9978 10115 10368 10437 10342>, + <9967 10120 10372 10407 10282>, + <9846 10126 10371 10393 10237>, + <9534 10132 10368 10388 10217>, + <9372 10137 10365 10382 10206>, + <9574 10141 10365 10378 10208>, + <9873 10143 10365 10386 10216>, + <9940 10145 10357 10384 10231>, + <9908 10147 10346 10370 10273>, + <9890 10148 10344 10357 10310>, + <9864 10149 10352 10353 10325>, + <9749 10147 10354 10353 10336>, + <9714 10144 10347 10355 10342>, + <10069 10146 10343 10360 10343>, + <10530 10156 10344 10366 10344>, + <10637 10166 10343 10378 10353>, + <10631 10154 10344 10396 10363>, + <10605 10119 10374 10405 10360>, + <10392 10103 10415 10412 10326>, + <10061 10118 10414 10414 10294>, + <9958 10135 10371 10402 10266>, + <9962 10132 10339 10387 10241>, + <9968 10117 10335 10377 10241>, + <9971 10107 10337 10360 10253>, + <9975 10109 10342 10353 10270>, + <9977 10112 10351 10373 10299>, + <9855 10116 10359 10397 10330>, + <9628 10123 10362 10398 10343>, + <9563 10131 10365 10389 10349>, + <9597 10143 10370 10392 10366>, + <9647 10159 10379 10443 10415>, + <9714 10166 10389 10499 10464>, + <9809 10169 10397 10520 10486>, + <9844 10172 10405 10533 10511>, + <9756 10186 10432 10548 10531>, + <9631 10212 10505 10586 10563>, + <9541 10225 10551 10621 10587>, + <9445 10161 10538 10637 10540>, + <9378 10144 10527 10646 10468>, + <9335 10322 10539 10611 10495>, + <9269 13378 10554 10627 10491>, + <9218 14361 10475 10629 10534>, + <9220 14794 10469 10642 10588>, + <9212 15070 10496 10651 10586>, + <9188 13785 10469 10739 10647>, + <9170 13219 10622 10694 10458>, + <9151 12652 10655 10557 10325>, + <9135 12236 10610 10495 10272>, + <9116 11644 10496 10432 10195>, + <9081 11027 10456 10300 10139>, + <9081 11027 10456 10300 10139>, + <9081 11027 10456 10300 10139>; + }; + + qcom,pc-temp-z3-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <19308 19258 19367 19369 19345>, + <19567 19611 19463 19395 19370>, + <19850 19705 19512 19411 19381>, + <19967 19740 19520 19416 19385>, + <19987 19749 19515 19414 19384>, + <19996 19735 19507 19405 19379>, + <19860 19713 19499 19400 19373>, + <19484 19698 19492 19395 19369>, + <19288 19687 19483 19391 19365>, + <19508 19679 19473 19388 19362>, + <19829 19673 19467 19382 19358>, + <19858 19667 19463 19378 19357>, + <19678 19660 19461 19372 19355>, + <19567 19648 19461 19369 19353>, + <19627 19641 19463 19369 19353>, + <19647 19646 19465 19368 19355>, + <19577 19654 19458 19367 19355>, + <19415 19653 19447 19366 19345>, + <19268 19631 19443 19365 19337>, + <19258 19613 19443 19365 19337>, + <19258 19623 19446 19366 19337>, + <19260 19652 19459 19374 19342>, + <19450 19665 19480 19393 19364>, + <19797 19666 19494 19403 19379>, + <19919 19667 19506 19402 19379>, + <19924 19671 19511 19400 19378>, + <19927 19681 19507 19400 19374>, + <19922 19686 19499 19400 19366>, + <19906 19684 19492 19399 19360>, + <19891 19680 19487 19397 19359>, + <19798 19673 19482 19393 19359>, + <19639 19661 19476 19390 19359>, + <19579 19650 19470 19386 19357>, + <19566 19644 19465 19382 19355>, + <19553 19639 19460 19380 19352>, + <19468 19636 19457 19378 19348>, + <19316 19630 19455 19375 19346>, + <19261 19624 19453 19373 19344>, + <19262 19618 19450 19371 19343>, + <19263 19609 19443 19369 19345>, + <19264 19576 19437 19368 19347>, + <19267 19367 19435 19368 19350>, + <19269 19261 19432 19367 19353>, + <19270 19260 19421 19365 19353>, + <19274 19257 19413 19361 19354>, + <19278 19257 19368 19354 19332>, + <19278 19257 19367 19346 19332>, + <19279 19257 19362 19331 19323>, + <19282 19257 19368 19326 19327>, + <19284 19257 19354 19338 19350>, + <19287 19257 19361 19346 19348>, + <19290 19257 19368 19356 19347>, + <19295 19257 19370 19353 19356>, + <19308 19258 19392 19382 19373>, + <19308 19258 19392 19382 19373>, + <19308 19258 19392 19382 19373>; + }; + + qcom,pc-temp-z4-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <16598 15992 15337 14972 14879>, + <16815 16035 15386 15059 14940>, + <16561 15923 15277 14982 14899>, + <16283 15657 15173 14901 14842>, + <15982 15436 15082 14879 14824>, + <15774 15304 15020 14868 14816>, + <15800 15207 14988 14856 14809>, + <15941 15154 14966 14843 14802>, + <16005 15119 14946 14830 14794>, + <15750 15094 14928 14818 14785>, + <15383 15076 14912 14807 14775>, + <15316 15063 14897 14797 14766>, + <15433 15048 14884 14788 14757>, + <15501 15033 14874 14778 14748>, + <15463 15025 14866 14769 14737>, + <15509 15037 14860 14760 14725>, + <15596 15057 14852 14751 14718>, + <15677 15056 14841 14742 14715>, + <15729 15002 14835 14738 14712>, + <15708 14951 14832 14736 14709>, + <15684 15017 14833 14735 14707>, + <15650 15207 14923 14756 14718>, + <15508 15302 15068 14837 14777>, + <15298 15313 15091 14879 14814>, + <15235 15319 15040 14870 14809>, + <15282 15294 14989 14855 14800>, + <15330 15200 14962 14841 14793>, + <15320 15131 14943 14826 14787>, + <15270 15105 14932 14814 14780>, + <15232 15088 14926 14805 14771>, + <15276 15076 14923 14798 14761>, + <15373 15065 14921 14794 14754>, + <15397 15057 14920 14791 14747>, + <15385 15051 14919 14789 14742>, + <15376 15043 14916 14787 14738>, + <15430 15036 14914 14786 14736>, + <15544 15016 14915 14794 14745>, + <15577 14998 14918 14811 14767>, + <15550 14991 14917 14816 14774>, + <15520 14987 14909 14811 14768>, + <15502 14998 14896 14803 14760>, + <15491 15139 14873 14788 14752>, + <15475 15211 14850 14774 14747>, + <15445 15195 14842 14774 14750>, + <15345 15130 14813 14764 14741>, + <15318 15079 14802 14736 14721>, + <15308 15066 14777 14720 14700>, + <15301 15057 14757 14705 14684>, + <15285 15045 14739 14698 14668>, + <15274 15053 14775 14717 14688>, + <15294 15076 14782 14719 14696>, + <15311 15080 14778 14712 14701>, + <15326 15091 14779 14719 14701>, + <15354 15108 14768 14706 14703>, + <15354 15108 14768 14706 14703>, + <15354 15108 14768 14706 14703>; + }; + + qcom,pc-temp-z5-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <10764 10957 12110 13794 13670>, + <11745 12925 13686 14768 14977>, + <12716 14010 14746 16056 16445>, + <13404 14718 15521 16744 17361>, + <13905 15321 16180 16789 17415>, + <14200 15933 16545 16568 17166>, + <13611 16455 16653 16420 16940>, + <11869 16730 16710 16364 16838>, + <10978 16895 16699 16401 16763>, + <12521 17062 16594 16402 16659>, + <14783 17315 16549 16292 16587>, + <15011 17507 16656 16178 16634>, + <13819 17490 16845 16003 16770>, + <13134 17527 17100 15977 16943>, + <13823 17638 17538 16159 17435>, + <14192 17626 17786 16425 18421>, + <13660 17482 17557 16723 18632>, + <12194 17384 17254 17131 17493>, + <10877 17447 17366 17305 16542>, + <10795 17704 18253 17609 16717>, + <10808 18910 18937 18108 17070>, + <10857 21136 18167 17900 17037>, + <13850 21892 16713 16569 16529>, + <19285 19957 16394 15708 16174>, + <21102 17736 16736 15560 16006>, + <20977 17560 17186 15557 15832>, + <20752 18050 17734 15845 15773>, + <20272 18693 18431 16567 15708>, + <19413 19705 19132 17289 15707>, + <18772 20743 19927 17959 16182>, + <17386 21034 20581 18611 16967>, + <15327 21059 21018 19179 17620>, + <14631 21034 21355 19699 18403>, + <14512 21133 21507 20256 19056>, + <14338 21373 21604 21000 19675>, + <13329 21460 21643 21494 20064>, + <11563 21322 21601 20994 19488>, + <10927 21163 21493 19730 18023>, + <10937 21134 21270 19156 17559>, + <10948 21040 20651 18991 17865>, + <10942 20318 20135 18929 18319>, + <10912 14582 19994 18903 18925>, + <10885 11608 19761 18788 19444>, + <10861 11587 18126 17802 18686>, + <10871 11314 17978 17266 18426>, + <10857 11130 15054 17271 15914>, + <10841 11088 15214 17078 16658>, + <10831 11067 15184 16484 17071>, + <10841 11046 15966 16365 19357>, + <10877 11142 14378 15551 19427>, + <10922 11156 14140 15626 17699>, + <10887 11109 14272 16679 16814>, + <10848 11069 14202 15606 17668>, + <10790 10995 15166 19180 19716>, + <10790 10995 15166 19180 19716>, + <10790 10995 15166 19180 19716>; + }; + + qcom,pc-temp-z6-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <17029 15901 15123 14807 14723>, + <17156 16022 15165 14844 14750>, + <17081 15990 15131 14815 14734>, + <16977 15851 15090 14780 14711>, + <16818 15720 15039 14766 14700>, + <16645 15630 15000 14756 14693>, + <16486 15560 14978 14746 14686>, + <16331 15519 14962 14737 14680>, + <16255 15490 14945 14728 14674>, + <16244 15468 14929 14720 14668>, + <16238 15452 14916 14712 14662>, + <16217 15438 14905 14704 14656>, + <16172 15422 14897 14697 14651>, + <16139 15401 14891 14691 14646>, + <16146 15390 14887 14686 14642>, + <16166 15395 14883 14681 14638>, + <16163 15403 14876 14677 14633>, + <16120 15402 14866 14672 14627>, + <16076 15372 14862 14670 14622>, + <16063 15345 14862 14670 14621>, + <16057 15380 14865 14671 14621>, + <16055 15480 14915 14684 14629>, + <16092 15533 14991 14732 14668>, + <16168 15543 15006 14757 14692>, + <16218 15549 14992 14753 14691>, + <16251 15541 14976 14746 14687>, + <16270 15511 14964 14741 14683>, + <16266 15488 14954 14735 14676>, + <16246 15479 14948 14730 14671>, + <16227 15473 14944 14726 14666>, + <16204 15467 14942 14722 14662>, + <16176 15459 14941 14719 14659>, + <16164 15454 14939 14716 14657>, + <16159 15453 14938 14715 14654>, + <16154 15453 14937 14714 14651>, + <16145 15453 14936 14714 14649>, + <16133 15450 14939 14717 14652>, + <16130 15447 14943 14725 14662>, + <16133 15449 14943 14727 14665>, + <16139 15454 14940 14725 14664>, + <16147 15454 14936 14723 14663>, + <16161 15429 14929 14718 14662>, + <16171 15417 14922 14712 14662>, + <16178 15424 14918 14713 14664>, + <16162 15408 14909 14708 14663>, + <16165 15399 14883 14694 14643>, + <16168 15398 14875 14684 14633>, + <16172 15401 14867 14670 14622>, + <16179 15405 14866 14665 14618>, + <16193 15425 14881 14682 14641>, + <16228 15451 14892 14690 14645>, + <16262 15468 14902 14695 14650>, + <16300 15497 14912 14700 14657>, + <16361 15535 14930 14716 14672>, + <16361 15535 14930 14716 14672>, + <16361 15535 14930 14716 14672>; + }; + + qcom,pc-temp-y1-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7929 6704 6050 5566 5322 5235>, + <8028 6701 6050 5560 5320 5234>, + <8101 6693 6051 5554 5318 5233>, + <8151 6684 6051 5548 5316 5231>, + <8179 6676 6052 5543 5313 5230>, + <8186 6673 6053 5540 5311 5228>, + <8157 6667 6054 5539 5308 5225>, + <8120 6659 6054 5538 5305 5222>, + <8110 6663 6055 5536 5302 5222>, + <8104 6693 6056 5529 5299 5222>, + <8099 6717 6055 5525 5298 5222>, + <8120 6716 6050 5525 5297 5220>, + <8146 6707 6044 5526 5296 5217>, + <8147 6706 6044 5528 5295 5216>, + <8147 6707 6049 5533 5293 5217>, + <8146 6709 6052 5536 5291 5217>, + <8135 6705 6053 5534 5290 5219>, + <8119 6699 6055 5532 5288 5221>, + <8100 6700 6057 5532 5289 5221>, + <8079 6708 6062 5531 5290 5220>, + <8070 6715 6065 5531 5292 5219>, + <8070 6712 6067 5532 5294 5220>, + <8076 6706 6071 5532 5296 5222>, + <8117 6703 6071 5532 5297 5223>, + <8170 6702 6070 5532 5298 5225>, + <8167 6702 6069 5532 5299 5227>, + <8118 6700 6068 5535 5301 5229>, + <8084 6699 6065 5539 5305 5232>, + <8087 6697 6062 5540 5309 5236>, + <8100 6691 6059 5541 5311 5240>, + <8092 6688 6059 5542 5314 5243>, + <8059 6691 6063 5546 5317 5244>, + <8043 6695 6069 5550 5320 5245>, + <8027 6693 6072 5553 5324 5247>, + <8011 6677 6077 5556 5329 5251>, + <8021 6667 6080 5558 5333 5255>, + <8050 6679 6081 5563 5336 5258>, + <8082 6697 6082 5568 5339 5261>, + <8123 6698 6085 5570 5342 5263>, + <8148 6684 6094 5571 5348 5265>, + <8101 6675 6101 5572 5352 5268>, + <8041 6691 6098 5581 5353 5271>, + <8104 6707 6096 5586 5356 5275>, + <8088 6704 6102 5586 5363 5282>, + <8048 6708 6104 5593 5368 5284>, + <8055 6725 6098 5595 5370 5288>, + <8059 6724 6114 5601 5370 5288>, + <8092 6743 6089 5598 5376 5290>, + <8157 6750 6086 5605 5374 5291>, + <8197 6722 6104 5609 5381 5293>, + <8269 6738 6105 5608 5384 5292>, + <8288 6759 6112 5624 5392 5304>, + <8380 6766 6128 5643 5400 5313>, + <8422 6779 6149 5656 5417 5324>, + <8422 6779 6149 5656 5417 5324>, + <8422 6779 6149 5656 5417 5324>; + }; + + qcom,pc-temp-y2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <9654 9643 10639 11070 11121 11086>, + <9654 9643 10662 11056 11097 11058>, + <9655 9643 10675 11037 11063 11029>, + <9655 9871 10680 11014 11027 11001>, + <9656 10190 10680 10988 10997 10976>, + <9656 10325 10677 10959 10981 10958>, + <9657 10308 10664 10918 10973 10946>, + <9657 10282 10644 10881 10967 10935>, + <9657 10301 10632 10875 10959 10916>, + <9658 10440 10623 10874 10933 10882>, + <9658 10534 10619 10874 10919 10864>, + <9658 10489 10626 10869 10936 10874>, + <9659 10417 10643 10861 10961 10888>, + <9658 10413 10676 10856 10952 10885>, + <9657 10487 10748 10851 10897 10860>, + <9657 10553 10801 10851 10866 10840>, + <9657 10580 10826 10885 10876 10837>, + <9657 10597 10843 10946 10896 10845>, + <9657 10521 10842 11018 10943 10884>, + <9656 10042 10822 11115 11060 10984>, + <9656 9696 10809 11159 11120 11034>, + <9656 9682 10815 11129 11098 11013>, + <9656 9676 10826 11091 11071 10987>, + <9656 9675 10835 11085 11079 11009>, + <9656 9676 10846 11088 11121 11106>, + <9655 9676 10848 11093 11154 11162>, + <9655 9675 10684 11108 11176 11166>, + <9655 9671 10460 11130 11199 11168>, + <9655 9668 10652 11152 11224 11182>, + <9654 9665 11565 11178 11263 11214>, + <9654 9662 12069 11192 11286 11238>, + <9654 9660 11796 11199 11310 11257>, + <9654 9659 11319 11203 11338 11277>, + <9654 9657 10963 11202 11344 11307>, + <9654 9656 10643 11198 11320 11345>, + <9654 9655 10423 11189 11299 11359>, + <9653 9654 10140 11148 11294 11325>, + <9653 9653 9828 11108 11301 11280>, + <9653 9653 9733 11099 11301 11271>, + <9653 9653 9707 11096 11290 11278>, + <9653 9652 9692 11071 11287 11277>, + <9653 9652 9681 10975 11329 11250>, + <9653 9652 9674 10939 11356 11231>, + <9653 9652 9668 10913 11303 11229>, + <9653 9652 9664 10802 11253 11135>, + <9653 9652 9663 10839 11180 11044>, + <9653 9652 9661 10832 11146 11009>, + <9652 9652 9660 10811 11105 10962>, + <9652 9651 9659 10794 11061 10965>, + <9651 9651 9658 10764 11053 10938>, + <9650 9651 9658 10711 10981 10871>, + <9650 9651 9656 10651 10927 10829>, + <9649 9651 9654 10594 10851 10747>, + <9648 9651 9654 10531 10798 10659>, + <9648 9651 9654 10531 10798 10659>, + <9648 9651 9654 10531 10798 10659>; + }; + + qcom,pc-temp-y3-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <14501 13677 13390 13309 13301 13279>, + <14412 13657 13393 13309 13294 13279>, + <14328 13634 13397 13311 13289 13279>, + <14249 13612 13400 13312 13285 13279>, + <14179 13596 13403 13314 13283 13279>, + <14117 13590 13406 13315 13282 13279>, + <14063 13594 13408 13315 13283 13280>, + <14017 13600 13410 13316 13286 13281>, + <13976 13594 13412 13317 13287 13282>, + <13939 13548 13416 13319 13287 13282>, + <13929 13515 13419 13321 13287 13282>, + <13957 13513 13421 13322 13289 13282>, + <13986 13512 13423 13323 13291 13282>, + <13945 13509 13422 13325 13291 13283>, + <13843 13504 13414 13328 13291 13284>, + <13803 13497 13407 13329 13291 13286>, + <13797 13488 13401 13328 13292 13287>, + <13793 13478 13395 13325 13294 13288>, + <13788 13470 13387 13324 13297 13290>, + <13783 13465 13376 13323 13301 13294>, + <13783 13458 13367 13322 13303 13296>, + <13788 13428 13360 13315 13297 13290>, + <13796 13384 13354 13306 13287 13281>, + <13814 13362 13349 13303 13283 13278>, + <13843 13349 13346 13300 13281 13277>, + <13874 13344 13341 13299 13280 13277>, + <13910 13351 13308 13299 13280 13277>, + <13952 13369 13266 13299 13282 13277>, + <13999 13391 13259 13298 13282 13277>, + <14052 13422 13259 13299 13283 13277>, + <14110 13460 13258 13299 13283 13277>, + <14174 13503 13258 13298 13283 13277>, + <14243 13554 13259 13298 13283 13277>, + <14318 13615 13263 13298 13283 13277>, + <14398 13690 13285 13299 13283 13278>, + <14481 13777 13302 13299 13283 13278>, + <14568 13879 13294 13296 13281 13277>, + <14658 13996 13281 13292 13279 13276>, + <14750 14118 13282 13292 13278 13276>, + <14850 14247 13299 13292 13277 13277>, + <14963 14377 13319 13293 13277 13277>, + <15082 14502 13343 13295 13277 13278>, + <15198 14624 13368 13298 13277 13278>, + <15302 14737 13402 13303 13278 13276>, + <15264 14824 13470 13304 13280 13278>, + <15439 14801 13476 13307 13284 13280>, + <15557 14824 13517 13316 13291 13286>, + <15783 14890 13560 13319 13292 13287>, + <16058 14961 13607 13332 13295 13287>, + <16423 15021 13665 13332 13292 13286>, + <16935 15095 13703 13333 13294 13286>, + <17701 15215 13779 13341 13296 13289>, + <18847 15382 13934 13350 13299 13292>, + <20636 15571 14143 13370 13308 13299>, + <20636 15571 14143 13370 13308 13299>, + <20636 15571 14143 13370 13308 13299>; + }; + + qcom,pc-temp-y4-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <17448 17305 16798 16610 16483 16470>, + <17520 17330 16862 16610 16486 16469>, + <17601 17378 16934 16609 16489 16468>, + <17679 17433 17001 16608 16491 16467>, + <17744 17479 17051 16607 16493 16467>, + <17783 17501 17070 16605 16493 16466>, + <17798 17503 17059 16603 16493 16466>, + <17813 17504 17041 16601 16492 16466>, + <17918 17511 17030 16599 16493 16466>, + <18180 17550 17023 16599 16497 16470>, + <18279 17608 17020 16599 16500 16473>, + <18148 17742 17034 16602 16502 16478>, + <17945 17902 17062 16609 16506 16483>, + <17736 17876 17086 16619 16512 16487>, + <17506 17547 17110 16638 16523 16492>, + <17399 17320 17134 16659 16535 16498>, + <17363 17344 17161 16679 16546 16506>, + <17328 17386 17183 16703 16560 16518>, + <17266 17370 17170 16748 16586 16537>, + <17193 17216 17080 16821 16630 16569>, + <17141 17060 16974 16852 16651 16585>, + <17100 16974 16865 16754 16602 16552>, + <17077 16908 16761 16616 16529 16502>, + <17070 16873 16703 16567 16502 16483>, + <17066 16851 16662 16543 16489 16473>, + <17066 16841 16647 16535 16485 16469>, + <17066 16841 16681 16535 16485 16470>, + <17067 16842 16727 16535 16487 16471>, + <17070 16843 16732 16537 16489 16474>, + <17074 16844 16721 16543 16497 16482>, + <17079 16845 16716 16549 16507 16491>, + <17088 16852 16721 16554 16521 16504>, + <17095 16866 16730 16558 16535 16515>, + <17099 16879 16732 16556 16540 16518>, + <17103 16893 16714 16549 16540 16515>, + <17111 16906 16704 16540 16534 16509>, + <17124 16920 16735 16528 16505 16492>, + <17134 16932 16784 16517 16477 16475>, + <17142 16941 16805 16517 16476 16471>, + <17149 16947 16815 16522 16479 16469>, + <17157 16950 16818 16530 16481 16469>, + <17167 16948 16818 16544 16482 16469>, + <17187 16945 16817 16555 16481 16467>, + <17208 16947 16815 16561 16471 16454>, + <17140 16965 16826 16575 16477 16456>, + <17176 16961 16849 16584 16493 16477>, + <17202 16977 16893 16606 16503 16495>, + <17281 17046 16954 16635 16528 16531>, + <17390 17107 17025 16679 16557 16532>, + <17524 17131 17054 16682 16515 16493>, + <17690 17101 17038 16673 16527 16498>, + <17978 17060 17051 16712 16548 16514>, + <18577 17063 17124 16764 16588 16554>, + <20156 17135 17255 16879 16727 16719>, + <20156 17135 17255 16879 16727 16719>, + <20156 17135 17255 16879 16727 16719>; + }; + + qcom,pc-temp-y5-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <10030 8712 14223 14774 19943 16308>, + <10448 8888 14349 15148 18667 15835>, + <10794 10562 14526 15365 17009 15457>, + <11054 12204 14713 15466 15353 15176>, + <11214 13579 14867 15489 14086 14997>, + <11260 14452 14948 15472 13593 14920>, + <11143 14948 14973 15335 13800 15003>, + <11001 15270 14986 15151 14123 15144>, + <11151 15028 14986 15098 14118 15087>, + <11850 13370 14973 15056 13826 14716>, + <12871 12246 14930 14978 13664 14315>, + <15188 13353 14287 14743 13788 13961>, + <17100 15163 13386 14398 13870 13634>, + <15786 15495 13334 14078 13643 13482>, + <12439 15197 13853 13740 13191 13549>, + <11406 14993 14346 13497 12887 13638>, + <11547 15443 14672 13207 12793 13546>, + <11662 16191 15006 12923 12796 13423>, + <11574 16138 15417 13004 13001 13548>, + <11364 14708 15994 13654 13569 14033>, + <11181 13284 16419 14434 14193 14440>, + <10986 12599 16670 15491 14905 14826>, + <10835 12068 16832 16433 15541 15160>, + <10734 11544 16827 16644 15650 15196>, + <10666 10962 16682 16591 15306 15346>, + <10655 10655 16390 16622 15048 15474>, + <10654 10648 14341 16597 15293 15494>, + <10654 10645 11728 16540 15744 15472>, + <10689 10665 11156 16578 15865 15229>, + <10734 10802 11032 16695 15749 14663>, + <10745 10946 10959 16756 15607 14352>, + <10765 11017 10901 16831 15502 14290>, + <10797 11076 10865 16959 15400 14311>, + <10882 11177 11054 17363 15705 14665>, + <10953 11367 12196 18097 16573 15740>, + <10940 11520 13011 18310 16919 16424>, + <10897 11584 12496 17269 16620 16376>, + <10863 11627 11602 15914 16091 16215>, + <10835 11630 11486 15213 15448 16327>, + <10820 11595 11681 14700 14692 16543>, + <10867 11570 11787 14330 14365 16550>, + <10955 11579 11797 14105 14243 16259>, + <11030 11596 11778 14219 14209 16346>, + <11029 11509 11647 14611 15058 16893>, + <11044 11331 11779 14198 14882 16382>, + <11143 11388 11508 14156 14882 14589>, + <11321 11488 11654 14603 16012 16142>, + <11356 11493 11662 14001 15040 14960>, + <11206 11613 11939 14918 15399 14828>, + <10932 11747 12726 15439 17093 17327>, + <10539 11665 12655 15981 17753 17255>, + <10263 11585 12280 16288 17881 17960>, + <9994 11459 12118 16141 17436 18200>, + <9668 11818 11932 16090 17352 17825>, + <9668 11818 11932 16090 17352 17825>, + <9668 11818 11932 16090 17352 17825>; + }; + + qcom,pc-temp-y6-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7467 6132 5538 5158 5055 5027>, + <7418 6176 5550 5158 5053 5026>, + <7371 6205 5557 5158 5050 5025>, + <7326 6223 5561 5157 5048 5025>, + <7283 6232 5562 5156 5046 5025>, + <7242 6234 5562 5154 5046 5025>, + <7194 6227 5555 5152 5046 5025>, + <7159 6211 5540 5150 5047 5026>, + <7167 6191 5531 5149 5047 5027>, + <7202 6161 5522 5149 5048 5028>, + <7216 6144 5519 5149 5049 5029>, + <7195 6170 5520 5150 5051 5030>, + <7155 6214 5522 5151 5053 5031>, + <7075 6207 5523 5154 5055 5033>, + <6953 6119 5523 5160 5058 5035>, + <6899 6058 5522 5167 5061 5038>, + <6884 6060 5524 5172 5065 5041>, + <6872 6065 5527 5177 5070 5045>, + <6853 6054 5521 5188 5079 5052>, + <6834 5986 5487 5208 5095 5064>, + <6828 5923 5449 5216 5102 5070>, + <6826 5892 5413 5184 5083 5056>, + <6825 5871 5381 5138 5056 5035>, + <6839 5868 5365 5122 5045 5028>, + <6867 5872 5355 5114 5040 5024>, + <6893 5878 5349 5111 5038 5023>, + <6923 5895 5343 5112 5039 5023>, + <6956 5926 5339 5113 5040 5024>, + <6991 5960 5339 5115 5042 5026>, + <7030 5999 5342 5118 5045 5028>, + <7074 6044 5346 5121 5048 5031>, + <7122 6096 5354 5124 5053 5034>, + <7175 6156 5367 5126 5057 5038>, + <7232 6222 5383 5127 5059 5039>, + <7293 6297 5405 5127 5060 5039>, + <7357 6380 5430 5127 5058 5038>, + <7425 6470 5458 5124 5049 5032>, + <7495 6568 5491 5120 5041 5027>, + <7567 6667 5530 5121 5040 5027>, + <7643 6768 5579 5127 5041 5027>, + <7727 6867 5632 5133 5042 5028>, + <7816 6963 5689 5144 5044 5028>, + <7908 7053 5751 5155 5044 5028>, + <7994 7135 5817 5167 5043 5024>, + <7959 7206 5905 5181 5046 5026>, + <8096 7192 5921 5188 5056 5034>, + <8195 7214 5976 5205 5063 5044>, + <8412 7280 6034 5219 5072 5055>, + <8678 7350 6096 5248 5083 5055>, + <9031 7405 6155 5252 5069 5043>, + <9521 7454 6196 5257 5074 5046>, + <10251 7535 6282 5285 5084 5053>, + <11352 7666 6442 5320 5100 5069>, + <13075 7846 6646 5385 5148 5123>, + <13075 7846 6646 5385 5148 5123>, + <13075 7846 6646 5385 5148 5123>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3593457e63d723351b5dcee75cf1c05389061080 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155 ADP-STAR"; + compatible = "qcom,sa6155-adp-star", "qcom,sa6155", "qcom,adp-star"; + qcom,msm-id = <384 0x0>; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dts b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dts new file mode 100644 index 0000000000000000000000000000000000000000..1cea61aa7024c9eb9335a8211bb8334f0cf890de --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +#include "sa6155.dtsi" +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155 ADP-STAR"; + compatible = "qcom,sa6155-adp-star", "qcom,sa6155", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bed9204466fa617c4928651a818b7cc951083189 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -0,0 +1,23 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,lpass@62400000 { + status = "disabled"; + }; + + qcom,glink { + modem { + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dts b/arch/arm64/boot/dts/qcom/sa6155.dts new file mode 100644 index 0000000000000000000000000000000000000000..0494f3f96a369e5678635ff43745e17a426f51f3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa6155.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155 SoC"; + compatible = "qcom,sa6155"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dtsi b/arch/arm64/boot/dts/qcom/sa6155.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0c7d23ff50473d986385d1ea8085177d97e74600 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155"; + compatible = "qcom,sa6155"; + qcom,msm-name = "SA6155"; + qcom,msm-id = <384 0x10000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ba038632f1e8dc62efa89ba139748a822a23aee1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P ADP-STAR"; + compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; + qcom,msm-id = <377 0x0>; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts new file mode 100644 index 0000000000000000000000000000000000000000..3ff625aa2bfb411c0a2916df33a577b0b769d6f3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa6155p.dtsi" +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P ADP-STAR"; + compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dts b/arch/arm64/boot/dts/qcom/sa6155p.dts new file mode 100644 index 0000000000000000000000000000000000000000..371125467fd69049b5633a1efd86827362e6d9c1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa6155p.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P SoC"; + compatible = "qcom,sa6155p"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dtsi b/arch/arm64/boot/dts/qcom/sa6155p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..83c0783cd5caf0285bec9f3872b9bb8574241000 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P"; + qcom,msm-name = "SA6155P"; + qcom,msm-id = <377 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts index d4322630a3a01814adb2c017c18694e8dea69480..351ce2b1a19f922ab0861b6d6a77f18969f2c32c 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts @@ -11,7 +11,7 @@ */ /dts-v1/; -#include "sa8155.dtsi" +#include "sa8155-v1.dtsi" #include "sa8155-adp-star.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi index a300ec8e5b6002361c06b3293fa5642bd11daffb..69b5b38fb564b233bb5d1e2e8536f8e672613831 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi @@ -23,8 +23,8 @@ interrupt-parent = <&tlmm>; interrupts = <38 0>; spi-max-frequency = <5000000>; - qcom,clk-freq-mhz = <16000000>; - qcom,max-can-channels = <4>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <1>; qcom,bits-per-word = <8>; qcom,support-can-fd; }; @@ -138,7 +138,6 @@ &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v4"; - vdda-phy-supply = <&pm8150_2_l18>; vdda-pll-supply = <&pm8150_2_l8>; vdda-phy-max-microamp = <87100>; vdda-pll-max-microamp = <18300>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v1.dtsi b/arch/arm64/boot/dts/qcom/sa8155-v1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..24b43228ab9c1d5f0d416fc9ef5902ca80e49c84 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v1.dtsi @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150.dtsi" +#include "sa8155.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155"; + compatible = "qcom,sa8155"; + qcom,msm-name = "SA8155 V1"; + qcom,msm-id = <362 0x10000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts new file mode 100644 index 0000000000000000000000000000000000000000..7f411ed1e62ef934ac4fed6ffad046759a650383 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155-v2.dtsi" +#include "sa8155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 V2 ADP STAR"; + compatible = "qcom,sa8155-adp-star", "qcom,sa8155", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2.dts b/arch/arm64/boot/dts/qcom/sa8155-v2.dts new file mode 100644 index 0000000000000000000000000000000000000000..4e3838fc5e3c2d5b3e95d2965ce4e1d8269180b0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 v2 SoC"; + compatible = "qcom,sa8155"; + qcom,pmic-name = "PM8150"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f13249b2f5c749170e3fb2ab7990dfa8b47890d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150-v2.dtsi" +#include "sa8155.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 V2"; + qcom,msm-name = "SA8155 V2"; + qcom,msm-id = <362 0x20000>; +}; + +&ufsphy_mem { + vdda-phy-supply = <&pm8150_1_l5>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dts b/arch/arm64/boot/dts/qcom/sa8155.dts index 0fbb4769485b20eae446bb1afaa7993f97197f0f..6309bd7a211d0fafcc2fec8c3ee9ee99c83ee539 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dts +++ b/arch/arm64/boot/dts/qcom/sa8155.dts @@ -12,7 +12,7 @@ /dts-v1/; -#include "sa8155.dtsi" +#include "sa8155-v1.dtsi" / { model = "Qualcomm Technologies, Inc. SA8155 SoC"; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index ce073c9f892033a5a009ab64aac0b3fa0d947719..e232fdf7892b7c30b068088e7576462fa9d40160 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -10,15 +10,6 @@ * GNU General Public License for more details. */ -#include "sm8150.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. SA8155"; - compatible = "qcom,sa8155"; - qcom,msm-name = "SA8155"; - qcom,msm-id = <362 0x10000>; -}; - /* Remove regulator nodes specific to SA8155 */ &soc { /delete-node/ regulator-pm8150-s4; @@ -180,6 +171,10 @@ vdd_parent-supply = <&pm8150_2_s3_level>; }; +&ufsphy_mem { + vdda-phy-supply = <&pm8150_2_l18>; +}; + &thermal_zones { aoss0-lowf { cooling-maps { diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts new file mode 100644 index 0000000000000000000000000000000000000000..838d963872750c2db40df6f231a0bb40500fb69f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155p-v2.dtsi" +#include "sa8155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P V2 ADP STAR"; + compatible = "qcom,sa8155p-adp-star", "qcom,sa8155p", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2.dts new file mode 100644 index 0000000000000000000000000000000000000000..62889ab921c62a896bb0dde6f831d67d8da5ca52 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155p-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P v2 SoC"; + compatible = "qcom,sa8155p"; + qcom,pmic-name = "PM8150"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi b/arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ac6ec4a18d7259114d7205e219e8d96192fcc661 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sa8155-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P v2"; + qcom,msm-name = "SA8155P v2"; + qcom,msm-id = <367 0x20000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p.dtsi b/arch/arm64/boot/dts/qcom/sa8155p.dtsi index 9b49c4fbd11b78d7a4cd01837b4d787d32d508f6..7d70bb52ed7781aae18bce2ef8bf5d594baacb7f 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155p.dtsi @@ -10,11 +10,11 @@ * GNU General Public License for more details. */ -#include "sa8155.dtsi" +#include "sa8155-v1.dtsi" / { model = "Qualcomm Technologies, Inc. SA8155P "; - qcom,msm-name = "SA8155P"; + qcom,msm-name = "SA8155P V1"; compatible = "qcom,sa8155p"; qcom,msm-id = <367 0x10000>; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d038729519519d3943b9057d7687365f4cd15762 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi @@ -0,0 +1,2589 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +&soc { + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + qcom,blk-size = <1>; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_replicator1_in: endpoint { + remote-endpoint= + <&replicator1_in_replicator_out>; + }; + }; + + port@2 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + replicator_qdss1: replicator@604a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x604a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <1>; + replicator1_out_funnel_swao: endpoint { + remote-endpoint= + <&funnel_swao_in_replicator1_out>; + }; + }; + + port@1 { + reg = <1>; + replicator1_in_replicator_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator_out_replicator1_in>; + }; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x05e0 0>, + <&apps_smmu 0x04a0 0>; + + arm,buffer-size = <0x400000>; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti0>; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0 &cti0>; + arm,default-sink; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator: endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <1>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + + port@3 { + reg = <2>; + funnel_merg_in_funnel_in2: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in2_out_funnel_merg>; + }; + }; + }; + }; + + funnel_in0: funnel@0x6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <4>; + funnel_in0_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_in0>; + }; + }; + + port@2 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@3 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_audio_etm0>; + }; + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <3>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + + port@2 { + reg = <4>; + funnel_in1_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_funnel_in1>; + }; + }; + + port@3 { + reg = <0>; + funnel_in1_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_in1>; + }; + }; + }; + }; + + funnel_modem: funnel@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6832000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_out_funnel_modem>; + }; + }; + }; + }; + + tpda_modem: tpda@6831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6831000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_modem_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_modem_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + dummy_eud: dummy_sink { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-eud"; + + qcom,dummy-sink; + port { + eud_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_eud>; + }; + }; + }; + + replicator_swao: replicator@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6b0a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@0 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&eud_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_replicator_swao>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator_swao>; + }; + }; + + }; + }; + + tmc_etf_swao: tmc@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6b09000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf-swao"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator_swao: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + + }; + + swao_csr: csr@6b0e000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0e000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + funnel_swao: funnel@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b08000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <6>; + funnel_swao_in_replicator1_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator1_out_funnel_swao>; + }; + }; + + port@2 { + reg = <7>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b01000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + + }; + }; + }; + + tpdm_swao0: tpdm@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6b02000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b03000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + funnel_in2: funnel@6043000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6043000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in2_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in2>; + }; + }; + + port@1 { + reg = <2>; + funnel_in2_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in2>; + }; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + coresight-name = "coresight-etm2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + coresight-name = "coresight-etm3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + coresight-name = "coresight-etm4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + coresight-name = "coresight-etm5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + coresight-name = "coresight-etm6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + coresight-name = "coresight-etm7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <3>; + funnel_qatb_in_funnel_dl_south_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_1_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <5>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; + }; + }; + + funnel_wcss: funnel@699e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x699e000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-wcss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_wcss_out_funnel_dl_south_1: endpoint { + remote-endpoint = + <&funnel_dl_south_1_in_funnel_wcss>; + }; + }; + + port@1 { + reg = <1>; + funnel_wcss_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_wcss>; + }; + }; + }; + }; + + funnel_dl_south_1: funnel_1@6b53000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b58000 0x10>, + <0x6b53000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_south_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_dl_south_1>; + }; + }; + + port@1 { + reg = <2>; + funnel_dl_south_1_in_funnel_wcss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_wcss_out_funnel_dl_south_1>; + }; + }; + }; + }; + + tpdm_wcss: tpdm@699c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_wcss: endpoint { + remote-endpoint = + <&funnel_wcss_in_tpdm_wcss>; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <13 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + + }; + + port@1 { + reg = <1>; + tpda_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_tpda>; + }; + }; + + port@2 { + reg = <2>; + tpda_in_tpdm_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_center_out_tpda>; + }; + }; + + + port@3 { + reg = <3>; + tpda_in_funnel_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_out_tpda>; + }; + }; + + port@4 { + reg = <5>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + port@5 { + reg = <6>; + tpda_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_tpda>; + }; + }; + + port@6 { + reg = <7>; + tpda_in_funnel_gfx: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gfx_out_tpda>; + }; + }; + + port@7 { + reg = <8>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@8 { + reg = <9>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + + port@9 { + reg = <10>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@10 { + reg = <11>; + tpda_in_tpdm_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_north_out_tpda>; + }; + }; + + port@11 { + reg = <12>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + + port@12 { + reg = <13>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + + port@13 { + reg = <15>; + tpda_in_tpdm_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_center_out_tpda>; + }; + }; + }; + }; + + funnel_dl_mm: funnel@69C3000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x69C3000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_mm_in_tpdm_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_mm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_dl_mm: tpdm@69c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69c0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_mm_out_funnel_dl_mm: endpoint { + remote-endpoint = + <&funnel_dl_mm_in_tpdm_dl_mm>; + }; + }; + }; + + tpdm_dl_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-center"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_dl_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dl_center>; + }; + }; + }; + + funnel_dl_south: funnel@6b53000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6b53000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_south_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_south>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_south_in_tpdm_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_south_out_funnel_dl_south>; + }; + }; + }; + }; + + tpdm_dl_south: tpdm@6b52000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b52000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_south_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_tpdm_dl_south>; + }; + }; + }; + + funnel_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + funnel_turing1: funnel_1@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867010 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-turing1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing_1>; + }; + }; + }; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + funnel_ddr_0: funnel@6a05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6a05000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ddr_0_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@6a00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x06a00000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + funnel_gfx: funnel@6943000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6943000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gfx_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_gfx>; + }; + }; + + port@1 { + reg = <0>; + funnel_gfx_in_tpdm_gfx: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gfx_out_funnel_gfx>; + }; + }; + }; + }; + + tpdm_gfx: tpdm@6940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6940000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_gfx_out_funnel_gfx: endpoint { + remote-endpoint = <&funnel_gfx_in_tpdm_gfx>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@6870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_north: tpdm@6b48000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b48000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_north_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_north>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_qm>; + }; + }; + }; + + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + tpdm_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + qcom,msr-fix-req; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_center>; + }; + }; + }; + + hwevent: hwevent@0x014066f0 { + compatible = "qcom,coresight-hwevent"; + reg = <0x14066f0 0x4>, + <0x14166f0 0x4>, + <0x1406038 0x4>, + <0x1416038 0x4>; + reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl", + "ddr-ch23-ctrl"; + + coresight-csr = <&csr>; + coresight-name = "coresight-hwevent"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6a03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6a10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6a11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ddr1: cti@6a12000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a12000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_wcss: cti@69a4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_wcss: cti@69a5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_wcss: cti@69a6000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a6000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@683b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x683b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing: cti@6867000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6867000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao: cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao: cti@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b05000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao: cti@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b06000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao: cti@6b07000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b07000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-aop-m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_titan: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-titan"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_venus_arm9: cti@6c20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-venus-arm9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06b0c000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi index 7a7053222d1f3c7a3ee7503fb261703aba47721e..6c4228397337cad666f7b576085bf9aed21b7b3b 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi @@ -14,7 +14,7 @@ &soc { /* GDSCs in Global CC */ pcie_0_gdsc: qcom,gdsc@16b004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "pcie_0_gdsc"; reg = <0x16b004 0x4>; qcom,poll-cfg-gdscr; @@ -22,7 +22,7 @@ }; pcie_tbu_gdsc: qcom,gdsc@128004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "pcie_tbu_gdsc"; reg = <0x128004 0x4>; qcom,poll-cfg-gdscr; @@ -30,7 +30,7 @@ }; ufs_phy_gdsc: qcom,gdsc@177004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "ufs_phy_gdsc"; reg = <0x177004 0x4>; qcom,poll-cfg-gdscr; @@ -38,7 +38,7 @@ }; usb30_prim_gdsc: qcom,gdsc@10f004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "usb30_prim_gdsc"; reg = <0x10f004 0x4>; qcom,poll-cfg-gdscr; @@ -46,7 +46,7 @@ }; hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc: qcom,gdsc@17d030 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc"; reg = <0x17d030 0x4>; qcom,no-status-check-on-disable; @@ -55,7 +55,7 @@ }; hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc: qcom,gdsc@17d03c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc"; reg = <0x17d03c 0x4>; qcom,no-status-check-on-disable; @@ -64,7 +64,7 @@ }; hlos1_vote_aggre_noc_mmu_tbu1_gdsc: qcom,gdsc@17d034 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_tbu1_gdsc"; reg = <0x17d034 0x4>; qcom,no-status-check-on-disable; @@ -73,7 +73,7 @@ }; hlos1_vote_aggre_noc_mmu_tbu2_gdsc: qcom,gdsc@17d038 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_tbu2_gdsc"; reg = <0x17d038 0x4>; qcom,no-status-check-on-disable; @@ -82,7 +82,7 @@ }; hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc: qcom,gdsc@17d040 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc"; reg = <0x17d040 0x4>; qcom,no-status-check-on-disable; @@ -91,7 +91,7 @@ }; hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc: qcom,gdsc@17d048 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc"; reg = <0x17d048 0x4>; qcom,no-status-check-on-disable; @@ -100,7 +100,7 @@ }; hlos1_vote_mmnoc_mmu_tbu_sf_gdsc: qcom,gdsc@17d044 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc"; reg = <0x17d044 0x4>; qcom,no-status-check-on-disable; @@ -175,8 +175,18 @@ reg = <0x5091540 0x4>; }; + gpu_gx_domain_addr: syscon@0x5091508 { + compatible = "syscon"; + reg = <0x5091508 0x4>; + }; + + gpu_gx_sw_reset: syscon@0x5091008 { + compatible = "syscon"; + reg = <0x5091008 0x4>; + }; + gpu_cx_gdsc: qcom,gdsc@509106c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "gpu_cx_gdsc"; reg = <0x509106c 0x4>; hw-ctrl-addr = <&gpu_cx_hw_ctrl>; @@ -187,30 +197,32 @@ }; gpu_gx_gdsc: qcom,gdsc@509100c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "gpu_gx_gdsc"; reg = <0x509100c 0x4>; qcom,poll-cfg-gdscr; + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; status = "disabled"; }; /* GDSCs in Video CC */ mvsc_gdsc: qcom,gdsc@0b00814 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "mvsc_gdsc"; reg = <0xab00814 0x4>; status = "disabled"; }; mvs0_gdsc: qcom,gdsc@ab00874 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "mvs0_gdsc"; reg = <0xab00874 0x4>; status = "disabled"; }; mvs1_gdsc: qcom,gdsc@ab008b4 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "mvs1_gdsc"; reg = <0xab008b4 0x4>; status = "disabled"; @@ -218,7 +230,7 @@ /* GDSCs in NPU CC */ npu_core_gdsc: qcom,gdsc@9911028 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "npu_core_gdsc"; reg = <0x9911028 0x4>; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi index a8bfab8603ec6535fd3177cccda2bff14f5736f6..f89f20ef5c376060fde6dc2381e1b0d1dfb80f74 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi @@ -21,12 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@22 { /* ADSP HEAP */ - reg = <22>; - memory-region = <&adsp_mem>; - qcom,ion-heap-type = "DMA"; - }; - qcom,ion-heap@27 { /* QSEECOM HEAP */ reg = <27>; memory-region = <&qseecom_mem>; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi index 70e03825fc965172cb38d83ccbc9fc1697883681..b6987a2fa25611db851189277969373c33853d15 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi @@ -17,7 +17,7 @@ qupv3_0: qcom,qupv3_0_geni_se@0x8c0000 { compatible = "qcom,qupv3-geni-se"; reg = <0x8c0000 0x2000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; @@ -263,7 +263,7 @@ qupv3_1: qcom,qupv3_1_geni_se@0xac0000 { compatible = "qcom,qupv3-geni-se"; reg = <0xac0000 0x2000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index b56beacea7249c5226d1dda6d92068f87d92f4bb..3573b2d99754cd160b8d2b58de36bb8143bdcae9 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -331,11 +331,11 @@ }; cluster1 { - core6 { + core0 { cpu = <&CPU6>; }; - core7 { + core1 { cpu = <&CPU7>; }; }; @@ -643,9 +643,12 @@ mbox-names = "qdss_clk"; }; - clock_gcc: qcom,gcc { - compatible = "qcom,dummycc"; - clock-output-names = "gcc_clocks"; + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-sdmmagpie", "syscon"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; #clock-cells = <1>; #reset-cells = <1>; }; @@ -658,15 +661,21 @@ }; clock_gpucc: qcom,gpucc { - compatible = "qcom,dummycc"; - clock-output-names = "gpucc_clocks"; + compatible = "qcom,gpucc-sdmmagpie", "syscon"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_gfx-supply = <&VDD_GFX_LEVEL>; #clock-cells = <1>; #reset-cells = <1>; }; - clock_videocc: qcom,videocc { - compatible = "qcom,dummycc"; - clock-output-names = "videocc_clocks"; + clock_videocc: qcom,videocc@ab00000 { + compatible = "qcom,videocc-sdmmagpie", "syscon"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + reg = <0xab00000 0x10000>; + reg-names = "cc_base"; #clock-cells = <1>; #reset-cells = <1>; }; @@ -679,8 +688,11 @@ }; clock_npucc: qcom,npucc { - compatible = "qcom,dummycc"; - clock-output-names = "npucc_clocks"; + compatible = "qcom,npucc-sdmmagpie", "syscon"; + reg = <0x9910000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + npu_gdsc-supply = <&npu_core_gdsc>; #clock-cells = <1>; #reset-cells = <1>; }; @@ -696,6 +708,13 @@ interrupts = ; }; + dsu_pmu@0 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, + <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>; + }; + qcom,msm-imem@146aa000 { compatible = "qcom,msm-imem"; reg = <0x146aa000 0x1000>; @@ -736,6 +755,12 @@ reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; + qcom,mpm2-sleep-counter@0xc221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; + }; + qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; @@ -825,6 +850,15 @@ qcom,wakeup-enable; }; + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x88e0000 0x2000>; + reg-names = "eud_base"; + status = "ok"; + }; + qcom,chd_sliver { compatible = "qcom,core-hang-detect"; label = "silver"; @@ -1010,6 +1044,16 @@ qcom,dump-node = <&L2_TLB_700>; qcom,dump-id = <0x127>; }; + + qcom,llcc1_d_cache { + qcom,dump-node = <&LLCC_1>; + qcom,dump-id = <0x140>; + }; + + qcom,llcc2_d_cache { + qcom,dump-node = <&LLCC_2>; + qcom,dump-id = <0x141>; + }; }; thermal_zones: thermal-zones {}; @@ -1036,6 +1080,15 @@ #thermal-sensor-cells = <1>; }; + dcc: dcc_v2@10a2000 { + compatible = "qcom,dcc-v2"; + reg = <0x10a2000 0x1000>, + <0x10ae000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + + dcc-ram-offset = <0x6000>; + }; + qcom,llcc@9200000 { compatible = "qcom,llcc-core", "syscon", "simple-mfd"; reg = <0x9200000 0x450000>; @@ -1050,6 +1103,10 @@ cap-based-alloc-and-pwr-collapse; }; + qcom,llcc-perfmon { + compatible = "qcom,llcc-perfmon"; + }; + qcom,llcc-erp { compatible = "qcom,llcc-erp"; interrupt-names = "ecc_irq"; @@ -1059,6 +1116,14 @@ qcom,llcc-amon { compatible = "qcom,llcc-amon"; }; + + LLCC_1: llcc_1_dcache { + qcom,dump-size = <0x6c000>; + }; + + LLCC_2: llcc_2_dcache { + qcom,dump-size = <0x6c000>; + }; }; apps_rsc: mailbox@18220000 { @@ -1126,6 +1191,118 @@ #mbox-cells = <1>; }; + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,rpc-latency-us = <611>; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1441 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1442 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1443 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1444 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1445 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1446 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1449 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B23 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B24 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B25 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb13 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B26 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb14 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B27 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb15 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B28 0x0>; + shared-cb = <3>; + dma-coherent; + }; + }; + qcom,glink { compatible = "qcom,glink"; #address-cells = <1>; @@ -1515,7 +1692,7 @@ spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; - reg = <0xc440000 0x2300>, + reg = <0xc440000 0x1100>, <0xc600000 0x2000000>, <0xe600000 0x100000>, <0xe700000 0xa0000>, @@ -1654,26 +1831,42 @@ }; &gpu_cx_gdsc { + parent-supply = <&VDD_CX_LEVEL>; status = "ok"; }; &gpu_gx_gdsc { + clock-names = "core_root_clk"; + clocks = <&clock_gpucc GPU_CC_GX_GFX3D_CLK_SRC>; + qcom,force-enable-root-clk; + parent-supply = <&VDD_GFX_LEVEL>; + qcom,reset-aon-logic; status = "ok"; }; &mvsc_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; status = "ok"; }; &mvs0_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; &mvs1_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; &npu_core_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_NPU_CFG_AHB_CLK>; status = "ok"; }; @@ -1683,3 +1876,4 @@ #include "pm6150.dtsi" #include "pm6150l.dtsi" #include "sdmmagpie-regulator.dtsi" +#include "sdmmagpie-coresight.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 42b9c875dcf32ee2d247a5360b569204f18a33f6..d8ed44602fefef74c3efae0668ad5bb264de5253 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -181,6 +181,11 @@ compatible = "qcom,msm_gsi"; }; + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + }; + ipa_hw: qcom,ipa@01e00000 { compatible = "qcom,ipa"; reg = <0x1e00000 0xc0000>, diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index 8c4d761bfc59bb49fcfcd03fda66691b673f2979..0ffcb7c42ece8654620a41a8071f12b04c244968 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -20,56 +20,89 @@ #include "sm6150-lpi.dtsi" #include +#include &bolero { qcom,num-macros = <4>; qcom,va-without-decimation; - wsa_macro: wsa-macro@62F00000 { - compatible = "qcom,wsa-macro"; - reg = <0x62F00000 0x0>; - clock-names = "wsa_core_clk", "wsa_npl_clk"; - clocks = <&clock_audio_wsa_1 0>, - <&clock_audio_wsa_2 0>; - qcom,wsa-swr-gpios = <&wsa_swr_gpios>; - }; - - va_macro: va-macro@62F20000 { - compatible = "qcom,va-macro"; - reg = <0x62F20000 0x0>; - clock-names = "va_core_clk"; - clocks = <&clock_audio_va 0>; + tx_macro: tx-macro@62ec0000 { + compatible = "qcom,tx-macro"; + reg = <0x62ec0000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <2400000>; + swr_2: tx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + qcom,swr_master_id = <3>; + swrm-io-base = <0x62ed0000 0x0>; + interrupts = <0 137 0>, <0 528 0>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 PCM_OUT1 0xF>, + <2 ADC1 0x1>, <2 ADC2 0x2>, + <3 ADC3 0x1>, <3 ADC4 0x2>, + <4 DMIC0 0x1>, <4 DMIC1 0x2>, + <4 DMIC2 0x4>, <4 DMIC3 0x8>, + <5 DMIC4 0x1>, <5 DMIC5 0x2>, + <5 DMIC6 0x4>, <5 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd937x_tx_slave: wcd937x-tx-slave { + compatible = "qcom,wcd937x-slave"; + reg = <0x0 0x01170223>; + }; + }; }; - rx_macro: rx-macro@62EE0000 { + rx_macro: rx-macro@62ee0000 { compatible = "qcom,rx-macro"; - reg = <0x62EE0000 0x0>; + reg = <0x62ee0000 0x0>; clock-names = "rx_core_clk", "rx_npl_clk"; clocks = <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>; qcom,rx-swr-gpios = <&rx_swr_gpios>; - qcom,rx_mclk_mode_muxsel = <0x62C25020>; + qcom,rx_mclk_mode_muxsel = <0x62c25020>; swr_1: rx_swr_master { compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + qcom,swr_master_id = <2>; + swrm-io-base = <0x62ef0000 0x0>; + interrupts = <0 138 0>; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x3>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; wcd937x_rx_slave: wcd937x-rx-slave { compatible = "qcom,wcd937x-slave"; + reg = <0x0 0x01170224>; }; }; }; - tx_macro: tx-macro@62EC0000 { - compatible = "qcom,tx-macro"; - reg = <0x62EC0000 0x0>; - clock-names = "tx_core_clk", "tx_npl_clk"; - clocks = <&clock_audio_tx_1 0>, - <&clock_audio_tx_2 0>; - qcom,tx-swr-gpios = <&tx_swr_gpios>; - qcom,tx-dmic-sample-rate = <4800000>; - swr_2: tx_swr_master { - compatible = "qcom,swr-mstr"; - wcd937x_tx_slave: wcd937x-tx-slave { - compatible = "qcom,wcd937x-slave"; - }; - }; + wsa_macro: wsa-macro@62f00000 { + compatible = "qcom,wsa-macro"; + reg = <0x62f00000 0x0>; + clock-names = "wsa_core_clk", "wsa_npl_clk"; + clocks = <&clock_audio_wsa_1 0>, + <&clock_audio_wsa_2 0>; + qcom,wsa-swr-gpios = <&wsa_swr_gpios>; + }; + + va_macro: va-macro@62f20000 { + compatible = "qcom,va-macro"; + reg = <0x62f20000 0x0>; + clock-names = "va_core_clk"; + clocks = <&clock_audio_va 0>; }; }; @@ -81,13 +114,13 @@ qcom,audio-routing = "AMIC2", "MIC BIAS2", "MIC BIAS2", "Analog Mic2", - "DMIC0", "MIC BIAS1", + "TX DMIC0", "MIC BIAS1", "MIC BIAS1", "Digital Mic0", - "DMIC1", "MIC BIAS1", + "TX DMIC1", "MIC BIAS1", "MIC BIAS1", "Digital Mic1", - "DMIC2", "MIC BIAS3", + "TX DMIC2", "MIC BIAS3", "MIC BIAS3", "Digital Mic2", - "DMIC3", "MIC BIAS3", + "TX DMIC3", "MIC BIAS3", "MIC BIAS3", "Digital Mic3", "TX_AIF1 CAP", "VA_MCLK", "TX_AIF2 CAP", "VA_MCLK", @@ -103,7 +136,13 @@ "IN3_AUX", "AUX_OUT", "TX SWR_ADC0", "ADC1_OUTPUT", "TX SWR_ADC2", "ADC2_OUTPUT", - "TX SWR_ADC3", "ADC3_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", "SpkrLeft IN", "WSA_SPK1 OUT", "SpkrRight IN", "WSA_SPK2 OUT", "WSA_SPK1 OUT", "VA_MCLK", @@ -125,6 +164,17 @@ &soc { wcd937x_codec: wcd937x-codec { compatible = "qcom,wcd937x-codec"; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x3 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; qcom,wcd-rst-gpio-node = <&wcd937x_rst_gpio>; qcom,rx-slave = <&wcd937x_rx_slave>; @@ -147,9 +197,9 @@ qcom,cdc-vdd-mic-bias-current = <25000>; qcom,cdc-static-supplies = "cdc-vdd-ldo-rxtx", - "cdc-vddpx-1"; - qcom,cdc-on-demand-supplies = "cdc-vdd-buck", - "cdc-vdd-mic-bias"; + "cdc-vddpx-1", + "cdc-vdd-buck", + "cdc-vdd-mic-bias"; }; cdc_dmic01_gpios: cdc_dmic01_pinctrl { @@ -236,7 +286,7 @@ qcom,lpi-gpios; }; - qcom,wcd-dsp-glink { + tavil_glink: qcom,wcd-dsp-glink { status = "disabled"; compatible = "qcom,wcd-dsp-glink"; qcom,wdsp-channels = "g_glink_ctrl", @@ -312,14 +362,17 @@ clock_audio: audio_ext_clk { status = "disabled"; + qcom,codec-ext-clk-src = <0>; compatible = "qcom,audio-ref-clk"; pinctrl-names = "active", "sleep"; pinctrl-0 = <&wcd934x_mclk_default>; pinctrl-1 = <&wcd934x_mclk_default>; + qcom,use-pinctrl = <1>; qcom,audio-ref-clk-gpio = <&pm6150_gpios 8 0>; clock-names = "osr_clk"; clocks = <&pm6150_clkdiv>; qcom,node_has_rpm_clock; + pmic-clock-names = "pm6150_div_clk1"; #clock-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi index 625b5531be48751f79628cd5f28094f4aea09221..3b4b5795c5b5325ea65cbb2820e68cfa00487a4f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi @@ -14,7 +14,7 @@ #include "msm-audio-lpass.dtsi" &msm_audio_ion { - iommus = <&apps_smmu 0x1b21 0x0>; + iommus = <&apps_smmu 0x1721 0x0>; qcom,smmu-sid-mask = /bits/ 64 <0xf>; }; @@ -43,6 +43,7 @@ compatible = "qcom,sm6150-asoc-snd"; qcom,mi2s-audio-intf = <1>; qcom,auxpcm-audio-intf = <1>; + qcom,wcn-btfm = <1>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, @@ -125,7 +126,7 @@ &slim_aud { status = "disabled"; - msm_dai_slim { + dai_slim: msm_dai_slim { status = "disabled"; compatible = "qcom,msm-dai-slim"; elemental-addr = [ff ff ff fe 17 02]; diff --git a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi index 0b71cd5e14f45b54acd9c3594abd5f733cd1e0c4..c216c45afd35d233bd1b05b71f925ee277ea8d78 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi @@ -409,8 +409,8 @@ qcom,qos-off = <4096>; qcom,base-offset = <45056>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; + qcom,bypass-qos-prg; clocks = <>; }; @@ -501,7 +501,7 @@ }; mas_qhm_qup1: mas-qhm-qup1 { - cell-id = ; + cell-id = ; label = "mas-qhm-qup1"; qcom,buswidth = <4>; qcom,agg-ports = <1>; @@ -551,6 +551,8 @@ qcom,ap-owned; qcom,prio = <2>; qcom,forwarding; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; }; mas_xm_emac_avb: mas-xm-emac-avb { @@ -574,7 +576,7 @@ qcom,connections = <&slv_qns_pcie_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; - qcom,prio = <2>; + qcom,prio = <0>; }; mas_xm_qdss_etr: mas-xm-qdss-etr { @@ -623,6 +625,12 @@ qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + clock-names = + "clk-aggre-ufs-phy-axi-no-rate"; + }; }; mas_xm_usb2: mas-xm-usb2 { @@ -635,6 +643,12 @@ qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB2_SEC_AXI_CLK>; + clock-names = + "clk-usb3-sec-axi-no-rate"; + }; }; mas_xm_usb3_0: mas-xm-usb3-0 { @@ -647,6 +661,12 @@ qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-usb3-sec-axi-no-rate"; + }; }; mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp { @@ -833,6 +853,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { @@ -847,6 +868,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qnm_snoc_gc: mas-qnm-snoc-gc { @@ -914,6 +936,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 { @@ -928,6 +951,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { @@ -942,6 +966,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_mdp0: mas-qxm-mdp0 { @@ -956,6 +981,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_rot: mas-qxm-rot { @@ -970,6 +996,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus0: mas-qxm-venus0 { @@ -984,6 +1011,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus_arm9: mas-qxm-venus-arm9 { @@ -998,6 +1026,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { @@ -1042,6 +1071,9 @@ qcom,connections = <&slv_xs_pcie>; qcom,bus-dev = <&fab_system_noc>; qcom,bcms = <&bcm_sn8>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; }; mas_qnm_lpass_anoc: mas-qnm-lpass-anoc { diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eaf3c8a9ab61c8819bdc410ba2b887f46c848eb4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0>; + torch-source = <&pm6150l_torch1>; + switch-source = <&pm6150l_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash1>; + torch-source = <&pm6150l_torch1>; + switch-source = <&pm6150l_switch1>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash2>; + torch-source = <&pm6150l_torch2>; + switch-source = <&pm6150l_switch2>; + status = "ok"; + enable-active-high; + gpio = <&tlmm 38 0>; + pinctrl-names = "default"; + pinctrl-0 = <&flash_led3_front_en>; + }; + + camera_ldo: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm6150l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_dvdd_en>; + vin-supply = <&pm6150l_s8>; + }; + + camera_vana0_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_vana0_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm6150l_gpios 9 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_0_vana>; + vin-supply = <&pm6150l_bob>; + }; + + camera_vana1_2_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_vana1_2_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm6150l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_1_2_vana>; + vin-supply = <&pm6150l_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana0_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 47 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 45 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 30 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana0_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 47 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 45 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 30 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..50506ac400384092c8de227168a2ea799eedef8e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -0,0 +1,1058 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_cci: qcom,cci@ac4a000 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x4000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = <0 460 0>; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CCI_CLK>, + <&clock_camcc CAM_CC_CCI_CLK_SRC>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cci_clk", + "cci_clk_src"; + src-clock-name = "cci_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 0 0 0 0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x820 0x0>, + <&apps_smmu 0x840 0x0>, + <&apps_smmu 0x860 0x0>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0cc0 0x0>, + <&apps_smmu 0x0d40 0x0>; + label = "lrme"; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1060 0x8>; + label = "jpeg"; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0de2 0x0>, + <&apps_smmu 0x0c80 0x0>, + <&apps_smmu 0x0ca0 0x0>, + <&apps_smmu 0x0d00 0x0>, + <&apps_smmu 0x0d20 0x0>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0xd800000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3 GB */ + iova-region-name = "io"; + iova-region-start = <0xd911000>; + iova-region-len = <0xd26ef000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 64K */ + iova-region-name = "qdss"; + iova-region-start = <0xd900000>; + iova-region-len = <0x10000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0c00 0x0>, + <&apps_smmu 0x0c01 0x0>; + label = "cpas-cdm0"; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x150100>; /* Titan v150 v1.0.0 */ + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas0"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "gcc_camera_ahb", + "gcc_camera_axi", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = <0 464 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = <0 465 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = <0 466 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = <0 467 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <2>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = <0 468 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <2>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = <0 469 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0>, + <0 0 0 0 0 0 432000000 0>, + <0 0 0 0 0 0 540000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_fast_ahb", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_clk", + "icp_clk_src"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <0 0 200000000 0 0 0 0 360000000>, + <0 0 200000000 0 0 0 0 600000000>; + clock-cntl-level = "svs", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x73 0x1CF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 320000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@ac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 320000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 200000000 200000000>, + <0 0 0 0 0 216000000 216000000>, + <0 0 0 0 0 300000000 300000000>, + <0 0 0 0 0 404000000 404000000>, + <0 0 0 0 0 404000000 404000000>, + <0 0 0 0 0 404000000 404000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", + "nominal_l1", "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..12f9774b0fa29e975b6685c1560d1bad3b7f5233 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sm6150-idp.dtsi" +#include "sm6150-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM6150 Command mode display IDP"; + compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; + qcom,msm-id = <355 0x0>; + qcom,board-id = <34 3>; +}; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..0769cb287d91a1656a619dbb35ffc5b599889451 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts @@ -0,0 +1,52 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm6150.dtsi" +#include "sm6150-idp.dtsi" + +&qupv3_se1_i2c { + status = "okay"; + synaptics_dsx@20 { + compatible = "synaptics,dsx-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <89 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,ub-i2c-addr = <0x20>; + synaptics,max-y-for-2d = <2159>; + synaptics,irq-gpio = <&tlmm 89 0x2008>; + synaptics,reset-gpio = <&tlmm 88 0x0>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + }; + + /delete-node/ himax_ts@48; +}; + +/ { + model = "Qualcomm Technologies, Inc. SM6150 Command mode display IDP"; + compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; + qcom,board-id = <34 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index 2e5d6ecb62f3227b6c36871f7f0981f947c364a7..6f9c9fcf93bd413fb290b79e7c0182353de13abd 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -110,6 +110,8 @@ reg-names = "tmc-base", "bam-base"; qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x01e0 0>, + <&apps_smmu 0x00a0 0>; arm,buffer-size = <0x400000>; coresight-name = "coresight-tmc-etr"; @@ -440,6 +442,19 @@ }; }; + tpdm_wcss: tpdm@699c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_in1: endpoint { + remote-endpoint = <&funnel_in1_in_tpdm_wcss>; + }; + }; + }; + tpdm_west: tpdm@6b48000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b968>; @@ -551,7 +566,7 @@ }; port@2 { - reg = <6>; + reg = <7>; funnel_monaq_1_in_funnel_modem: endpoint { slave-mode; remote-endpoint = @@ -560,7 +575,7 @@ }; port@3 { - reg = <7>; + reg = <6>; funnel_monaq_1_in_modem_etm0: endpoint { slave-mode; remote-endpoint = @@ -825,7 +840,7 @@ }; port@1 { - reg = <0>; + reg = <1>; funnel_turing_1_in_turing_etm0: endpoint { slave-mode; remote-endpoint = @@ -1015,11 +1030,20 @@ }; port@2 { + reg = <4>; + funnel_in1_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_in1>; + }; + }; + + port@3 { reg = <7>; funnel_in1_in_funnel_apss_merg: endpoint { slave-mode; remote-endpoint = - <&funnel_apss_merg_out_funnel_in1>; + <&funnel_apss_merg_out_funnel_in1>; }; }; }; @@ -1354,6 +1378,78 @@ }; }; + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6a03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6a10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6a11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + cti_mss_q6: cti@683b000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi index 275faf437eb45d5ffffeb1e77539852cdfd3a8a7..fddfc562d0e0aac1df2b82846d7e860ab6567b3a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi @@ -56,11 +56,15 @@ status = "okay"; }; -&wdsp_mgr { +&qupv3_se4_spi { status = "okay"; }; -&wdsp_glink { +&tavil_wdsp { + status = "okay"; +}; + +&tavil_glink { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts index de91a769324e00a4ce52c9dd8875e53cbb128ad0..345251a025aee913861cf7fea90333600a975b15 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts @@ -14,8 +14,11 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" +#include "sm6150-ext-codec-audio-overlay.dtsi" +#include "sm6150-external-codec.dtsi" / { model = "Qualcomm Technologies, Inc. SM6150 External Audio Codec IDP"; @@ -23,3 +26,7 @@ qcom,msm-id = <355 0x0>; qcom,board-id = <34 1>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts index 4c852ccb490b32cd0cefca526109f0b7100b1eb9..d86f77e2e1a7d60e2f6099504170e865f95d6c9e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts @@ -14,6 +14,8 @@ #include "sm6150.dtsi" #include "sm6150-idp.dtsi" +#include "sm6150-ext-codec-audio-overlay.dtsi" +#include "sm6150-external-codec.dtsi" / { model = "Qualcomm Technologies, Inc. SM6150 External Audio Codec IDP"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi index 5a5daeaa9a95668558d8250385b469d72779980a..7bbe80ab99a5ea5ca22b5a124a0181dad70a55bb 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi @@ -17,6 +17,7 @@ }; }; +#include #include "sm6150-wcd.dtsi" &sm6150_snd { @@ -110,11 +111,17 @@ &slim_aud { status = "okay"; tavil_codec { - swr_tavil: tavil_wsa_swr_master { + swr_tavil: swr_master { compatible = "qcom,swr-mstr"; #address-cells = <2>; #size-cells = <0>; - + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr_master_id = <1>; wsa881x_11: wsa881x@11 { compatible = "qcom,wsa881x"; reg = <0x00 0x20170211>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi index 13a62b58b2f8cb0c1b4af053223effcf754ef2ba..2c8fea8b75923abc0ae1e2c7a2c3f267c11bb46c 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi @@ -33,8 +33,10 @@ label = "kgsl-3d0"; compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; status = "ok"; - reg = <0x5000000 0x40000>; - reg-names = "kgsl_3d0_reg_memory"; + reg = <0x5000000 0x40000>, + <0x780000 0x6fff>; + reg-names = "kgsl_3d0_reg_memory", + "qfprom_memory"; interrupts = <0 300 0>; interrupt-names = "kgsl_3d0_irq"; qcom,id = <0>; @@ -108,6 +110,8 @@ /* Context aware jump target power level */ qcom,ca-target-pwrlevel = <3>; + qcom,gpu-speed-bin = <0x6004 0x1fe00000 21>; + /* GPU Mempools */ qcom,gpu-mempools { #address-cells = <1>; @@ -140,73 +144,242 @@ }; }; - qcom,gpu-pwrlevels { + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calulated as FMAX/4.8 MHz round up to zero + * decimal places. + */ + qcom,gpu-pwrlevel-bins { #address-cells = <1>; #size-cells = <0>; - compatible = "qcom,gpu-pwrlevels"; - - /* TURBO */ - qcom,gpu-pwrlevel@0 { - reg = <0>; - qcom,gpu-freq = <845000000>; - qcom,bus-freq = <11>; - qcom,bus-min = <10>; - qcom,bus-max = <11>; - }; - - /* NOM L1 */ - qcom,gpu-pwrlevel@1 { - reg = <1>; - qcom,gpu-freq = <745000000>; - qcom,bus-freq = <10>; - qcom,bus-min = <9>; - qcom,bus-max = <11>; - }; - - /* NOM */ - qcom,gpu-pwrlevel@2 { - reg = <2>; - qcom,gpu-freq = <700000000>; - qcom,bus-freq = <9>; - qcom,bus-min = <8>; - qcom,bus-max = <10>; - }; - - /* SVS L1 */ - qcom,gpu-pwrlevel@3 { - reg = <3>; - qcom,gpu-freq = <550000000>; - qcom,bus-freq = <8>; - qcom,bus-min = <7>; - qcom,bus-max = <9>; - }; - - /* SVS */ - qcom,gpu-pwrlevel@4 { - reg = <4>; - qcom,gpu-freq = <435000000>; - qcom,bus-freq = <7>; - qcom,bus-min = <5>; - qcom,bus-max = <8>; + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <845000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <706000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <645000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <513000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; }; - /* Low SVS */ - qcom,gpu-pwrlevel@5 { - reg = <5>; - qcom,gpu-freq = <290000000>; - qcom,bus-freq = <4>; - qcom,bus-min = <4>; - qcom,bus-max = <5>; + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <177>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <845000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <706000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <645000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <513000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; }; - /* XO */ - qcom,gpu-pwrlevel@6 { - reg = <6>; - qcom,gpu-freq = <0>; - qcom,bus-freq = <0>; - qcom,bus-min = <0>; - qcom,bus-max = <0>; + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <187>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <4>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <895000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + /* SVS_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <845000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <706000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <645000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <513000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts index f172568ec0e2eac4446a9b1b7e387a1a150547bf..9eaf6e4711efe9685a47a4a79a1278d498a99130 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" #include "sm6150-audio-overlay.dtsi" @@ -24,3 +25,7 @@ qcom,msm-id = <355 0x0>; qcom,board-id = <34 0>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 1467f00847a64603c4afa584e04d27f80195d789..1bb32e90e620cdd829f78c2c6c24561ed25da55e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -10,15 +10,48 @@ * GNU General Public License for more details. */ +#include "sm6150-thermal-overlay.dtsi" +#include "sm6150-camera-sensor-idp.dtsi" +#include #include +#include +#include "sm6150-sde-display.dtsi" -&soc { +&qupv3_se3_i2c { + status = "ok"; + #include "smb1390.dtsi" + #include "smb1355.dtsi" }; -/ { - mtp_batterydata: qcom,battery-data { - qcom,batt-id-range-pct = <15>; - #include "qg-batterydata-alium-3600mah.dtsi" +&pm6150l_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; }; }; @@ -26,6 +59,10 @@ status = "ok"; }; +&qupv3_se7_4uart { + status = "ok"; +}; + &pm6150l_wled { qcom,string-cfg= <3>; status = "ok"; @@ -63,6 +100,28 @@ status = "ok"; }; +&qupv3_se1_i2c { + status = "okay"; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <89 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + himax,panel-coords = <0 1080 0 2160>; + himax,display-coords = <0 1080 0 2160>; + himax,irq-gpio = <&tlmm 89 0x00>; + himax,rst-gpio = <&tlmm 88 0x00>; + report_type = <1>; + }; +}; + &sdhc_1 { vdd-supply = <&pm6150l_l11>; qcom,vdd-voltage-level = <2950000 2950000>; @@ -113,4 +172,68 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; + qcom,sec-charger-config = <3>; +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm6150_vadc ADC_AMUX_THM3>; + io-channel-names = "cp_die_temp"; + status = "ok"; +}; + +&smb1355 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + status = "ok"; +}; + +&smb1355_charger { + status = "ok"; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_hx83112a_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_td4328_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_td4328_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index dc916bb2c4323a46c215c619ba1eb6a3ce3d0edc..7bb36d5013a8abe02f36cd1f06ec50f009887211 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include + &soc { tlmm: pinctrl@03000000 { compatible = "qcom,sm6150-pinctrl"; @@ -469,6 +471,62 @@ }; }; + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio90"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio90"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + /* SDC pin type */ sdc1_clk_on: sdc1_clk_on { config { @@ -852,6 +910,337 @@ }; }; + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio89", "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio89", "gpio88"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32", "gpio33"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32", "gpio33"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34", "gpio35"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34", "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET */ + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET */ + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio29"; + function = "cam_mclk"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio29"; + function = "cam_mclk"; + }; + + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + flash_led3_front { + flash_led3_front_en: flash_led3_front_en { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_front_dis: flash_led3_front_dis { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; }; }; @@ -866,4 +1255,37 @@ output-low; }; }; + + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio3"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&pm6150l_gpios { + cam_sensor_dvdd_en: cam_sensor_dvdd_en { + pins = "gpio3"; + function = "normal"; + power-source = <0>; + output-low; + }; + cam_sensor_0_vana: cam_sensor_0_vana { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + output-low; + }; + cam_sensor_1_2_vana: cam_sensor_1_2_vana { + pins = "gpio4"; + function = "normal"; + power-source = <0>; + output-low; + + }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts index 2854d1471c9981b4ccac43025c518b4d6006f3f7..798260de18464dbff3bcb3744546c6f50b00b82d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts @@ -14,7 +14,9 @@ /plugin/; #include +#include +#include "sm6150-audio-overlay.dtsi" #include "sm6150-qrd.dtsi" / { @@ -22,3 +24,38 @@ compatible = "qcom,sm6150-qrd", "qcom,sm6150", "qcom,qrd"; qcom,board-id = <11 0>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; + +&sm6150_snd { + qcom,model = "sm6150-qrd-snd-card"; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "TX_AIF1 CAP", "VA_MCLK", + "TX_AIF2 CAP", "VA_MCLK", + "RX AIF1 PB", "VA_MCLK", + "RX AIF2 PB", "VA_MCLK", + "RX AIF3 PB", "VA_MCLK", + "RX AIF4 PB", "VA_MCLK", + "HPHL_OUT", "VA_MCLK", + "HPHR_OUT", "VA_MCLK", + "AUX_OUT", "VA_MCLK", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC2", "ADC2_OUTPUT", + "TX SWR_ADC3", "ADC3_OUTPUT", + "SpkrLeft IN", "WSA_SPK1 OUT", + "WSA_SPK1 OUT", "VA_MCLK"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 17710610b9d130828541e1493bf0ae4c77babe6f..4c203a107a0f3dcdaaedea96256eacda86e0ab24 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -11,18 +11,66 @@ */ #include "sm6150-thermal-overlay.dtsi" +#include #include +#include +#include "sm6150-sde-display.dtsi" -&soc { +&qupv3_se3_i2c { + status = "ok"; + #include "smb1390.dtsi" + #include "smb1355.dtsi" }; -/ { - mtp_batterydata: qcom,battery-data { - qcom,batt-id-range-pct = <15>; - #include "qg-batterydata-alium-3600mah.dtsi" +&pm6150l_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; }; }; +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; +}; + +&qupv3_se7_4uart { + status = "ok"; +}; + +&pm6150l_wled { + qcom,string-cfg= <3>; + status = "ok"; +}; + +&pm6150l_lcdb { + status = "ok"; +}; + +&qupv3_se0_2uart { + status = "ok"; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3-660"; @@ -65,4 +113,86 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; + qcom,sec-charger-config = <1>; +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm6150_vadc ADC_AMUX_THM3>; + io-channel-names = "cp_die_temp"; + status = "ok"; +}; + +&qupv3_se1_i2c { + status = "okay"; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <125 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + himax,panel-coords = <0 1080 0 2160>; + himax,display-coords = <0 1080 0 2160>; + himax,irq-gpio = <&tlmm 89 0x00>; + himax,rst-gpio = <&tlmm 88 0x00>; + report_type = <1>; + }; +}; + +&dsi_hx83112a_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&sdhc_1 { + vdd-supply = <&pm6150l_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm6150_l12>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm6150l_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm6150l_l6>; + qcom,vdd-io-voltage-level = <1800000 3100000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 99 0>; + + status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi index 1ab49b81d1081e8bb610a65ee8c22b09a06a9e19..1b57e796d5d64885469bb1b5456d4c9708c0599b 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi @@ -29,7 +29,7 @@ qupv3_0: qcom,qupv3_0_geni_se@8c0000 { compatible = "qcom,qupv3-geni-se"; reg = <0x8c0000 0x6000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; @@ -144,7 +144,7 @@ qupv3_1: qcom,qupv3_1_geni_se@ac0000 { compatible = "qcom,qupv3-geni-se"; reg = <0xac0000 0x6000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; diff --git a/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi index c77682c57ea6d4011808e9c7509bb7f17767763d..8b540cf966270f948134a08338d0796360f803c7 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi @@ -117,7 +117,7 @@ regulator-name = "pm6150l_s2"; qcom,set = ; regulator-min-microvolt = <348000>; - regulator-max-microvolt = <1200000>; + regulator-max-microvolt = <648000>; qcom,init-voltage = <348000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts index 47b69d4655115b69ebc0d10dd0b1dbb652754ccd..40685f9ae444e821504a6b96869f95ddaa0fa7e1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-rumi.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi index 18d98efc50cc78bf86235bb31a0d255aa5b66a53..34ff3eb557eb423f5cba7e3d8d07f8c77ee6e0dd 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi @@ -191,11 +191,16 @@ }; &usb0 { + /delete-property/ extcon; dwc3@a600000 { usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; maximum-speed = "high-speed"; - dr_mode = "peripheral"; + dr_mode = "otg"; }; }; +&usb_qmp_phy { + status = "disabled"; +}; + #include "sm6150-stub-regulator.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..834d377bd9f762211e8d29f6d08e6193124105c4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -0,0 +1,303 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi" +#include "dsi-panel-td4328-1080p-video.dtsi" +#include "dsi-panel-td4328-1080p-cmd.dtsi" +#include + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_sim_vid_display: qcom,dsi-display@0 { + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@1 { + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_hx83112a_truly_vid_display: qcom,dsi-display@2 { + label = "dsi_hx83112a_truly_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_hx83112a_truly_video>; + }; + + dsi_td4328_truly_vid_display: qcom,dsi-display@3 { + label = "dsi_td4328_truly_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_td4328_truly_video>; + }; + + dsi_td4328_truly_cmd_display: qcom,dsi-display@4 { + label = "dsi_td4328_truly_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_td4328_truly_cmd>; + }; + + sde_dsi: qcom,dsi-display { + compatible = "qcom,dsi-display"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + + clocks = <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 90 0>; + + vddio-supply = <&pm6150_l13>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + + qcom,dsi-display-list = + <&dsi_sim_vid_display + &dsi_sim_cmd_display + &dsi_hx83112a_truly_vid_display + &dsi_td4328_truly_vid_display + &dsi_td4328_truly_cmd_display>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + 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"; + }; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi>; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-display-timings { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-display-timings { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@1{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@2{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_hx83112a_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_td4328_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x32>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 1d 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_td4328_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x32>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 1d 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ae37a8c22eb7f436d59bdcaedab13289395a0d83 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi @@ -0,0 +1,64 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94400 { + compatible = "qcom,mdss_dsi_pll_14nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94400 0x588>, + <0xaf03000 0x8>; + reg-names = "pll_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + status = "disabled"; + compatible = "qcom,mdss_dp_pll_7nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "gcc_iface", + "ref_clk", "pipe_clk"; + clock-rate = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7804c58b579b2eb0a8cd6d4bf2518401dfdf5440 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi @@ -0,0 +1,547 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x84208>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0x214>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_HF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 256000000 19200000 256000000>; + clock-max-rate = <0 0 0 307000000 19200000 307000000>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&apps_smmu 0x800 0x0>; + + #address-cells = <1>; + #size-cells = <0>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x45c>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800 0x2a00>; + qcom,sde-ctl-size = <0x1e0>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 + 0x0 0x0 0x0>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "none", "none", + "none", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000>; + qcom,sde-dspp-size = <0x1800>; + + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x3b8 24>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "dp", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000>; + qcom,sde-pp-slave = <0x0 0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + + + qcom,sde-te2-off = <0x2000 0x2000 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "dma", "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x25000 0x27000 0x29000 + 0x2b000>; + qcom,sde-sspp-src-size = <0x1f0>; + + qcom,sde-sspp-xin-id = <0 1 5 9 13>; + qcom,sde-sspp-excl-rect = <1 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <5 1 2 3 4>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <3 0 1 0 0 0>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-max-per-pipe-bw-kbps = <4500000 + 4500000 4500000 + 4500000 4500000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2ac 8>, <0x2b4 8>, <0x2bc 8>, + <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2160>; + qcom,sde-wb-linewidth = <2160>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + + qcom,sde-max-bw-low-kbps = <4800000>; + qcom,sde-max-bw-high-kbps = <4800000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x0000000f 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff8>; + qcom,sde-safe-lut-macrotile = <0 0xf000>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xf000>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0xffff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010001>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + + qcom,sde-secure-sid-mask = <0x0000801>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-inverse-pma; + }; + + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040001>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x801 0x0>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 4800000>, + <22 512 0 4800000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <1>; + status = "disabled"; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + clock-rate = <0 0 0>; + + qcom,sde-dram-channels = <2>; + + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20003 20515 0 0>, + <20003 20515 0 4800000>, + <20003 20515 0 4800000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator@ae00000 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0xc40 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0xc41 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.3"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm6150l_l3>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1232000>; + qcom,supply-max-voltage = <1232000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v2.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x588>; + reg-names = "dsi_phy"; + vdda-0p9-supply = <&pm6150_l4>; + qcom,platform-strength-ctrl = [ff 06 + ff 06 + ff 06 + ff 06 + ff 00]; + qcom,platform-lane-config = [00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 8f]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <975000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + sde_dp: qcom,dp_display@0{ + status = "disabled"; + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&pm6150l_l3>; + vdda-0p9-supply = <&pm6150_l4>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>, + <0xae91000 0x094>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + qcom,phy-version = <0x420>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,mst-enable; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi index fe5a89d4ced9d496674b29b7d9548d9097d70782..f47d16937319f90936558fff5b4e5a3a6c7e578e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi @@ -176,3 +176,7 @@ }; }; }; + +&mdss_mdp { + #cooling-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi index 87c52ad023a37a6b88bc7b68373966aeaa2f7bc4..bcc831e3c16d358ff76cf5033a6485b38aa5ae08 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi @@ -21,7 +21,7 @@ interrupts = ; qcom,affinity = <0>; reg = <0x18358800 0x1000>, - <0x18321000 0x1000>; + <0x18323000 0x1000>; #thermal-sensor-cells = <0>; }; @@ -30,7 +30,7 @@ interrupts = ; qcom,affinity = <1>; reg = <0x18350800 0x1000>, - <0x18323000 0x1000>; + <0x18325800 0x1000>; #thermal-sensor-cells = <0>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi index 7ba008e638686bce0aa0b8f1c997639c420a5227..73150062fa224e899c2473efae286d3d08b1e7b2 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi @@ -26,8 +26,9 @@ #size-cells = <1>; ranges; - interrupts = <0 130 0>, <0 607 0>, <0 131 0>; - interrupt-names = "pwr_event_irq", "ss_phy_irq", "hs_phy_irq"; + interrupts = <0 489 0>, <0 130 0>, <0 607 0>, <0 488 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; qcom,use-pdc-interrupts; USB3_GDSC-supply = <&usb30_prim_gdsc>; @@ -49,7 +50,7 @@ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,msm-bus,name = "usb0"; - qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <3>; qcom,msm-bus,vectors-KBps = /* suspend vote */ @@ -86,8 +87,6 @@ snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; snps,usb3_lpm_capable; - snps,ssp-u3-u0-quirk; - snps,usb3-u1u2-disable; usb-core-id = <0>; maximum-speed = "super-speed"; dr_mode = "otg"; @@ -136,7 +135,7 @@ vdd-supply = <&pm6150_l4>; vdda18-supply = <&pm6150_l11>; vdda33-supply = <&pm6150_l17>; - qcom,vdd-voltage-level = <0 875000 875000>; + qcom,vdd-voltage-level = <0 925000 975000>; qcom,tune2-efuse-bit-pos = <25>; qcom,tune2-efuse-num-bits = <4>; qcom,qusb-phy-init-seq = <0xf8 0x80 @@ -164,13 +163,13 @@ /* Primary USB port related QMP USB PHY */ usb_qmp_phy: ssphy@88e6000 { - compatible = "qcom,usb-ssphy-qmp-dp-combo"; + compatible = "qcom,usb-ssphy-qmp-v2"; reg = <0x88e6000 0x1000>; reg-names = "qmp_phy_base"; vdd-supply = <&pm6150_l4>; core-supply = <&pm6150_l11>; - qcom,vdd-voltage-level = <0 875000 875000>; + qcom,vdd-voltage-level = <0 925000 975000>; qcom,core-voltage-level = <0 1800000 1800000>; qcom,qmp-phy-init-seq = /* */ @@ -292,13 +291,15 @@ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, - <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&clock_gcc GCC_AHB2PHY_WEST_CLK>; clock-names = "aux_clk", "pipe_clk", "ref_clk_src", - "ref_clk", "com_aux_clk"; + "ref_clk", "com_aux_clk", "cfg_ahb_clk"; - resets = <&clock_gcc GCC_USB30_PRIM_BCR>; - reset-names = "phy_reset"; + resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_SP0_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_PRIM_SP0_BCR>; + reset-names = "phy_phy_reset", "phy_reset"; }; usb_audio_qmi_dev { @@ -324,8 +325,9 @@ #size-cells = <1>; ranges; - interrupts = <0 664 0>, <0 663 0>; - interrupt-names = "pwr_event_irq", "hs_phy_irq"; + interrupts = <0 491 0>, <0 663 0>, <0 490 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "dm_hs_phy_irq"; qcom,use-pdc-interrupts; USB3_GDSC-supply = <&usb20_sec_gdsc>; @@ -341,10 +343,9 @@ resets = <&clock_gcc GCC_USB20_SEC_BCR>; reset-names = "core_reset"; - qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate = <120000000>; qcom,core-clk-rate-hs = <66666667>; - qcom,num-gsi-evt-buffs = <0x3>; - qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,charging-disabled; qcom,msm-bus,name = "usb1"; @@ -362,7 +363,7 @@ compatible = "snps,dwc3"; reg = <0xa800000 0xcd00>; interrupt-parent = <&intc>; - interrupts = <0 665 0>; + interrupts = <0 664 0>; usb-phy = <&qusb_phy1>, <&usb_nop_phy>; tx-fifo-resize; linux,sysdev_is_parent; @@ -385,7 +386,7 @@ vdd-supply = <&pm6150_l4>; vdda18-supply = <&pm6150_l11>; vdda33-supply = <&pm6150_l17>; - qcom,vdd-voltage-level = <0 875000 875000>; + qcom,vdd-voltage-level = <0 925000 975000>; qcom,qusb-phy-init-seq = <0xf8 0x80 0xb3 0x84 0x83 0x88 diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts index ba198fbdcd1a9929ec2b0903b20c9f0cfe94403c..634d127d31eeb406e33619ea658cf5c58057f67f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" @@ -23,3 +24,7 @@ qcom,msm-id = <355 0x0>; qcom,board-id = <34 2>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi index 539d3866ba80b90b8dd7eb0bf16d054c9f9ec078..0772619d8dea60ad5ea96ba8043da33aff081330 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi @@ -17,12 +17,24 @@ }; }; +#include + &wsa_macro { swr_0: wsa_swr_master { compatible = "qcom,swr-mstr"; #address-cells = <2>; #size-cells = <0>; - + qcom,swr_master_id = <1>; + swrm-io-base = <0x62f10000 0x0>; + interrupts = <0 136 0>; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr-num-dev = <2>; wsa881x_0211: wsa881x@20170211 { compatible = "qcom,wsa881x"; reg = <0x0 0x20170211>; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 2ffed070f41804dd33bcf90cd94a43d9da82b2ca..d06dcc9ac8fa5cfa2f2baa859df3615f27ab0591 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -384,6 +384,7 @@ CPU_COST_0: core-cost0 { busy-cost-data = < + 300000 24 576000 25 748800 31 1017600 54 @@ -391,6 +392,7 @@ 1363200 105 1516800 116 1593600 139 + 1708800 168 1804800 178 >; idle-cost-data = < @@ -400,6 +402,7 @@ CPU_COST_1: core-cost1 { busy-cost-data = < + 300000 180 652800 236 768000 273 979200 446 @@ -409,6 +412,7 @@ 1516800 989 1708800 1276 1900800 1652 + 2016000 2040 2112000 2242 2208000 2713 >; @@ -419,6 +423,7 @@ CLUSTER_COST_0: cluster-cost0 { busy-cost-data = < + 300000 8 576000 8 748800 9 1017600 12 @@ -426,6 +431,7 @@ 1363200 18 1516800 21 1593600 22 + 1708800 23 1804800 24 >; idle-cost-data = < @@ -435,17 +441,19 @@ CLUSTER_COST_1: cluster-cost1 { busy-cost-data = < - 652800 26 - 768000 27 - 979200 36 - 1017600 45 - 1209600 55 - 1363200 64 - 1516800 66 - 1708800 72 - 1900800 77 - 2112000 84 - 2208000 90 + 300000 28 + 652800 35 + 768000 36 + 979200 48 + 1017600 59 + 1209600 73 + 1363200 86 + 1516800 88 + 1708800 96 + 1900800 103 + 2016000 107 + 2112000 112 + 2208000 120 >; idle-cost-data = < 4 3 2 1 @@ -467,6 +475,10 @@ firmware: firmware { android { compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; fstab { compatible = "android,fstab"; vendor { @@ -638,511 +650,281 @@ }; }; - llcc_pmu: llcc-pmu@90cc000 { - compatible = "qcom,qcom-llcc-pmu"; - reg = <0x090cc000 0x300>; - reg-names = "lagg-base"; + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-mlp356477-2800mah.dtsi" }; +}; - llcc_bw_opp_table: llcc-bw-opp-table { - compatible = "operating-points-v2"; - BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ - BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ - BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ - BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ - BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ - BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + interrupt-parent = <&intc>; }; - cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&llcc_bw_opp_table>; + pdc: interrupt-controller@b220000{ + compatible = "qcom,pdc-sm6150"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; }; - cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { - compatible = "qcom,bimc-bwmon4"; - reg = <0x90b6400 0x300>, <0x90b6300 0x200>; - reg-names = "base", "global_base"; - interrupts = ; - qcom,mport = <0>; - qcom,hw-timer-hz = <19200000>; - qcom,target-dev = <&cpu_cpu_llcc_bw>; - qcom,count-unit = <0x10000>; + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; }; - ddr_bw_opp_table: ddr-bw-opp-table { - compatible = "operating-points-v2"; - BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ - BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ - BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ - BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ - BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ - BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ - BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ - BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ - BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ - BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + timer@0x17c20000{ + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c20000 0x1000>; + clock-frequency = <19200000>; + + frame@0x17c21000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 6 0x4>; + reg = <0x17c21000 0x1000>, + <0x17c22000 0x1000>; + }; + + frame@17c23000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0x17c23000 0x1000>; + status = "disabled"; + }; + + frame@17c25000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0x17c25000 0x1000>; + status = "disabled"; + }; + + frame@17c27000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0x17c27000 0x1000>; + status = "disabled"; + }; + + frame@17c29000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0x17c29000 0x1000>; + status = "disabled"; + }; + + frame@17c2b000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0x17c2b000 0x1000>; + status = "disabled"; + }; + + frame@17c2d000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0x17c2d000 0x1000>; + status = "disabled"; + }; }; - cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; + clocks { + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + clock-output-names = "chip_sleep_clk"; + #clock-cells = <1>; + }; }; - cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { - compatible = "qcom,bimc-bwmon5"; - reg = <0x90cd000 0x1000>; - reg-names = "base"; - interrupts = ; - qcom,hw-timer-hz = <19200000>; - qcom,target-dev = <&cpu_llcc_ddr_bw>; - qcom,count-unit = <0x10000>; + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sm6150"; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + #clock-cells = <1>; }; - suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { - compatible = "operating-points-v2"; - BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ - BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ - BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ - BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ - BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ - BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ - BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ - BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ - BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ - BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ - BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + clock_aop: qcom,aopclk { + compatible = "qcom,aop-qmp-clk"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; }; - cdsp_cdsp_l3_lat: qcom,cdsp-cdsp-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; - governor = "powersave"; + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-sm6150", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + #clock-cells = <1>; + #reset-cells = <1>; }; - cpu0_cpu_l3_lat: qcom,cpu0-cpu-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; - governor = "performance"; + clock_videocc: qcom,videocc@ab00000 { + compatible = "qcom,videocc-sm6150", "syscon"; + reg = <0xab00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; }; - cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_cpu_l3_lat>; - qcom,cachemiss-ev = <0x17>; - qcom,core-dev-table = - < 576000 300000000 >, - < 1017600 556800000 >, - < 1209660 806400000 >, - < 1516800 940800000 >, - < 1804800 1363200000 >; + clock_camcc: qcom,camcc@ad00000 { + compatible = "qcom,camcc-sm6150", "syscon"; + reg = <0xad00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; }; - cpu6_cpu_l3_lat: qcom,cpu6-cpu-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; - governor = "performance"; + clock_dispcc: qcom,dispcc@af00000 { + compatible = "qcom,dispcc-sm6150", "syscon"; + reg = <0xaf00000 0x20000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; }; - cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_cpu_l3_lat>; - qcom,cachemiss-ev = <0x17>; - qcom,core-dev-table = - < 1017600 556800000 >, - < 1209600 806400000 >, - < 1516800 940800000 >, - < 1708800 1209600000 >, - < 2208000 1363200000 >; + clock_gpucc: qcom,gpupcc@5090000 { + compatible = "qcom,gpucc-sm6150", "syscon"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; }; - cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&llcc_bw_opp_table>; + cpucc_debug: syscon@182a0018 { + compatible = "syscon"; + reg = <0x182a0018 0x4>; }; - cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_cpu_llcc_lat>; - qcom,cachemiss-ev = <0x2A>; - qcom,core-dev-table = - < 748000 MHZ_TO_MBPS(150, 16) >, - < 1209600 MHZ_TO_MBPS(300, 16) >, - < 1516800 MHZ_TO_MBPS(466, 16) >, - < 1804800 MHZ_TO_MBPS(600, 16) >; - }; - - cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&llcc_bw_opp_table>; - }; - - cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_cpu_llcc_lat>; - qcom,cachemiss-ev = <0x2A>; - qcom,core-dev-table = - < 768000 MHZ_TO_MBPS(300, 16) >, - < 1017600 MHZ_TO_MBPS(466, 16) >, - < 1209600 MHZ_TO_MBPS(600, 16) >, - < 1708800 MHZ_TO_MBPS(806, 16) >, - < 2208000 MHZ_TO_MBPS(933, 16) >; - }; - - cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_llcc_ddr_lat>; - qcom,cachemiss-ev = <0x1000>; - qcom,core-dev-table = - < 748000 MHZ_TO_MBPS( 300, 4) >, - < 1017600 MHZ_TO_MBPS( 451, 4) >, - < 1209600 MHZ_TO_MBPS( 547, 4) >, - < 1516800 MHZ_TO_MBPS( 768, 4) >, - < 1804800 MHZ_TO_MBPS(1017, 4) >; - }; - - cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_llcc_ddr_lat>; - qcom,cachemiss-ev = <0x1000>; - qcom,core-dev-table = - < 768000 MHZ_TO_MBPS( 451, 4) >, - < 1017600 MHZ_TO_MBPS( 547, 4) >, - < 1209600 MHZ_TO_MBPS(1017, 4) >, - < 1708800 MHZ_TO_MBPS(1555, 4) >, - < 2208000 MHZ_TO_MBPS(1804, 4) >; - }; - - cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu0_computemon: qcom,cpu0-computemon { - compatible = "qcom,arm-cpu-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; - qcom,core-dev-table = - < 748800 MHZ_TO_MBPS( 300, 4) >, - < 1209600 MHZ_TO_MBPS( 451, 4) >, - < 1593600 MHZ_TO_MBPS( 547, 4) >, - < 1804800 MHZ_TO_MBPS( 768, 4) >; - }; - - cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu6_computemon: qcom,cpu6-computemon { - compatible = "qcom,arm-cpu-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; - qcom,core-dev-table = - < 1017600 MHZ_TO_MBPS( 300, 4) >, - < 1209600 MHZ_TO_MBPS( 547, 4) >, - < 1516800 MHZ_TO_MBPS( 768, 4) >, - < 1708800 MHZ_TO_MBPS(1017, 4) >, - < 2208000 MHZ_TO_MBPS(1804, 4) >; + mccc_debug: syscon@90b0000 { + compatible = "syscon"; + reg = <0x90b0000 0x1000>; + }; + + clock_cpucc: qcom,cpucc@18321000 { + compatible = "qcom,clk-cpu-osm-sm6150"; + reg = <0x18321000 0x1400>, + <0x18323000 0x1400>, + <0x18325800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", + "osm_perfcl_base"; + l3-devs = <&cpu0_cpu_l3_lat &cpu6_cpu_l3_lat + &cdsp_cdsp_l3_lat &msm_gpu>; + #clock-cells = <1>; }; -}; - -&soc { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0 0 0xffffffff>; - compatible = "simple-bus"; - intc: interrupt-controller@17a00000 { - compatible = "arm,gic-v3"; - #interrupt-cells = <3>; - interrupt-controller; - #redistributor-regions = <1>; - redistributor-stride = <0x0 0x20000>; - reg = <0x17a00000 0x10000>, /* GICD */ - <0x17a60000 0x100000>; /* GICR * 8 */ - interrupts = <1 9 4>; - interrupt-parent = <&intc>; + clock_debugcc: qcom,cc-debug { + compatible = "qcom,debugcc-sm6150"; + qcom,gcc = <&clock_gcc>; + qcom,videocc = <&clock_videocc>; + qcom,camcc = <&clock_camcc>; + qcom,dispcc = <&clock_dispcc>; + qcom,gpucc = <&clock_gpucc>; + qcom,cpucc = <&cpucc_debug>; + qcom,mccc = <&mccc_debug>; + clock-names = "cxo"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + #clock-cells = <1>; }; - pdc: interrupt-controller@b220000{ - compatible = "qcom,pdc-sm6150"; - reg = <0xb220000 0x400>; - #interrupt-cells = <3>; - interrupt-parent = <&intc>; - interrupt-controller; + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 5 4>; }; - timer { - compatible = "arm,armv8-timer"; - interrupts = <1 1 0xf08>, - <1 2 0xf08>, - <1 3 0xf08>, - <1 0 0xf08>; - clock-frequency = <19200000>; + dsu_pmu@0 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, + <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>; }; - timer@0x17c20000{ + qcom,msm-imem@146aa000 { + compatible = "qcom,msm-imem"; + reg = <0x146aa000 0x1000>; + ranges = <0x0 0x146aa000 0x1000>; #address-cells = <1>; #size-cells = <1>; - ranges; - compatible = "arm,armv7-timer-mem"; - reg = <0x17c20000 0x1000>; - clock-frequency = <19200000>; - frame@0x17c21000 { - frame-number = <0>; - interrupts = <0 8 0x4>, - <0 6 0x4>; - reg = <0x17c21000 0x1000>, - <0x17c22000 0x1000>; + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; }; - frame@17c23000 { - frame-number = <1>; - interrupts = <0 9 0x4>; - reg = <0x17c23000 0x1000>; - status = "disabled"; + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; }; - frame@17c25000 { - frame-number = <2>; - interrupts = <0 10 0x4>; - reg = <0x17c25000 0x1000>; - status = "disabled"; + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; }; - frame@17c27000 { - frame-number = <3>; - interrupts = <0 11 0x4>; - reg = <0x17c27000 0x1000>; - status = "disabled"; + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; }; - frame@17c29000 { - frame-number = <4>; - interrupts = <0 12 0x4>; - reg = <0x17c29000 0x1000>; - status = "disabled"; + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; }; - frame@17c2b000 { - frame-number = <5>; - interrupts = <0 13 0x4>; - reg = <0x17c2b000 0x1000>; - status = "disabled"; + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; }; - frame@17c2d000 { - frame-number = <6>; - interrupts = <0 14 0x4>; - reg = <0x17c2d000 0x1000>; - status = "disabled"; + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; }; }; - clocks { - sleep_clk: sleep-clk { - compatible = "fixed-clock"; - clock-frequency = <32000>; - clock-output-names = "chip_sleep_clk"; - #clock-cells = <1>; - }; + restart@c264000 { + compatible = "qcom,pshold"; + reg = <0xc264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; - clock_rpmh: qcom,rpmhclk { - compatible = "qcom,rpmh-clk-sm6150"; - mboxes = <&apps_rsc 0>; - mbox-names = "apps"; - #clock-cells = <1>; - }; - - clock_aop: qcom,aopclk { - compatible = "qcom,aop-qmp-clk"; - #clock-cells = <1>; - mboxes = <&qmp_aop 0>; - mbox-names = "qdss_clk"; - }; - - clock_gcc: qcom,gcc@100000 { - compatible = "qcom,gcc-sm6150", "syscon"; - reg = <0x100000 0x1f0000>; - reg-names = "cc_base"; - vdd_cx-supply = <&VDD_CX_LEVEL>; - vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_videocc: qcom,videocc@ab00000 { - compatible = "qcom,videocc-sm6150", "syscon"; - reg = <0xab00000 0x10000>; - reg-names = "cc_base"; - vdd_cx-supply = <&VDD_CX_LEVEL>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_camcc: qcom,camcc@ad00000 { - compatible = "qcom,camcc-sm6150", "syscon"; - reg = <0xad00000 0x10000>; - reg-names = "cc_base"; - vdd_cx-supply = <&VDD_CX_LEVEL>; - vdd_mx-supply = <&VDD_MX_LEVEL>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_dispcc: qcom,dispcc@af00000 { - compatible = "qcom,dispcc-sm6150", "syscon"; - reg = <0xaf00000 0x20000>; - reg-names = "cc_base"; - vdd_cx-supply = <&VDD_CX_LEVEL>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_gpucc: qcom,gpupcc@5090000 { - compatible = "qcom,gpucc-sm6150", "syscon"; - reg = <0x5090000 0x9000>; - reg-names = "cc_base"; - vdd_cx-supply = <&VDD_CX_LEVEL>; - vdd_mx-supply = <&VDD_MX_LEVEL>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_cpucc: qcom,cpucc { - compatible = "qcom,dummycc"; - clock-output-names = "cpucc_clocks"; - #clock-cells = <1>; - }; - - clock_debugcc: qcom,cc-debug { - compatible = "qcom,debugcc-sm6150"; - qcom,gcc = <&clock_gcc>; - qcom,videocc = <&clock_videocc>; - qcom,camcc = <&clock_camcc>; - qcom,dispcc = <&clock_dispcc>; - qcom,gpucc = <&clock_gpucc>; - clock-names = "cxo"; - clocks = <&clock_rpmh RPMH_CXO_CLK>; - #clock-cells = <1>; - }; - - cpu_pmu: cpu-pmu { - compatible = "arm,armv8-pmuv3"; - qcom,irq-is-percpu; - interrupts = <1 5 4>; - }; - - dsu_pmu@0 { - compatible = "arm,dsu-pmu"; - interrupts = ; - cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, - <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>; - }; - - qcom,msm-imem@146aa000 { - compatible = "qcom,msm-imem"; - reg = <0x146aa000 0x1000>; - ranges = <0x0 0x146aa000 0x1000>; - #address-cells = <1>; - #size-cells = <1>; - - mem_dump_table@10 { - compatible = "qcom,msm-imem-mem_dump_table"; - reg = <0x10 8>; - }; - - restart_reason@65c { - compatible = "qcom,msm-imem-restart_reason"; - reg = <0x65c 4>; - }; - - boot_stats@6b0 { - compatible = "qcom,msm-imem-boot_stats"; - reg = <0x6b0 32>; - }; - - kaslr_offset@6d0 { - compatible = "qcom,msm-imem-kaslr_offset"; - reg = <0x6d0 12>; - }; - - pil@94c { - compatible = "qcom,msm-imem-pil"; - reg = <0x94c 200>; - }; - - diag_dload@c8 { - compatible = "qcom,msm-imem-diag-dload"; - reg = <0xc8 200>; - }; - }; - - restart@c264000 { - compatible = "qcom,pshold"; - reg = <0xc264000 0x4>, - <0x1fd3000 0x4>; - reg-names = "pshold-base", "tcsr-boot-misc-detect"; - }; - - qcom,mpm2-sleep-counter@0xc221000 { - compatible = "qcom,mpm2-sleep-counter"; - reg = <0xc221000 0x1000>; - clock-frequency = <32768>; + qcom,mpm2-sleep-counter@0xc221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; }; qcom,sps { @@ -1202,6 +984,8 @@ qcom,pet-time = <9360>; qcom,ipi-ping; qcom,wakeup-enable; + qcom,scandump-sizes = <0x10100 0x10100 0x10100 0x10100 + 0x10100 0x10100 0x25900 0x25900>; }; qcom,chd_sliver { @@ -1471,9 +1255,9 @@ interrupts = <0 129 0>; #mbox-cells = <1>; qcom,drv-id = <0>; - qcom,tcs-config = , - , + qcom,tcs-config = , , + , ; }; @@ -1579,6 +1363,44 @@ status = "disabled"; }; + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 0xe00000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + qcom,appsbl-qseecom-support; + qcom,commonlib64-loaded-by-uefi; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_smcinvoke: smcinvoke@86d00000 { + compatible = "qcom,smcinvoke"; + reg = <0x86d00000 0xe00000>; + reg-names = "secapp-region"; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 300000>; /* 75 MHz */ + clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + ufsphy_mem: ufsphy_mem@1d87000 { reg = <0x1d87000 0xdb8>; /* PHY regs */ reg-names = "phy_mem"; @@ -1626,10 +1448,10 @@ <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; freq-table-hz = - <37500000 300000000>, + <50000000 240000000>, <0 0>, <0 0>, - <37500000 300000000>, + <37500000 150000000>, <75000000 300000000>, <0 0>, <0 0>, @@ -1684,9 +1506,70 @@ status = "disabled"; }; + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0106 0x0011>, + <&apps_smmu 0x0116 0x0011>; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0104 0x0011>, + <&apps_smmu 0x0114 0x0011>; + }; + + qcom_tzlog: tz-log@146aa720 { + compatible = "qcom,tz-log"; + reg = <0x146aa720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; - reg = <0xc440000 0x2300>, + reg = <0xc440000 0x1100>, <0xc600000 0x2000000>, <0xe600000 0x100000>, <0xe700000 0xa0000>, @@ -1696,8 +1579,8 @@ interrupts = ; qcom,ee = <0>; qcom,channel = <0>; - #address-cells = <2>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <1>; interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; @@ -2113,6 +1996,18 @@ interrupt-controller; #interrupt-cells = <2>; }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; qcom,smp2p-adsp { @@ -2351,7 +2246,7 @@ interrupts = <0 311 0>, <0 432 0>; interrupt-names = "ipa-irq", "gsi-irq"; qcom,ipa-hw-ver = <16>; /* IPA core version = IPAv4.2 */ - qcom,ipa-hw-mode = <1>; + qcom,ipa-hw-mode = <0>; qcom,ee = <0>; qcom,use-ipa-tethering-bridge; qcom,modem-cfg-emb-pipe-flt; @@ -2360,6 +2255,8 @@ qcom,ipa-fltrt-not-hashable; qcom,use-64-bit-dma-mask; qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,use-ipa-pm; qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; qcom,msm-bus,num-cases = <5>; @@ -2392,7 +2289,45 @@ ; qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x1520 0x0>; + qcom,iova-mapping = <0x20000000 0x40000000>; + /* modem tables in IMEM */ + qcom,additional-mapping = <0x146bd000 0x146bd000 0x2000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x1521 0x0>; + /* ipa-uc ram */ + qcom,additional-mapping = <0x1e60000 0x1e60000 0x80000>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x1522 0x0>; + qcom,iova-mapping = <0x40400000 0x1fc00000>; }; qcom,ipa_fws { @@ -2404,10 +2339,12 @@ }; icnss: qcom,icnss@18800000 { - status = "disabled"; compatible = "qcom,icnss"; - reg = <0x18800000 0x800000>; - reg-names = "membase"; + reg = <0x18800000 0x800000>, + <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x1640 0x1>; interrupts = <0 414 0 /* CE0 */ >, <0 415 0 /* CE1 */ >, <0 416 0 /* CE2 */ >, @@ -2422,12 +2359,280 @@ <0 425 0 /* CE11 */ >; qcom,smmu-s1-bypass; qcom,wlan-msa-memory = <0x100000>; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; vdd-0.8-cx-mx-supply = <&pm6150_l9>; vdd-1.8-xo-supply = <&pm6150l_l1>; vdd-1.3-rfa-supply = <&pm6150l_l2>; vdd-3.3-ch0-supply = <&pm6150l_l10>; qcom,vdd-0.8-cx-mx-config = <640000 640000>; }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + }; + + llcc_pmu: llcc-pmu@90cc000 { + compatible = "qcom,qcom-llcc-pmu"; + reg = <0x090cc000 0x300>; + reg-names = "lagg-base"; + }; + + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x90b6300 0x300>, <0x90b6200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90cd000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cdsp_cdsp_l3_lat: qcom,cdsp-cdsp-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; + governor = "powersave"; + }; + + cpu0_cpu_l3_lat: qcom,cpu0-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; + governor = "performance"; + }; + + cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 576000 300000000 >, + < 1017600 556800000 >, + < 1209660 806400000 >, + < 1516800 940800000 >, + < 1804800 1363200000 >; + }; + + cpu6_cpu_l3_lat: qcom,cpu6-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; + governor = "performance"; + }; + + cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 1017600 556800000 >, + < 1209600 806400000 >, + < 1516800 940800000 >, + < 1708800 1209600000 >, + < 2208000 1363200000 >; + }; + + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 748000 MHZ_TO_MBPS(150, 16) >, + < 1209600 MHZ_TO_MBPS(300, 16) >, + < 1516800 MHZ_TO_MBPS(466, 16) >, + < 1804800 MHZ_TO_MBPS(600, 16) >; + }; + + cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS(300, 16) >, + < 1017600 MHZ_TO_MBPS(466, 16) >, + < 1209600 MHZ_TO_MBPS(600, 16) >, + < 1708800 MHZ_TO_MBPS(806, 16) >, + < 2208000 MHZ_TO_MBPS(933, 16) >; + }; + + cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 748000 MHZ_TO_MBPS( 300, 4) >, + < 1017600 MHZ_TO_MBPS( 451, 4) >, + < 1209600 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS( 451, 4) >, + < 1017600 MHZ_TO_MBPS( 547, 4) >, + < 1209600 MHZ_TO_MBPS(1017, 4) >, + < 1708800 MHZ_TO_MBPS(1555, 4) >, + < 2208000 MHZ_TO_MBPS(1804, 4) >; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 748800 MHZ_TO_MBPS( 300, 4) >, + < 1209600 MHZ_TO_MBPS( 451, 4) >, + < 1593600 MHZ_TO_MBPS( 547, 4) >, + < 1804800 MHZ_TO_MBPS( 768, 4) >; + }; + + cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_computemon: qcom,cpu6-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1017600 MHZ_TO_MBPS( 300, 4) >, + < 1209600 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1708800 MHZ_TO_MBPS(1017, 4) >, + < 2208000 MHZ_TO_MBPS(1804, 4) >; + }; }; #include "pm6150.dtsi" @@ -2443,11 +2648,11 @@ &pm6150_charger { dpdm-supply = <&qusb_phy0>; + qcom,suspend-input-on-debug-batt; }; &usb0 { extcon = <&pm6150_pdphy>; - vbus_dwc3-supply = <&smb5_vbus>; }; &pm6150_vadc { @@ -2667,9 +2872,12 @@ status = "ok"; }; +#include "sm6150-camera.dtsi" #include "sm6150-ion.dtsi" #include "msm-arm-smmu-sm6150.dtsi" #include "sm6150-coresight.dtsi" #include "sm6150-bus.dtsi" #include "sm6150-vidc.dtsi" #include "sm6150-audio.dtsi" +#include "sm6150-sde-pll.dtsi" +#include "sm6150-sde.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts index 6645a619958cb37b8cc9dca3f5cf4cf8111c09f9..a5423f1ef523a83604105c8b9fce4010be6dcb93 100644 --- a/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" @@ -23,3 +24,7 @@ qcom,msm-id = <369 0x0>; qcom,board-id = <34 0>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts index e6286ee3ca58c888d2e9b12e1cdb0f3622eb9c72..b08051cdc0c1bfe95fa4ade86a029a4cee0d6c7a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-qrd.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi index a4c32e4df8c1704fb1ef0ffec80fb0fd6c60f6de..f419222d6fd55ebb83d373f56ce11ec04eb87e0a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi @@ -666,6 +666,15 @@ qcom,prio = <2>; }; + mas_qhm_sensorss_ahb: mas-qhm-sensorss-ahb { + cell-id = ; + label = "mas-qhm-sensorss-ahb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + mas_qhm_tsif: mas-qhm-tsif { cell-id = ; label = "mas-qhm-tsif"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi index 5bfc2b8e562a60ee7f16c5a0915b53ca83861726..8acc37dddd575dfacd9cde189dfd0a43c681be6a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi @@ -242,8 +242,8 @@ clock-cntl-level = "lowsvs"; clock-rates = <37500000 0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cci2_active &cci2_active>; - pinctrl-1 = <&cci3_suspend &cci3_suspend>; + pinctrl-0 = <&cci2_active &cci3_active>; + pinctrl-1 = <&cci2_suspend &cci3_suspend>; gpios = <&tlmm 31 0>, <&tlmm 32 0>, <&tlmm 33 0>, diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index e20e54f343da62959601abc6f8f014dac85fdbe2..340bc0599bab07d97b2063bba3cb39e48351b9c5 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -199,10 +199,10 @@ }; port@1 { reg = <5>; - funnel_swao_in_funnel_ssc: endpoint { + funnel_swao_in_ssc_etm0: endpoint { slave-mode; remote-endpoint= - <&funnel_ssc_out_funnel_swao>; + <&ssc_etm0_out_funnel_swao>; }; }; port@2 { @@ -321,7 +321,12 @@ reg-names = "tmc-base", "bam-base"; qcom,smmu-s1-bypass; - iommus = <&apps_smmu 0x05e0 0>; + iommus = <&apps_smmu 0x05e0 0>, + <&apps_smmu 0x04a0 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + arm,buffer-size = <0x400000>; coresight-name = "coresight-tmc-etr"; @@ -2383,9 +2388,9 @@ qcom,inst-id = <8>; port { - ssc_etm0_out_funnel_ssc: endpoint { + ssc_etm0_out_funnel_swao: endpoint { remote-endpoint = - <&funnel_ssc_in_ssc_etm0>; + <&funnel_swao_in_ssc_etm0>; }; }; }; @@ -2710,39 +2715,4 @@ }; }; }; - - funnel_ssc: funnel@6b14000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b908>; - - reg = <0x6b14000 0x1000>; - reg-names = "funnel-base"; - - coresight-name = "coresight-funnel-ssc"; - - clocks = <&clock_aop QDSS_CLK>; - clock-names = "apb_pclk"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - funnel_ssc_out_funnel_swao: endpoint { - remote-endpoint = - <&funnel_swao_in_funnel_ssc>; - }; - }; - - port@1 { - reg = <0>; - funnel_ssc_in_ssc_etm0: endpoint { - slave-mode; - remote-endpoint = - <&ssc_etm0_out_funnel_ssc>; - }; - }; - }; - }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi index f83eb2a10064e22255c3ec9825a414393238f9b8..6baac00ed014ce78cc9a17c36846a17cb2bf5660 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi @@ -208,7 +208,7 @@ regulator-name = "gpu_cx_gdsc"; reg = <0x2c9106c 0x4>; hw-ctrl-addr = <&gpu_cx_hw_ctrl>; - qcom,no-status-check-on-disable; + qcom,skip-disable; qcom,gds-timeout = <500>; qcom,clk-dis-wait-val = <8>; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index 753d0627b09126961d15979260b1d52d3f0817c8..284c821e77fdc3328430575983af8b581ea3509f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -215,6 +215,7 @@ qcom,bus-freq = <12>; qcom,bus-min = <10>; qcom,bus-max = <12>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@1 { @@ -223,6 +224,7 @@ qcom,bus-freq = <10>; qcom,bus-min = <9>; qcom,bus-max = <11>; + qcom,dvm-val = <0xffffffff>; }; @@ -232,6 +234,7 @@ qcom,bus-freq = <9>; qcom,bus-min = <8>; qcom,bus-max = <10>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@3 { @@ -240,6 +243,7 @@ qcom,bus-freq = <8>; qcom,bus-min = <7>; qcom,bus-max = <9>; + qcom,dvm-val = <0xffffffff>; }; @@ -249,6 +253,7 @@ qcom,bus-freq = <5>; qcom,bus-min = <5>; qcom,bus-max = <7>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@5 { @@ -257,6 +262,7 @@ qcom,bus-freq = <4>; qcom,bus-min = <3>; qcom,bus-max = <5>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@6 { @@ -265,6 +271,7 @@ qcom,bus-freq = <0>; qcom,bus-min = <0>; qcom,bus-max = <0>; + qcom,dvm-val = <0xffffffff>; }; }; }; @@ -330,6 +337,10 @@ clock-names = "gmu_clk", "cxo_clk", "axi_clk", "memnoc_clk", "gpu_cc_ahb"; + /* AOP mailbox for sending ACD enable and disable messages */ + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + qcom,gmu-pwrlevels { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi index dd96699d55a3fd88c927185139a0c88868619123..86221703c85526dcb92030d0e2b3131804032ff9 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi @@ -11,858 +11,836 @@ * GNU General Public License for more details. */ -&pcie1 { - pci,bus@1 { - reg = <0 0 0 0 0>; - - mhi_0: qcom,mhi@0 { - reg = <0 0 0 0 0 >; - - /* controller specific configuration */ - qcom,smmu-cfg = <0x3>; - qcom,msm-bus,name = "mhi"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <100 512 0 0>, - <100 512 1200000000 650000000>; - - /* mhi bus specific settings */ - mhi,max-channels = <106>; - mhi,timeout = <2000>; - - #address-cells = <1>; - #size-cells = <0>; - - mhi_chan@0 { - reg = <0>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@1 { - reg = <1>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@2 { - reg = <2>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@3 { - reg = <3>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@4 { - reg = <4>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@5 { - reg = <5>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@8 { - reg = <8>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@9 { - reg = <9>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@10 { - reg = <10>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@11 { - reg = <11>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@14 { - reg = <14>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@15 { - reg = <15>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@16 { - reg = <16>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@17 { - reg = <17>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@18 { - reg = <18>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@19 { - reg = <19>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - mhi,auto-queue; - }; - - mhi_chan@20 { - reg = <20>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - mhi,auto-start; - }; - - mhi_chan@21 { - reg = <21>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - mhi,auto-queue; - mhi,auto-start; - }; - - mhi_chan@22 { - reg = <22>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@23 { - reg = <23>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@24 { - reg = <24>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@25 { - reg = <25>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@26 { - reg = <26>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@27 { - reg = <27>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@32 { - reg = <32>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@33 { - reg = <33>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@100 { - reg = <100>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <2>; - mhi,db-mode-switch; - }; - - mhi_chan@101 { - reg = <101>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <2>; - }; - - mhi_chan@104 { - reg = <104>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <3>; - mhi,ee = <2>; - mhi,offload-chan; - }; - - mhi_chan@105 { - reg = <105>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <3>; - mhi,ee = <2>; - mhi,offload-chan; - mhi,lpm-notify; - }; - - mhi_event@0 { - mhi,num-elements = <32>; - mhi,intmod = <1>; - mhi,msi = <1>; - mhi,priority = <1>; - mhi,brstmode = <2>; - mhi,data-type = <1>; - }; - - mhi_event@1 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <2>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@2 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <3>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@3 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <4>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@4 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <5>; - mhi,chan = <100>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - }; - - mhi_event@5 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <6>; - mhi,chan = <101>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - mhi,client-manage; - }; - - mhi_netdev_0: mhi_rmnet@0 { - reg = <0x0>; - mhi,chan = "IP_HW0"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; - - mhi_netdev_1: mhi_rmnet@1 { - reg = <0x1>; - mhi,chan = "IP_HW_ADPL"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; +&pcie_rc1 { + reg = <0 0 0 0 0>; + + mhi_0: qcom,mhi@0 { + reg = <0 0 0 0 0 >; + + /* controller specific configuration */ + qcom,smmu-cfg = <0x3>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 1200000000 650000000>; + + /* mhi bus specific settings */ + mhi,max-channels = <106>; + mhi,timeout = <2000>; + + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@2 { + reg = <2>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@3 { + reg = <3>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@8 { + reg = <8>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@9 { + reg = <9>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@10 { + reg = <10>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@11 { + reg = <11>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@14 { + reg = <14>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@15 { + reg = <15>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@16 { + reg = <16>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@17 { + reg = <17>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@18 { + reg = <18>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@19 { + reg = <19>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@22 { + reg = <22>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@23 { + reg = <23>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@25 { + reg = <25>; + label = "BL"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@26 { + reg = <26>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@27 { + reg = <27>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@32 { + reg = <32>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@33 { + reg = <33>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@100 { + reg = <100>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + mhi,db-mode-switch; + }; + + mhi_chan@101 { + reg = <101>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + }; + + mhi_chan@104 { + reg = <104>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@105 { + reg = <105>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_event@0 { + mhi,num-elements = <32>; + mhi,intmod = <1>; + mhi,msi = <1>; + mhi,priority = <1>; + mhi,brstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <2>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@2 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <3>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@3 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <4>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@4 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <5>; + mhi,chan = <100>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + }; + + mhi_event@5 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <6>; + mhi,chan = <101>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + }; + + mhi_netdev_0: mhi_rmnet@0 { + reg = <0x0>; + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; + }; + + mhi_netdev_1: mhi_rmnet@1 { + reg = <0x1>; + mhi,chan = "IP_HW_ADPL"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; }; }; }; -&pcie0 { - pci,bus@1 { - reg = <0 0 0 0 0>; - - mhi_1: qcom,mhi@0 { - reg = <0 0 0 0 0 >; - - /* controller specific configuration */ - qcom,smmu-cfg = <0x3>; - qcom,msm-bus,name = "mhi"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <45 512 0 0>, - <45 512 1200000000 650000000>; - - /* mhi bus specific settings */ - mhi,max-channels = <106>; - mhi,timeout = <2000>; - - #address-cells = <1>; - #size-cells = <0>; - - mhi_chan@0 { - reg = <0>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@1 { - reg = <1>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@2 { - reg = <2>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@3 { - reg = <3>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@4 { - reg = <4>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@5 { - reg = <5>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@8 { - reg = <8>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@9 { - reg = <9>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@10 { - reg = <10>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@11 { - reg = <11>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@14 { - reg = <14>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@15 { - reg = <15>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@16 { - reg = <16>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@17 { - reg = <17>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@18 { - reg = <18>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@19 { - reg = <19>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - mhi,auto-queue; - }; - - mhi_chan@20 { - reg = <20>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - mhi,auto-start; - }; - - mhi_chan@21 { - reg = <21>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - mhi,auto-queue; - mhi,auto-start; - }; - - mhi_chan@22 { - reg = <22>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@23 { - reg = <23>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@24 { - reg = <24>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@25 { - reg = <25>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <1>; - }; - - mhi_chan@26 { - reg = <26>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@27 { - reg = <27>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@32 { - reg = <32>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@33 { - reg = <33>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <2>; - }; - - mhi_chan@100 { - reg = <100>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <2>; - mhi,db-mode-switch; - }; - - mhi_chan@101 { - reg = <101>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <2>; - }; - - mhi_chan@104 { - reg = <104>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <3>; - mhi,ee = <2>; - mhi,offload-chan; - }; - - mhi_chan@105 { - reg = <105>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <3>; - mhi,ee = <2>; - mhi,offload-chan; - mhi,lpm-notify; - }; - - mhi_event@0 { - mhi,num-elements = <32>; - mhi,intmod = <1>; - mhi,msi = <1>; - mhi,priority = <1>; - mhi,brstmode = <2>; - mhi,data-type = <1>; - }; - - mhi_event@1 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <2>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@2 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <3>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@3 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <4>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@4 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <5>; - mhi,chan = <100>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - }; - - mhi_event@5 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <6>; - mhi,chan = <101>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - mhi,client-manage; - }; - - mhi_netdev_2: mhi_rmnet@0 { - reg = <0x0>; - mhi,chan = "IP_HW0"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; - - mhi_netdev_3: mhi_rmnet@1 { - reg = <0x1>; - mhi,chan = "IP_HW_ADPL"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; +&pcie_rc0 { + reg = <0 0 0 0 0>; + + mhi_1: qcom,mhi@0 { + reg = <0 0 0 0 0 >; + + /* controller specific configuration */ + qcom,smmu-cfg = <0x3>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 1200000000 650000000>; + + /* mhi bus specific settings */ + mhi,max-channels = <106>; + mhi,timeout = <2000>; + + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@2 { + reg = <2>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@3 { + reg = <3>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@8 { + reg = <8>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@9 { + reg = <9>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@10 { + reg = <10>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@11 { + reg = <11>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@14 { + reg = <14>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@15 { + reg = <15>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@16 { + reg = <16>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@17 { + reg = <17>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@18 { + reg = <18>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@19 { + reg = <19>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@22 { + reg = <22>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@23 { + reg = <23>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@25 { + reg = <25>; + label = "BL"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@26 { + reg = <26>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@27 { + reg = <27>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@32 { + reg = <32>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@33 { + reg = <33>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@100 { + reg = <100>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + mhi,db-mode-switch; + }; + + mhi_chan@101 { + reg = <101>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + }; + + mhi_chan@104 { + reg = <104>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@105 { + reg = <105>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_event@0 { + mhi,num-elements = <32>; + mhi,intmod = <1>; + mhi,msi = <1>; + mhi,priority = <1>; + mhi,brstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <2>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@2 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <3>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@3 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <4>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@4 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <5>; + mhi,chan = <100>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + }; + + mhi_event@5 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <6>; + mhi,chan = <101>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + }; + + mhi_netdev_2: mhi_rmnet@0 { + reg = <0x0>; + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; + }; + + mhi_netdev_3: mhi_rmnet@1 { + reg = <0x1>; + mhi,chan = "IP_HW_ADPL"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi index f11fc041bd2bd0c844539c399556c598039cb828..3c48494c30d2f4bbce08a9a90eeea0075a8c0e45 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi @@ -282,6 +282,10 @@ reset-names = "pcie_0_core_reset", "pcie_0_phy_reset"; + + pcie_rc0: pcie_rc0 { + reg = <0 0 0 0 0>; + }; }; pcie1: qcom,pcie@1c08000 { @@ -602,5 +606,9 @@ reset-names = "pcie_1_core_reset", "pcie_1_phy_reset"; + + pcie_rc1: pcie_rc1 { + reg = <0 0 0 0 0>; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index 67cdda3993e93d80cd1972dd02448e990fcb70af..13e81f156c47b1067b5c5bd1cbfb595d34c07b1d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -4017,6 +4017,66 @@ }; }; + tsif0_signals_active: tsif0_signals_active { + tsif1_clk { + pins = "gpio88"; /* TSIF0 CLK */ + function = "tsif1_clk"; + }; + tsif1_en { + pins = "gpio89"; /* TSIF0 Enable */ + function = "tsif1_en"; + }; + tsif1_data { + pins = "gpio90"; /* TSIF0 DATA */ + function = "tsif1_data"; + }; + signals_cfg { + pins = "gpio88", "gpio89", "gpio90"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif0_sync_active: tsif0_sync_active { + tsif1_sync { + pins = "gpio91"; /* TSIF0 SYNC */ + function = "tsif1_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + tsif1_signals_active: tsif1_signals_active { + tsif2_clk { + pins = "gpio92"; /* TSIF1 CLK */ + function = "tsif2_clk"; + }; + tsif2_en { + pins = "gpio93"; /* TSIF1 Enable */ + function = "tsif2_en"; + }; + tsif2_data { + pins = "gpio94"; /* TSIF1 DATA */ + function = "tsif2_data"; + }; + signals_cfg { + pins = "gpio92", "gpio93", "gpio94"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif1_sync_active: tsif1_sync_active { + tsif2_sync { + pins = "gpio95"; /* TSIF1 SYNC */ + function = "tsif2_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + trigout_a: trigout_a { mux { pins = "gpio49"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi index a737d8ff24fd2678fa6e0a3055d4276c56a7c2e5..c525073ac2afffb66c751f51722e8fccaf2b673d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi @@ -16,3 +16,14 @@ vdd-supply = <&pm8150_l18>; qcom,vdd-voltage-level = <0 912000 912000>; }; + +&sde_dp { + vdda-0p9-supply = <&pm8150_l18>; + qcom,phy-supply-entries { + qcom,phy-supply-entry@0 { + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <912000>; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index a24d7dedf0adfeb138e3068ce8f93bf1646a8ca4..c548de3b99df16a6c8f475168a0e48b0a77e7c23 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -190,10 +190,10 @@ compatible = "onnn,redriver"; reg = <0x19>; extcon = <&pm8150b_pdphy>, <&pm8150b_pdphy>; - eq = /bits/ 8 <0x5 0x4 0x4 0x5>; + eq = /bits/ 8 <0x4 0x4 0x4 0x4>; flat-gain = /bits/ 8 <0x3 0x1 0x1 0x3>; output-comp = /bits/ 8 <0x2 0x2 0x2 0x2>; - loss-match = /bits/ 8 <0x0 0x3 0x3 0x0>; + loss-match = /bits/ 8 <0x1 0x3 0x3 0x1>; }; }; @@ -521,6 +521,38 @@ status = "ok"; }; +&pm8150b_haptics { + qcom,vmax-mv = <2545>; + qcom,play-rate-us = <4255>; + wf_0 { + /* CLICK */ + qcom,wf-pattern = [3e 3e 3e 3e]; + qcom,wf-play-rate-us = <4255>; + }; + wf_1 { + /* DOUBLE CLICK */ + qcom,wf-play-rate-us = <7143>; + }; + wf_2 { + /* TICK */ + qcom,wf-play-rate-us = <4000>; + }; + wf_3 { + /* THUD */ + qcom,wf-pattern = [7e 7e 7e 7e]; + qcom,wf-play-rate-us = <4255>; + }; + wf_4 { + /* POP */ + qcom,wf-play-rate-us = <5000>; + }; + wf_5 { + /* HEAVY CLICK */ + qcom,wf-pattern = [7e 7e 7e 7e]; + qcom,wf-play-rate-us = <4255>; + }; +}; + &pm8150b_charger { qcom,sec-charger-config = <1>; qcom,auto-recharge-soc = <98>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index 6f8250cdfdaeda0d22777ddb92f9b6cc1a4e66ba..6deadd72e4d4484a83c61e23cc4ae2e56263c639 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -74,7 +74,7 @@ qcom,sde-dest-scaler-top-off = <0x00061000>; qcom,sde-dest-scaler-top-size = <0x1c>; qcom,sde-dest-scaler-off = <0x800 0x1000>; - qcom,sde-dest-scaler-size = <0x800>; + qcom,sde-dest-scaler-size = <0xa0>; qcom,sde-wb-off = <0x66000>; qcom,sde-wb-size = <0x2c8>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts index 0822195eddc932c9545d1ab86009aba15986d819..8d384978ba3a081832593f43e3fe4ddc88608b2d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts @@ -29,3 +29,11 @@ compatible = "qcom,sm8150-qrd", "qcom,sm8150", "qcom,qrd"; qcom,board-id = <11 1>; }; + +&cam_cci0 { + status = "disabled"; +}; + +&qupv3_se9_i2c { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index ba8679baa3e81a703f7a51ac191427ccc6cfaaab..0f66048824b6dc6d48cd9a7aac483f4261899946 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -159,10 +159,6 @@ iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, <0x100 &apps_smmu 0x1e7f 0x1>; - - qcom,no-l1-supported; - qcom,no-l1ss-supported; - qcom,no-aux-clk-sync; }; &soc { diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index 1c13601e4496b77419f0c4898cc51248a145f3df..32748b4672d18c2c4dbd9f75312412b99323edf6 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -40,6 +40,10 @@ }; }; +&tmc_etr { + /delete-property/ qcom,smmu-s1-bypass; +}; + &spss_utils { qcom,spss-dev-firmware-name = "spss2d"; /* 8 chars max */ qcom,spss-test-firmware-name = "spss2t"; /* 8 chars max */ @@ -402,15 +406,38 @@ qcom,bus-max = <0>; }; }; + + qcom,l3-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,l3-pwrlevels"; + + qcom,l3-pwrlevel@0 { + reg = <0>; + qcom,l3-freq = <0>; + }; + + qcom,l3-pwrlevel@1 { + reg = <1>; + qcom,l3-freq = <1344000000>; + }; + + qcom,l3-pwrlevel@2 { + reg = <2>; + qcom,l3-freq = <1612800000>; + }; + }; }; /* NPU overrides */ &msm_npu { + iommus = <&apps_smmu 0x1081 0x400>; qcom,npu-pwrlevels { #address-cells = <1>; #size-cells = <0>; compatible = "qcom,npu-pwrlevels"; - initial-pwrlevel = <3>; + initial-pwrlevel = <5>; qcom,npu-pwrlevel@0 { reg = <0>; clk-freq = <300000000 @@ -482,12 +509,12 @@ }; qcom,npu-pwrlevel@3 { reg = <3>; - clk-freq = <773000000 + clk-freq = <652000000 19200000 300000000 19200000 19200000 - 773000000 + 652000000 403000000 75000000 19200000 @@ -496,7 +523,7 @@ 150000000 300000000 19200000 - 773000000 + 652000000 19200000 0 0 @@ -505,6 +532,29 @@ }; qcom,npu-pwrlevel@4 { reg = <4>; + clk-freq = <811000000 + 19200000 + 400000000 + 19200000 + 19200000 + 811000000 + 533000000 + 75000000 + 19200000 + 300000000 + 400000000 + 150000000 + 400000000 + 19200000 + 811000000 + 19200000 + 0 + 0 + 0 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; clk-freq = <908000000 19200000 400000000 @@ -526,7 +576,6 @@ 0 0>; }; - /delete-node/ qcom,npu-pwrlevel@5; }; }; @@ -649,3 +698,147 @@ < 2649600 MHZ_TO_MBPS( 933, 16) >, < 3000000 MHZ_TO_MBPS(1000, 16) >; }; + +&usb_qmp_dp_phy { + qcom,qmp-phy-init-seq = + ; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index c7d9fd9765c972452f3ca692b906b8ab5d296083..7d2bbd0bfffe59e2fa51af088e67805920e71543 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -33,13 +33,14 @@ / { model = "Qualcomm Technologies, Inc. SM8150"; compatible = "qcom,sm8150"; - qcom,msm-name = "SM8150"; + qcom,msm-name = "SM8150 V1"; qcom,msm-id = <339 0x10000>; interrupt-parent = <&pdc>; mem-offline { compatible = "qcom,mem-offline"; - mem-percent = "35"; + /* 1 Gb out of 6 Gb*/ + mem-percent = "17"; granule = <512>; mboxes = <&qmp_aop 0>; }; @@ -1656,6 +1657,7 @@ qcom,firmware-name = "adsp"; memory-region = <&pil_adsp_mem>; qcom,signal-aop; + qcom,complete-ramdump; /* Inputs from lpass */ interrupts-extended = <&pdc 0 162 1>, @@ -1703,6 +1705,7 @@ status = "ok"; memory-region = <&pil_slpi_mem>; qcom,signal-aop; + qcom,complete-ramdump; /* Inputs from ssc */ interrupts-extended = <&pdc 0 494 1>, @@ -1748,6 +1751,7 @@ qcom,pil-generic-irq-handler; status = "ok"; qcom,signal-aop; + qcom,complete-ramdump; qcom,pas-id = <14>; qcom,proxy-timeout-ms = <10000>; @@ -1803,6 +1807,7 @@ qcom,firmware-name = "cdsp"; memory-region = <&pil_cdsp_mem>; qcom,signal-aop; + qcom,complete-ramdump; qcom,msm-bus,name = "pil-cdsp"; qcom,msm-bus,num-cases = <2>; @@ -1838,6 +1843,7 @@ vdd-supply = <&mvsc_gdsc>; qcom,proxy-reg-names = "vdd"; + qcom,complete-ramdump; clocks = <&clock_videocc VIDEO_CC_XO_CLK>, <&clock_videocc VIDEO_CC_MVSC_CORE_CLK>, @@ -3639,6 +3645,65 @@ qcom,smmu-coherent; status = "disabled"; }; + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + memory-region = <&qseecom_mem>; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x620 0x00>; + }; + + demux { + compatible = "qcom,demux"; + }; }; &emac_gdsc { diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi index 9eb11a8d9edacf93227b93a37a10e9e1e010fdd9..26a978616071da1aab135ff66ae3cd31d6e1ed0f 100644 --- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi @@ -93,20 +93,12 @@ regulator-always-on; }; - rsnd_ak4613: sound { - compatible = "simple-audio-card"; + sound_card: sound { + compatible = "audio-graph-card"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&sndcpu>; - simple-audio-card,frame-master = <&sndcpu>; + label = "rcar-sound"; - sndcpu: simple-audio-card,cpu { - sound-dai = <&rcar_sound>; - }; - - sndcodec: simple-audio-card,codec { - sound-dai = <&ak4613>; - }; + dais = <&rsnd_port0>; }; vbus0_usb2: regulator-vbus0-usb2 { @@ -320,6 +312,12 @@ asahi-kasei,out4-single-end; asahi-kasei,out5-single-end; asahi-kasei,out6-single-end; + + port { + ak4613_endpoint: endpoint { + remote-endpoint = <&rsnd_endpoint0>; + }; + }; }; cs2000: clk_multiplier@4f { @@ -538,10 +536,18 @@ <&audio_clk_c>, <&cpg CPG_CORE CPG_AUDIO_CLK_I>; - rcar_sound,dai { - dai0 { - playback = <&ssi0 &src0 &dvc0>; - capture = <&ssi1 &src1 &dvc1>; + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { + remote-endpoint = <&ak4613_endpoint>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; + frame-master = <&rsnd_endpoint0>; + + playback = <&ssi0 &src0 &dvc0>; + capture = <&ssi1 &src1 &dvc1>; + }; }; }; }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 36e21112113e2db2c6074cd265cd3ae69fc6216d..14f170fa433c805943547cedff2b3ca6ee1f8e97 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -304,6 +304,8 @@ CONFIG_GPIO_XGENE_SB=y CONFIG_GPIO_PCA953X=y CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_MAX77620=y +CONFIG_POWER_AVS=y +CONFIG_ROCKCHIP_IODOMAIN=y CONFIG_POWER_RESET_MSM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig deleted file mode 120000 index 03b88505560a94d015f119e6e0c281bf4921186c..0000000000000000000000000000000000000000 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405-perf_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig deleted file mode 120000 index 372fd3e54d888c039678b077724b27f28e68fa29..0000000000000000000000000000000000000000 --- a/arch/arm64/configs/qcs405_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig deleted file mode 120000 index faafc59228eed38d31213dcfe467f48b4b642fde..0000000000000000000000000000000000000000 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sm8150-perf_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig deleted file mode 120000 index 4ff005a12e6427e0dfd4511ecd668db6017b9933..0000000000000000000000000000000000000000 --- a/arch/arm64/configs/sm8150_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sm8150_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/vendor/qcs405-perf_defconfig b/arch/arm64/configs/vendor/qcs405-perf_defconfig index b59bd3c4cdfa6a094aa40fb8ba26a533a8c68096..5f8f1d9159bd06fe5bb5bd22b1edf1ba9ff1d578 100644 --- a/arch/arm64/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs405-perf_defconfig @@ -370,6 +370,7 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PCA9956B=y CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y diff --git a/arch/arm64/configs/vendor/qcs405_defconfig b/arch/arm64/configs/vendor/qcs405_defconfig index 176e2138eb0d2c1c50216736e023c7bd0262b6dc..405ebbad24bff92c3ba5c89df0732b0f778a20cb 100644 --- a/arch/arm64/configs/vendor/qcs405_defconfig +++ b/arch/arm64/configs/vendor/qcs405_defconfig @@ -208,6 +208,7 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y @@ -384,6 +385,7 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PCA9956B=y CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y @@ -462,6 +464,7 @@ CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index 66e46fbf98e3177123e9580172ac9c5cd3324c13..40413a4c7c398c79ee547d9968a79f284a5bfad0 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -315,6 +315,7 @@ CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_QCOM_GENI=y CONFIG_SPI=y CONFIG_SPI_QCOM_GENI=y @@ -326,6 +327,7 @@ CONFIG_PM8150B_PMIC_SIMULATOR=y CONFIG_PM8150L_PMIC_SIMULATOR=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SM8150=y CONFIG_GPIO_SYSFS=y @@ -379,6 +381,7 @@ CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y +CONFIG_DRM_ANALOGIX_ANX7625=y CONFIG_FB_ARMCLCD=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y CONFIG_LOGO=y @@ -409,6 +412,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -573,9 +577,7 @@ CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_EXT4_FS_ENCRYPTION=y diff --git a/arch/arm64/configs/vendor/sa8155_defconfig b/arch/arm64/configs/vendor/sa8155_defconfig index 065ae9b16f8acc302f98c3937fa3fb090dbfab78..ddc6887dfbbcac9201b6ceaac51564601f13c1f0 100644 --- a/arch/arm64/configs/vendor/sa8155_defconfig +++ b/arch/arm64/configs/vendor/sa8155_defconfig @@ -430,6 +430,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y CONFIG_USB_MSM_SSPHY_QMP=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index afcb03ddfed331998448a54c8e9fd27c3c65e543..e938ff5a29c00f0c62d53fa594068f8758a90f73 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -99,6 +99,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -110,6 +111,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -140,6 +142,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -157,8 +160,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -230,6 +235,7 @@ CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_WCD_IRQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y @@ -239,6 +245,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -280,8 +287,17 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y CONFIG_INPUT_MISC=y -CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set @@ -423,11 +439,13 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y @@ -472,6 +490,10 @@ CONFIG_MSM_VIDEOCC_SM6150=y CONFIG_MSM_DEBUGCC_SM6150=y CONFIG_MSM_CAMCC_SM6150=y CONFIG_MSM_DISPCC_SM6150=y +CONFIG_MSM_GCC_SDMMAGPIE=y +CONFIG_MSM_VIDEOCC_SDMMAGPIE=y +CONFIG_MSM_NPUCC_SDMMAGPIE=y +CONFIG_MSM_GPUCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y @@ -496,6 +518,7 @@ CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_SMP2P=y +CONFIG_QPNP_PBS=y CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_SUBSYSTEM_RESTART=y @@ -524,6 +547,7 @@ CONFIG_QCOM_FSA4480_I2C=y CONFIG_MSM_PERFORMANCE=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 04247ca6e6771665601a8b725c7ddb011599569f..e088e015df3a1edff54b32b0980b475147743525 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -103,6 +103,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -114,6 +115,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -144,6 +146,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -161,8 +164,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -237,6 +242,7 @@ CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_WCD_IRQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y @@ -246,6 +252,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -288,8 +295,17 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y CONFIG_INPUT_MISC=y -CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set @@ -436,11 +452,13 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y @@ -489,6 +507,10 @@ CONFIG_MSM_VIDEOCC_SM6150=y CONFIG_MSM_DEBUGCC_SM6150=y CONFIG_MSM_CAMCC_SM6150=y CONFIG_MSM_DISPCC_SM6150=y +CONFIG_MSM_GCC_SDMMAGPIE=y +CONFIG_MSM_VIDEOCC_SDMMAGPIE=y +CONFIG_MSM_NPUCC_SDMMAGPIE=y +CONFIG_MSM_GPUCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y @@ -514,6 +536,7 @@ CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y CONFIG_QCOM_SMP2P=y +CONFIG_QPNP_PBS=y CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_SUBSYSTEM_RESTART=y @@ -539,12 +562,14 @@ CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y CONFIG_QCOM_FSA4480_I2C=y CONFIG_MSM_PERFORMANCE=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 557bbeb3d20c65ff446a5d415e3debf42e05393a..fed30e51e3a09253e54848db56c01c2c18da659c 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -81,6 +81,7 @@ CONFIG_SETEND_EMULATION=y CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y @@ -272,6 +273,7 @@ CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -316,6 +318,7 @@ CONFIG_INPUT_UINPUT=y CONFIG_SERIAL_MSM_GENI=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y @@ -370,6 +373,7 @@ CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -383,6 +387,10 @@ CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y @@ -417,6 +425,8 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_USB_REDRIVER_NB7VPQ904M=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y @@ -462,7 +472,6 @@ CONFIG_LEDS_QTI_TRI_LED=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y -CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y @@ -535,6 +544,10 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y CONFIG_QCOM_SECURE_BUFFER=y @@ -637,6 +650,7 @@ CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y CONFIG_PFK=y +CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 0b4cfcc55eb2f72ea9e7f748984ecefb16cbf01c..07e5cb7ba6a5dcbaf482809e9287b431b8853ede 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -87,6 +87,7 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y @@ -285,6 +286,7 @@ CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -324,13 +326,13 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y @@ -385,6 +387,7 @@ CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -398,6 +401,10 @@ CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y @@ -434,6 +441,8 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_USB_REDRIVER_NB7VPQ904M=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y @@ -558,6 +567,10 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y @@ -717,6 +730,7 @@ CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y CONFIG_PFK=y +CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index 4a85c6952a221ec8e02df17b39b09ddf8f9c13d4..a91933b1e2e62ba235ef05ddf8f9d34dbb6bcf49 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -5,6 +5,8 @@ #include #include +#define ARM64_CB_PATCH ARM64_NCAPS + #ifndef __ASSEMBLY__ #include @@ -12,6 +14,8 @@ #include #include +extern int alternatives_applied; + struct alt_instr { s32 orig_offset; /* offset to original instruction */ s32 alt_offset; /* offset to replacement instruction */ @@ -20,12 +24,19 @@ struct alt_instr { u8 alt_len; /* size of new instruction(s), <= orig_len */ }; +typedef void (*alternative_cb_t)(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); + void __init apply_alternatives_all(void); void apply_alternatives(void *start, size_t length); -#define ALTINSTR_ENTRY(feature) \ +#define ALTINSTR_ENTRY(feature,cb) \ " .word 661b - .\n" /* label */ \ + " .if " __stringify(cb) " == 0\n" \ " .word 663f - .\n" /* new instruction */ \ + " .else\n" \ + " .word " __stringify(cb) "- .\n" /* callback */ \ + " .endif\n" \ " .hword " __stringify(feature) "\n" /* feature bit */ \ " .byte 662b-661b\n" /* source len */ \ " .byte 664f-663f\n" /* replacement len */ @@ -43,15 +54,18 @@ void apply_alternatives(void *start, size_t length); * but most assemblers die if insn1 or insn2 have a .inst. This should * be fixed in a binutils release posterior to 2.25.51.0.2 (anything * containing commit 4e4d08cf7399b606 or c1baaddf8861). + * + * Alternatives with callbacks do not generate replacement instructions. */ -#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \ +#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \ ".if "__stringify(cfg_enabled)" == 1\n" \ "661:\n\t" \ oldinstr "\n" \ "662:\n" \ ".pushsection .altinstructions,\"a\"\n" \ - ALTINSTR_ENTRY(feature) \ + ALTINSTR_ENTRY(feature,cb) \ ".popsection\n" \ + " .if " __stringify(cb) " == 0\n" \ ".pushsection .altinstr_replacement, \"a\"\n" \ "663:\n\t" \ newinstr "\n" \ @@ -59,11 +73,17 @@ void apply_alternatives(void *start, size_t length); ".popsection\n\t" \ ".org . - (664b-663b) + (662b-661b)\n\t" \ ".org . - (662b-661b) + (664b-663b)\n" \ + ".else\n\t" \ + "663:\n\t" \ + "664:\n\t" \ + ".endif\n" \ ".endif\n" #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ - __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg)) + __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0) +#define ALTERNATIVE_CB(oldinstr, cb) \ + __ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb) #else #include @@ -130,6 +150,14 @@ void apply_alternatives(void *start, size_t length); 661: .endm +.macro alternative_cb cb + .set .Lasm_alt_mode, 0 + .pushsection .altinstructions, "a" + altinstruction_entry 661f, \cb, ARM64_CB_PATCH, 662f-661f, 0 + .popsection +661: +.endm + /* * Provide the other half of the alternative code sequence. */ @@ -155,6 +183,13 @@ void apply_alternatives(void *start, size_t length); .org . - (662b-661b) + (664b-663b) .endm +/* + * Callback-based alternative epilogue + */ +.macro alternative_cb_end +662: +.endm + /* * Provides a trivial alternative or default sequence consisting solely * of NOPs. The number of NOPs is chosen automatically to match the diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 1851e217e2c9070cc7d4f05ffc0bb948d58994de..fe2a97ab7b92d2e3c973295a9bd87eebe6d613e7 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -272,7 +272,11 @@ lr .req x30 // link register #else adr_l \dst, \sym #endif +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN mrs \tmp, tpidr_el1 +alternative_else + mrs \tmp, tpidr_el2 +alternative_endif add \dst, \dst, \tmp .endm @@ -283,7 +287,11 @@ lr .req x30 // link register */ .macro ldr_this_cpu dst, sym, tmp adr_l \dst, \sym +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN mrs \tmp, tpidr_el1 +alternative_else + mrs \tmp, tpidr_el2 +alternative_endif ldr \dst, [\dst, \tmp] .endm diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index ae852add053d835cdeb98ede5458419dd2958c6a..0f2e1ab5e16669d3cc7dd27170243f5f79424a6b 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -229,7 +229,9 @@ static inline void __cmpwait_case_##name(volatile void *ptr, \ unsigned long tmp; \ \ asm volatile( \ - " ldxr" #sz "\t%" #w "[tmp], %[v]\n" \ + " sevl\n" \ + " wfe\n" \ + " ldxr" #sz "\t%" #w "[tmp], %[v]\n" \ " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ " cbnz %" #w "[tmp], 1f\n" \ " wfe\n" \ diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index a7ef5a0519115f9325bd33e5cbf46df8fe2a899f..1a6d02350fc68955924ff6c3a728403acf50447b 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -33,6 +33,10 @@ #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0 #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT) +#define VCPU_WORKAROUND_2_FLAG_SHIFT 0 +#define VCPU_WORKAROUND_2_FLAG (_AC(1, UL) << VCPU_WORKAROUND_2_FLAG_SHIFT) + +/* Translate a kernel address of @sym into its equivalent linear mapping */ #define kvm_ksym_ref(sym) \ ({ \ void *val = &sym; \ @@ -68,6 +72,43 @@ extern u32 __init_stage2_translation(void); extern void __qcom_hyp_sanitize_btac_predictors(void); +/* Home-grown __this_cpu_{ptr,read} variants that always work at HYP */ +#define __hyp_this_cpu_ptr(sym) \ + ({ \ + void *__ptr = hyp_symbol_addr(sym); \ + __ptr += read_sysreg(tpidr_el2); \ + (typeof(&sym))__ptr; \ + }) + +#define __hyp_this_cpu_read(sym) \ + ({ \ + *__hyp_this_cpu_ptr(sym); \ + }) + +#else /* __ASSEMBLY__ */ + +.macro hyp_adr_this_cpu reg, sym, tmp + adr_l \reg, \sym + mrs \tmp, tpidr_el2 + add \reg, \reg, \tmp +.endm + +.macro hyp_ldr_this_cpu reg, sym, tmp + adr_l \reg, \sym + mrs \tmp, tpidr_el2 + ldr \reg, [\reg, \tmp] +.endm + +.macro get_host_ctxt reg, tmp + hyp_adr_this_cpu \reg, kvm_host_cpu_state, \tmp +.endm + +.macro get_vcpu_ptr vcpu, ctxt + get_host_ctxt \ctxt, \vcpu + ldr \vcpu, [\ctxt, #HOST_CONTEXT_VCPU] + kern_hyp_va \vcpu +.endm + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8abec9f7f430cde43759a92c4253a1c26a10fc2f..b01ad3489bd8dc9567d1c159833ea1069b879adc 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -194,6 +194,8 @@ struct kvm_cpu_context { u64 sys_regs[NR_SYS_REGS]; u32 copro[NR_COPRO_REGS]; }; + + struct kvm_vcpu *__hyp_running_vcpu; }; typedef struct kvm_cpu_context kvm_cpu_context_t; @@ -208,6 +210,9 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; + /* State of various workarounds, see kvm_asm.h for bit assignment */ + u64 workaround_flags; + /* Guest debug state */ u64 debug_flags; @@ -348,10 +353,15 @@ int kvm_perf_teardown(void); struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr); +void __kvm_set_tpidr_el2(u64 tpidr_el2); +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state); + static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, unsigned long hyp_stack_ptr, unsigned long vector_ptr) { + u64 tpidr_el2; + /* * Call initialization code, and switch to the full blown HYP code. * If the cpucaps haven't been finalized yet, something has gone very @@ -360,6 +370,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, */ BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr); + + /* + * Calculate the raw per-cpu offset without a translation from the + * kernel's mapping to the linear mapping, and store it in tpidr_el2 + * so that we can use adr_l to access per-cpu variables in EL2. + */ + tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state) + - (u64)kvm_ksym_ref(kvm_host_cpu_state); + + kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2); } static inline void kvm_arch_hardware_unsetup(void) {} @@ -392,4 +412,27 @@ static inline bool kvm_arm_harden_branch_predictor(void) return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR); } +#define KVM_SSBD_UNKNOWN -1 +#define KVM_SSBD_FORCE_DISABLE 0 +#define KVM_SSBD_KERNEL 1 +#define KVM_SSBD_FORCE_ENABLE 2 +#define KVM_SSBD_MITIGATED 3 + +static inline int kvm_arm_have_ssbd(void) +{ + switch (arm64_get_ssbd_state()) { + case ARM64_SSBD_FORCE_DISABLE: + return KVM_SSBD_FORCE_DISABLE; + case ARM64_SSBD_KERNEL: + return KVM_SSBD_KERNEL; + case ARM64_SSBD_FORCE_ENABLE: + return KVM_SSBD_FORCE_ENABLE; + case ARM64_SSBD_MITIGATED: + return KVM_SSBD_MITIGATED; + case ARM64_SSBD_UNKNOWN: + default: + return KVM_SSBD_UNKNOWN; + } +} + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index fe55b516f018d0adf8d0b31d1d93d66618931cce..e42c1f0ae6cf7febfccba956ec0eed8ab47f4717 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -130,6 +130,26 @@ static inline unsigned long __kern_hyp_va(unsigned long v) #define kern_hyp_va(v) ((typeof(v))(__kern_hyp_va((unsigned long)(v)))) +/* + * Obtain the PC-relative address of a kernel symbol + * s: symbol + * + * The goal of this macro is to return a symbol's address based on a + * PC-relative computation, as opposed to a loading the VA from a + * constant pool or something similar. This works well for HYP, as an + * absolute VA is guaranteed to be wrong. Only use this if trying to + * obtain the address of a symbol (i.e. not something you obtained by + * following a pointer). + */ +#define hyp_symbol_addr(s) \ + ({ \ + typeof(s) *addr; \ + asm("adrp %0, %1\n" \ + "add %0, %0, :lo12:%1\n" \ + : "=r" (addr) : "S" (&s)); \ + addr; \ + }) + /* * We currently only support a 40bit IPA. */ @@ -363,5 +383,29 @@ static inline int kvm_map_vectors(void) } #endif +#ifdef CONFIG_ARM64_SSBD +DECLARE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); + +static inline int hyp_map_aux_data(void) +{ + int cpu, err; + + for_each_possible_cpu(cpu) { + u64 *ptr; + + ptr = per_cpu_ptr(&arm64_ssbd_callback_required, cpu); + err = create_hyp_mappings(ptr, ptr + 1, PAGE_HYP); + if (err) + return err; + } + return 0; +} +#else +static inline int hyp_map_aux_data(void) +{ + return 0; +} +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 3bd498e4de4cf298c8a24bb5e97e235ebed17245..43393208229eb8d64ec476f5b7b098bc73f498f9 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -16,11 +16,15 @@ #ifndef __ASM_PERCPU_H #define __ASM_PERCPU_H +#include #include static inline void set_my_cpu_offset(unsigned long off) { - asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); + asm volatile(ALTERNATIVE("msr tpidr_el1, %0", + "msr tpidr_el2, %0", + ARM64_HAS_VIRT_HOST_EXTN) + :: "r" (off) : "memory"); } static inline unsigned long __my_cpu_offset(void) @@ -31,7 +35,10 @@ static inline unsigned long __my_cpu_offset(void) * We want to allow caching the value, so avoid using volatile and * instead use a fake stack read to hazard against barrier(). */ - asm("mrs %0, tpidr_el1" : "=r" (off) : + asm(ALTERNATIVE("mrs %0, tpidr_el1", + "mrs %0, tpidr_el2", + ARM64_HAS_VIRT_HOST_EXTN) + : "=r" (off) : "Q" (*(const unsigned long *)current_stack_pointer)); return off; diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index e873dc6f40a45d72233e9685efd1acb3f4fbba2e..3f547dc09ae88cd2bf36229fc83f9ac32fdece35 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -92,8 +92,8 @@ void arch_setup_new_exec(void); #define TIF_RESTORE_SIGMASK 20 #define TIF_SINGLESTEP 21 #define TIF_32BIT 22 /* 32bit process */ +#define TIF_SSBD 23 /* Wants SSB mitigation */ #define TIF_MM_RELEASED 24 -#define TIF_SSBD 25 /* Wants SSB mitigation */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index a15a07e94182a3978b4b00639791f472f45cc923..031c211bb69c4bc6350508b2693d68cd8ed2cae8 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -55,6 +55,7 @@ arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o ifeq ($(CONFIG_KVM),y) arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 6dd0a3a3e5c98d447f7017c70b328a70bb82c9d3..5c4bce4ac381a4ab87107e4aa47a9b7beef7d891 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -32,6 +32,8 @@ #define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset) #define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset) +int alternatives_applied; + struct alt_region { struct alt_instr *begin; struct alt_instr *end; @@ -105,32 +107,53 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp return insn; } +static void patch_alternative(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst) +{ + __le32 *replptr; + int i; + + replptr = ALT_REPL_PTR(alt); + for (i = 0; i < nr_inst; i++) { + u32 insn; + + insn = get_alt_insn(alt, origptr + i, replptr + i); + updptr[i] = cpu_to_le32(insn); + } +} + static void __apply_alternatives(void *alt_region, bool use_linear_alias) { struct alt_instr *alt; struct alt_region *region = alt_region; - __le32 *origptr, *replptr, *updptr; + __le32 *origptr, *updptr; + alternative_cb_t alt_cb; for (alt = region->begin; alt < region->end; alt++) { - u32 insn; - int i, nr_inst; + int nr_inst; - if (!cpus_have_cap(alt->cpufeature)) + /* Use ARM64_CB_PATCH as an unconditional patch */ + if (alt->cpufeature < ARM64_CB_PATCH && + !cpus_have_cap(alt->cpufeature)) continue; - BUG_ON(alt->alt_len != alt->orig_len); + if (alt->cpufeature == ARM64_CB_PATCH) + BUG_ON(alt->alt_len != 0); + else + BUG_ON(alt->alt_len != alt->orig_len); pr_info_once("patching kernel code\n"); origptr = ALT_ORIG_PTR(alt); - replptr = ALT_REPL_PTR(alt); updptr = use_linear_alias ? lm_alias(origptr) : origptr; - nr_inst = alt->alt_len / sizeof(insn); + nr_inst = alt->orig_len / AARCH64_INSN_SIZE; - for (i = 0; i < nr_inst; i++) { - insn = get_alt_insn(alt, origptr + i, replptr + i); - updptr[i] = cpu_to_le32(insn); - } + if (alt->cpufeature < ARM64_CB_PATCH) + alt_cb = patch_alternative; + else + alt_cb = ALT_REPL_PTR(alt); + + alt_cb(alt, origptr, updptr, nr_inst); flush_icache_range((uintptr_t)origptr, (uintptr_t)(origptr + nr_inst)); @@ -143,7 +166,6 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias) */ static int __apply_alternatives_multi_stop(void *unused) { - static int patched = 0; struct alt_region region = { .begin = (struct alt_instr *)__alt_instructions, .end = (struct alt_instr *)__alt_instructions_end, @@ -151,14 +173,14 @@ static int __apply_alternatives_multi_stop(void *unused) /* We always have a CPU 0 at this point (__init) */ if (smp_processor_id()) { - while (!READ_ONCE(patched)) + while (!READ_ONCE(alternatives_applied)) cpu_relax(); isb(); } else { - BUG_ON(patched); + BUG_ON(alternatives_applied); __apply_alternatives(®ion, true); /* Barriers provided by the cache flushing */ - WRITE_ONCE(patched, 1); + WRITE_ONCE(alternatives_applied, 1); } return 0; diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c index 66be504edb6cf5be422afa59d82aa2db4fd3ed7f..ca1cf2d2b4931fd4bbe7c19b906338d453f61871 100644 --- a/arch/arm64/kernel/arm64ksyms.c +++ b/arch/arm64/kernel/arm64ksyms.c @@ -29,6 +29,7 @@ #include #include +#include #include EXPORT_SYMBOL(copy_page); @@ -75,3 +76,8 @@ NOKPROBE_SYMBOL(_mcount); /* arm-smccc */ EXPORT_SYMBOL(__arm_smccc_smc); EXPORT_SYMBOL(__arm_smccc_hvc); + + /* caching functions */ +EXPORT_SYMBOL(__dma_inv_area); +EXPORT_SYMBOL(__dma_clean_area); +EXPORT_SYMBOL(__dma_flush_area); diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index af247d10252f5019e8b44361bb4a8a724300d7e1..b5e43b01b396c80a0ef2252a3d835232ad277b7f 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -131,11 +131,13 @@ int main(void) BLANK(); #ifdef CONFIG_KVM_ARM_HOST DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt)); + DEFINE(VCPU_WORKAROUND_FLAGS, offsetof(struct kvm_vcpu, arch.workaround_flags)); DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs)); DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs)); DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs)); DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2])); DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context)); + DEFINE(HOST_CONTEXT_VCPU, offsetof(struct kvm_cpu_context, __hyp_running_vcpu)); #endif #ifdef CONFIG_CPU_PM DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx)); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index e28b8bed64172470c4b7980329abeddef781c11f..57dde8be92a4bf294bf918877a6e7a6889e97ba9 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -362,7 +362,7 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, return required; } -#endif /* CONFIG_ARM64_SSBD */ +#endif /* CONFIG_ARM64_SSBD */ #define MIDR_RANGE(model, min, max) \ .def_scope = SCOPE_LOCAL_CPU, \ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 5c0a83096aaa7a22b9b8d66633160ebb92d47194..5e621db943c9326931f6b6a9be0cf75c46ce0b3d 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -958,6 +958,22 @@ static bool has_hw_dbm(const struct arm64_cpu_capabilities *cap, #endif +static int cpu_copy_el2regs(void *__unused) +{ + /* + * Copy register values that aren't redirected by hardware. + * + * Before code patching, we only set tpidr_el1, all CPUs need to copy + * this value to tpidr_el2 before we patch the code. Once we've done + * that, freshly-onlined CPUs will set tpidr_el2, so we don't need to + * do anything here. + */ + if (!alternatives_applied) + write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); + + return 0; +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -1027,6 +1043,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .capability = ARM64_HAS_VIRT_HOST_EXTN, .def_scope = SCOPE_SYSTEM, .matches = runs_at_el2, + .enable = cpu_copy_el2regs, }, { .desc = "32-bit EL0 Support", diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c index 3432e5ef9f41882c06462b7f3ec4ff91f02fd931..0560738c1d5ccad415d1f50d2ffec56ba7e9ff08 100644 --- a/arch/arm64/kernel/ssbd.c +++ b/arch/arm64/kernel/ssbd.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -11,9 +12,7 @@ /* * prctl interface for SSBD - * FIXME: Drop the below ifdefery once merged in 4.18. */ -#ifdef PR_SPEC_STORE_BYPASS static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) { int state = arm64_get_ssbd_state(); @@ -107,4 +106,3 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) return -ENODEV; } } -#endif /* PR_SPEC_STORE_BYPASS */ diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S index 870828c364c508f825eacc1c49c17886dc9c8cb2..dea20651a5f167e70f1d38b9728d263a0c78eb58 100644 --- a/arch/arm64/kvm/hyp-init.S +++ b/arch/arm64/kvm/hyp-init.S @@ -122,6 +122,10 @@ CPU_BE( orr x4, x4, #SCTLR_ELx_EE) kern_hyp_va x2 msr vbar_el2, x2 + /* copy tpidr_el1 into tpidr_el2 for use by HYP */ + mrs x1, tpidr_el1 + msr tpidr_el2, x1 + /* Hello, World! */ eret ENDPROC(__kvm_hyp_init) diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S index 9c45c6af1f5828099ca00ad8ca16d17197138857..a7b3c198d4de87ff7d2f103a01971be4d40b543b 100644 --- a/arch/arm64/kvm/hyp/entry.S +++ b/arch/arm64/kvm/hyp/entry.S @@ -62,9 +62,6 @@ ENTRY(__guest_enter) // Store the host regs save_callee_saved_regs x1 - // Store the host_ctxt for use at exit time - str x1, [sp, #-16]! - add x18, x0, #VCPU_CONTEXT // Restore guest regs x0-x17 @@ -118,8 +115,7 @@ ENTRY(__guest_exit) // Store the guest regs x19-x29, lr save_callee_saved_regs x1 - // Restore the host_ctxt from the stack - ldr x2, [sp], #16 + get_host_ctxt x2, x3 // Now restore the host regs restore_callee_saved_regs x2 @@ -159,6 +155,10 @@ abort_guest_exit_end: ENDPROC(__guest_exit) ENTRY(__fpsimd_guest_restore) + // x0: esr + // x1: vcpu + // x2-x29,lr: vcpu regs + // vcpu x0-x1 on the stack stp x2, x3, [sp, #-16]! stp x4, lr, [sp, #-16]! @@ -173,7 +173,7 @@ alternative_else alternative_endif isb - mrs x3, tpidr_el2 + mov x3, x1 ldr x0, [x3, #VCPU_HOST_CONTEXT] kern_hyp_va x0 diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S index f49b53331d28118d0b3e5419c17b4f3ec1513ca3..3c283fd8c8f5a5fd258475069a4cf280845c7929 100644 --- a/arch/arm64/kvm/hyp/hyp-entry.S +++ b/arch/arm64/kvm/hyp/hyp-entry.S @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call) el1_sync: // Guest trapped into EL2 stp x0, x1, [sp, #-16]! -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN - mrs x1, esr_el2 -alternative_else - mrs x1, esr_el1 -alternative_endif - lsr x0, x1, #ESR_ELx_EC_SHIFT - + mrs x0, esr_el2 + lsr x0, x0, #ESR_ELx_EC_SHIFT cmp x0, #ESR_ELx_EC_HVC64 ccmp x0, #ESR_ELx_EC_HVC32, #4, ne b.ne el1_trap @@ -111,14 +106,55 @@ el1_hvc_guest: */ ldr x1, [sp] // Guest's x0 eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1 + cbz w1, wa_epilogue + + /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */ + eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \ + ARM_SMCCC_ARCH_WORKAROUND_2) cbnz w1, el1_trap - mov x0, x1 + +#ifdef CONFIG_ARM64_SSBD +alternative_cb arm64_enable_wa2_handling + b wa2_end +alternative_cb_end + get_vcpu_ptr x2, x0 + ldr x0, [x2, #VCPU_WORKAROUND_FLAGS] + + // Sanitize the argument and update the guest flags + ldr x1, [sp, #8] // Guest's x1 + clz w1, w1 // Murphy's device: + lsr w1, w1, #5 // w1 = !!w1 without using + eor w1, w1, #1 // the flags... + bfi x0, x1, #VCPU_WORKAROUND_2_FLAG_SHIFT, #1 + str x0, [x2, #VCPU_WORKAROUND_FLAGS] + + /* Check that we actually need to perform the call */ + hyp_ldr_this_cpu x0, arm64_ssbd_callback_required, x2 + cbz x0, wa2_end + + mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2 + smc #0 + + /* Don't leak data from the SMC call */ + mov x3, xzr +wa2_end: + mov x2, xzr + mov x1, xzr +#endif + +wa_epilogue: + mov x0, xzr add sp, sp, #16 eret el1_trap: + get_vcpu_ptr x1, x0 + + mrs x0, esr_el2 + lsr x0, x0, #ESR_ELx_EC_SHIFT /* * x0: ESR_EC + * x1: vcpu pointer */ /* @@ -132,19 +168,18 @@ alternative_if_not ARM64_HAS_NO_FPSIMD b.eq __fpsimd_guest_restore alternative_else_nop_endif - mrs x1, tpidr_el2 mov x0, #ARM_EXCEPTION_TRAP b __guest_exit el1_irq: stp x0, x1, [sp, #-16]! - mrs x1, tpidr_el2 + get_vcpu_ptr x1, x0 mov x0, #ARM_EXCEPTION_IRQ b __guest_exit el1_error: stp x0, x1, [sp, #-16]! - mrs x1, tpidr_el2 + get_vcpu_ptr x1, x0 mov x0, #ARM_EXCEPTION_EL1_SERROR b __guest_exit @@ -179,6 +214,11 @@ ENTRY(__hyp_do_panic) eret ENDPROC(__hyp_do_panic) +ENTRY(__hyp_panic) + get_host_ctxt x0, x1 + b hyp_panic +ENDPROC(__hyp_panic) + .macro invalid_vector label, target = __hyp_panic .align 2 \label: diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index e08ae6b6b63e9f8ad63af77b338cc9279d55cc05..b2f1992c6234cbbff1c1fbf6629160292bae4cc9 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -281,6 +282,39 @@ static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu) write_sysreg_el2(*vcpu_pc(vcpu), elr); } +static inline bool __hyp_text __needs_ssbd_off(struct kvm_vcpu *vcpu) +{ + if (!cpus_have_const_cap(ARM64_SSBD)) + return false; + + return !(vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG); +} + +static void __hyp_text __set_guest_arch_workaround_state(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_ARM64_SSBD + /* + * The host runs with the workaround always present. If the + * guest wants it disabled, so be it... + */ + if (__needs_ssbd_off(vcpu) && + __hyp_this_cpu_read(arm64_ssbd_callback_required)) + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 0, NULL); +#endif +} + +static void __hyp_text __set_host_arch_workaround_state(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_ARM64_SSBD + /* + * If the guest has disabled the workaround, bring it back on. + */ + if (__needs_ssbd_off(vcpu) && + __hyp_this_cpu_read(arm64_ssbd_callback_required)) + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 1, NULL); +#endif +} + int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *host_ctxt; @@ -289,9 +323,9 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) u64 exit_code; vcpu = kern_hyp_va(vcpu); - write_sysreg(vcpu, tpidr_el2); host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context); + host_ctxt->__hyp_running_vcpu = vcpu; guest_ctxt = &vcpu->arch.ctxt; __sysreg_save_host_state(host_ctxt); @@ -311,6 +345,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) __sysreg_restore_guest_state(guest_ctxt); __debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt); + __set_guest_arch_workaround_state(vcpu); + /* Jump in the fire! */ again: exit_code = __guest_enter(vcpu, host_ctxt); @@ -367,6 +403,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) /* 0 falls through to be handled out of EL2 */ } + __set_host_arch_workaround_state(vcpu); + if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) { u32 midr = read_cpuid_id(); @@ -406,7 +444,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n"; -static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par) +static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par, + struct kvm_vcpu *vcpu) { unsigned long str_va; @@ -420,35 +459,32 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par) __hyp_do_panic(str_va, spsr, elr, read_sysreg(esr_el2), read_sysreg_el2(far), - read_sysreg(hpfar_el2), par, - (void *)read_sysreg(tpidr_el2)); + read_sysreg(hpfar_el2), par, vcpu); } -static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par) +static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par, + struct kvm_vcpu *vcpu) { panic(__hyp_panic_string, spsr, elr, read_sysreg_el2(esr), read_sysreg_el2(far), - read_sysreg(hpfar_el2), par, - (void *)read_sysreg(tpidr_el2)); + read_sysreg(hpfar_el2), par, vcpu); } static hyp_alternate_select(__hyp_call_panic, __hyp_call_panic_nvhe, __hyp_call_panic_vhe, ARM64_HAS_VIRT_HOST_EXTN); -void __hyp_text __noreturn __hyp_panic(void) +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt) { + struct kvm_vcpu *vcpu = NULL; + u64 spsr = read_sysreg_el2(spsr); u64 elr = read_sysreg_el2(elr); u64 par = read_sysreg(par_el1); if (read_sysreg(vttbr_el2)) { - struct kvm_vcpu *vcpu; - struct kvm_cpu_context *host_ctxt; - - vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2); - host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context); + vcpu = host_ctxt->__hyp_running_vcpu; __timer_save_state(vcpu); __deactivate_traps(vcpu); __deactivate_vm(vcpu); @@ -456,7 +492,7 @@ void __hyp_text __noreturn __hyp_panic(void) } /* Call panic for real */ - __hyp_call_panic()(spsr, elr, par); + __hyp_call_panic()(spsr, elr, par, vcpu); unreachable(); } diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c index 9341376478370a836c55ede6fb0a8f17481bdd14..e19d89cabf2a2e09c8a27f0f348f93f5546bd883 100644 --- a/arch/arm64/kvm/hyp/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/sysreg-sr.c @@ -27,8 +27,8 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { } /* * Non-VHE: Both host and guest must save everything. * - * VHE: Host must save tpidr*_el[01], actlr_el1, mdscr_el1, sp0, pc, - * pstate, and guest must save everything. + * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0, + * and guest must save everything. */ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt) @@ -36,11 +36,8 @@ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt) ctxt->sys_regs[ACTLR_EL1] = read_sysreg(actlr_el1); ctxt->sys_regs[TPIDR_EL0] = read_sysreg(tpidr_el0); ctxt->sys_regs[TPIDRRO_EL0] = read_sysreg(tpidrro_el0); - ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1); ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1); ctxt->gp_regs.regs.sp = read_sysreg(sp_el0); - ctxt->gp_regs.regs.pc = read_sysreg_el2(elr); - ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr); } static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt) @@ -62,10 +59,13 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt) ctxt->sys_regs[AMAIR_EL1] = read_sysreg_el1(amair); ctxt->sys_regs[CNTKCTL_EL1] = read_sysreg_el1(cntkctl); ctxt->sys_regs[PAR_EL1] = read_sysreg(par_el1); + ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1); ctxt->gp_regs.sp_el1 = read_sysreg(sp_el1); ctxt->gp_regs.elr_el1 = read_sysreg_el1(elr); ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr); + ctxt->gp_regs.regs.pc = read_sysreg_el2(elr); + ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr); } static hyp_alternate_select(__sysreg_call_save_host_state, @@ -89,11 +89,8 @@ static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctx write_sysreg(ctxt->sys_regs[ACTLR_EL1], actlr_el1); write_sysreg(ctxt->sys_regs[TPIDR_EL0], tpidr_el0); write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0); - write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1); write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1); write_sysreg(ctxt->gp_regs.regs.sp, sp_el0); - write_sysreg_el2(ctxt->gp_regs.regs.pc, elr); - write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr); } static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt) @@ -115,10 +112,13 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt) write_sysreg_el1(ctxt->sys_regs[AMAIR_EL1], amair); write_sysreg_el1(ctxt->sys_regs[CNTKCTL_EL1], cntkctl); write_sysreg(ctxt->sys_regs[PAR_EL1], par_el1); + write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1); write_sysreg(ctxt->gp_regs.sp_el1, sp_el1); write_sysreg_el1(ctxt->gp_regs.elr_el1, elr); write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr); + write_sysreg_el2(ctxt->gp_regs.regs.pc, elr); + write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr); } static hyp_alternate_select(__sysreg_call_restore_host_state, @@ -183,3 +183,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu) if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY) write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2); } + +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2) +{ + asm("msr tpidr_el2, %0": : "r" (tpidr_el2)); +} diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 3256b9228e75801a7d91ad9c95235bd7c420d779..a74311beda35d9f54a15e5c9cb1230367f70865f 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -122,6 +122,10 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) /* Reset PMU */ kvm_pmu_vcpu_reset(vcpu); + /* Default workaround setup is enabled (if supported) */ + if (kvm_arm_have_ssbd() == KVM_SSBD_KERNEL) + vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG; + /* Reset timer */ return kvm_timer_vcpu_reset(vcpu); } diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index fdf9525d375ee4c6bab292fd7cb05a01715c60e3..cc1b7acea13e1527476267c12fd32cce3c8dd213 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -721,11 +721,13 @@ void __init mem_init(void) BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64); #endif +#ifdef CONFIG_SPARSEMEM_VMEMMAP /* * Make sure we chose the upper bound of sizeof(struct page) - * correctly. + * correctly when sizing the VMEMMAP array. */ BUILD_BUG_ON(sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT)); +#endif if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) { extern int sysctl_overcommit_memory; diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 22f0c81e5504cec16d97f49c715e921d287463be..f2ca818eb7958fcfa7dc8a6bae17a647ee0f52a1 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -116,7 +116,11 @@ ENTRY(cpu_do_suspend) mrs x8, mdscr_el1 mrs x9, oslsr_el1 mrs x10, sctlr_el1 +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN mrs x11, tpidr_el1 +alternative_else + mrs x11, tpidr_el2 +alternative_endif mrs x12, sp_el0 stp x2, x3, [x0] stp x4, xzr, [x0, #16] @@ -162,7 +166,11 @@ ENTRY(cpu_do_resume) msr mdscr_el1, x10 msr sctlr_el1, x12 +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN msr tpidr_el1, x13 +alternative_else + msr tpidr_el2, x13 +alternative_endif msr sp_el0, x14 /* * Restore oslsr_el1 by writing oslar_el1 diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 47f94cc383b65746eb5698db4038c2fea0c1b522..7c2f52d4a0e45f47c381fd38a4aec4180352c8cf 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -22,17 +22,19 @@ $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) -quiet_cmd_strip = STRIP $@ +quiet_cmd_strip = STRIP $< $@$2 cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \ - -K _fdt_start vmlinux -o $@ + -K _fdt_start $< -o $@$2 UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR) +UIMAGE_IN = $@ +UIMAGE_OUT = $@.ub $(obj)/simpleImage.%: vmlinux FORCE $(call if_changed,cp,.unstrip) $(call if_changed,objcopy) $(call if_changed,uimage) - $(call if_changed,strip) - @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' + $(call if_changed,strip,.strip) + @echo 'Kernel: $(UIMAGE_OUT) is ready' ' (#'`cat .version`')' clean-files += simpleImage.*.unstrip linux.bin.ub dts/*.dtb diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 10a405d593df3b5c64fa84ce9ae27eaa7ba222df..c782b10ddf50d6a09713edc21f23356399ce1a4b 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init); void ath79_ddr_wb_flush(u32 reg) { - void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg; + void __iomem *flush_reg = ath79_ddr_wb_flush_base + (reg * 4); /* Flush the DDR write buffer. */ __raw_writel(0x1, flush_reg); diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 9632436d74d7a74b3d584ab6e87a1fc7e55827cc..c2e94cf5ecdab7c7f3263bd65e76c30cf8eb32fc 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -54,5 +54,5 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, phys_addr_t size = resource_size(rsrc); *start = fixup_bigphys_addr(rsrc->start, size); - *end = rsrc->start + size; + *end = rsrc->start + size - 1; } diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index c7c63959ba91066f69b1147f59d4df4e20b39b1f..e582d2c880922504c6d93b3df72f655953437aae 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -76,6 +76,21 @@ do { \ ___p1; \ }) +#ifdef CONFIG_PPC_BOOK3S_64 +/* + * Prevent execution of subsequent instructions until preceding branches have + * been fully resolved and are no longer executing speculatively. + */ +#define barrier_nospec_asm ori 31,31,0 + +// This also acts as a compiler barrier due to the memory clobber. +#define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: "memory") + +#else /* !CONFIG_PPC_BOOK3S_64 */ +#define barrier_nospec_asm +#define barrier_nospec() +#endif + #include #endif /* _ASM_POWERPC_BARRIER_H */ diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index c1d257aa4c2d350d23774420eafed6deb57ec5f9..66298461b640f06a247106af6045dfe1f2f8c963 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -9,11 +9,14 @@ #if defined(CONFIG_PPC_8xx) || defined(CONFIG_403GCX) #define L1_CACHE_SHIFT 4 #define MAX_COPY_PREFETCH 1 +#define IFETCH_ALIGN_SHIFT 2 #elif defined(CONFIG_PPC_E500MC) #define L1_CACHE_SHIFT 6 #define MAX_COPY_PREFETCH 4 +#define IFETCH_ALIGN_SHIFT 3 #elif defined(CONFIG_PPC32) #define MAX_COPY_PREFETCH 4 +#define IFETCH_ALIGN_SHIFT 3 /* 603 fetches 2 insn at a time */ #if defined(CONFIG_PPC_47x) #define L1_CACHE_SHIFT 7 #else diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 44fdf4786638b1fe2f21b8c15927eea8c19ee47f..6f67ff5a52672329f52f2c02c44daa655803368e 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -35,9 +35,9 @@ extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup_rm( extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, unsigned long ua, unsigned long entries); extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa); + unsigned long ua, unsigned int pageshift, unsigned long *hpa); extern long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa); + unsigned long ua, unsigned int pageshift, unsigned long *hpa); extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem); extern void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem); #endif diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index ca2243df9cb2ecce7a805c33aff253d6678f9252..470284f9e4f6661f6716b0be1a78b14bae9f33b3 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -450,9 +450,11 @@ static void *eeh_add_virt_device(void *data, void *userdata) driver = eeh_pcid_get(dev); if (driver) { - eeh_pcid_put(dev); - if (driver->err_handler) + if (driver->err_handler) { + eeh_pcid_put(dev); return NULL; + } + eeh_pcid_put(dev); } #ifdef CONFIG_PPC_POWERNV @@ -489,17 +491,19 @@ static void *eeh_rmv_device(void *data, void *userdata) if (eeh_dev_removed(edev)) return NULL; - driver = eeh_pcid_get(dev); - if (driver) { - eeh_pcid_put(dev); - if (removed && - eeh_pe_passed(edev->pe)) - return NULL; - if (removed && - driver->err_handler && - driver->err_handler->error_detected && - driver->err_handler->slot_reset) + if (removed) { + if (eeh_pe_passed(edev->pe)) return NULL; + driver = eeh_pcid_get(dev); + if (driver) { + if (driver->err_handler && + driver->err_handler->error_detected && + driver->err_handler->slot_reset) { + eeh_pcid_put(dev); + return NULL; + } + eeh_pcid_put(dev); + } } /* Remove it from PCI subsystem */ diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 4fee00d414e87c78d8a09ef3e9662b7bb7234c66..2d0d89e2cb9a8c5765583e0f2d99031dbf0c7e80 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -958,7 +958,7 @@ start_here: tovirt(r6,r6) lis r5, abatron_pteptrs@h ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* Must match your Abatron config file */ + stw r5, 0xf0(0) /* Must match your Abatron config file */ tophys(r5,r5) stw r6, 0(r5) diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index e35cebd45c35e0bfb90075a99a7d8de54f1d24ab..4efbde0984b2dece9e3c4f10893706204270db48 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -140,6 +140,8 @@ power9_restore_additional_sprs: ld r4, STOP_MMCR2(r13) mtspr SPRN_MMCR1, r3 mtspr SPRN_MMCR2, r4 + ld r4, PACA_SPRG_VDSO(r13) + mtspr SPRN_SPRG3, r4 blr /* diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 1d817f4d97d960cae8b2c75ec580588538c31282..2094f2b249fd5ecb0de9cc29fb49a390bbd7a9a8 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 02190e90c7aef4a1a71d513542ebcef556295753..f8782c7ef50f1350a58b4fb28e303cb7f8a68f2e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -334,6 +334,7 @@ static void __init prom_print_dec(unsigned long val) call_prom("write", 3, 1, prom.stdout, buf+i, size); } +__printf(1, 2) static void __init prom_printf(const char *format, ...) { const char *p, *q, *s; @@ -1148,7 +1149,7 @@ static void __init prom_send_capabilities(void) */ cores = DIV_ROUND_UP(NR_CPUS, prom_count_smt_threads()); - prom_printf("Max number of cores passed to firmware: %lu (NR_CPUS = %lu)\n", + prom_printf("Max number of cores passed to firmware: %u (NR_CPUS = %d)\n", cores, NR_CPUS); ibm_architecture_vec.vec5.max_cpus = cpu_to_be32(cores); @@ -1230,7 +1231,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) if (align) base = _ALIGN_UP(base, align); - prom_debug("alloc_up(%x, %x)\n", size, align); + prom_debug("%s(%lx, %lx)\n", __func__, size, align); if (ram_top == 0) prom_panic("alloc_up() called with mem not initialized\n"); @@ -1241,7 +1242,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) for(; (base + size) <= alloc_top; base = _ALIGN_UP(base + 0x100000, align)) { - prom_debug(" trying: 0x%x\n\r", base); + prom_debug(" trying: 0x%lx\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); if (addr != PROM_ERROR && addr != 0) break; @@ -1253,12 +1254,12 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) return 0; alloc_bottom = addr + size; - prom_debug(" -> %x\n", addr); - prom_debug(" alloc_bottom : %x\n", alloc_bottom); - prom_debug(" alloc_top : %x\n", alloc_top); - prom_debug(" alloc_top_hi : %x\n", alloc_top_high); - prom_debug(" rmo_top : %x\n", rmo_top); - prom_debug(" ram_top : %x\n", ram_top); + prom_debug(" -> %lx\n", addr); + prom_debug(" alloc_bottom : %lx\n", alloc_bottom); + prom_debug(" alloc_top : %lx\n", alloc_top); + prom_debug(" alloc_top_hi : %lx\n", alloc_top_high); + prom_debug(" rmo_top : %lx\n", rmo_top); + prom_debug(" ram_top : %lx\n", ram_top); return addr; } @@ -1273,7 +1274,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, { unsigned long base, addr = 0; - prom_debug("alloc_down(%x, %x, %s)\n", size, align, + prom_debug("%s(%lx, %lx, %s)\n", __func__, size, align, highmem ? "(high)" : "(low)"); if (ram_top == 0) prom_panic("alloc_down() called with mem not initialized\n"); @@ -1301,7 +1302,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, base = _ALIGN_DOWN(alloc_top - size, align); for (; base > alloc_bottom; base = _ALIGN_DOWN(base - 0x100000, align)) { - prom_debug(" trying: 0x%x\n\r", base); + prom_debug(" trying: 0x%lx\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); if (addr != PROM_ERROR && addr != 0) break; @@ -1312,12 +1313,12 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, alloc_top = addr; bail: - prom_debug(" -> %x\n", addr); - prom_debug(" alloc_bottom : %x\n", alloc_bottom); - prom_debug(" alloc_top : %x\n", alloc_top); - prom_debug(" alloc_top_hi : %x\n", alloc_top_high); - prom_debug(" rmo_top : %x\n", rmo_top); - prom_debug(" ram_top : %x\n", ram_top); + prom_debug(" -> %lx\n", addr); + prom_debug(" alloc_bottom : %lx\n", alloc_bottom); + prom_debug(" alloc_top : %lx\n", alloc_top); + prom_debug(" alloc_top_hi : %lx\n", alloc_top_high); + prom_debug(" rmo_top : %lx\n", rmo_top); + prom_debug(" ram_top : %lx\n", ram_top); return addr; } @@ -1443,7 +1444,7 @@ static void __init prom_init_mem(void) if (size == 0) continue; - prom_debug(" %x %x\n", base, size); + prom_debug(" %lx %lx\n", base, size); if (base == 0 && (of_platform & PLATFORM_LPAR)) rmo_top = size; if ((base + size) > ram_top) @@ -1463,12 +1464,12 @@ static void __init prom_init_mem(void) if (prom_memory_limit) { if (prom_memory_limit <= alloc_bottom) { - prom_printf("Ignoring mem=%x <= alloc_bottom.\n", - prom_memory_limit); + prom_printf("Ignoring mem=%lx <= alloc_bottom.\n", + prom_memory_limit); prom_memory_limit = 0; } else if (prom_memory_limit >= ram_top) { - prom_printf("Ignoring mem=%x >= ram_top.\n", - prom_memory_limit); + prom_printf("Ignoring mem=%lx >= ram_top.\n", + prom_memory_limit); prom_memory_limit = 0; } else { ram_top = prom_memory_limit; @@ -1500,12 +1501,13 @@ static void __init prom_init_mem(void) alloc_bottom = PAGE_ALIGN(prom_initrd_end); prom_printf("memory layout at init:\n"); - prom_printf(" memory_limit : %x (16 MB aligned)\n", prom_memory_limit); - prom_printf(" alloc_bottom : %x\n", alloc_bottom); - prom_printf(" alloc_top : %x\n", alloc_top); - prom_printf(" alloc_top_hi : %x\n", alloc_top_high); - prom_printf(" rmo_top : %x\n", rmo_top); - prom_printf(" ram_top : %x\n", ram_top); + prom_printf(" memory_limit : %lx (16 MB aligned)\n", + prom_memory_limit); + prom_printf(" alloc_bottom : %lx\n", alloc_bottom); + prom_printf(" alloc_top : %lx\n", alloc_top); + prom_printf(" alloc_top_hi : %lx\n", alloc_top_high); + prom_printf(" rmo_top : %lx\n", rmo_top); + prom_printf(" ram_top : %lx\n", ram_top); } static void __init prom_close_stdin(void) @@ -1566,7 +1568,7 @@ static void __init prom_instantiate_opal(void) return; } - prom_printf("instantiating opal at 0x%x...", base); + prom_printf("instantiating opal at 0x%llx...", base); if (call_prom_ret("call-method", 4, 3, rets, ADDR("load-opal-runtime"), @@ -1582,10 +1584,10 @@ static void __init prom_instantiate_opal(void) reserve_mem(base, size); - prom_debug("opal base = 0x%x\n", base); - prom_debug("opal align = 0x%x\n", align); - prom_debug("opal entry = 0x%x\n", entry); - prom_debug("opal size = 0x%x\n", (long)size); + prom_debug("opal base = 0x%llx\n", base); + prom_debug("opal align = 0x%llx\n", align); + prom_debug("opal entry = 0x%llx\n", entry); + prom_debug("opal size = 0x%llx\n", size); prom_setprop(opal_node, "/ibm,opal", "opal-base-address", &base, sizeof(base)); @@ -1662,7 +1664,7 @@ static void __init prom_instantiate_rtas(void) prom_debug("rtas base = 0x%x\n", base); prom_debug("rtas entry = 0x%x\n", entry); - prom_debug("rtas size = 0x%x\n", (long)size); + prom_debug("rtas size = 0x%x\n", size); prom_debug("prom_instantiate_rtas: end...\n"); } @@ -1720,7 +1722,7 @@ static void __init prom_instantiate_sml(void) if (base == 0) prom_panic("Could not allocate memory for sml\n"); - prom_printf("instantiating sml at 0x%x...", base); + prom_printf("instantiating sml at 0x%llx...", base); memset((void *)base, 0, size); @@ -1739,8 +1741,8 @@ static void __init prom_instantiate_sml(void) prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-size", &size, sizeof(size)); - prom_debug("sml base = 0x%x\n", base); - prom_debug("sml size = 0x%x\n", (long)size); + prom_debug("sml base = 0x%llx\n", base); + prom_debug("sml size = 0x%x\n", size); prom_debug("prom_instantiate_sml: end...\n"); } @@ -1841,7 +1843,7 @@ static void __init prom_initialize_tce_table(void) prom_debug("TCE table: %s\n", path); prom_debug("\tnode = 0x%x\n", node); - prom_debug("\tbase = 0x%x\n", base); + prom_debug("\tbase = 0x%llx\n", base); prom_debug("\tsize = 0x%x\n", minsize); /* Initialize the table to have a one-to-one mapping @@ -1928,12 +1930,12 @@ static void __init prom_hold_cpus(void) } prom_debug("prom_hold_cpus: start...\n"); - prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); - prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); - prom_debug(" 1) acknowledge = 0x%x\n", + prom_debug(" 1) spinloop = 0x%lx\n", (unsigned long)spinloop); + prom_debug(" 1) *spinloop = 0x%lx\n", *spinloop); + prom_debug(" 1) acknowledge = 0x%lx\n", (unsigned long)acknowledge); - prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); - prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); + prom_debug(" 1) *acknowledge = 0x%lx\n", *acknowledge); + prom_debug(" 1) secondary_hold = 0x%lx\n", secondary_hold); /* Set the common spinloop variable, so all of the secondary cpus * will block when they are awakened from their OF spinloop. @@ -1961,7 +1963,7 @@ static void __init prom_hold_cpus(void) prom_getprop(node, "reg", ®, sizeof(reg)); cpu_no = be32_to_cpu(reg); - prom_debug("cpu hw idx = %lu\n", cpu_no); + prom_debug("cpu hw idx = %u\n", cpu_no); /* Init the acknowledge var which will be reset by * the secondary cpu when it awakens from its OF @@ -1971,7 +1973,7 @@ static void __init prom_hold_cpus(void) if (cpu_no != prom.cpu) { /* Primary Thread of non-boot cpu or any thread */ - prom_printf("starting cpu hw idx %lu... ", cpu_no); + prom_printf("starting cpu hw idx %u... ", cpu_no); call_prom("start-cpu", 3, 0, node, secondary_hold, cpu_no); @@ -1982,11 +1984,11 @@ static void __init prom_hold_cpus(void) if (*acknowledge == cpu_no) prom_printf("done\n"); else - prom_printf("failed: %x\n", *acknowledge); + prom_printf("failed: %lx\n", *acknowledge); } #ifdef CONFIG_SMP else - prom_printf("boot cpu hw idx %lu\n", cpu_no); + prom_printf("boot cpu hw idx %u\n", cpu_no); #endif /* CONFIG_SMP */ } @@ -2264,7 +2266,7 @@ static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, while ((*mem_start + needed) > *mem_end) { unsigned long room, chunk; - prom_debug("Chunk exhausted, claiming more at %x...\n", + prom_debug("Chunk exhausted, claiming more at %lx...\n", alloc_bottom); room = alloc_top - alloc_bottom; if (room > DEVTREE_CHUNK_SIZE) @@ -2490,7 +2492,7 @@ static void __init flatten_device_tree(void) room = alloc_top - alloc_bottom - 0x4000; if (room > DEVTREE_CHUNK_SIZE) room = DEVTREE_CHUNK_SIZE; - prom_debug("starting device tree allocs at %x\n", alloc_bottom); + prom_debug("starting device tree allocs at %lx\n", alloc_bottom); /* Now try to claim that */ mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); @@ -2553,7 +2555,7 @@ static void __init flatten_device_tree(void) int i; prom_printf("reserved memory map:\n"); for (i = 0; i < mem_reserve_cnt; i++) - prom_printf(" %x - %x\n", + prom_printf(" %llx - %llx\n", be64_to_cpu(mem_reserve_map[i].base), be64_to_cpu(mem_reserve_map[i].size)); } @@ -2563,9 +2565,9 @@ static void __init flatten_device_tree(void) */ mem_reserve_cnt = MEM_RESERVE_MAP_SIZE; - prom_printf("Device tree strings 0x%x -> 0x%x\n", + prom_printf("Device tree strings 0x%lx -> 0x%lx\n", dt_string_start, dt_string_end); - prom_printf("Device tree struct 0x%x -> 0x%x\n", + prom_printf("Device tree struct 0x%lx -> 0x%lx\n", dt_struct_start, dt_struct_end); } @@ -2997,7 +2999,7 @@ static void __init prom_find_boot_cpu(void) prom_getprop(cpu_pkg, "reg", &rval, sizeof(rval)); prom.cpu = be32_to_cpu(rval); - prom_debug("Booting CPU hw index = %lu\n", prom.cpu); + prom_debug("Booting CPU hw index = %d\n", prom.cpu); } static void __init prom_check_initrd(unsigned long r3, unsigned long r4) @@ -3019,8 +3021,8 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) reserve_mem(prom_initrd_start, prom_initrd_end - prom_initrd_start); - prom_debug("initrd_start=0x%x\n", prom_initrd_start); - prom_debug("initrd_end=0x%x\n", prom_initrd_end); + prom_debug("initrd_start=0x%lx\n", prom_initrd_start); + prom_debug("initrd_end=0x%lx\n", prom_initrd_end); } #endif /* CONFIG_BLK_DEV_INITRD */ } @@ -3273,7 +3275,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* Don't print anything after quiesce under OPAL, it crashes OFW */ if (of_platform != PLATFORM_OPAL) { prom_printf("Booting Linux via __start() @ 0x%lx ...\n", kbase); - prom_debug("->dt_header_start=0x%x\n", hdr); + prom_debug("->dt_header_start=0x%lx\n", hdr); } #ifdef CONFIG_PPC32 diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 4dffa611376d67850ac4ef8730a547fcccf63491..e14cec6bc3398ef4d9d7ae2b608ae0a4a806ed26 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -433,7 +433,7 @@ long kvmppc_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl, /* This only handles v2 IOMMU type, v1 is handled via ioctl() */ return H_TOO_HARD; - if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, &hpa))) + if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, tbl->it_page_shift, &hpa))) return H_HARDWARE; if (mm_iommu_mapped_inc(mem)) diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index c32e9bfe75b1abbf6b27a574f91bf5b3fcaf5e66..648cf6c0134899b67181f30122810669387631f5 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -262,7 +262,8 @@ static long kvmppc_rm_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl, if (!mem) return H_TOO_HARD; - if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, &hpa))) + if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, tbl->it_page_shift, + &hpa))) return H_HARDWARE; pua = (void *) vmalloc_to_phys(pua); @@ -431,7 +432,8 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K); if (mem) - prereg = mm_iommu_ua_to_hpa_rm(mem, ua, &tces) == 0; + prereg = mm_iommu_ua_to_hpa_rm(mem, ua, + IOMMU_PAGE_SHIFT_4K, &tces) == 0; } if (!prereg) { diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index a787776822d86639964febb518943b2e24435507..0378def28d411debec742d282991b8ef5c3ba097 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -12,6 +12,7 @@ #include #include #include +#include .text @@ -23,7 +24,7 @@ _GLOBAL(strncpy) mtctr r5 addi r6,r3,-1 addi r4,r4,-1 - .balign 16 + .balign IFETCH_ALIGN_BYTES 1: lbzu r0,1(r4) cmpwi 0,r0,0 stbu r0,1(r6) @@ -43,7 +44,7 @@ _GLOBAL(strncmp) mtctr r5 addi r5,r3,-1 addi r4,r4,-1 - .balign 16 + .balign IFETCH_ALIGN_BYTES 1: lbzu r3,1(r5) cmpwi 1,r3,0 lbzu r0,1(r4) @@ -77,7 +78,7 @@ _GLOBAL(memchr) beq- 2f mtctr r5 addi r3,r3,-1 - .balign 16 + .balign IFETCH_ALIGN_BYTES 1: lbzu r0,1(r3) cmpw 0,r0,r4 bdnzf 2,1b diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index e0a2d8e806edb01a3b24ab063ec41e87defb0e1f..816055927ee47ba05db7e1d3675461de66052636 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -19,6 +19,7 @@ #include #include #include +#include static DEFINE_MUTEX(mem_list_mutex); @@ -27,6 +28,7 @@ struct mm_iommu_table_group_mem_t { struct rcu_head rcu; unsigned long used; atomic64_t mapped; + unsigned int pageshift; u64 ua; /* userspace address */ u64 entries; /* number of entries in hpas[] */ u64 *hpas; /* vmalloc'ed */ @@ -126,6 +128,8 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, { struct mm_iommu_table_group_mem_t *mem; long i, j, ret = 0, locked_entries = 0; + unsigned int pageshift; + unsigned long flags; struct page *page = NULL; mutex_lock(&mem_list_mutex); @@ -160,6 +164,12 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, goto unlock_exit; } + /* + * For a starting point for a maximum page size calculation + * we use @ua and @entries natural alignment to allow IOMMU pages + * smaller than huge pages but still bigger than PAGE_SIZE. + */ + mem->pageshift = __ffs(ua | (entries << PAGE_SHIFT)); mem->hpas = vzalloc(entries * sizeof(mem->hpas[0])); if (!mem->hpas) { kfree(mem); @@ -200,6 +210,23 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, } } populate: + pageshift = PAGE_SHIFT; + if (PageCompound(page)) { + pte_t *pte; + struct page *head = compound_head(page); + unsigned int compshift = compound_order(head); + + local_irq_save(flags); /* disables as well */ + pte = find_linux_pte(mm->pgd, ua, NULL, &pageshift); + local_irq_restore(flags); + + /* Double check it is still the same pinned page */ + if (pte && pte_page(*pte) == head && + pageshift == compshift) + pageshift = max_t(unsigned int, pageshift, + PAGE_SHIFT); + } + mem->pageshift = min(mem->pageshift, pageshift); mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; } @@ -350,7 +377,7 @@ struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, EXPORT_SYMBOL_GPL(mm_iommu_find); long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa) + unsigned long ua, unsigned int pageshift, unsigned long *hpa) { const long entry = (ua - mem->ua) >> PAGE_SHIFT; u64 *va = &mem->hpas[entry]; @@ -358,6 +385,9 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, if (entry >= mem->entries) return -EFAULT; + if (pageshift > mem->pageshift) + return -EFAULT; + *hpa = *va | (ua & ~PAGE_MASK); return 0; @@ -365,7 +395,7 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, EXPORT_SYMBOL_GPL(mm_iommu_ua_to_hpa); long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa) + unsigned long ua, unsigned int pageshift, unsigned long *hpa) { const long entry = (ua - mem->ua) >> PAGE_SHIFT; void *va = &mem->hpas[entry]; @@ -374,6 +404,9 @@ long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, if (entry >= mem->entries) return -EFAULT; + if (pageshift > mem->pageshift) + return -EFAULT; + pa = (void *) vmalloc_to_phys(va); if (!pa) return -EFAULT; diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 13cfe413b40d48cf0bca57fd757dc63bc01487dc..6d9bf014b3e78173fec41ade3d33d4d8bbc97512 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -62,14 +62,14 @@ static inline void slb_shadow_update(unsigned long ea, int ssize, * updating it. No write barriers are needed here, provided * we only update the current CPU's SLB shadow buffer. */ - p->save_area[index].esid = 0; - p->save_area[index].vsid = cpu_to_be64(mk_vsid_data(ea, ssize, flags)); - p->save_area[index].esid = cpu_to_be64(mk_esid_data(ea, ssize, index)); + WRITE_ONCE(p->save_area[index].esid, 0); + WRITE_ONCE(p->save_area[index].vsid, cpu_to_be64(mk_vsid_data(ea, ssize, flags))); + WRITE_ONCE(p->save_area[index].esid, cpu_to_be64(mk_esid_data(ea, ssize, index))); } static inline void slb_shadow_clear(enum slb_index index) { - get_slb_shadow()->save_area[index].esid = 0; + WRITE_ONCE(get_slb_shadow()->save_area[index].esid, 0); } static inline void create_shadowed_slbe(unsigned long ea, int ssize, diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index bd0786c23109b51f61ab352d873e01c32c7cd45d..254634fb3fc75198b037c3a8e68da1baf16ac424 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -203,25 +203,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func) { + unsigned int i, ctx_idx = ctx->idx; + + /* Load function address into r12 */ + PPC_LI64(12, func); + + /* For bpf-to-bpf function calls, the callee's address is unknown + * until the last extra pass. As seen above, we use PPC_LI64() to + * load the callee's address, but this may optimize the number of + * instructions required based on the nature of the address. + * + * Since we don't want the number of instructions emitted to change, + * we pad the optimized PPC_LI64() call with NOPs to guarantee that + * we always have a five-instruction sequence, which is the maximum + * that PPC_LI64() can emit. + */ + for (i = ctx->idx - ctx_idx; i < 5; i++) + PPC_NOP(); + #ifdef PPC64_ELF_ABI_v1 - /* func points to the function descriptor */ - PPC_LI64(b2p[TMP_REG_2], func); - /* Load actual entry point from function descriptor */ - PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); - /* ... and move it to LR */ - PPC_MTLR(b2p[TMP_REG_1]); /* * Load TOC from function descriptor at offset 8. * We can clobber r2 since we get called through a * function pointer (so caller will save/restore r2) * and since we don't use a TOC ourself. */ - PPC_BPF_LL(2, b2p[TMP_REG_2], 8); -#else - /* We can clobber r12 */ - PPC_FUNC_ADDR(12, func); - PPC_MTLR(12); + PPC_BPF_LL(2, 12, 8); + /* Load actual entry point from function descriptor */ + PPC_BPF_LL(12, 12, 0); #endif + + PPC_MTLR(12); PPC_BLRL(); } diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c index 03d115aaa1916638d01e782326a8f3fc6412f730..acde7bbe07164ebfb1459c5fda7255863f8a30ed 100644 --- a/arch/powerpc/platforms/chrp/time.c +++ b/arch/powerpc/platforms/chrp/time.c @@ -28,6 +28,8 @@ #include #include +#include + extern spinlock_t rtc_lock; #define NVRAM_AS0 0x74 @@ -63,7 +65,7 @@ long __init chrp_time_init(void) return 0; } -int chrp_cmos_clock_read(int addr) +static int chrp_cmos_clock_read(int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -71,7 +73,7 @@ int chrp_cmos_clock_read(int addr) return (inb(nvram_data)); } -void chrp_cmos_clock_write(unsigned long val, int addr) +static void chrp_cmos_clock_write(unsigned long val, int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 89c54de88b7a0f3a13ebd851d91f481fcb82d47b..bf4a125faec66664cd8c76d29852ee37c3bee166 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -35,6 +35,8 @@ */ #define HW_BROADWAY_ICR 0x00 #define HW_BROADWAY_IMR 0x04 +#define HW_STARLET_ICR 0x08 +#define HW_STARLET_IMR 0x0c /* @@ -74,6 +76,9 @@ static void hlwd_pic_unmask(struct irq_data *d) void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); + + /* Make sure the ARM (aka. Starlet) doesn't handle this interrupt. */ + clrbits32(io_base + HW_STARLET_IMR, 1 << irq); } diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index c3c9bbb3573ae6bcbc0ff77e73bd68305bf50f43..ba0964c1762082e6eb5b982f8d6336192f98fbc1 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -468,7 +468,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) boot_infos_t *bi = (boot_infos_t *) r4; unsigned long hdr; unsigned long space; - unsigned long ptr, x; + unsigned long ptr; char *model; unsigned long offset = reloc_offset(); @@ -562,6 +562,8 @@ void __init bootx_init(unsigned long r3, unsigned long r4) * MMU switched OFF, so this should not be useful anymore. */ if (bi->version < 4) { + unsigned long x __maybe_unused; + bootx_printf("Touching pages...\n"); /* diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index ab668cb72263ce69da918e712183c3083d2140d9..8b2eab1340f4ecb3a8d9ac7b95e46de0ac803982 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -352,6 +352,7 @@ static int pmac_late_init(void) } machine_late_initcall(powermac, pmac_late_init); +void note_bootable_part(dev_t dev, int part, int goodness); /* * This is __ref because we check for "initializing" before * touching any of the __init sensitive things and "initializing" diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index 05480e4cc5cabdab4e8bcc5006b8d0691b4bfef7..bc764a674594e040989345795d37dba9512895db 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -116,7 +116,7 @@ struct hws_basic_entry { struct hws_diag_entry { unsigned int def:16; /* 0-15 Data Entry Format */ - unsigned int R:14; /* 16-19 and 20-30 reserved */ + unsigned int R:15; /* 16-19 and 20-30 reserved */ unsigned int I:1; /* 31 entry valid or invalid */ u8 data[]; /* Machine-dependent sample data */ } __packed; @@ -132,7 +132,9 @@ struct hws_trailer_entry { unsigned int f:1; /* 0 - Block Full Indicator */ unsigned int a:1; /* 1 - Alert request control */ unsigned int t:1; /* 2 - Timestamp format */ - unsigned long long:61; /* 3 - 63: Reserved */ + unsigned int :29; /* 3 - 31: Reserved */ + unsigned int bsdes:16; /* 32-47: size of basic SDE */ + unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ }; unsigned long long flags; /* 0 - 63: All indicators */ }; diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 26a42b91140b39d5ad5a4547d38d5cd3ab73a6fc..19e3a812306b028d96127c152375f3db9ca70934 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -219,7 +219,9 @@ CONFIG_DM_MIRROR=y CONFIG_DM_ZERO=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE=1 CONFIG_DM_VERITY_FEC=y +CONFIG_DM_ANDROID_VERITY=y CONFIG_NETDEVICES=y CONFIG_NETCONSOLE=y CONFIG_NETCONSOLE_DYNAMIC=y @@ -447,6 +449,12 @@ CONFIG_SECURITY_PATH=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_CRYPTO_RSA=y # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="verity_dev_keys.x509" diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index f7bfa701219b3cd67d2891b85901be88ada912af..0fae7096ae23cc5372cc78fa43ebfaa84f0e66a7 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -933,7 +933,7 @@ ENTRY(\sym) call \do_sym - jmp error_exit /* %ebx: no swapgs flag */ + jmp error_exit .endif END(\sym) .endm @@ -1166,7 +1166,6 @@ END(paranoid_exit) /* * Save all registers in pt_regs, and switch GS if needed. - * Return: EBX=0: came from user mode; EBX=1: otherwise */ ENTRY(error_entry) UNWIND_HINT_FUNC @@ -1213,7 +1212,6 @@ ENTRY(error_entry) * for these here too. */ .Lerror_kernelspace: - incl %ebx leaq native_irq_return_iret(%rip), %rcx cmpq %rcx, RIP+8(%rsp) je .Lerror_bad_iret @@ -1247,28 +1245,20 @@ ENTRY(error_entry) /* * Pretend that the exception came from user mode: set up pt_regs - * as if we faulted immediately after IRET and clear EBX so that - * error_exit knows that we will be returning to user mode. + * as if we faulted immediately after IRET. */ mov %rsp, %rdi call fixup_bad_iret mov %rax, %rsp - decl %ebx jmp .Lerror_entry_from_usermode_after_swapgs END(error_entry) - -/* - * On entry, EBX is a "return to kernel mode" flag: - * 1: already in kernel mode, don't need SWAPGS - * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode - */ ENTRY(error_exit) UNWIND_HINT_REGS DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF - testl %ebx, %ebx - jnz retint_kernel + testb $3, CS(%rsp) + jz retint_kernel jmp retint_user END(error_exit) diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 10b39d44981c69a2002dfc9608e7a705eaa562f0..25386be0d7576252ac1757b54d06040577747a30 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -410,9 +410,11 @@ static int alloc_bts_buffer(int cpu) ds->bts_buffer_base = (unsigned long) cea; ds_update_cea(cea, buffer, BTS_BUFFER_SIZE, PAGE_KERNEL); ds->bts_index = ds->bts_buffer_base; - max = BTS_RECORD_SIZE * (BTS_BUFFER_SIZE / BTS_RECORD_SIZE); - ds->bts_absolute_maximum = ds->bts_buffer_base + max; - ds->bts_interrupt_threshold = ds->bts_absolute_maximum - (max / 16); + max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE; + ds->bts_absolute_maximum = ds->bts_buffer_base + + max * BTS_RECORD_SIZE; + ds->bts_interrupt_threshold = ds->bts_absolute_maximum - + (max / 16) * BTS_RECORD_SIZE; return 0; } diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index d45e06346f14d8636f1b4348a84a6e503012c686..c56cb37b88e337dd34a46cd7ffc421062cdaddfd 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -218,7 +218,7 @@ void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *e u64 prev_count, new_count, delta; int shift; - if (event->hw.idx >= UNCORE_PMC_IDX_FIXED) + if (event->hw.idx == UNCORE_PMC_IDX_FIXED) shift = 64 - uncore_fixed_ctr_bits(box); else shift = 64 - uncore_perf_ctr_bits(box); diff --git a/arch/x86/events/intel/uncore_nhmex.c b/arch/x86/events/intel/uncore_nhmex.c index 93e7a8397cde249625a624ffa2c3f248f3b21009..173e2674be6ef24293c5113b43d738af3d3f1981 100644 --- a/arch/x86/events/intel/uncore_nhmex.c +++ b/arch/x86/events/intel/uncore_nhmex.c @@ -246,7 +246,7 @@ static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct p { struct hw_perf_event *hwc = &event->hw; - if (hwc->idx >= UNCORE_PMC_IDX_FIXED) + if (hwc->idx == UNCORE_PMC_IDX_FIXED) wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0); else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0) wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h index c356098b6fb92b8ff7d42b2fd813c2a8551d3db1..4d4015ddcf2633e9e8388216f9e9c8639e2eced8 100644 --- a/arch/x86/include/asm/apm.h +++ b/arch/x86/include/asm/apm.h @@ -7,8 +7,6 @@ #ifndef _ASM_X86_MACH_DEFAULT_APM_H #define _ASM_X86_MACH_DEFAULT_APM_H -#include - #ifdef APM_ZERO_SEGS # define APM_DO_ZERO_SEGS \ "pushl %%ds\n\t" \ @@ -34,7 +32,6 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, * N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ - firmware_restrict_branch_speculation_start(); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -47,7 +44,6 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, "=S" (*esi) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); - firmware_restrict_branch_speculation_end(); } static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, @@ -60,7 +56,6 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, * N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ - firmware_restrict_branch_speculation_start(); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -73,7 +68,6 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, "=S" (si) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); - firmware_restrict_branch_speculation_end(); return error; } diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 386a6900e206f6578e3b38ee7f085d36ac50a928..3bf87f92b932d1a023c55e5cf28bd7cd085f9198 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -46,6 +46,65 @@ #define _ASM_SI __ASM_REG(si) #define _ASM_DI __ASM_REG(di) +#ifndef __x86_64__ +/* 32 bit */ + +#define _ASM_ARG1 _ASM_AX +#define _ASM_ARG2 _ASM_DX +#define _ASM_ARG3 _ASM_CX + +#define _ASM_ARG1L eax +#define _ASM_ARG2L edx +#define _ASM_ARG3L ecx + +#define _ASM_ARG1W ax +#define _ASM_ARG2W dx +#define _ASM_ARG3W cx + +#define _ASM_ARG1B al +#define _ASM_ARG2B dl +#define _ASM_ARG3B cl + +#else +/* 64 bit */ + +#define _ASM_ARG1 _ASM_DI +#define _ASM_ARG2 _ASM_SI +#define _ASM_ARG3 _ASM_DX +#define _ASM_ARG4 _ASM_CX +#define _ASM_ARG5 r8 +#define _ASM_ARG6 r9 + +#define _ASM_ARG1Q rdi +#define _ASM_ARG2Q rsi +#define _ASM_ARG3Q rdx +#define _ASM_ARG4Q rcx +#define _ASM_ARG5Q r8 +#define _ASM_ARG6Q r9 + +#define _ASM_ARG1L edi +#define _ASM_ARG2L esi +#define _ASM_ARG3L edx +#define _ASM_ARG4L ecx +#define _ASM_ARG5L r8d +#define _ASM_ARG6L r9d + +#define _ASM_ARG1W di +#define _ASM_ARG2W si +#define _ASM_ARG3W dx +#define _ASM_ARG4W cx +#define _ASM_ARG5W r8w +#define _ASM_ARG6W r9w + +#define _ASM_ARG1B dil +#define _ASM_ARG2B sil +#define _ASM_ARG3B dl +#define _ASM_ARG4B cl +#define _ASM_ARG5B r8b +#define _ASM_ARG6B r9b + +#endif + /* * Macros to generate condition code outputs from inline assembly, * The output operand must be type "bool". diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 89f08955fff733c688a5ce4f4a0b8d74050ee617..c4fc17220df959f2d5feb493af6374e7dacce613 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -13,7 +13,7 @@ * Interrupt control: */ -static inline unsigned long native_save_fl(void) +extern inline unsigned long native_save_fl(void) { unsigned long flags; diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 295abaa58addefb01f99051c5b9bc32b2e48054d..4137f7ba0f881ad6478a26af3706ce36c30e1d5d 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -58,6 +58,7 @@ obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o obj-y += tsc.o tsc_msr.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o +obj-y += irqflags.o obj-y += process.o obj-y += fpu/ diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index ebdcc368a2d3dc34c0f81b86c1afd2ac457bf1c3..f48a51335538813cdd96ba82a46e87e745d9ef3f 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -580,6 +580,9 @@ static u32 skx_deadline_rev(void) case 0x04: return 0x02000014; } + if (boot_cpu_data.x86_stepping > 4) + return 0; + return ~0U; } diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 2a7fd56e67b364abd75e4d340faba01998f57b1c..63d3e6a6b5efc463f4e2b2003bdbf032df27d5d9 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -240,6 +240,7 @@ #include #include #include +#include #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) extern int (*console_blank_hook)(int); @@ -614,11 +615,13 @@ static long __apm_bios_call(void *_call) gdt[0x40 / 8] = bad_bios_desc; apm_irq_save(flags); + firmware_restrict_branch_speculation_start(); APM_DO_SAVE_SEGS; apm_bios_call_asm(call->func, call->ebx, call->ecx, &call->eax, &call->ebx, &call->ecx, &call->edx, &call->esi); APM_DO_RESTORE_SEGS; + firmware_restrict_branch_speculation_end(); apm_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; put_cpu(); @@ -690,10 +693,12 @@ static long __apm_bios_call_simple(void *_call) gdt[0x40 / 8] = bad_bios_desc; apm_irq_save(flags); + firmware_restrict_branch_speculation_start(); APM_DO_SAVE_SEGS; error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx, &call->eax); APM_DO_RESTORE_SEGS; + firmware_restrict_branch_speculation_end(); apm_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; put_cpu(); diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 58f887f5e03636de85b7785c95bf3d7d658ce573..98e4e4dc4a3bc6ddac0af7098b6a1847f83a176b 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -2150,9 +2150,6 @@ static ssize_t store_int_with_restart(struct device *s, if (check_interval == old_check_interval) return ret; - if (check_interval < 1) - check_interval = 1; - mutex_lock(&mce_sysfs_mutex); mce_restart(); mutex_unlock(&mce_sysfs_mutex); diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index c8e0cda0f272f3b005fa7bba2726fccd41e87f80..4fc0e08a30b9981faf809132ef74a129bd1572a1 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -70,7 +70,7 @@ static DEFINE_MUTEX(microcode_mutex); /* * Serialize late loading so that CPUs get updated one-by-one. */ -static DEFINE_SPINLOCK(update_lock); +static DEFINE_RAW_SPINLOCK(update_lock); struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; @@ -560,9 +560,9 @@ static int __reload_late(void *info) if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC)) return -1; - spin_lock(&update_lock); + raw_spin_lock(&update_lock); apply_microcode_local(&err); - spin_unlock(&update_lock); + raw_spin_unlock(&update_lock); /* siblings return UCODE_OK because their engine got updated already */ if (err > UCODE_NFOUND) { diff --git a/arch/x86/kernel/irqflags.S b/arch/x86/kernel/irqflags.S new file mode 100644 index 0000000000000000000000000000000000000000..ddeeaac8addadcb0556975d31a3262e5473a0141 --- /dev/null +++ b/arch/x86/kernel/irqflags.S @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include + +/* + * unsigned long native_save_fl(void) + */ +ENTRY(native_save_fl) + pushf + pop %_ASM_AX + ret +ENDPROC(native_save_fl) +EXPORT_SYMBOL(native_save_fl) + +/* + * void native_restore_fl(unsigned long flags) + * %eax/%rdi: flags + */ +ENTRY(native_restore_fl) + push %_ASM_ARG1 + popf + ret +ENDPROC(native_restore_fl) +EXPORT_SYMBOL(native_restore_fl) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 43bbece92632a7bc9c1693bae2e75d99ed3d6d33..2ef2f1fe875bf7aa908876014a134d6e91e13e9e 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -890,7 +890,7 @@ static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - page = (void *)__get_free_page(GFP_KERNEL); + page = (void *)__get_free_page(GFP_KERNEL_ACCOUNT); if (!page) return -ENOMEM; cache->objects[cache->nobjs++] = page; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 90747865205d2eba664bfe16ebe678893c99f1e4..8d000fde14140e43f7b535a19c2346033bdbb203 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -7354,6 +7354,8 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu) HRTIMER_MODE_REL_PINNED); vmx->nested.preemption_timer.function = vmx_preemption_timer_fn; + vmx->nested.vpid02 = allocate_vpid(); + vmx->nested.vmxon = true; return 0; @@ -9802,10 +9804,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) goto free_vmcs; } - if (nested) { + if (nested) nested_vmx_setup_ctls_msrs(vmx); - vmx->nested.vpid02 = allocate_vpid(); - } vmx->nested.posted_intr_nv = -1; vmx->nested.current_vmptr = -1ull; @@ -9822,7 +9822,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) return &vmx->vcpu; free_vmcs: - free_vpid(vmx->nested.vpid02); free_loaded_vmcs(vmx->loaded_vmcs); free_msrs: kfree(vmx->guest_msrs); diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index db6d90e451de908d6be6165e6e2e47c5379619e0..e3b18ad49889afc5ae35d2e2796aecd108a93819 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -430,6 +430,7 @@ static void xen_pv_play_dead(void) /* used only with HOTPLUG_CPU */ * data back is to call: */ tick_nohz_idle_enter(); + tick_nohz_idle_stop_tick_protected(); cpuhp_online_idle(CPUHP_AP_ONLINE_IDLE); } diff --git a/arch/x86/xen/xen-pvh.S b/arch/x86/xen/xen-pvh.S index e1a5fbeae08d8a3bf3cb619c023bab096ad4ba2d..5d7554c025fd3b82e5cab0459030079f595a35ee 100644 --- a/arch/x86/xen/xen-pvh.S +++ b/arch/x86/xen/xen-pvh.S @@ -54,6 +54,9 @@ * charge of setting up it's own stack, GDT and IDT. */ +#define PVH_GDT_ENTRY_CANARY 4 +#define PVH_CANARY_SEL (PVH_GDT_ENTRY_CANARY * 8) + ENTRY(pvh_start_xen) cld @@ -98,6 +101,12 @@ ENTRY(pvh_start_xen) /* 64-bit entry point. */ .code64 1: + /* Set base address in stack canary descriptor. */ + mov $MSR_GS_BASE,%ecx + mov $_pa(canary), %eax + xor %edx, %edx + wrmsr + call xen_prepare_pvh /* startup_64 expects boot_params in %rsi. */ @@ -107,6 +116,17 @@ ENTRY(pvh_start_xen) #else /* CONFIG_X86_64 */ + /* Set base address in stack canary descriptor. */ + movl $_pa(gdt_start),%eax + movl $_pa(canary),%ecx + movw %cx, (PVH_GDT_ENTRY_CANARY * 8) + 2(%eax) + shrl $16, %ecx + movb %cl, (PVH_GDT_ENTRY_CANARY * 8) + 4(%eax) + movb %ch, (PVH_GDT_ENTRY_CANARY * 8) + 7(%eax) + + mov $PVH_CANARY_SEL,%eax + mov %eax,%gs + call mk_early_pgtbl_32 mov $_pa(initial_page_table), %eax @@ -150,9 +170,13 @@ gdt_start: .quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* __KERNEL_CS */ #endif .quad GDT_ENTRY(0xc092, 0, 0xfffff) /* __KERNEL_DS */ + .quad GDT_ENTRY(0x4090, 0, 0x18) /* PVH_CANARY_SEL */ gdt_end: - .balign 4 + .balign 16 +canary: + .fill 48, 1, 0 + early_stack: .fill 256, 1, 0 early_stack_end: diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 56c9cd01fd1d6cc70e4c895acb292f5f80808b9e..4a4b7d3c909a846ac66144cedca8fa891e09080d 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -1678,7 +1678,6 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq, if (!RB_EMPTY_NODE(&rq->rb_node)) goto end; - spin_lock_irq(&bfqq->bfqd->lock); /* * If next and rq belong to the same bfq_queue and next is older @@ -1702,7 +1701,6 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq, bfq_remove_request(q, next); - spin_unlock_irq(&bfqq->bfqd->lock); end: bfqg_stats_update_io_merged(bfqq_group(bfqq), next->cmd_flags); } diff --git a/block/bio.c b/block/bio.c index 61975a2bd9e0dd2224138b760e528a73855006e3..3fa014e609997ff693fcd3d98a565a4d05ff57be 100644 --- a/block/bio.c +++ b/block/bio.c @@ -577,6 +577,18 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio) } EXPORT_SYMBOL(bio_phys_segments); +static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src) +{ +#ifdef CONFIG_PFK + dst->bi_iter.bi_dun = src->bi_iter.bi_dun; +#ifdef CONFIG_DM_DEFAULT_KEY + dst->bi_crypt_key = src->bi_crypt_key; + dst->bi_crypt_skip = src->bi_crypt_skip; +#endif + dst->bi_dio_inode = src->bi_dio_inode; +#endif +} + /** * __bio_clone_fast - clone a bio that shares the original bio's biovec * @bio: destination bio @@ -606,6 +618,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; bio->bi_dio_inode = bio_src->bi_dio_inode; + bio_clone_crypt_key(bio, bio_src); bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); @@ -881,16 +894,16 @@ EXPORT_SYMBOL(bio_add_page); */ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) { - unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt; + unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx; struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; struct page **pages = (struct page **)bv; - size_t offset, diff; + size_t offset; ssize_t size; size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset); if (unlikely(size <= 0)) return size ? size : -EFAULT; - nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE; + idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE; /* * Deep magic below: We need to walk the pinned pages backwards @@ -903,17 +916,15 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) bio->bi_iter.bi_size += size; bio->bi_vcnt += nr_pages; - diff = (nr_pages * PAGE_SIZE - offset) - size; - while (nr_pages--) { - bv[nr_pages].bv_page = pages[nr_pages]; - bv[nr_pages].bv_len = PAGE_SIZE; - bv[nr_pages].bv_offset = 0; + while (idx--) { + bv[idx].bv_page = pages[idx]; + bv[idx].bv_len = PAGE_SIZE; + bv[idx].bv_offset = 0; } bv[0].bv_offset += offset; bv[0].bv_len -= offset; - if (diff) - bv[bio->bi_vcnt - 1].bv_len -= diff; + bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size; iov_iter_advance(iter, size); return 0; @@ -1891,6 +1902,7 @@ struct bio *bio_split(struct bio *bio, int sectors, bio_integrity_trim(split); bio_advance(bio, split->bi_iter.bi_size); + bio->bi_iter.bi_done = 0; if (bio_flagged(bio, BIO_TRACE_COMPLETION)) bio_set_flag(split, BIO_TRACE_COMPLETION); diff --git a/block/blk-core.c b/block/blk-core.c index c13b98d883a02cb721cd1bd7765ce9cf98a80aae..a8ca7d4ed992b482e872598317287e34a0652abf 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -781,7 +781,6 @@ EXPORT_SYMBOL(blk_alloc_queue); int blk_queue_enter(struct request_queue *q, bool nowait) { while (true) { - int ret; if (percpu_ref_tryget_live(&q->q_usage_counter)) return 0; @@ -798,13 +797,11 @@ int blk_queue_enter(struct request_queue *q, bool nowait) */ smp_rmb(); - ret = wait_event_interruptible(q->mq_freeze_wq, - !atomic_read(&q->mq_freeze_depth) || - blk_queue_dying(q)); + wait_event(q->mq_freeze_wq, + !atomic_read(&q->mq_freeze_depth) || + blk_queue_dying(q)); if (blk_queue_dying(q)) return -ENODEV; - if (ret) - return ret; } } diff --git a/block/blk-merge.c b/block/blk-merge.c index 4f7e70419ba24ee616f41e5bfa4167887fb7150c..e8c45fd4a9726e2750462eedd3b2036ed9fc75a0 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -7,9 +7,9 @@ #include #include #include -#include -#include +#include +#include #include "blk.h" static struct bio *blk_bio_discard_split(struct request_queue *q, @@ -705,6 +705,7 @@ static struct request *attempt_merge(struct request_queue *q, if (crypto_not_mergeable(req->bio, next->bio)) return 0; + /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn diff --git a/block/elevator.c b/block/elevator.c index 153926a909011e5f2a9759d19e90ab74ef00f405..154dc38a03a394f834efdf7d1f5a2bb14a06098b 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -436,7 +436,7 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, { struct elevator_queue *e = q->elevator; struct request *__rq; - + enum elv_merge ret; /* * Levels of merges: * nomerges: No merges at all attempted @@ -449,9 +449,11 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, /* * First try one-hit cache. */ - if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { - enum elv_merge ret = blk_try_merge(q->last_merge, bio); + if (q->last_merge) { + if (!elv_bio_merge_ok(q->last_merge, bio)) + return ELEVATOR_NO_MERGE; + ret = blk_try_merge(q->last_merge, bio); if (ret != ELEVATOR_NO_MERGE) { *req = q->last_merge; return ret; diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 6251d1b27f0cbd1414287770c8510774a61ba4bc..0e1ea235c12a31363234964bac2482d4836a4928 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -263,5 +263,46 @@ int verify_pkcs7_signature(const void *data, size_t len, return ret; } EXPORT_SYMBOL_GPL(verify_pkcs7_signature); - #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ + +/** + * verify_signature_one - Verify a signature with keys from given keyring + * @sig: The signature to be verified + * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only, + * (void *)1UL for all trusted keys). + * @keyid: key description (not partial) + */ +int verify_signature_one(const struct public_key_signature *sig, + struct key *trusted_keys, const char *keyid) +{ + key_ref_t ref; + struct key *key; + int ret; + + if (!sig) + return -EBADMSG; + if (!trusted_keys) { + trusted_keys = builtin_trusted_keys; + } else if (trusted_keys == (void *)1UL) { +#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING + trusted_keys = secondary_trusted_keys; +#else + trusted_keys = builtin_trusted_keys; +#endif + } + + ref = keyring_search(make_key_ref(trusted_keys, 1), + &key_type_asymmetric, keyid); + if (IS_ERR(ref)) { + pr_err("Asymmetric key (%s) not found in keyring(%s)\n", + keyid, trusted_keys->description); + return -ENOKEY; + } + + key = key_ref_to_ptr(ref); + ret = verify_signature(key, sig); + key_put(key); + return ret; +} +EXPORT_SYMBOL_GPL(verify_signature_one); + diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 815ee1075574af7a03aca33b4d820e5bb4bbaa9b..42dfdd1fd6d88cc1db65b65048c707189b546a0c 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1183,8 +1183,10 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, /* make one iovec available as scatterlist */ err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen); - if (err < 0) + if (err < 0) { + rsgl->sg_num_bytes = 0; return err; + } /* chain the new scatterlist with previous one */ if (areq->last_rsgl) diff --git a/crypto/authenc.c b/crypto/authenc.c index 875470b0e026fb5b61a9e6dfea4dc6e7d9ff06a3..0db344d5a01adc68150145e9b0f32f3303b51569 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -108,6 +108,7 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 0cf5fefdb859b1158460faa278017a524f54a93a..6de852ce4cf8f24f7345376c33f0bb64053f658b 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -90,6 +90,7 @@ static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 * CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 602ae58ee2d81a9754b9a3beda4c3084695c964d..75c3cb377b98b1073cf1e5f9d97f3385e2c05325 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -69,6 +69,10 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_SAVE_CTX BIT(4) #define LPSS_NO_D3_DELAY BIT(5) +/* Crystal Cove PMIC shares same ACPI ID between different platforms */ +#define BYT_CRC_HRV 2 +#define CHT_CRC_HRV 3 + struct lpss_private_data; struct lpss_device_desc { @@ -162,7 +166,7 @@ static void byt_pwm_setup(struct lpss_private_data *pdata) if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1")) return; - if (!acpi_dev_present("INT33FD", NULL, -1)) + if (!acpi_dev_present("INT33FD", NULL, BYT_CRC_HRV)) pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 6fc204a524932e97f4a2743ae7076f1e12e86ad8..eb857d6ea1fef04725c28d479e3f3268754f82a3 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -472,9 +472,11 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) } control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | OSC_PCI_EXPRESS_PME_CONTROL; + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + if (pci_aer_available()) { if (aer_acpi_firmware_first()) dev_info(&device->dev, diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 7dce3795b8874ba83d29215e5c70daf7e4a3cee9..ee4880bfdcdc98d21f139bdce51bb5776f3f17ab 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -10,7 +10,7 @@ if ANDROID config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" - depends on MMU + depends on MMU && !M68K default n ---help--- Binder is used in Android for both communication between processes, @@ -32,19 +32,6 @@ config ANDROID_BINDER_DEVICES created. Each binder device has its own context manager, and is therefore logically separated from the other devices. -config ANDROID_BINDER_IPC_32BIT - bool "Use old (Android 4.4 and earlier) 32-bit binder API" - depends on !64BIT && ANDROID_BINDER_IPC - default y - ---help--- - The Binder API has been changed to support both 32 and 64bit - applications in a mixed environment. - - Enable this to support an old 32-bit Android user-space (v4.4 and - earlier). - - Note that enabling this will break newer Android user-space. - config ANDROID_BINDER_IPC_SELFTEST bool "Android Binder IPC Driver Selftest" depends on ANDROID_BINDER_IPC diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 751777fd64bb7274376ca110c2cea32b2eaca19b..9c06e7f46d7f0f1037b6c36bccfa4a939f926946 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -72,10 +72,6 @@ #include #include -#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT -#define BINDER_IPC_32BIT 1 -#endif - #include #include #include "binder_alloc.h" @@ -142,7 +138,7 @@ enum { }; static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; -module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); +module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, 0444); @@ -161,7 +157,7 @@ static int binder_set_stop_on_user_error(const char *val, return ret; } module_param_call(stop_on_user_error, binder_set_stop_on_user_error, - param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); + param_get_int, &binder_stop_on_user_error, 0644); #define binder_debug(mask, x...) \ do { \ @@ -250,7 +246,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( unsigned int cur = atomic_inc_return(&log->cur); if (cur >= ARRAY_SIZE(log->entry)) - log->full = 1; + log->full = true; e = &log->entry[cur % ARRAY_SIZE(log->entry)]; WRITE_ONCE(e->debug_id_done, 0); /* @@ -2212,8 +2208,8 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) struct binder_object_header *hdr; size_t object_size = 0; - if (offset > buffer->data_size - sizeof(*hdr) || - buffer->data_size < sizeof(*hdr) || + if (buffer->data_size < sizeof(*hdr) || + offset > buffer->data_size - sizeof(*hdr) || !IS_ALIGNED(offset, sizeof(u32))) return 0; @@ -2802,7 +2798,7 @@ static bool binder_proc_transaction(struct binder_transaction *t, if (node->has_async_transaction) { pending_async = true; } else { - node->has_async_transaction = 1; + node->has_async_transaction = true; } } @@ -3667,7 +3663,7 @@ static int binder_thread_write(struct binder_proc *proc, w = binder_dequeue_work_head_ilocked( &buf_node->async_todo); if (!w) { - buf_node->has_async_transaction = 0; + buf_node->has_async_transaction = false; } else { binder_enqueue_work_ilocked( w, &proc->todo); @@ -4095,6 +4091,7 @@ static int binder_thread_read(struct binder_proc *proc, binder_inner_proc_unlock(proc); if (put_user(e->cmd, (uint32_t __user *)ptr)) return -EFAULT; + cmd = e->cmd; e->cmd = BR_OK; ptr += sizeof(uint32_t); @@ -4901,7 +4898,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) failure_string = "bad vm_flags"; goto err_bad_arg; } - vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; + vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP; + vma->vm_flags &= ~VM_MAYWRITE; + vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; @@ -4914,7 +4913,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) return 0; err_bad_arg: - pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -4924,7 +4923,7 @@ static int binder_open(struct inode *nodp, struct file *filp) struct binder_proc *proc; struct binder_device *binder_dev; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); @@ -4970,7 +4969,7 @@ static int binder_open(struct inode *nodp, struct file *filp) * anyway print all contexts that a given PID has, so this * is not a problem. */ - proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + proc->debugfs_entry = debugfs_create_file(strbuf, 0444, binder_debugfs_dir_entry_proc, (void *)(unsigned long)proc->pid, &binder_proc_fops); @@ -5801,7 +5800,9 @@ static int __init binder_init(void) struct binder_device *device; struct hlist_node *tmp; - binder_alloc_shrinker_init(); + ret = binder_alloc_shrinker_init(); + if (ret) + return ret; atomic_set(&binder_transaction_log.cur, ~0U); atomic_set(&binder_transaction_log_failed.cur, ~0U); @@ -5813,27 +5814,27 @@ static int __init binder_init(void) if (binder_debugfs_dir_entry_root) { debugfs_create_file("state", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_state_fops); debugfs_create_file("stats", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_stats_fops); debugfs_create_file("transactions", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_transactions_fops); debugfs_create_file("transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, &binder_transaction_log, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, &binder_transaction_log_fops); diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index ba6d8d23f20658563cfdea89d850965cf371ee4d..4f382d51def11f4816694be6e7e02aa1598f720f 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -219,7 +219,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, mm = alloc->vma_vm_mm; if (mm) { - down_write(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = alloc->vma; } @@ -288,7 +288,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, /* vm_insert_page does not seem to increment the refcount */ } if (mm) { - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); } return 0; @@ -321,17 +321,18 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, } err_no_vma: if (mm) { - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); } return vma ? -ENOMEM : -ESRCH; } -struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) +static struct binder_buffer *binder_alloc_new_buf_locked( + struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) { struct rb_node *n = alloc->free_buffers.rb_node; struct binder_buffer *buffer; @@ -1006,8 +1007,14 @@ void binder_alloc_init(struct binder_alloc *alloc) INIT_LIST_HEAD(&alloc->buffers); } -void binder_alloc_shrinker_init(void) +int binder_alloc_shrinker_init(void) { - list_lru_init(&binder_alloc_lru); - register_shrinker(&binder_shrinker); + int ret = list_lru_init(&binder_alloc_lru); + + if (ret == 0) { + ret = register_shrinker(&binder_shrinker); + if (ret) + list_lru_destroy(&binder_alloc_lru); + } + return ret; } diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 0b145307f1fd1cfdc76fd03c819bb3c533c28414..9ef64e56385667a53abeab2f41f67b198a8ce86e 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -130,7 +130,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t extra_buffers_size, int is_async); extern void binder_alloc_init(struct binder_alloc *alloc); -void binder_alloc_shrinker_init(void); +extern int binder_alloc_shrinker_init(void); extern void binder_alloc_vma_close(struct binder_alloc *alloc); extern struct binder_buffer * binder_alloc_prepare_to_free(struct binder_alloc *alloc, diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 711dd91b5e2c457211a2b34044cc77123a391a0f..2651c81d1edff9e43766b01ee738b7c8c84a2f10 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2217,12 +2217,16 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (qc->err_mask & ~AC_ERR_OTHER) qc->err_mask &= ~AC_ERR_OTHER; - /* SENSE_VALID trumps dev/unknown error and revalidation */ + /* + * SENSE_VALID trumps dev/unknown error and revalidation. Upper + * layers will determine whether the command is worth retrying + * based on the sense data and device class/type. Otherwise, + * determine directly if the command is worth retrying using its + * error mask and flags. + */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - - /* determine whether the command is worth retrying */ - if (ata_eh_worth_retry(qc)) + else if (ata_eh_worth_retry(qc)) qc->flags |= ATA_QCFLAG_RETRY; /* accumulate error info */ diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index a8d2eb0ceb8d8f78788182f81f8e1e9f9dc8fbbb..2c288d1f42bba0fcdf31ccec72c069bfa60688b9 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1483,6 +1483,8 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) return -EFAULT; if (pool < 0 || pool > ZATM_LAST_POOL) return -EINVAL; + pool = array_index_nospec(pool, + ZATM_LAST_POOL + 1); if (copy_from_user(&info, &((struct zatm_pool_req __user *) arg)->info, sizeof(info))) return -EFAULT; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 692d397ea1e84d8b46c51fae2c3dfbc23a6d178e..a027ef52d77d16ec14103fdf62c001f0ad9eb382 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -422,14 +422,6 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto probe_failed; } - /* - * Ensure devices are listed in devices_kset in correct order - * It's important to move Dev to the end of devices_kset before - * calling .probe, because it could be recursive and parent Dev - * should always go first - */ - devices_kset_move_last(dev); - if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 08a3f3abd5023c21d0b718e4d4be329208e1a3c5..1b065bf7ea1414789dc9e68c5e044cf3e4207037 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -38,6 +38,17 @@ config REGMAP_MMIO config REGMAP_IRQ bool +config REGMAP_WCD_IRQ + depends on SND_SOC + bool "Enable REGMAP IRQ for WCD" + select REGMAP_IRQ + default n + help + Say 'y' here to enable REGMAP_IRQ for generic WCD IRQ. + This config is intended for enabling REGMAP_IRQ for + WCD IRQ. Generic WCD IRQ will be used for + wcd937x and later targets. + config REGMAP_ALLOW_WRITE_DEBUGFS depends on REGMAP && DEBUG_FS bool "Allow REGMAP debugfs write" diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 88564222f4737f162d21a7df59f8b0317f932fad..036c9a37b2269b34e64dc3bb58b123855538897d 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -998,13 +998,14 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, __GFP_KSWAPD_RECLAIM | __GFP_NOWARN | __GFP_HIGHMEM | - __GFP_MOVABLE); + __GFP_MOVABLE | + __GFP_CMA); if (!handle) { zcomp_stream_put(zram->comp); atomic64_inc(&zram->stats.writestall); handle = zs_malloc(zram->mem_pool, comp_len, GFP_NOIO | __GFP_HIGHMEM | - __GFP_MOVABLE); + __GFP_MOVABLE | __GFP_CMA); if (handle) goto compress_again; return -ENOMEM; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 86d7975afaeb84c20f94ebab1c7ed6cac8cd044c..819521d5895e1dd3b78105d0b7f52612358ed982 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -279,6 +279,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME }, /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, @@ -373,6 +374,9 @@ static const struct usb_device_id blacklist_table[] = { /* Additional Realtek 8723BU Bluetooth devices */ { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8723DE Bluetooth devices */ + { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 6f4ebd5e54c8ef3577c960a91e86f5646dfd8779..a6173ddfb5a76afaef672894bd7f130cfe3e507d 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -881,7 +881,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS)); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_RUNNING); return 0; } diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index 72fd1750134d2d5107ffdfef9fe482977548d9e3..942d076cbb0af19c5ac8d73e8bf6dc2f6b4aab80 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c @@ -736,7 +736,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ccn = pmu_to_arm_ccn(event->pmu); if (hw->sample_period) { - dev_warn(ccn->dev, "Sampling not supported!\n"); + dev_dbg(ccn->dev, "Sampling not supported!\n"); return -EOPNOTSUPP; } @@ -744,12 +744,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) event->attr.exclude_kernel || event->attr.exclude_hv || event->attr.exclude_idle || event->attr.exclude_host || event->attr.exclude_guest) { - dev_warn(ccn->dev, "Can't exclude execution levels!\n"); + dev_dbg(ccn->dev, "Can't exclude execution levels!\n"); return -EINVAL; } if (event->cpu < 0) { - dev_warn(ccn->dev, "Can't provide per-task data!\n"); + dev_dbg(ccn->dev, "Can't provide per-task data!\n"); return -EOPNOTSUPP; } /* @@ -771,13 +771,13 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) switch (type) { case CCN_TYPE_MN: if (node_xp != ccn->mn_id) { - dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp); + dev_dbg(ccn->dev, "Invalid MN ID %d!\n", node_xp); return -EINVAL; } break; case CCN_TYPE_XP: if (node_xp >= ccn->num_xps) { - dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp); + dev_dbg(ccn->dev, "Invalid XP ID %d!\n", node_xp); return -EINVAL; } break; @@ -785,11 +785,11 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) break; default: if (node_xp >= ccn->num_nodes) { - dev_warn(ccn->dev, "Invalid node ID %d!\n", node_xp); + dev_dbg(ccn->dev, "Invalid node ID %d!\n", node_xp); return -EINVAL; } if (!arm_ccn_pmu_type_eq(type, ccn->node[node_xp].type)) { - dev_warn(ccn->dev, "Invalid type 0x%x for node %d!\n", + dev_dbg(ccn->dev, "Invalid type 0x%x for node %d!\n", type, node_xp); return -EINVAL; } @@ -808,19 +808,19 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) if (event_id != e->event) continue; if (e->num_ports && port >= e->num_ports) { - dev_warn(ccn->dev, "Invalid port %d for node/XP %d!\n", + dev_dbg(ccn->dev, "Invalid port %d for node/XP %d!\n", port, node_xp); return -EINVAL; } if (e->num_vcs && vc >= e->num_vcs) { - dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n", + dev_dbg(ccn->dev, "Invalid vc %d for node/XP %d!\n", vc, node_xp); return -EINVAL; } valid = 1; } if (!valid) { - dev_warn(ccn->dev, "Invalid event 0x%x for node/XP %d!\n", + dev_dbg(ccn->dev, "Invalid event 0x%x for node/XP %d!\n", event_id, node_xp); return -EINVAL; } diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c index c2c88d443ec7be52c633c8f655a34f804cda30be..f6ef83ff7ce084cb805d2fd0aa2dbe619c541196 100644 --- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -38,6 +39,16 @@ struct arch_info { struct dma_iommu_mapping *mapping; }; +struct mhi_bl_info { + struct mhi_device *mhi_device; + async_cookie_t cookie; + void *ipc_log; +}; + +/* ipc log markings */ +#define DLOG "Dev->Host: " +#define HLOG "Host: " + #ifdef CONFIG_MHI_DEBUG #define MHI_IPC_LOG_PAGES (100) @@ -142,6 +153,107 @@ void mhi_arch_esoc_ops_power_off(void *priv, bool mdm_state) mhi_dev->powered_on = false; } +static void mhi_bl_dl_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ + struct mhi_bl_info *mhi_bl_info = mhi_device_get_devdata(mhi_dev); + char *buf = mhi_result->buf_addr; + + /* force a null at last character */ + buf[mhi_result->bytes_xferd - 1] = 0; + + ipc_log_string(mhi_bl_info->ipc_log, "%s %s", DLOG, buf); +} + +static void mhi_bl_dummy_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ +} + +static void mhi_bl_remove(struct mhi_device *mhi_dev) +{ + struct mhi_bl_info *mhi_bl_info = mhi_device_get_devdata(mhi_dev); + + ipc_log_string(mhi_bl_info->ipc_log, HLOG "Received Remove notif.\n"); + + /* wait for boot monitor to exit */ + async_synchronize_cookie(mhi_bl_info->cookie + 1); +} + +static void mhi_bl_boot_monitor(void *data, async_cookie_t cookie) +{ + struct mhi_bl_info *mhi_bl_info = data; + struct mhi_device *mhi_device = mhi_bl_info->mhi_device; + struct mhi_controller *mhi_cntrl = mhi_device->mhi_cntrl; + /* 15 sec timeout for booting device */ + const u32 timeout = msecs_to_jiffies(15000); + + /* wait for device to enter boot stage */ + wait_event_timeout(mhi_cntrl->state_event, mhi_cntrl->ee == MHI_EE_AMSS + || mhi_cntrl->ee == MHI_EE_DISABLE_TRANSITION, + timeout); + + if (mhi_cntrl->ee == MHI_EE_AMSS) { + ipc_log_string(mhi_bl_info->ipc_log, HLOG + "Device successfully booted to mission mode\n"); + + mhi_unprepare_from_transfer(mhi_device); + } else { + ipc_log_string(mhi_bl_info->ipc_log, HLOG + "Device failed to boot to mission mode, ee = %s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee)); + } +} + +static int mhi_bl_probe(struct mhi_device *mhi_dev, + const struct mhi_device_id *id) +{ + char node_name[32]; + struct mhi_bl_info *mhi_bl_info; + + mhi_bl_info = devm_kzalloc(&mhi_dev->dev, sizeof(*mhi_bl_info), + GFP_KERNEL); + if (!mhi_bl_info) + return -ENOMEM; + + snprintf(node_name, sizeof(node_name), "mhi_bl_%04x_%02u.%02u.%02u", + mhi_dev->dev_id, mhi_dev->domain, mhi_dev->bus, mhi_dev->slot); + + mhi_bl_info->ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, + node_name, 0); + if (!mhi_bl_info->ipc_log) + return -EINVAL; + + mhi_bl_info->mhi_device = mhi_dev; + mhi_device_set_devdata(mhi_dev, mhi_bl_info); + + ipc_log_string(mhi_bl_info->ipc_log, HLOG + "Entered SBL, Session ID:0x%x\n", + mhi_dev->mhi_cntrl->session_id); + + /* start a thread to monitor entering mission mode */ + mhi_bl_info->cookie = async_schedule(mhi_bl_boot_monitor, mhi_bl_info); + + return 0; +} + +static const struct mhi_device_id mhi_bl_match_table[] = { + { .chan = "BL" }, + {}, +}; + +static struct mhi_driver mhi_bl_driver = { + .id_table = mhi_bl_match_table, + .remove = mhi_bl_remove, + .probe = mhi_bl_probe, + .ul_xfer_cb = mhi_bl_dummy_cb, + .dl_xfer_cb = mhi_bl_dl_cb, + .driver = { + .name = "MHI_BL", + .owner = THIS_MODULE, + }, +}; + int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); @@ -212,6 +324,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* save reference state for pcie config space */ arch_info->ref_pcie_state = pci_store_saved_state( mhi_dev->pci_dev); + + mhi_driver_register(&mhi_bl_driver); } return mhi_arch_set_bus_request(mhi_cntrl, 1); diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 84dbbd72a86727b578d80284d1fee97dfbc4697f..32060a9f96fc56d9c712fb9c8867a9cba2f2d590 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -257,12 +257,18 @@ static int mhi_system_resume(struct device *dev) int mhi_system_suspend(struct device *dev) { struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + int ret; MHI_LOG("Entered\n"); /* if rpm status still active then force suspend */ - if (!pm_runtime_status_suspended(dev)) - return mhi_runtime_suspend(dev); + if (!pm_runtime_status_suspended(dev)) { + ret = mhi_runtime_suspend(dev); + if (ret) { + MHI_LOG("suspend failed ret:%d\n", ret); + return ret; + } + } pm_runtime_set_suspended(dev); pm_runtime_disable(dev); diff --git a/drivers/bus/mhi/controllers/mhi_qcom.h b/drivers/bus/mhi/controllers/mhi_qcom.h index 1d06dfeeb1383daeda3955f7454078d1af152183..30333c3fb38533f38a72beaac7824156ddb15f54 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.h +++ b/drivers/bus/mhi/controllers/mhi_qcom.h @@ -24,6 +24,9 @@ #define MHI_RPM_SUSPEND_TMR_MS (1000) #define MHI_PCI_BAR_NUM (0) +extern const char * const mhi_ee_str[MHI_EE_MAX]; +#define TO_MHI_EXEC_STR(ee) (ee >= MHI_EE_MAX ? "INVALID_EE" : mhi_ee_str[ee]) + struct mhi_dev { struct pci_dev *pci_dev; u32 smmu_cfg; diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index ff0dfccb8861abbec8bcd2087a101ea82492bbfc..8fa1d037c3df7c0e8a41c13d1998ebb8a5a8c433 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -50,7 +50,7 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) struct mhi_buf *mhi_buf; u32 sequence_id; u32 rx_status; - enum MHI_EE ee; + enum mhi_ee ee; struct image_info *rddm_image = mhi_cntrl->rddm_image; const u32 delayus = 100; u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus; @@ -556,9 +556,9 @@ void mhi_fw_load_worker(struct work_struct *work) goto error_read; } - /* wait for BHIE event */ + /* wait for SBL event */ ret = wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_BHIE || + mhi_cntrl->ee == MHI_EE_SBL || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), msecs_to_jiffies(mhi_cntrl->timeout_ms)); diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 048c85b9b63449ee2971a94d16fbd9a2b31574fe..76960cef1a7056e86cd06b6f35713e375f07327a 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -27,8 +27,8 @@ const char * const mhi_ee_str[MHI_EE_MAX] = { [MHI_EE_PBL] = "PBL", [MHI_EE_SBL] = "SBL", [MHI_EE_AMSS] = "AMSS", - [MHI_EE_BHIE] = "BHIE", [MHI_EE_RDDM] = "RDDM", + [MHI_EE_WFW] = "WFW", [MHI_EE_PTHRU] = "PASS THRU", [MHI_EE_EDL] = "EDL", [MHI_EE_DISABLE_TRANSITION] = "DISABLE", @@ -38,8 +38,7 @@ const char * const mhi_state_tran_str[MHI_ST_TRANSITION_MAX] = { [MHI_ST_TRANSITION_PBL] = "PBL", [MHI_ST_TRANSITION_READY] = "READY", [MHI_ST_TRANSITION_SBL] = "SBL", - [MHI_ST_TRANSITION_AMSS] = "AMSS", - [MHI_ST_TRANSITION_BHIE] = "BHIE", + [MHI_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", }; const char * const mhi_state_str[MHI_STATE_MAX] = { @@ -900,8 +899,8 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, if (ret) goto error_chan_cfg; - ret = of_property_read_u32(child, "mhi,ee", &mhi_chan->ee); - if (ret || mhi_chan->ee >= MHI_EE_MAX_SUPPORTED) + ret = of_property_read_u32(child, "mhi,ee", &mhi_chan->ee_mask); + if (ret) goto error_chan_cfg; of_property_read_u32(child, "mhi,pollcfg", diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 520616f57a96edb34a0442334c49764972354364..aa1e043033fbaf4cb35fb2e1942e913e8e5e0863 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -375,19 +375,6 @@ enum MHI_BRSTMODE { #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_BRSTMODE_DISABLE && \ mode != MHI_BRSTMODE_ENABLE) -enum MHI_EE { - MHI_EE_PBL = 0x0, - MHI_EE_SBL = 0x1, - MHI_EE_AMSS = 0x2, - MHI_EE_BHIE = 0x3, - MHI_EE_RDDM = 0x4, - MHI_EE_PTHRU = 0x5, - MHI_EE_EDL = 0x6, - MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, - MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ - MHI_EE_MAX, -}; - extern const char * const mhi_ee_str[MHI_EE_MAX]; #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ "INVALID_EE" : mhi_ee_str[ee]) @@ -395,12 +382,13 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \ ee == MHI_EE_EDL) +#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW) + enum MHI_ST_TRANSITION { MHI_ST_TRANSITION_PBL, MHI_ST_TRANSITION_READY, MHI_ST_TRANSITION_SBL, - MHI_ST_TRANSITION_AMSS, - MHI_ST_TRANSITION_BHIE, + MHI_ST_TRANSITION_MISSION_MODE, MHI_ST_TRANSITION_MAX, }; @@ -408,18 +396,6 @@ extern const char * const mhi_state_tran_str[MHI_ST_TRANSITION_MAX]; #define TO_MHI_STATE_TRANS_STR(state) (((state) >= MHI_ST_TRANSITION_MAX) ? \ "INVALID_STATE" : mhi_state_tran_str[state]) -enum MHI_STATE { - MHI_STATE_RESET = 0x0, - MHI_STATE_READY = 0x1, - MHI_STATE_M0 = 0x2, - MHI_STATE_M1 = 0x3, - MHI_STATE_M2 = 0x4, - MHI_STATE_M3 = 0x5, - MHI_STATE_BHI = 0x7, - MHI_STATE_SYS_ERR = 0xFF, - MHI_STATE_MAX, -}; - extern const char * const mhi_state_str[MHI_STATE_MAX]; #define TO_MHI_STATE_STR(state) ((state >= MHI_STATE_MAX || \ !mhi_state_str[state]) ? \ @@ -501,6 +477,16 @@ enum mhi_er_data_type { MHI_ER_DATA_TYPE_MAX = MHI_ER_TSYNC_ELEMENT_TYPE, }; +enum mhi_ch_ee_mask { + MHI_CH_EE_PBL = BIT(MHI_EE_PBL), + MHI_CH_EE_SBL = BIT(MHI_EE_SBL), + MHI_CH_EE_AMSS = BIT(MHI_EE_AMSS), + MHI_CH_EE_RDDM = BIT(MHI_EE_RDDM), + MHI_CH_EE_PTHRU = BIT(MHI_EE_PTHRU), + MHI_CH_EE_WFW = BIT(MHI_EE_WFW), + MHI_CH_EE_EDL = BIT(MHI_EE_EDL), +}; + struct db_cfg { bool reset_req; bool db_mode; @@ -596,7 +582,7 @@ struct mhi_chan { u32 intmod; enum dma_data_direction dir; struct db_cfg db_cfg; - enum MHI_EE ee; + u32 ee_mask; enum MHI_XFER_TYPE xfer_type; enum MHI_CH_STATE ch_state; enum MHI_EV_CCS ccs; @@ -663,8 +649,8 @@ enum MHI_PM_STATE __must_check mhi_tryset_pm_state( const char *to_mhi_pm_state_str(enum MHI_PM_STATE state); void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); -enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl); -enum MHI_STATE mhi_get_m_state(struct mhi_controller *mhi_cntrl); +enum mhi_ee mhi_get_exec_env(struct mhi_controller *mhi_cntrl); +enum mhi_dev_state mhi_get_m_state(struct mhi_controller *mhi_cntrl); int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl, enum MHI_ST_TRANSITION state); void mhi_pm_st_worker(struct work_struct *work); @@ -720,7 +706,8 @@ void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr, void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd); void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); -void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state); +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, + enum mhi_dev_state state); int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability, u32 *offset); int mhi_init_timesync(struct mhi_controller *mhi_cntrl); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 5b79d2fa168d153f75de21dd0952aeea6123c287..c22b474678b2528a0dd6ac6b9cceebabf038cf6a 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -182,7 +182,7 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, db); } -enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl) +enum mhi_ee mhi_get_exec_env(struct mhi_controller *mhi_cntrl) { u32 exec; int ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_EXECENV, &exec); @@ -190,7 +190,7 @@ enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl) return (ret) ? MHI_EE_MAX : exec; } -enum MHI_STATE mhi_get_m_state(struct mhi_controller *mhi_cntrl) +enum mhi_dev_state mhi_get_m_state(struct mhi_controller *mhi_cntrl) { u32 state; int ret = mhi_read_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, @@ -613,7 +613,7 @@ static void mhi_create_time_sync_dev(struct mhi_controller *mhi_cntrl) if (!mhi_tsync || !mhi_tsync->db) return; - if (mhi_cntrl->ee != MHI_EE_AMSS) + if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) return; mhi_dev = mhi_alloc_device(mhi_cntrl); @@ -657,7 +657,8 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) mhi_chan = mhi_cntrl->mhi_chan; for (i = 0; i < mhi_cntrl->max_chan; i++, mhi_chan++) { - if (!mhi_chan->configured || mhi_chan->ee != mhi_cntrl->ee) + if (!mhi_chan->configured || mhi_chan->mhi_dev || + !(mhi_chan->ee_mask & BIT(mhi_cntrl->ee))) continue; mhi_dev = mhi_alloc_device(mhi_cntrl); if (!mhi_dev) @@ -920,7 +921,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, switch (type) { case MHI_PKT_TYPE_STATE_CHANGE_EVENT: { - enum MHI_STATE new_state; + enum mhi_dev_state new_state; new_state = MHI_TRE_GET_EV_STATE(local_rp); @@ -964,7 +965,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, case MHI_PKT_TYPE_EE_EVENT: { enum MHI_ST_TRANSITION st = MHI_ST_TRANSITION_MAX; - enum MHI_EE event = MHI_TRE_GET_EV_EXECENV(local_rp); + enum mhi_ee event = MHI_TRE_GET_EV_EXECENV(local_rp); MHI_LOG("MHI EE received event:%s\n", TO_MHI_EXEC_STR(event)); @@ -972,19 +973,18 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, case MHI_EE_SBL: st = MHI_ST_TRANSITION_SBL; break; + case MHI_EE_WFW: case MHI_EE_AMSS: - st = MHI_ST_TRANSITION_AMSS; + st = MHI_ST_TRANSITION_MISSION_MODE; break; case MHI_EE_RDDM: mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_EE_RDDM); - /* fall thru to wake up the event */ - case MHI_EE_BHIE: write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = event; write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); break; default: MHI_ERR("Unhandled EE event:%s\n", @@ -1160,7 +1160,7 @@ void mhi_ctrl_ev_task(unsigned long data) { struct mhi_event *mhi_event = (struct mhi_event *)data; struct mhi_controller *mhi_cntrl = mhi_event->mhi_cntrl; - enum MHI_STATE state = MHI_STATE_MAX; + enum mhi_dev_state state = MHI_STATE_MAX; enum MHI_PM_STATE pm_state = 0; int ret; @@ -1218,7 +1218,7 @@ irqreturn_t mhi_msi_handlr(int irq_number, void *dev) irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) { struct mhi_controller *mhi_cntrl = dev; - enum MHI_STATE state = MHI_STATE_MAX; + enum mhi_dev_state state = MHI_STATE_MAX; enum MHI_PM_STATE pm_state = 0; MHI_VERB("Enter\n"); @@ -1247,7 +1247,7 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev) /* wake up any events waiting for state change */ MHI_VERB("Enter\n"); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); MHI_VERB("Exit\n"); return IRQ_WAKE_THREAD; @@ -1320,10 +1320,9 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, MHI_LOG("Entered: preparing channel:%d\n", mhi_chan->chan); - if (mhi_cntrl->ee != mhi_chan->ee) { - MHI_ERR("Current EE:%s Required EE:%s for chan:%s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), - TO_MHI_EXEC_STR(mhi_chan->ee), + if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { + MHI_ERR("Current EE:%s Required EE Mask:0x%x for chan:%s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask, mhi_chan->name); return -ENOTCONN; } diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 6ad7a1c6d7e95f9e89ff43f1b992498dbc3826bf..132fb705323f7bbf26c8299d575eb9ad6834b5f4 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -148,7 +148,8 @@ enum MHI_PM_STATE __must_check mhi_tryset_pm_state( return mhi_cntrl->pm_state; } -void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state) +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, + enum mhi_dev_state state) { if (state == MHI_STATE_RESET) { mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, @@ -318,8 +319,8 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_get(mhi_cntrl, false); - /* ring all event rings and CMD ring only if we're in AMSS */ - if (mhi_cntrl->ee == MHI_EE_AMSS) { + /* ring all event rings and CMD ring only if we're in mission mode */ + if (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) { struct mhi_event *mhi_event = mhi_cntrl->mhi_event; struct mhi_cmd *mhi_cmd = &mhi_cntrl->mhi_cmd[PRIMARY_CMD_RING]; @@ -357,7 +358,7 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); MHI_VERB("Exited\n"); return 0; @@ -377,6 +378,7 @@ void mhi_pm_m1_transition(struct mhi_controller *mhi_cntrl) mhi_cntrl->M2++; write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); /* transfer pending, exit M2 immediately */ if (unlikely(atomic_read(&mhi_cntrl->dev_wake))) { @@ -409,7 +411,7 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl) to_mhi_pm_state_str(mhi_cntrl->pm_state)); return -EIO; } - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); mhi_cntrl->M3++; MHI_LOG("Entered mhi_state:%s pm_state:%s\n", @@ -418,17 +420,22 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl) return 0; } -static int mhi_pm_amss_transition(struct mhi_controller *mhi_cntrl) +static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) { int i; struct mhi_event *mhi_event; - MHI_LOG("Processing AMSS Transition\n"); + MHI_LOG("Processing Mission Mode Transition\n"); write_lock_irq(&mhi_cntrl->pm_lock); - mhi_cntrl->ee = MHI_EE_AMSS; + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up(&mhi_cntrl->state_event); + + if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) + return -EIO; + + wake_up_all(&mhi_cntrl->state_event); /* add elements to all HW event rings */ read_lock_bh(&mhi_cntrl->pm_lock); @@ -498,6 +505,9 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, } write_unlock_irq(&mhi_cntrl->pm_lock); + /* wake up any threads waiting for state transitions */ + wake_up_all(&mhi_cntrl->state_event); + /* not handling sys_err, could be middle of shut down */ if (cur_state != transition_state) { MHI_LOG("Failed to transition to state:0x%x from:0x%x\n", @@ -550,7 +560,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, /* release lock and wait for all pending thread to complete */ mutex_unlock(&mhi_cntrl->pm_mutex); MHI_LOG("Waiting for all pending threads to complete\n"); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); flush_work(&mhi_cntrl->st_worker); flush_work(&mhi_cntrl->fw_worker); @@ -697,16 +707,17 @@ void mhi_pm_st_worker(struct work_struct *work) mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); if (MHI_IN_PBL(mhi_cntrl->ee)) - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); break; case MHI_ST_TRANSITION_SBL: write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = MHI_EE_SBL; write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); mhi_create_devices(mhi_cntrl); break; - case MHI_ST_TRANSITION_AMSS: - mhi_pm_amss_transition(mhi_cntrl); + case MHI_ST_TRANSITION_MISSION_MODE: + mhi_pm_mission_mode_transition(mhi_cntrl); break; case MHI_ST_TRANSITION_READY: mhi_ready_state_transition(mhi_cntrl); @@ -722,7 +733,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) { int ret; u32 val; - enum MHI_EE current_ee; + enum mhi_ee current_ee; enum MHI_ST_TRANSITION next_state; MHI_LOG("Requested to power on\n"); @@ -866,11 +877,11 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) return ret; wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_AMSS || + MHI_IN_MISSION_MODE(mhi_cntrl->ee) || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), msecs_to_jiffies(mhi_cntrl->timeout_ms)); - return (mhi_cntrl->ee == MHI_EE_AMSS) ? 0 : -EIO; + return (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -EIO; } EXPORT_SYMBOL(mhi_sync_power_up); diff --git a/drivers/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c index eed5429e918ad400e513ff9697e8d8908a779f65..43527572463f0b6ee9e7ba78a89dce698b8e9406 100644 --- a/drivers/bus/mhi/devices/mhi_uci.c +++ b/drivers/bus/mhi/devices/mhi_uci.c @@ -653,7 +653,6 @@ static const struct mhi_device_id mhi_uci_match_table[] = { { .chan = "QMI0", .driver_data = 0x1000 }, { .chan = "QMI1", .driver_data = 0x1000 }, { .chan = "TF", .driver_data = 0x1000 }, - { .chan = "BL", .driver_data = 0x1000 }, { .chan = "DUN", .driver_data = 0x1000 }, {}, }; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 1316dd5212b8500782863a6d64317a9cd4e0cb67..fd86e1ba09f68be78c34238883fd7303bd5baa1b 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -790,7 +790,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, goto bail; map->phys = (uintptr_t)region_phys; map->size = len; - map->va = (uintptr_t)region_vaddr; + map->va = 0; } else if (mflags == FASTRPC_DMAHANDLE_NOMAP) { VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); if (err) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 8c77d88245c5b1645b6379c79e90352d89ed639f..0b0911baae0912049e0507b7ac1181a9542e807e 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -249,8 +249,6 @@ static void dci_chk_handshake(unsigned long data) if (index < 0 || index >= NUM_DCI_PROC) return; - queue_work(driver->diag_dci_wq, - &dci_channel_status[index].handshake_work); } #endif @@ -2710,8 +2708,8 @@ static void diag_dci_init_handshake_remote(void) for (i = DCI_REMOTE_BASE; i < NUM_DCI_PROC; i++) { temp = &dci_channel_status[i]; temp->id = i; - setup_timer(&temp->wait_time, dci_chk_handshake, i); INIT_WORK(&temp->handshake_work, dci_handshake_work_fn); + setup_timer(&temp->wait_time, dci_chk_handshake, i); } } diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 75413b9e472df833f2fe62482f614f645d0cb494..4fd21d8327cc8ad54d2d773119fb80829fe69dd0 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -336,12 +336,13 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) int header_len = sizeof(struct diag_ctrl_msg_mask); uint8_t *buf = NULL, *temp = NULL; uint8_t upd = 0; - uint8_t msg_mask_tbl_count_local; + uint8_t msg_mask_tbl_count_local = 0; uint32_t mask_size = 0, pd_mask = 0; struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; struct diagfwd_info *fwd_info = NULL; + struct diag_md_session_t *md_session_info = NULL; if (peripheral >= NUM_PERIPHERALS) return; @@ -357,14 +358,19 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) if (driver->md_session_mask != 0) { if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) { - if (driver->md_session_map[peripheral]) + if (driver->md_session_map[peripheral]) { mask_info = driver->md_session_map[peripheral]->msg_mask; + md_session_info = + driver->md_session_map[peripheral]; + } } else if (driver->md_session_mask & pd_mask) { upd = diag_mask_to_pd_value(driver->md_session_mask); - if (upd && driver->md_session_map[upd]) + if (upd && driver->md_session_map[upd]) { mask_info = driver->md_session_map[upd]->msg_mask; + md_session_info = driver->md_session_map[upd]; + } } else { DIAG_LOG(DIAG_DEBUG_MASKS, "asking for mask update with unknown session mask\n"); @@ -383,7 +389,10 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } buf = mask_info->update_buf; - msg_mask_tbl_count_local = driver->msg_mask_tbl_count; + if (md_session_info) + msg_mask_tbl_count_local = md_session_info->msg_mask_tbl_count; + else + msg_mask_tbl_count_local = driver->msg_mask_tbl_count; mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { @@ -565,6 +574,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, { int i; int write_len = 0; + uint8_t msg_mask_tbl_count = 0; struct diag_msg_mask_t *mask_ptr = NULL; struct diag_msg_ssid_query_t rsp; struct diag_ssid_range_t ssid_range; @@ -594,15 +604,17 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, return 0; } mutex_lock(&driver->msg_mask_lock); + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE; rsp.status = MSG_STATUS_SUCCESS; rsp.padding = 0; - rsp.count = driver->msg_mask_tbl_count; + rsp.count = msg_mask_tbl_count; memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); mask_ptr = (struct diag_msg_mask_t *)mask_info->ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask_ptr++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask_ptr++) { if (write_len + sizeof(ssid_range) > dest_len) { pr_err("diag: In %s, Truncating response due to size limitations of rsp buffer\n", __func__); @@ -679,6 +691,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, int i; int write_len = 0; uint32_t mask_size = 0; + uint8_t msg_mask_tbl_count = 0; struct diag_msg_mask_t *mask = NULL; struct diag_build_mask_req_t *req = NULL; struct diag_msg_build_mask_t rsp; @@ -709,6 +722,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, } mutex_lock(&driver->msg_mask_lock); + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_MSG_MASK; @@ -724,7 +739,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (!mask->ptr) continue; if ((req->ssid_first < mask->ssid_first) || @@ -760,6 +775,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask_next = NULL; struct diag_md_session_t *info = NULL; + uint8_t msg_mask_tbl_count = 0; mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); @@ -792,10 +808,12 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (!mask->ptr) continue; - if (i < (driver->msg_mask_tbl_count - 1)) { + if (i < (msg_mask_tbl_count - 1)) { mask_next = mask; mask_next++; } else @@ -905,6 +923,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, struct diag_msg_mask_t *mask = NULL; struct diag_mask_info *mask_info = NULL; struct diag_md_session_t *info = NULL; + uint8_t msg_mask_tbl_count = 0; mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); @@ -939,9 +958,11 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (mask && mask->ptr) { mutex_lock(&mask->lock); memset(mask->ptr, req->rt_mask, @@ -1755,7 +1776,6 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, } kmemleak_not_leak(mask_info->update_buf); } - mutex_init(&mask_info->lock); return 0; } @@ -1778,9 +1798,10 @@ int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) struct diag_log_mask_t *src_mask = NULL; struct diag_log_mask_t *dest_mask = NULL; - if (!src) + if (!src || !dest) return -EINVAL; + mutex_init(&dest->lock); err = __diag_mask_init(dest, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -1842,9 +1863,11 @@ static int diag_msg_mask_init(void) { int err = 0, i; + mutex_init(&msg_mask.lock); err = __diag_mask_init(&msg_mask, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; + err = diag_create_msg_mask_table(); if (err) { pr_err("diag: Unable to create msg masks, err: %d\n", err); @@ -1859,7 +1882,8 @@ static int diag_msg_mask_init(void) return 0; } -int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) +int diag_msg_mask_copy(struct diag_md_session_t *new_session, + struct diag_mask_info *dest, struct diag_mask_info *src) { int i, err = 0, mask_size = 0; struct diag_msg_mask_t *src_mask = NULL; @@ -1869,17 +1893,25 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) if (!src || !dest) return -EINVAL; - err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); - if (err) - return err; + mutex_init(&dest->lock); mutex_lock(&dest->lock); mutex_lock(&driver->msg_mask_lock); + new_session->msg_mask_tbl_count = + driver->msg_mask_tbl_count; + err = __diag_mask_init(dest, + (new_session->msg_mask_tbl_count * + sizeof(struct diag_msg_mask_t)), APPS_BUF_SIZE); + if (err) { + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&dest->lock); + return err; + } src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; dest->mask_len = src->mask_len; dest->status = src->status; - for (i = 0; i < driver->msg_mask_tbl_count; i++) { + for (i = 0; i < new_session->msg_mask_tbl_count; i++) { range.ssid_first = src_mask->ssid_first; range.ssid_last = src_mask->ssid_last; err = diag_create_msg_mask_table_entry(dest_mask, &range); @@ -1898,10 +1930,12 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) return err; } -void diag_msg_mask_free(struct diag_mask_info *mask_info) +void diag_msg_mask_free(struct diag_mask_info *mask_info, + struct diag_md_session_t *session_info) { int i; struct diag_msg_mask_t *mask = NULL; + uint8_t msg_mask_tbl_count = 0; if (!mask_info || !mask_info->ptr) return; @@ -1915,7 +1949,10 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) mutex_unlock(&mask_info->lock); return; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (session_info) ? + session_info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } @@ -1947,6 +1984,7 @@ static int diag_build_time_mask_init(void) int err = 0; /* There is no need for update buffer for Build Time masks */ + mutex_init(&msg_bt_mask.lock); err = __diag_mask_init(&msg_bt_mask, MSG_MASK_SIZE, 0); if (err) return err; @@ -1980,6 +2018,7 @@ static int diag_log_mask_init(void) { int err = 0, i; + mutex_init(&log_mask.lock); err = __diag_mask_init(&log_mask, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -2013,6 +2052,7 @@ static int diag_event_mask_init(void) { int err = 0, i; + mutex_init(&event_mask.lock); err = __diag_mask_init(&event_mask, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -2034,6 +2074,7 @@ int diag_event_mask_copy(struct diag_mask_info *dest, if (!src || !dest) return -EINVAL; + mutex_init(&dest->lock); err = __diag_mask_init(dest, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -2070,6 +2111,7 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; unsigned char *ptr = NULL; + uint8_t msg_mask_tbl_count = 0; if (!buf || count == 0) return -EINVAL; @@ -2094,7 +2136,9 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, mutex_unlock(&mask_info->lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (!mask->ptr) continue; ptr = mask_info->update_buf; @@ -2209,6 +2253,9 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, void diag_send_updates_peripheral(uint8_t peripheral) { + if (!driver->feature[peripheral].rcvd_feature_mask) + return; + if (!driver->feature[peripheral].sent_feature_mask) diag_send_feature_mask_update(peripheral); /* diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h index 0e87f3835113d4496bc929b5f910d85b6b204970..0ccadf30f092b4a59833e97ad88c22f7d9c02c0b 100644 --- a/drivers/char/diag/diag_masks.h +++ b/drivers/char/diag/diag_masks.h @@ -160,12 +160,13 @@ int diag_masks_init(void); void diag_masks_exit(void); int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src); -int diag_msg_mask_copy(struct diag_mask_info *dest, - struct diag_mask_info *src); +int diag_msg_mask_copy(struct diag_md_session_t *new_session, + struct diag_mask_info *dest, struct diag_mask_info *src); int diag_event_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src); void diag_log_mask_free(struct diag_mask_info *mask_info); -void diag_msg_mask_free(struct diag_mask_info *mask_info); +void diag_msg_mask_free(struct diag_mask_info *mask_info, + struct diag_md_session_t *session_info); void diag_event_mask_free(struct diag_mask_info *mask_info); int diag_process_apps_masks(unsigned char *buf, int len, int pid); void diag_send_updates_peripheral(uint8_t peripheral); diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index bad5fcf0bbce7749f9560b1f64a9676826de9ec0..06169336dad88d106e07e5bd2d39f27262f6ca8e 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -286,7 +286,7 @@ static void usb_read_work_fn(struct work_struct *work) req->buf = ch->read_buf; req->length = USB_MAX_OUT_BUF; err = usb_diag_read(ch->hdl, req); - if (err) { + if (err && err != -EIO) { pr_debug("diag: In %s, error in reading from USB %s, err: %d\n", __func__, ch->name, err); atomic_set(&ch->read_pending, 0); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 083622f84eed8bd22a5afdcfd68f35226a75a79e..cb33b3619e02134862f041831045cfd3d7ef1c34 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -482,6 +482,7 @@ struct diag_md_session_t { int pid; int peripheral_mask; uint8_t hdlc_disabled; + uint8_t msg_mask_tbl_count; struct timer_list hdlc_reset_timer; struct diag_mask_info *msg_mask; struct diag_mask_info *log_mask; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 4678e48a266a5ad4fcae3b885ddf5139ad2ec1c2..b1f2354951186644ed20a7c99dfe6b8464881d87 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1265,7 +1265,8 @@ static void diag_md_session_exit(void) diag_log_mask_free(session_info->log_mask); kfree(session_info->log_mask); session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); + diag_msg_mask_free(session_info->msg_mask, + session_info); kfree(session_info->msg_mask); session_info->msg_mask = NULL; diag_event_mask_free(session_info->event_mask); @@ -1336,7 +1337,9 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) "return value of event copy. err %d\n", err); goto fail_peripheral; } - err = diag_msg_mask_copy(new_session->msg_mask, &msg_mask); + new_session->msg_mask_tbl_count = 0; + err = diag_msg_mask_copy(new_session, new_session->msg_mask, + &msg_mask); if (err) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "return value of msg copy. err %d\n", err); @@ -1372,7 +1375,8 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) diag_event_mask_free(new_session->event_mask); kfree(new_session->event_mask); new_session->event_mask = NULL; - diag_msg_mask_free(new_session->msg_mask); + diag_msg_mask_free(new_session->msg_mask, + new_session); kfree(new_session->msg_mask); new_session->msg_mask = NULL; kfree(new_session); @@ -1400,7 +1404,8 @@ static void diag_md_session_close(int pid) diag_log_mask_free(session_info->log_mask); kfree(session_info->log_mask); session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); + diag_msg_mask_free(session_info->msg_mask, + session_info); kfree(session_info->msg_mask); session_info->msg_mask = NULL; diag_event_mask_free(session_info->event_mask); diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index e9e964cbf234355ac2e1fb16c203deb47da96255..1d3de3dd1644d438c015e4e8a40a851b97a2324b 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -519,7 +519,12 @@ static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask, } if (range->ssid_last >= mask->ssid_last) { temp_range = range->ssid_last - mask->ssid_first + 1; - mask->ssid_last = range->ssid_last; + if (temp_range > MAX_SSID_PER_RANGE) { + temp_range = MAX_SSID_PER_RANGE; + mask->ssid_last = mask->ssid_first + temp_range - 1; + } else + mask->ssid_last = range->ssid_last; + mask->ssid_last_tools = mask->ssid_last; mask->range = temp_range; } diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 215f5a54fa07086d9f913d9c63645a233cd565ec..cd2af65ffa088b22233b5bc357df9ffe0cdde474 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -213,11 +213,10 @@ static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag) if (!mhi_info->enabled) return -ENODEV; - if (close_flag == CLOSE_CHANNELS) { - atomic_set(&(mhi_info->read_ch.opened), 0); - atomic_set(&(mhi_info->write_ch.opened), 0); + atomic_set(&(mhi_info->read_ch.opened), 0); + atomic_set(&(mhi_info->write_ch.opened), 0); + if (close_flag == CLOSE_CHANNELS) mhi_unprepare_from_transfer(mhi_info->mhi_dev); - } if (!(atomic_read(&(mhi_info->read_ch.opened)))) flush_workqueue(mhi_info->mhi_wq); @@ -270,6 +269,9 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) if (!mhi_info->enabled) return -ENODEV; if (open_flag == OPEN_CHANNELS) { + if ((atomic_read(&(mhi_info->read_ch.opened))) && + (atomic_read(&(mhi_info->write_ch.opened)))) + return 0; err = mhi_prepare_for_transfer(mhi_info->mhi_dev); if (err) { pr_err("diag: In %s, unable to open ch, err: %d\n", @@ -598,14 +600,10 @@ static void diag_mhi_remove(struct mhi_device *mhi_dev) return; if (!mhi_info->enabled) return; + __mhi_close(mhi_info, CHANNELS_CLOSED); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 0; spin_unlock_irqrestore(&mhi_info->lock, flags); - atomic_set(&(mhi_info->read_ch.opened), 0); - atomic_set(&(mhi_info->write_ch.opened), 0); - flush_workqueue(mhi_info->mhi_wq); - mhi_buf_tbl_clear(mhi_info); - diag_remote_dev_close(mhi_info->dev_id); } static int diag_mhi_probe(struct mhi_device *mhi_dev, @@ -620,23 +618,12 @@ static int diag_mhi_probe(struct mhi_device *mhi_dev, "received probe for %d\n", index); diag_mhi[index].mhi_dev = mhi_dev; - ret = diag_remote_init(); - if (ret) { - diag_remote_exit(); - return ret; - } - ret = diagfwd_bridge_init(); - if (ret) { - diagfwd_bridge_exit(); - diag_remote_exit(); - return ret; - } DIAG_LOG(DIAG_DEBUG_BRIDGE, "diag: mhi device is ready to open\n"); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 1; spin_unlock_irqrestore(&mhi_info->lock, flags); - __mhi_open(&diag_mhi[index], CHANNELS_OPENED); + __mhi_open(&diag_mhi[index], OPEN_CHANNELS); queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].open_work)); return ret; @@ -737,5 +724,20 @@ static struct mhi_driver diag_mhi_driver = { void diag_register_with_mhi(void) { + int ret = 0; + + ret = diag_remote_init(); + if (ret) { + diag_remote_exit(); + return; + } + + ret = diagfwd_bridge_init(); + if (ret) { + diagfwd_bridge_exit(); + diag_remote_exit(); + return; + } + mhi_driver_register(&diag_mhi_driver); } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 70bd169d84e2ad5ddfcfe30b0c5050e5efa8ffc5..772b05bed3fe20e6edd0c16cc62e24721ae2afd6 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -1081,8 +1081,10 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) mutex_lock(&driver->diagfwd_channel_mutex[peripheral]); fwd_info = &early_init_info[transport][peripheral]; + mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]); if (fwd_info->p_ops && fwd_info->p_ops->close) fwd_info->p_ops->close(fwd_info->ctxt); + mutex_lock(&driver->diagfwd_channel_mutex[peripheral]); fwd_info = &early_init_info[transport_open][peripheral]; dest_info = &peripheral_info[TYPE_CNTL][peripheral]; dest_info->inited = 1; @@ -1106,9 +1108,7 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) * GLINK. GLINK supported peripheral mask update will * happen after glink buffers are initialized. */ - - if (dest_info->transport != TRANSPORT_RPMSG) - diagfwd_cntl_open(dest_info); + diagfwd_cntl_open(dest_info); init_fn(peripheral); mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]); diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]); diff --git a/drivers/char/diag/diagfwd_rpmsg.c b/drivers/char/diag/diagfwd_rpmsg.c index b5aafc31ba3ace2c5608913b95209dc096e2d815..3647c18ed5bd532f7abd9d7614d9c88e22fd6011 100644 --- a/drivers/char/diag/diagfwd_rpmsg.c +++ b/drivers/char/diag/diagfwd_rpmsg.c @@ -29,13 +29,22 @@ #include "diagfwd_rpmsg.h" #include "diag_ipc_logging.h" +struct diag_rpmsg_read_work { + struct diag_rpmsg_info *rpmsg_info; + const void *ptr_read_done; + const void *ptr_rx_done; + size_t ptr_read_size; + struct work_struct work; +}; + struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { { .peripheral = PERIPHERAL_MODEM, .type = TYPE_DATA, .edge = "mpss", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -43,7 +52,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "lpass", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -51,7 +61,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "wcnss", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -59,7 +70,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "dsps", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -67,7 +79,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "wdsp", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -75,7 +88,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "cdsp", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -86,6 +100,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "mpss", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -93,6 +109,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "lpass", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -100,6 +118,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "wcnss", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -107,6 +127,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "dsps", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -114,6 +136,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "wdsp", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -121,6 +145,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "cdsp", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -131,6 +157,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "mpss", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -138,6 +166,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "lpass", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -145,6 +175,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "wcnss", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -152,6 +184,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "dsps", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -159,6 +193,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "wdsp", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -166,6 +202,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "cdsp", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -176,6 +214,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "mpss", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -183,6 +223,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "lpass", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -190,6 +232,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "wcnss", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -197,6 +241,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "dsps", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -204,6 +250,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "wdsp", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -211,6 +259,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "cdsp", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -221,6 +271,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "mpss", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -228,6 +280,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "lpass", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -235,6 +289,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "wcnss", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -242,6 +298,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "dsps", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -249,6 +307,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "wdsp", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -256,6 +316,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "cdsp", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -265,7 +327,7 @@ static void diag_state_close_rpmsg(void *ctxt); static int diag_rpmsg_write(void *ctxt, unsigned char *buf, int len); static int diag_rpmsg_read(void *ctxt, unsigned char *buf, int buf_len); static void diag_rpmsg_queue_read(void *ctxt); - +static void diag_rpmsg_notify_rx_work_fn(struct work_struct *work); static struct diag_peripheral_ops rpmsg_ops = { .open = diag_state_open_rpmsg, .close = diag_state_close_rpmsg, @@ -341,7 +403,11 @@ static int diag_rpmsg_read(void *ctxt, unsigned char *buf, int buf_len) "diag:RPMSG channel not opened"); return -EIO; } - rpmsg_info->buf = buf; + if (!rpmsg_info->buf1) + rpmsg_info->buf1 = buf; + else if (!rpmsg_info->buf2) + rpmsg_info->buf2 = buf; + return ret_val; } @@ -418,9 +484,10 @@ static void diag_rpmsg_open_work_fn(struct work_struct *work) return; if (!rpmsg_info->inited) return; - atomic_set(&rpmsg_info->opened, 1); - diagfwd_channel_open(rpmsg_info->fwd_ctxt); - diagfwd_late_open(rpmsg_info->fwd_ctxt); + if (rpmsg_info->type != TYPE_CNTL) { + diagfwd_channel_open(rpmsg_info->fwd_ctxt); + diagfwd_late_open(rpmsg_info->fwd_ctxt); + } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", rpmsg_info->name); } @@ -442,16 +509,71 @@ static int diag_rpmsg_notify_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src) { struct diag_rpmsg_info *rpmsg_info = NULL; + struct diag_rpmsg_read_work *read_work; + void *buf; - rpmsg_info = (struct diag_rpmsg_info *)priv; + rpmsg_info = dev_get_drvdata(&rpdev->dev); if (!rpmsg_info) return 0; - memcpy(rpmsg_info->buf, data, len); - diagfwd_channel_read_done(rpmsg_info->fwd_ctxt, rpmsg_info->buf, len); - rpmsg_info->buf = NULL; + + if (!rpmsg_info->buf1 && !rpmsg_info->buf2) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "dropping data for %s len %d\n", + rpmsg_info->name, len); + return 0; + } + + if (rpmsg_info->buf1) + buf = rpmsg_info->buf1; + else + buf = rpmsg_info->buf2; + + if (!buf) + return 0; + + memcpy(buf, data, len); + + read_work = kmalloc(sizeof(*read_work), GFP_ATOMIC); + if (!read_work) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Could not allocate read_work\n"); + return 0; + } + read_work->rpmsg_info = rpmsg_info; + read_work->ptr_read_done = buf; + read_work->ptr_read_size = len; + INIT_WORK(&read_work->work, diag_rpmsg_notify_rx_work_fn); + queue_work(rpmsg_info->wq, &read_work->work); return 0; } +static void diag_rpmsg_notify_rx_work_fn(struct work_struct *work) +{ + struct diag_rpmsg_read_work *read_work = container_of(work, + struct diag_rpmsg_read_work, work); + struct diag_rpmsg_info *rpmsg_info = read_work->rpmsg_info; + struct mutex *channel_mutex; + + if (!rpmsg_info || !rpmsg_info->hdl) { + kfree(read_work); + return; + } + + channel_mutex = &driver->diagfwd_channel_mutex[rpmsg_info->peripheral]; + mutex_lock(channel_mutex); + diagfwd_channel_read_done(rpmsg_info->fwd_ctxt, + (unsigned char *)(read_work->ptr_read_done), + read_work->ptr_read_size); + mutex_unlock(channel_mutex); + + if (read_work->ptr_read_done == rpmsg_info->buf1) + rpmsg_info->buf1 = NULL; + else if (read_work->ptr_read_done == rpmsg_info->buf2) + rpmsg_info->buf2 = NULL; + + kfree(read_work); +} + static void rpmsg_late_init(struct diag_rpmsg_info *rpmsg_info) { struct diagfwd_info *fwd_info = NULL; @@ -547,6 +669,8 @@ int diag_rpmsg_init(void) (void *)rpmsg_info, &rpmsg_ops, &(rpmsg_info->fwd_ctxt)); rpmsg_info->inited = 1; + diagfwd_channel_open(rpmsg_info->fwd_ctxt); + diagfwd_late_open(rpmsg_info->fwd_ctxt); __diag_rpmsg_init(&rpmsg_data[peripheral]); __diag_rpmsg_init(&rpmsg_cmd[peripheral]); __diag_rpmsg_init(&rpmsg_dci[peripheral]); @@ -606,7 +730,7 @@ static struct diag_rpmsg_info *diag_get_rpmsg_ptr(char *name) return NULL; if (!strcmp(name, "DIAG_CMD")) return &rpmsg_cmd[PERIPHERAL_WDSP]; - else if (!strcmp(name, "DIAG_CNTL")) + else if (!strcmp(name, "DIAG_CTRL")) return &rpmsg_cntl[PERIPHERAL_WDSP]; else if (!strcmp(name, "DIAG_DATA")) return &rpmsg_data[PERIPHERAL_WDSP]; @@ -631,6 +755,8 @@ static int diag_rpmsg_probe(struct rpmsg_device *rpdev) if (rpmsg_info) { rpmsg_info->hdl = rpdev; dev_set_drvdata(&rpdev->dev, rpmsg_info); + atomic_set(&rpmsg_info->opened, 1); + diagfwd_channel_read(rpmsg_info->fwd_ctxt); queue_work(rpmsg_info->wq, &rpmsg_info->open_work); } @@ -651,7 +777,7 @@ static void diag_rpmsg_remove(struct rpmsg_device *rpdev) static struct rpmsg_device_id rpmsg_diag_table[] = { { .name = "DIAG_CMD" }, - { .name = "DIAG_CNTL" }, + { .name = "DIAG_CTRL" }, { .name = "DIAG_DATA" }, { .name = "DIAG_DCI_CMD" }, { .name = "DIAG_DCI_DATA" }, diff --git a/drivers/char/diag/diagfwd_rpmsg.h b/drivers/char/diag/diagfwd_rpmsg.h index 44b195952b33b867000c2f867a9826010ff94be9..2bed0324912afc366914fefaaecf93bfb784d505 100644 --- a/drivers/char/diag/diagfwd_rpmsg.h +++ b/drivers/char/diag/diagfwd_rpmsg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,7 +35,8 @@ struct diag_rpmsg_info { struct work_struct read_work; struct work_struct late_init_work; struct diagfwd_info *fwd_ctxt; - void *buf; + void *buf1; + void *buf2; }; extern struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS]; diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index 2312c85fad70af7c57ca58fac47fa20677e29280..d159db1f48b1cbdea9a477a4c6eac9206e904168 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -649,6 +649,7 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) int read_len = 0; int bytes_remaining = 0; int total_recd = 0; + int qrtr_ctrl_recd = 0; uint8_t buf_full = 0; unsigned char *temp = NULL; struct kvec iov = {0}; @@ -729,11 +730,15 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) if (info->port_type == PORT_TYPE_SERVER) socket_init_work_fn(&info->init_work); return read_len; - } else if (read_len <= 0) - goto fail; + } else if (read_len <= 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Invalid read_len: %d\n", read_len); + continue; + } if (src_addr.sq_port == QRTR_PORT_CTRL) { handle_ctrl_pkt(info, temp, read_len); + qrtr_ctrl_recd += read_len; continue; } @@ -755,13 +760,6 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) else __socket_open_channel(info); } - - if (read_len < 0) { - pr_err_ratelimited("diag: In %s, error receiving data, err: %d\n", - __func__, pkt_len); - err = read_len; - goto fail; - } temp += read_len; total_recd += read_len; bytes_remaining -= read_len; @@ -780,8 +778,14 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) if (err) goto fail; } else { - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s error in read, err: %d\n", - info->name, total_recd); + if (qrtr_ctrl_recd > 0) + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s read qrtr ctrl bytes: %d\n", + info->name, qrtr_ctrl_recd); + else + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s error in read, err: %d\n", + info->name, total_recd); goto fail; } diff --git a/drivers/char/random.c b/drivers/char/random.c index ddc493d976fdc5e559cac9999156649445d741f5..ea4dbfa3065747a0cd24754abc8e51e08403cbc1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1897,14 +1897,22 @@ static int write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { size_t bytes; - __u32 buf[16]; + __u32 t, buf[16]; const char __user *p = buffer; while (count > 0) { + int b, i = 0; + bytes = min(count, sizeof(buf)); if (copy_from_user(&buf, p, bytes)) return -EFAULT; + for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) { + if (!arch_get_random_int(&t)) + break; + buf[i] ^= t; + } + count -= bytes; p += bytes; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index d85bd0188effa9deb9237f7e5ff5840549100044..36fb964314dc9e701a64c1c4457fe21a435884e8 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -257,6 +257,9 @@ static bool _is_best_div(unsigned long rate, unsigned long now, { if (flags & CLK_DIVIDER_ROUND_CLOSEST) return abs(rate - now) < abs(rate - best); + else if (flags & CLK_DIVIDER_ROUND_KHZ) + return (DIV_ROUND_CLOSEST(abs(rate - now), 1000) + < DIV_ROUND_CLOSEST(abs(rate - best), 1000)); return now <= rate && now > best; } diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index c9b13710c6c38595c7cf499e6e6a0d91a7c80b39..ce3df73c66680aca18ca2bc95d1c871dcd1d44ce 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -396,6 +396,15 @@ config MSM_DISPCC_SM6150 Say Y if you want to support display devices and functionality such as splash screen. +config MSM_DISPCC_SDMMAGPIE + tristate "SDMMAGPIE Display Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the display clock controller on Qualcomm Technologies, Inc + SDMMAGPIE devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config MSM_GCC_SDMMAGPIE tristate "SDMMAGPIE Global Clock Controller" depends on COMMON_CLK_QCOM @@ -405,3 +414,28 @@ config MSM_GCC_SDMMAGPIE SDMMAGPIE devices. Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, UFS, SD/eMMC, PCIe, etc. + +config MSM_VIDEOCC_SDMMAGPIE + tristate "SDMMAGPIE Video Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the video clock controller on Qualcomm Technologies, Inc. + SDMMAGPIE devices. + Say Y if you want to support video devices and functionality such as + video encode/decode. + +config MSM_NPUCC_SDMMAGPIE + tristate "SDMMAGPIE NPU Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the NPU clock controller on Qualcomm Technologies, Inc + SDMMAGPIE devices. + Say Y if you want to enable use of the Network Processing Unit. + +config MSM_GPUCC_SDMMAGPIE + tristate "SDMMAGPIE graphics Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the graphics clock controller on Qualcomm Technologies, Inc. + SDMMAGPIE devices. + Say Y if you want to support graphics clocks. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 236935ff66d92e0dfaedddac047adabf5ebb9862..a454f82e8d345335c1d77a284da34555c4929a23 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_MSM_DEBUGCC_SM6150) += debugcc-sm6150.o obj-$(CONFIG_MSM_DEBUGCC_SM8150) += debugcc-sm8150.o obj-$(CONFIG_MSM_DISPCC_SM6150) += dispcc-sm6150.o obj-$(CONFIG_MSM_DISPCC_SM8150) += dispcc-sm8150.o +obj-$(CONFIG_MSM_DISPCC_SDMMAGPIE) += dispcc-sdmmagpie.o obj-$(CONFIG_MDM_DEBUGCC_QCS405) += debugcc-qcs405.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o @@ -48,13 +49,16 @@ obj-$(CONFIG_MSM_GCC_SM6150) += gcc-sm6150.o obj-$(CONFIG_MSM_GCC_SM8150) += gcc-sm8150.o obj-$(CONFIG_MSM_GCC_SDMMAGPIE) += gcc-sdmmagpie.o obj-$(CONFIG_MSM_GCC_SDMSHRIKE) += gcc-sdmshrike.o +obj-$(CONFIG_MSM_GPUCC_SDMMAGPIE) += gpucc-sdmmagpie.o obj-$(CONFIG_MSM_GPUCC_SM6150) += gpucc-sm6150.o obj-$(CONFIG_MSM_GPUCC_SM8150) += gpucc-sm8150.o obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_MSM_NPUCC_SDMMAGPIE) += npucc-sdmmagpie.o obj-$(CONFIG_MSM_NPUCC_SM8150) += npucc-sm8150.o +obj-$(CONFIG_MSM_VIDEOCC_SDMMAGPIE) += videocc-sdmmagpie.o obj-$(CONFIG_MSM_VIDEOCC_SM6150) += videocc-sm6150.o obj-$(CONFIG_MSM_VIDEOCC_SM8150) += videocc-sm8150.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index a67237de137dd9d16d57f66806fb8536ccfc746d..eda181fc6219d7e484f32ef089d4395069e6b34a 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -2009,7 +2009,7 @@ static long clk_generic_pll_postdiv_round_rate(struct clk_hw *hw, return -EINVAL; return divider_round_rate(hw, rate, prate, pll->post_div_table, - pll->width, CLK_DIVIDER_ROUND_CLOSEST); + pll->width, CLK_DIVIDER_ROUND_KHZ); } static int clk_generic_pll_postdiv_set_rate(struct clk_hw *hw, diff --git a/drivers/clk/qcom/clk-cpu-qcs405.c b/drivers/clk/qcom/clk-cpu-qcs405.c index dc2e03bac40cb8b8683a4bab2d65453e90557b01..331f3e195e3cb3ec91587eff31830f15bbe0c05e 100644 --- a/drivers/clk/qcom/clk-cpu-qcs405.c +++ b/drivers/clk/qcom/clk-cpu-qcs405.c @@ -267,8 +267,7 @@ static struct clk_pll apcs_cpu_pll = { .ops = &clk_pll_hf_ops, .vdd_class = &vdd_hf_pll, .rate_max = (unsigned long[VDD_HF_PLL_NUM]) { - [VDD_HF_PLL_SVS] = 1000000000, - [VDD_HF_PLL_NOM] = 2000000000, + [VDD_HF_PLL_SVS] = 2000000000, }, .num_rate_max = VDD_HF_PLL_NUM, }, diff --git a/drivers/clk/qcom/debugcc-qcs405.c b/drivers/clk/qcom/debugcc-qcs405.c index 3002ab99504ebe1b688d1d48b9ba37de42f77685..783d948fd7e39c9fe3c23fa868c688a7001bbe0f 100644 --- a/drivers/clk/qcom/debugcc-qcs405.c +++ b/drivers/clk/qcom/debugcc-qcs405.c @@ -134,192 +134,192 @@ static struct clk_debug_mux gcc_debug_mux = { .cbcr_offset = 0x74000, .src_sel_mask = 0x1FF, .src_sel_shift = 0, - .post_div_mask = 0xF000, + .post_div_mask = 0xF, .post_div_shift = 12, .en_mask = BIT(16), MUX_SRC_LIST( { "snoc_clk", 0x000, 1, GCC, - 0x000, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x000, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "pnoc_clk", 0x008, 1, GCC, - 0x008, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "bimc_clk", 0x15A, 1, GCC, - 0x15A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x008, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, + { "bimc_clk", 0x15A, 4, GCC, + 0x15A, 0x1FF, 0, 0xF, 12, 4, 0x74000, 0x74000, 0x74000 }, { "qpic_clk", 0x0C0, 1, GCC, - 0x0C0, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x0C0, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "ce1_clk", 0x138, 1, GCC, - 0x138, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x138, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "wcnss_m_clk", 0x08A, 1, GCC, - 0x08A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x08A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_apss_ahb_clk", 0x168, 1, GCC, - 0x168, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x168, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_bimc_gfx_clk", 0x2D, 1, GCC, - 0x2D, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x2D, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_ahb_clk", 0x88, 1, GCC, - 0x88, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x88, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup0_i2c_apps_clk", 0x99, 1, GCC, - 0x99, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x99, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup0_spi_apps_clk", 0x98, 1, GCC, - 0x98, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x98, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup1_i2c_apps_clk", 0x8B, 1, GCC, - 0x8B, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8B, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup1_spi_apps_clk", 0x8A, 1, GCC, - 0x8A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup2_i2c_apps_clk", 0x8F, 1, GCC, - 0x8F, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8F, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup2_spi_apps_clk", 0x8E, 1, GCC, - 0x8E, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8E, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup3_i2c_apps_clk", 0x93, 1, GCC, - 0x93, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x93, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup3_spi_apps_clk", 0x92, 1, GCC, - 0x92, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x92, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup4_i2c_apps_clk", 0x95, 1, GCC, - 0x95, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x95, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup4_spi_apps_clk", 0x94, 1, GCC, - 0x94, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x94, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart0_apps_clk", 0x9A, 1, GCC, - 0x9A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x9A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart1_apps_clk", 0x8C, 1, GCC, - 0x8C, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8C, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart2_apps_clk", 0x90, 1, GCC, - 0x90, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x90, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart3_apps_clk", 0x96, 1, GCC, - 0x96, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x96, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_ahb_clk", 0xA0, 1, GCC, - 0xA0, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA0, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_qup0_i2c_apps_clk", 0xA3, 1, GCC, - 0xA2, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA2, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_qup0_spi_apps_clk", 0xA2, 1, GCC, - 0xA3, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA3, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_uart0_apps_clk", 0xA4, 1, GCC, - 0xA4, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA4, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_boot_rom_ahb_clk", 0xF8, 1, GCC, - 0xF8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xF8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_dcc_clk", 0x1B9, 1, GCC, - 0x1B9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1B9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_axi_clk", 0x80, 1, GCC, - 0x80, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x80, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_ptp_clk", 0x83, 1, GCC, - 0x83, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x83, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_rgmii_clk", 0x81, 1, GCC, - 0x81, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x81, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_slave_ahb_clk", 0x82, 1, GCC, - 0x82, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x82, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_geni_ir_s_clk", 0xEE, 1, GCC, - 0xEE, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xEE, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gp1_clk", 0x10, 1, GCC, - 0x10, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x10, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gp2_clk", 0x11, 1, GCC, - 0x11, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x11, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gp3_clk", 0x12, 1, GCC, - 0x12, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x12, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_ahb_clk", 0x1F6, 1, GCC, - 0x1F6, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F6, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_axi_clk", 0x1F7, 1, GCC, - 0x1F7, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F7, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_byte0_clk", 0x1FC, 1, GCC, - 0x1FC, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1FC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_esc0_clk", 0x1FD, 1, GCC, - 0x1FD, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1FD, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_hdmi_app_clk", 0x1F2, 1, GCC, - 0x1F2, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F2, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_hdmi_pclk_clk", 0x1F1, 1, GCC, - 0x1F1, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F1, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_mdp_clk", 0x1F9, 1, GCC, - 0x1F9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_pclk0_clk", 0x1F8, 1, GCC, - 0x1F8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_vsync_clk", 0x1FB, 1, GCC, - 0x1FB, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1FB, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_oxili_ahb_clk", 0x1EB, 1, GCC, - 0x1EB, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1EB, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_oxili_gfx3d_clk", 0x1EA, 1, GCC, - 0x1EA, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1EA, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_aux_clk", 0xAB, 1, GCC, - 0xAB, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xAB, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_cfg_ahb_clk", 0xAA, 1, GCC, - 0xAA, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xAA, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_mstr_axi_clk", 0xA9, 1, GCC, - 0xA9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_pipe_clk", 0xAC, 1, GCC, - 0xAC, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xAC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_slv_axi_clk", 0xA8, 1, GCC, - 0xA8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcnoc_usb2_clk", 0x9, 1, GCC, - 0x9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcnoc_usb3_clk", 0xA, 1, GCC, - 0xA, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pdm2_clk", 0xD2, 1, GCC, - 0xD2, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD2, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pdm_ahb_clk", 0xD0, 1, GCC, - 0xD0, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD0, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_prng_ahb_clk", 0xD8, 1, GCC, - 0xD8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pwm0_xo512_clk", 0xD3, 1, GCC, - 0xD3, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD3, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pwm1_xo512_clk", 0xD4, 1, GCC, - 0xD4, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD4, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pwm2_xo512_clk", 0xD5, 1, GCC, - 0xD5, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD5, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc1_ahb_clk", 0x69, 1, GCC, - 0x69, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x69, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc1_apps_clk", 0x68, 1, GCC, - 0x68, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x68, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc1_ice_core_clk", 0x6A, 1, GCC, - 0x6A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x6A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc2_ahb_clk", 0x71, 1, GCC, - 0x71, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x71, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc2_apps_clk", 0x70, 1, GCC, - 0x70, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x70, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sys_noc_usb3_clk", 0x1, 1, GCC, - 0x1, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb20_mock_utmi_clk", 0x65, 1, GCC, - 0x65, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x65, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb2a_phy_sleep_clk", 0x63, 1, GCC, - 0x63, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x63, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb30_master_clk", 0x78, 1, GCC, - 0x78, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x78, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb30_mock_utmi_clk", 0x7A, 1, GCC, - 0x7A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x7A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb30_sleep_clk", 0x79, 1, GCC, - 0x79, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x79, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb3_phy_aux_clk", 0x7C, 1, GCC, - 0x7C, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x7C, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb3_phy_pipe_clk", 0x7B, 1, GCC, - 0x7B, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x7B, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb_hs_inactivity_timers_clk", 0x62, 1, GCC, - 0x62, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x62, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb_hs_phy_cfg_ahb_clk", 0x64, 1, GCC, - 0x64, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x64, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb_hs_system_clk", 0x60, 1, GCC, - 0x60, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x60, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_apss_tcu_clk", 0x159, 1, GCC, - 0x159, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x159, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_bimc_gpu_clk", 0x157, 1, GCC, - 0x157, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x157, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_bimc_mdss_clk", 0x15F, 1, GCC, - 0x15F, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x15F, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_crypto_ahb_clk", 0x13A, 1, GCC, - 0x13A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x13A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_crypto_axi_clk", 0x139, 1, GCC, - 0x139, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x139, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_crypto_clk", 0x138, 1, GCC, - 0x138, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x138, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gfx_tbu_clk", 0x052, 1, GCC, - 0x052, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x052, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gfx_tcu_clk", 0x053, 1, GCC, - 0x053, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x053, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gtcu_ahb_clk", 0x058, 1, GCC, - 0x058, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x058, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdp_tbu_clk", 0x051, 1, GCC, - 0x051, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x051, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_qdss_dap_clk", 0x049, 1, GCC, - 0x049, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x049, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_smmu_cfg_clk", 0x05B, 1, GCC, - 0x049, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x049, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_geni_ir_h_clk", 0xEC, 1, GCC, - 0xEC, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xEC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_dcc_xo_clk", 0x1B8, 1, GCC, - 0x1B8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1B8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "apcs_mux_clk", 0x16A, 1, CPU_CC, 0x000, 0x3, 8, 0xF, 11, 1, 0, 0, U32_MAX, 1 }, ), diff --git a/drivers/clk/qcom/debugcc-sm6150.c b/drivers/clk/qcom/debugcc-sm6150.c index d9625fc6e9e0f1b6578b9dd9521b2b0c18c7f123..42ca11807240bfb42f0500369a872af24ccab9c3 100644 --- a/drivers/clk/qcom/debugcc-sm6150.c +++ b/drivers/clk/qcom/debugcc-sm6150.c @@ -240,7 +240,7 @@ static const char *const debug_mux_parent_names[] = { "gpu_cc_gx_qdss_tsctr_clk", "gpu_cc_gx_vsense_clk", "gpu_cc_sleep_clk", - "measure_only_bimc_clk", + "measure_only_mccc_clk", "measure_only_cnoc_clk", "measure_only_ipa_2x_clk", "measure_only_snoc_clk", @@ -255,6 +255,9 @@ static const char *const debug_mux_parent_names[] = { "video_cc_venus_ctl_axi_clk", "video_cc_venus_ctl_core_clk", "video_cc_xo_clk", + "l3_clk", + "pwrcl_clk", + "perfcl_clk", }; static struct clk_debug_mux gcc_debug_mux = { @@ -266,6 +269,7 @@ static struct clk_debug_mux gcc_debug_mux = { .src_sel_shift = 0, .post_div_mask = 0xF, .post_div_shift = 0, + .period_offset = 0x50, MUX_SRC_LIST( { "cam_cc_bps_ahb_clk", 0x46, 1, CAM_CC, 0xE, 0xFF, 0, 0x3, 0, 2, 0xC000, 0xC004, 0xC008 }, @@ -681,7 +685,7 @@ static struct clk_debug_mux gcc_debug_mux = { 0xC, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_sleep_clk", 0x144, 1, GPU_CC, 0x16, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "measure_only_bimc_clk", 0xC2, 1, GCC, + { "measure_only_mccc_clk", 0xC2, 1, MC_CC, 0xC2, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_cnoc_clk", 0x15, 1, GCC, 0x15, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, @@ -711,6 +715,12 @@ static struct clk_debug_mux gcc_debug_mux = { 0x1, 0x3F, 0, 0x7, 0, 5, 0xA4C, 0xA30, 0xA38 }, { "video_cc_xo_clk", 0x48, 1, VIDEO_CC, 0xC, 0x3F, 0, 0x7, 0, 5, 0xA4C, 0xA30, 0xA38 }, + { "l3_clk", 0xD6, 4, CPU_CC, + 0x46, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "pwrcl_clk", 0xD6, 4, CPU_CC, + 0x44, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "perfcl_clk", 0xD6, 4, CPU_CC, + 0x45, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, ), .hw.init = &(struct clk_init_data){ .name = "gcc_debug_mux", @@ -784,6 +794,14 @@ static int clk_debug_sm6150_probe(struct platform_device *pdev) if (ret) return ret; + ret = map_debug_bases(pdev, "qcom,cpucc", CPU_CC); + if (ret) + return ret; + + ret = map_debug_bases(pdev, "qcom,mccc", MC_CC); + if (ret) + return ret; + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); diff --git a/drivers/clk/qcom/debugcc-sm8150.c b/drivers/clk/qcom/debugcc-sm8150.c index c614e69b69e70833cacc2a28661068735d432db6..34333df7dbbd03ed7f33e834d7fd89595122e4eb 100644 --- a/drivers/clk/qcom/debugcc-sm8150.c +++ b/drivers/clk/qcom/debugcc-sm8150.c @@ -118,6 +118,7 @@ static const char *const debug_mux_parent_names[] = { "disp_cc_mdss_rscc_vsync_clk", "disp_cc_mdss_vsync_clk", "disp_cc_xo_clk", + "measure_only_cdsp_clk", "measure_only_snoc_clk", "measure_only_cnoc_clk", "measure_only_mccc_clk", @@ -465,6 +466,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x14, 0xFF, 0, 0x3, 0, 4, 0x7000, 0x5008, 0x500C }, { "disp_cc_xo_clk", 0x56, 1, DISP_CC, 0x36, 0xFF, 0, 0x3, 0, 4, 0x7000, 0x5008, 0x500C }, + { "measure_only_cdsp_clk", 0xDB, 2, GCC, + 0xDB, 0x3FF, 0, 0xF, 0, 2, 0x62000, 0x62004, 0x62008 }, { "measure_only_snoc_clk", 0x7, 1, GCC, 0x7, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_cnoc_clk", 0x19, 1, GCC, diff --git a/drivers/clk/qcom/dispcc-sdmmagpie.c b/drivers/clk/qcom/dispcc-sdmmagpie.c new file mode 100644 index 0000000000000000000000000000000000000000..6f6cbe90eea4436ebad63e6eecd9a7977c8a343d --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdmmagpie.c @@ -0,0 +1,1162 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "reset.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +#define DISP_CC_MISC_CMD 0x8000 + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CHIP_SLEEP_CLK, + P_CORE_BI_PLL_TEST_SE, + P_DISP_CC_PLL0_OUT_EVEN, + P_DISP_CC_PLL0_OUT_MAIN, + P_DP_PHY_PLL_LINK_CLK, + P_DP_PHY_PLL_VCO_DIV_CLK, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_0[] = { + "bi_tcxo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_DP_PHY_PLL_LINK_CLK, 1 }, + { P_DP_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_1[] = { + "bi_tcxo", + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_DISP_CC_PLL0_OUT_EVEN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_3[] = { + "bi_tcxo", + "disp_cc_pll0", + "gpll0", + "disp_cc_pll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_4[] = { + "bi_tcxo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_5[] = { + "bi_tcxo", + "gpll0", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_6[] = { + { P_CHIP_SLEEP_CLK, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_6[] = { + "chip_sleep_clk", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +/* 860MHz configuration */ +static const struct alpha_pll_config disp_cc_pll0_config = { + .l = 0x2c, + .frac = 0xcaaa, + .test_ctl_val = 0x40000000, +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 430000000, + [VDD_LOW_L1] = 860000000}, + }, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { + .cmd_rcgr = 0x22bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_5, + .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_ahb_clk_src", + .parent_names = disp_cc_parent_names_5, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000, + [VDD_LOW] = 37500000, + [VDD_NOMINAL] = 75000000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_byte0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x2110, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_byte2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 180000000, + [VDD_LOW] = 275000000, + [VDD_LOW_L1] = 358000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x212c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_byte2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 180000000, + [VDD_LOW] = 275000000, + [VDD_LOW_L1] = 358000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_aux_clk_src = { + .cmd_rcgr = 0x21dc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_crypto_clk_src[] = { + F(108000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F(180000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F(360000, P_DP_PHY_PLL_LINK_CLK, 1.5, 0, 0), + F(540000, P_DP_PHY_PLL_LINK_CLK, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { + .cmd_rcgr = 0x2194, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_dp_crypto_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 108000, + [VDD_LOW] = 180000, + [VDD_LOW_L1] = 360000, + [VDD_NOMINAL] = 540000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { + F(162000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(270000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F(810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { + .cmd_rcgr = 0x2178, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_dp_link_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 162000, + [VDD_LOW] = 270000, + [VDD_LOW_L1] = 540000, + [VDD_NOMINAL] = 810000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_pixel1_clk_src = { + .cmd_rcgr = 0x21c4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_dp_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 202500, + [VDD_LOW] = 337500, + [VDD_NOMINAL] = 675000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_pixel_clk_src = { + .cmd_rcgr = 0x21ac, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_dp_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 202500, + [VDD_LOW] = 337500, + [VDD_NOMINAL] = 675000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x2148, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x2160, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(286666667, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x20c8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk_src", + .parent_names = disp_cc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 200000000, + [VDD_LOW] = 300000000, + [VDD_LOW_L1] = 344000000, + [VDD_NOMINAL] = 430000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x2098, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_names = disp_cc_parent_names_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_pixel_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 280000000, + [VDD_LOW] = 430000000, + [VDD_NOMINAL] = 570776256}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x20b0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_names = disp_cc_parent_names_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_pixel_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 280000000, + [VDD_LOW] = 430000000, + [VDD_NOMINAL] = 570776256}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_rot_clk_src = { + .cmd_rcgr = 0x20e0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_rot_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk_src", + .parent_names = disp_cc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 200000000, + [VDD_LOW] = 300000000, + [VDD_LOW_L1] = 344000000, + [VDD_NOMINAL] = 430000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x20f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = { + F(32000, P_CHIP_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_sleep_clk_src = { + .cmd_rcgr = 0x6060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_6, + .freq_tbl = ftbl_disp_cc_sleep_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_sleep_clk_src", + .parent_names = disp_cc_parent_names_6, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 32000}, + }, +}; + +static struct clk_rcg2 disp_cc_xo_clk_src = { + .cmd_rcgr = 0x6044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_xo_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb_clk = { + .halt_reg = 0x2080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_ahb_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_clk = { + .halt_reg = 0x2028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x2128, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_div_clk_src", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x202c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x202c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_div_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_clk = { + .halt_reg = 0x2030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x2144, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_div_clk_src", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x2034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_div_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_aux_clk = { + .halt_reg = 0x2054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_crypto_clk = { + .halt_reg = 0x2048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_crypto_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_link_clk = { + .halt_reg = 0x2040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { + .halt_reg = 0x2044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_pixel1_clk = { + .halt_reg = 0x2050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_pixel1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_pixel_clk = { + .halt_reg = 0x204c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x204c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_pixel_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc0_clk = { + .halt_reg = 0x2038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_esc0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc1_clk = { + .halt_reg = 0x203c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_esc1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_clk = { + .halt_reg = 0x200c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x200c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_mdp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x201c, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_lut_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_mdp_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = { + .halt_reg = 0x4004, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x4004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_non_gdsc_ahb_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x2004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_pclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x2008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_pclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rot_clk = { + .halt_reg = 0x2014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_rot_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0x400c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x400c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_ahb_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0x4008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_vsync_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync_clk = { + .halt_reg = 0x2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_sleep_clk = { + .halt_reg = 0x6078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_sleep_clk", + .parent_names = (const char *[]){ + "disp_cc_sleep_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_xo_clk = { + .halt_reg = 0x605c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x605c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_xo_clk", + .parent_names = (const char *[]){ + "disp_cc_xo_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *disp_cc_sdmmagpie_clocks[] = { + [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, + [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr, + [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr, + [DISP_CC_MDSS_DP_AUX_CLK] = &disp_cc_mdss_dp_aux_clk.clkr, + [DISP_CC_MDSS_DP_AUX_CLK_SRC] = &disp_cc_mdss_dp_aux_clk_src.clkr, + [DISP_CC_MDSS_DP_CRYPTO_CLK] = &disp_cc_mdss_dp_crypto_clk.clkr, + [DISP_CC_MDSS_DP_CRYPTO_CLK_SRC] = &disp_cc_mdss_dp_crypto_clk_src.clkr, + [DISP_CC_MDSS_DP_LINK_CLK] = &disp_cc_mdss_dp_link_clk.clkr, + [DISP_CC_MDSS_DP_LINK_CLK_SRC] = &disp_cc_mdss_dp_link_clk_src.clkr, + [DISP_CC_MDSS_DP_LINK_INTF_CLK] = &disp_cc_mdss_dp_link_intf_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL1_CLK] = &disp_cc_mdss_dp_pixel1_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL1_CLK_SRC] = &disp_cc_mdss_dp_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DP_PIXEL_CLK] = &disp_cc_mdss_dp_pixel_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL_CLK_SRC] = &disp_cc_mdss_dp_pixel_clk_src.clkr, + [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, + [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, + [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr, + [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr, + [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr, + [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr, + [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr, + [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, + [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr, + [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr, + [DISP_CC_MDSS_ROT_CLK] = &disp_cc_mdss_rot_clk.clkr, + [DISP_CC_MDSS_ROT_CLK_SRC] = &disp_cc_mdss_rot_clk_src.clkr, + [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr, + [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr, + [DISP_CC_PLL0] = &disp_cc_pll0.clkr, + [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr, + [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr, + [DISP_CC_XO_CLK] = &disp_cc_xo_clk.clkr, + [DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr, +}; + +static const struct regmap_config disp_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static const struct qcom_cc_desc disp_cc_sdmmagpie_desc = { + .config = &disp_cc_sdmmagpie_regmap_config, + .clks = disp_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sdmmagpie_clocks), +}; + +static const struct of_device_id disp_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,dispcc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_sdmmagpie_match_table); + +static int disp_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (PTR_ERR(vdd_cx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + regmap = qcom_cc_map(pdev, &disp_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the disp_cc registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + + /* Enable clock gating for DSI and MDP clocks */ + regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x7f0, 0x7f0); + + ret = qcom_cc_really_probe(pdev, &disp_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Display CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Display CC clocks\n"); + return ret; +} + +static struct platform_driver disp_cc_sdmmagpie_driver = { + .probe = disp_cc_sdmmagpie_probe, + .driver = { + .name = "disp_cc-sdmmagpie", + .of_match_table = disp_cc_sdmmagpie_match_table, + }, +}; + +static int __init disp_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&disp_cc_sdmmagpie_driver); +} +subsys_initcall(disp_cc_sdmmagpie_init); + +static void __exit disp_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&disp_cc_sdmmagpie_driver); +} +module_exit(disp_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI DISP_CC sdmmagpie Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:disp_cc-sdmmagpie"); diff --git a/drivers/clk/qcom/dispcc-sm6150.c b/drivers/clk/qcom/dispcc-sm6150.c index ba931b52fda3171a6f0c88fc786eb7fe2befa260..1f84e3add24d75ec08f100fbf5e58f5cb5cbc34c 100644 --- a/drivers/clk/qcom/dispcc-sm6150.c +++ b/drivers/clk/qcom/dispcc-sm6150.c @@ -160,8 +160,8 @@ static struct clk_alpha_pll disp_cc_pll0_out_main = { static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), - F(37500000, P_GPLL0_OUT_MAIN, 16, 0, 0), - F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(37500000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_MAIN, 4, 0, 0), { } }; @@ -171,10 +171,12 @@ static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { .hid_width = 5, .parent_map = disp_cc_parent_map_4, .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_ahb_clk_src", .parent_names = disp_cc_parent_names_4, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, @@ -470,7 +472,7 @@ static struct clk_branch disp_cc_mdss_byte0_intf_clk = { "disp_cc_mdss_byte0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/qcom/gcc-qcs405.c b/drivers/clk/qcom/gcc-qcs405.c index d656c595ae28c866d54de5277c75fe109d23bb91..3f6c4328a7e0b5c7383b9a88835cc79671817e53 100644 --- a/drivers/clk/qcom/gcc-qcs405.c +++ b/drivers/clk/qcom/gcc-qcs405.c @@ -873,12 +873,19 @@ static struct clk_rcg2 emac_clk_src = { }, }; +static const struct freq_tbl ftbl_emac_ptp_clk_src[] = { + F(50000000, P_GPLL1_OUT_MAIN, 10, 0, 0), + F(125000000, P_GPLL1_OUT_MAIN, 4, 0, 0), + F(250000000, P_GPLL1_OUT_MAIN, 2, 0, 0), + { } +}; + static struct clk_rcg2 emac_ptp_clk_src = { .cmd_rcgr = 0x4e014, .mnd_width = 0, .hid_width = 5, .parent_map = gcc_parent_map_4, - .freq_tbl = ftbl_emac_clk_src, + .freq_tbl = ftbl_emac_ptp_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "emac_ptp_clk_src", .parent_names = gcc_parent_names_4, diff --git a/drivers/clk/qcom/gcc-sdmmagpie.c b/drivers/clk/qcom/gcc-sdmmagpie.c index 79d533789c98bcfe5d03455edc35ab23d049a912..81a05f4c00e68de57b2f5ec9c8739e5bbc38e12d 100644 --- a/drivers/clk/qcom/gcc-sdmmagpie.c +++ b/drivers/clk/qcom/gcc-sdmmagpie.c @@ -238,6 +238,17 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = { }, }; +static struct clk_fixed_factor gcc_pll0_main_div_cdiv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "gcc_pll0_main_div_cdiv", + .parent_names = (const char *[]){ "gpll0" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_alpha_pll gpll6 = { .offset = 0x13000, .vco_table = fabia_vco, @@ -1493,7 +1504,7 @@ static struct clk_branch gcc_disp_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_disp_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_gpll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1635,7 +1646,7 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_gpu_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_gpll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1723,7 +1734,7 @@ static struct clk_branch gcc_mss_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_mss_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_pll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1843,7 +1854,7 @@ static struct clk_branch gcc_npu_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_npu_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_pll0_main_div_cdiv", }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -3141,6 +3152,8 @@ struct clk_hw *gcc_sdmmagpie_hws[] = { [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, + [GCC_GPLL0_MAIN_DIV_CDIV] = &gcc_pll0_main_div_cdiv.hw, + }; static struct clk_regmap *gcc_sdmmagpie_clocks[] = { diff --git a/drivers/clk/qcom/gcc-sm6150.c b/drivers/clk/qcom/gcc-sm6150.c index 5310730a162330b00755d61a10c6cc550434a2bb..ccab586d913cdc7b57f633f2700e0089077ef9ae 100644 --- a/drivers/clk/qcom/gcc-sm6150.c +++ b/drivers/clk/qcom/gcc-sm6150.c @@ -3191,10 +3191,10 @@ static struct clk_branch gcc_usb2_sec_clkref_clk = { }; /* Measure-only clock for ddrss_gcc_debug_clk. */ -static struct clk_dummy measure_only_bimc_clk = { +static struct clk_dummy measure_only_mccc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ - .name = "measure_only_bimc_clk", + .name = "measure_only_mccc_clk", .ops = &clk_dummy_ops, }, }; @@ -3228,7 +3228,7 @@ static struct clk_dummy measure_only_snoc_clk = { struct clk_hw *gcc_sm6150_hws[] = { [GPLL0_OUT_AUX2] = &gpll0_out_aux2.hw, - [MEASURE_ONLY_BIMC_CLK] = &measure_only_bimc_clk.hw, + [MEASURE_ONLY_MMCC_CLK] = &measure_only_mccc_clk.hw, [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, @@ -3424,6 +3424,8 @@ static const struct qcom_reset_map gcc_sm6150_resets[] = { [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, [GCC_UFS_PHY_BCR] = { 0x77000 }, [GCC_USB20_SEC_BCR] = { 0xa6000 }, + [GCC_USB3_DP_PHY_PRIM_SP0_BCR] = { 0x50010 }, + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x50008 }, }; static struct clk_dfs gcc_dfs_clocks[] = { @@ -3501,10 +3503,8 @@ static int gcc_sm6150_probe(struct platform_device *pdev) * Disable the GPLL0 active input to MM blocks and GPU * via MISC registers. */ - regmap_update_bits(regmap, GCC_DISPLAY_MISC, 0x1, 0x1); regmap_update_bits(regmap, GCC_CAMERA_MISC, 0x1, 0x1); regmap_update_bits(regmap, GCC_VIDEO_MISC, 0x1, 0x1); - regmap_update_bits(regmap, GCC_GPU_MISC, 0x3, 0x3); ret = qcom_cc_really_probe(pdev, &gcc_sm6150_desc, regmap); if (ret) { diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index 3cf223aadcad72ace4ff3da77bdbf1b47169f7e6..7d40149d840964ab217530b57ad0da917abe58a5 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -177,6 +177,14 @@ static const char * const gcc_parent_names_7[] = { "core_bi_pll_test_se", }; +static struct clk_dummy measure_only_cdsp_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_cdsp_clk", + .ops = &clk_dummy_ops, + }, +}; + static struct clk_dummy measure_only_snoc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ @@ -3899,6 +3907,7 @@ static struct clk_branch gcc_video_xo_clk = { }; struct clk_hw *gcc_sm8150_hws[] = { + [MEASURE_ONLY_CDSP_CLK] = &measure_only_cdsp_clk.hw, [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_MCCC_CLK] = &measure_only_mccc_clk.hw, diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 048d1ff302a60911a2d51d334adf3bcefb7478be..a579a5d1f0287c9df7be0177e356b90ba2b981c4 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -72,6 +72,7 @@ struct gdsc { bool root_en; bool force_root_en; bool no_status_check_on_disable; + bool skip_disable; bool is_gdsc_enabled; bool allow_clear; bool reset_aon; @@ -150,6 +151,13 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) int ret; bool is_enabled = false; + /* + * Return the logical GDSC enable state given that it will only be + * physically disabled by AOP during system sleep. + */ + if (sc->skip_disable) + return sc->is_gdsc_enabled; + if (!sc->toggle_logic) return !sc->resets_asserted; @@ -418,7 +426,12 @@ static int gdsc_disable(struct regulator_dev *rdev) /* Delay to account for staggered memory powerdown. */ udelay(1); - if (sc->toggle_logic) { + if (sc->skip_disable) { + /* + * Don't change the GDSCR register state on disable. AOP will + * handle this during system sleep. + */ + } else if (sc->toggle_logic) { regmap_read(sc->regmap, REG_OFFSET, ®val); regval |= SW_COLLAPSE_MASK; regmap_write(sc->regmap, REG_OFFSET, regval); @@ -831,6 +844,8 @@ static int gdsc_probe(struct platform_device *pdev) sc->no_status_check_on_disable = of_property_read_bool(pdev->dev.of_node, "qcom,no-status-check-on-disable"); + sc->skip_disable = of_property_read_bool(pdev->dev.of_node, + "qcom,skip-disable"); retain_mem = of_property_read_bool(pdev->dev.of_node, "qcom,retain-mem"); sc->toggle_mem = !retain_mem; diff --git a/drivers/clk/qcom/gpucc-sdmmagpie.c b/drivers/clk/qcom/gpucc-sdmmagpie.c new file mode 100644 index 0000000000000000000000000000000000000000..b2d18f94ddaa877c3593e360fb77434fd102a6f4 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sdmmagpie.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "reset.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +enum vdd_gx_levels { + VDD_GX_NONE, + VDD_GX_MIN, /* MIN SVS */ + VDD_GX_LOWER, /* SVS2 */ + VDD_GX_LOW, /* SVS */ + VDD_GX_LOW_L1, /* SVSL1 */ + VDD_GX_NOMINAL, /* NOM */ + VDD_GX_NOMINAL_L1, /* NOM1 */ + VDD_GX_HIGH, /* TURBO */ + VDD_GX_HIGH_L1, /* TURBO1 */ + VDD_GX_NUM, +}; + +static int vdd_gx_corner[] = { + RPMH_REGULATOR_LEVEL_OFF, /* VDD_GX_NONE */ + RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_GX_MIN */ + RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_GX_LOWER */ + RPMH_REGULATOR_LEVEL_SVS, /* VDD_GX_LOW */ + RPMH_REGULATOR_LEVEL_SVS_L1, /* VDD_GX_LOW_L1 */ + RPMH_REGULATOR_LEVEL_NOM, /* VDD_GX_NOMINAL */ + RPMH_REGULATOR_LEVEL_NOM_L1, /* VDD_GX_NOMINAL_L1 */ + RPMH_REGULATOR_LEVEL_TURBO, /* VDD_GX_HIGH */ + RPMH_REGULATOR_LEVEL_TURBO_L1, /* VDD_GX_HIGH_L1 */ + RPMH_REGULATOR_LEVEL_MAX, /* VDD_GX_MAX */ +}; + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_mx, VDD_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_gx, VDD_GX_NUM, 1, vdd_gx_corner); + +#define CX_GMU_CBCR_SLEEP_MASK 0xF +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xF +#define CX_GMU_CBCR_WAKE_SHIFT 8 + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_EVEN, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL0_OUT_ODD, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_0[] = { + "bi_tcxo", + "gpu_cc_pll0", + "gpu_cc_pll1", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_1[] = { + "bi_tcxo", + "gpu_cc_pll0_out_even", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x12, + .alpha = 0xC000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_even", + .parent_names = (const char *[]){ "gpu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_names = gpu_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 200000000}, + }, +}; + +/* PLL would be 2 times. */ +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { + F(180000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(267000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(355000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(430000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(565000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(750000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(780000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, + .flags = FORCE_ENABLE_RCG, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_names = gpu_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_gx, + .num_rate_max = VDD_GX_NUM, + .rate_max = (unsigned long[VDD_GX_NUM]) { + [VDD_GX_MIN] = 180000000, + [VDD_GX_LOWER] = 267000000, + [VDD_GX_LOW] = 355000000, + [VDD_GX_LOW_L1] = 430000000, + [VDD_GX_NOMINAL] = 565000000, + [VDD_GX_NOMINAL_L1] = 650000000, + [VDD_GX_HIGH] = 750000000, + [VDD_GX_HIGH_L1] = 780000000}, + }, +}; + +static struct clk_branch gpu_cc_acd_ahb_clk = { + .halt_reg = 0x1168, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1168, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_acd_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_acd_cxo_clk = { + .halt_reg = 0x1164, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1164, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_acd_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_apb_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { + .halt_reg = 0x10a8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_slv_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_cxo_clk = { + .halt_reg = 0x1060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_vsense_clk = { + .halt_reg = 0x1058, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_vsense_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gpu_cc_sdmmagpie_clocks[] = { + [GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr, + [GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr, + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, +}; + +static const struct regmap_config gpu_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8008, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sdmmagpie_desc = { + .config = &gpu_cc_sdmmagpie_regmap_config, + .clks = gpu_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sdmmagpie_clocks), +}; + +static const struct of_device_id gpu_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,gpucc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sdmmagpie_match_table); + +static int gpu_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + unsigned int value, mask; + + /* Get CX voltage regulator for CX and GMU clocks. */ + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + /* Get MX voltage regulator for GPU PLL graphic clock. */ + vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx"); + if (IS_ERR(vdd_mx.regulator[0])) { + if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_mx regulator\n"); + return PTR_ERR(vdd_mx.regulator[0]); + } + + /* GFX voltage regulators for GFX3D graphic clock. */ + vdd_gx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx"); + if (IS_ERR(vdd_gx.regulator[0])) { + if (PTR_ERR(vdd_gx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get vdd_gx regulator\n"); + return PTR_ERR(vdd_gx.regulator[0]); + } + + /* Avoid turning on the rail during clock registration */ + vdd_gx.skip_handoff = true; + + regmap = qcom_cc_map(pdev, &gpu_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the gpu_cc registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GPU CC clocks\n"); + return ret; + } + + /* Recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg, + mask, value); + + dev_info(&pdev->dev, "Registered GPU CC clocks\n"); + + return ret; +} + +static struct platform_driver gpu_cc_sdmmagpie_driver = { + .probe = gpu_cc_sdmmagpie_probe, + .driver = { + .name = "gpu_cc-sdmmagpie", + .of_match_table = gpu_cc_sdmmagpie_match_table, + }, +}; + +static int __init gpu_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&gpu_cc_sdmmagpie_driver); +} +subsys_initcall(gpu_cc_sdmmagpie_init); + +static void __exit gpu_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&gpu_cc_sdmmagpie_driver); +} +module_exit(gpu_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI GPU_CC SDMMAGPIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gpu_cc-sdmmagpie"); diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c index f42ec55046212a8ec4c736ac6b4e727e76712450..473a4fd6eec329bca935198dd826353dc2e2bffb 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c @@ -78,7 +78,7 @@ static struct dsi_pll_vco_clk dsi0pll_vco_clk = { .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, .hw.init = &(struct clk_init_data){ .name = "dsi0pll_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_dsi_vco, }, @@ -90,7 +90,7 @@ static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { .max_rate = 2600000000u, .hw.init = &(struct clk_init_data){ .name = "dsi0pll_shadow_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_shadow_dsi_vco, }, @@ -104,7 +104,7 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = { .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, .hw.init = &(struct clk_init_data){ .name = "dsi1pll_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_dsi_vco, }, @@ -118,7 +118,7 @@ static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, .hw.init = &(struct clk_init_data){ .name = "dsi1pll_shadow_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_shadow_dsi_vco, }, @@ -319,7 +319,7 @@ static struct clk_regmap_mux dsi0pll_pixel_clk_mux = { .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pixel_clk_mux", + .name = "dsi0_phy_pll_out_dsiclk", .parent_names = (const char *[]){ "dsi0pll_pixel_clk_src", "dsi0pll_shadow_pixel_clk_src"}, @@ -409,7 +409,7 @@ static struct clk_regmap_mux dsi0pll_byte_clk_mux = { .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_byte_clk_mux", + .name = "dsi0_phy_pll_out_byteclk", .parent_names = (const char *[]){"dsi0pll_byte_clk_src", "dsi0pll_shadow_byte_clk_src"}, diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 7de354a4de6827c6357ad938840606967f32270f..3710a08f12bff02fa659fd8b3f1ba86725c2ab02 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -408,6 +408,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_7nm"}, {.compatible = "qcom,mdss_dp_pll_7nm"}, {.compatible = "qcom,mdss_dsi_pll_28lpm"}, + {.compatible = "qcom,mdss_dsi_pll_14nm"}, {} }; diff --git a/drivers/clk/qcom/npucc-sdmmagpie.c b/drivers/clk/qcom/npucc-sdmmagpie.c new file mode 100644 index 0000000000000000000000000000000000000000..efa104d29189123363793478e3703d8e867b1183 --- /dev/null +++ b/drivers/clk/qcom/npucc-sdmmagpie.c @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +#define CRC_SID_FSM_CTRL 0x100c +#define CRC_SID_FSM_CTRL_SETTING 0x800000 +#define CRC_MND_CFG 0x1010 +#define CRC_MND_CFG_SETTING 0x15010 + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_NPU_CC_PLL0_OUT_EVEN, + P_NPU_CC_PLL1_OUT_EVEN, + P_NPU_CC_CRC_DIV, +}; + +static const struct parent_map npu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_NPU_CC_PLL1_OUT_EVEN, 1 }, + { P_NPU_CC_PLL0_OUT_EVEN, 2 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const npu_cc_parent_names_0[] = { + "bi_tcxo", + "npu_cc_pll1_out_even", + "npu_cc_pll0_out_even", + "gcc_npu_gpll0_clk_src", + "gcc_npu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct alpha_pll_config npu_cc_pll0_config = { + .l = 0x1F, + .frac = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll npu_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv npu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll0_out_even", + .parent_names = (const char *[]){ "npu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct alpha_pll_config npu_cc_pll1_config = { + .l = 0xF, + .frac = 0xA000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll npu_cc_pll1 = { + .offset = 0x400, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static struct clk_alpha_pll_postdiv npu_cc_pll1_out_even = { + .offset = 0x400, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll1_out_even", + .parent_names = (const char *[]){ "npu_cc_pll1" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct freq_tbl ftbl_npu_cc_cal_dp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(350000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(400000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(466500000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(600000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(700000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 npu_cc_cal_dp_clk_src = { + .cmd_rcgr = 0x1004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = npu_cc_parent_map_0, + .freq_tbl = ftbl_npu_cc_cal_dp_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_cal_dp_clk_src", + .parent_names = npu_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 300000000, + [VDD_LOW] = 400000000, + [VDD_LOW_L1] = 466500000, + [VDD_NOMINAL] = 600000000, + [VDD_HIGH] = 700000000}, + }, +}; + +static const struct freq_tbl ftbl_npu_cc_npu_core_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 npu_cc_npu_core_clk_src = { + .cmd_rcgr = 0x1030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = npu_cc_parent_map_0, + .freq_tbl = ftbl_npu_cc_npu_core_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_clk_src", + .parent_names = npu_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .flags = CLK_SET_RATE_PARENT, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 100000000, + [VDD_LOW] = 150000000, + [VDD_LOW_L1] = 200000000, + [VDD_NOMINAL] = 300000000, + [VDD_HIGH] = 400000000}, + }, +}; + +static struct clk_branch npu_cc_armwic_core_clk = { + .halt_reg = 0x1058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_armwic_core_clk", + .parent_names = (const char *[]){ + "npu_cc_npu_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_bto_core_clk = { + .halt_reg = 0x1090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_bto_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_bwmon_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_bwmon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_cal_dp_cdc_clk = { + .halt_reg = 0x1068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_cal_dp_cdc_clk", + .parent_names = (const char *[]){ + "npu_cc_cal_dp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_cal_dp_clk = { + .halt_reg = 0x101c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x101c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_cal_dp_clk", + .parent_names = (const char *[]){ + "npu_cc_cal_dp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_comp_noc_axi_clk = { + .halt_reg = 0x106c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x106c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_comp_noc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_conf_noc_ahb_clk = { + .halt_reg = 0x1074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1074, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_conf_noc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_apb_clk = { + .halt_reg = 0x1080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_atb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_atb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_clk = { + .halt_reg = 0x1048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_clk", + .parent_names = (const char *[]){ + "npu_cc_npu_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_cti_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_cti_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_cpc_clk = { + .halt_reg = 0x1050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_cpc_clk", + .parent_names = (const char *[]){ + "npu_cc_npu_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_cpc_timer_clk = { + .halt_reg = 0x105c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x105c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_cpc_timer_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_perf_cnt_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_perf_cnt_clk", + .parent_names = (const char *[]){ + "npu_cc_cal_dp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_qtimer_core_clk = { + .halt_reg = 0x1060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_qtimer_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_sleep_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_xo_clk = { + .halt_reg = 0x3020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_xo_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *npu_cc_sdmmagpie_clocks[] = { + [NPU_CC_PLL0] = &npu_cc_pll0.clkr, + [NPU_CC_PLL0_OUT_EVEN] = &npu_cc_pll0_out_even.clkr, + [NPU_CC_PLL1] = &npu_cc_pll1.clkr, + [NPU_CC_PLL1_OUT_EVEN] = &npu_cc_pll1_out_even.clkr, + [NPU_CC_ARMWIC_CORE_CLK] = &npu_cc_armwic_core_clk.clkr, + [NPU_CC_BTO_CORE_CLK] = &npu_cc_bto_core_clk.clkr, + [NPU_CC_BWMON_CLK] = &npu_cc_bwmon_clk.clkr, + [NPU_CC_CAL_DP_CDC_CLK] = &npu_cc_cal_dp_cdc_clk.clkr, + [NPU_CC_CAL_DP_CLK] = &npu_cc_cal_dp_clk.clkr, + [NPU_CC_CAL_DP_CLK_SRC] = &npu_cc_cal_dp_clk_src.clkr, + [NPU_CC_COMP_NOC_AXI_CLK] = &npu_cc_comp_noc_axi_clk.clkr, + [NPU_CC_CONF_NOC_AHB_CLK] = &npu_cc_conf_noc_ahb_clk.clkr, + [NPU_CC_NPU_CORE_APB_CLK] = &npu_cc_npu_core_apb_clk.clkr, + [NPU_CC_NPU_CORE_ATB_CLK] = &npu_cc_npu_core_atb_clk.clkr, + [NPU_CC_NPU_CORE_CLK] = &npu_cc_npu_core_clk.clkr, + [NPU_CC_NPU_CORE_CLK_SRC] = &npu_cc_npu_core_clk_src.clkr, + [NPU_CC_NPU_CORE_CTI_CLK] = &npu_cc_npu_core_cti_clk.clkr, + [NPU_CC_NPU_CPC_CLK] = &npu_cc_npu_cpc_clk.clkr, + [NPU_CC_NPU_CPC_TIMER_CLK] = &npu_cc_npu_cpc_timer_clk.clkr, + [NPU_CC_PERF_CNT_CLK] = &npu_cc_perf_cnt_clk.clkr, + [NPU_CC_QTIMER_CORE_CLK] = &npu_cc_qtimer_core_clk.clkr, + [NPU_CC_SLEEP_CLK] = &npu_cc_sleep_clk.clkr, + [NPU_CC_XO_CLK] = &npu_cc_xo_clk.clkr, +}; + +static const struct qcom_reset_map npu_cc_sdmmagpie_resets[] = { + [NPU_CC_CAL_DP_BCR] = { 0x1000 }, + [NPU_CC_NPU_CORE_BCR] = { 0x1024 }, +}; + +static const struct regmap_config npu_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8000, + .fast_io = true, +}; + +static const struct qcom_cc_desc npu_cc_sdmmagpie_desc = { + .config = &npu_cc_sdmmagpie_regmap_config, + .clks = npu_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(npu_cc_sdmmagpie_clocks), + .resets = npu_cc_sdmmagpie_resets, + .num_resets = ARRAY_SIZE(npu_cc_sdmmagpie_resets), +}; + +static const struct of_device_id npu_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,npucc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, npu_cc_sdmmagpie_match_table); + +static int enable_npu_crc(struct regmap *regmap, struct regulator *npu_gdsc) +{ + int ret; + + /* Set npu_cc_cal_cp_clk to the lowest supported frequency */ + clk_set_rate(npu_cc_cal_dp_clk.clkr.hw.clk, + clk_round_rate(npu_cc_cal_dp_clk_src.clkr.hw.clk, 1)); + + /* Turn on the NPU GDSC */ + ret = regulator_enable(npu_gdsc); + if (ret) { + pr_err("Failed to enable the NPU GDSC during CRC sequence\n"); + return ret; + } + + /* Enable npu_cc_cal_cp_clk */ + ret = clk_prepare_enable(npu_cc_cal_dp_clk.clkr.hw.clk); + if (ret) { + pr_err("Failed to enable npu_cc_cal_dp_clk during CRC sequence\n"); + regulator_disable(npu_gdsc); + return ret; + } + + /* Enable MND RC */ + regmap_write(regmap, CRC_MND_CFG, CRC_MND_CFG_SETTING); + regmap_write(regmap, CRC_SID_FSM_CTRL, CRC_SID_FSM_CTRL_SETTING); + + /* Wait for 16 cycles before continuing */ + udelay(1); + + /* Disable npu_cc_cal_cp_clk */ + clk_disable_unprepare(npu_cc_cal_dp_clk.clkr.hw.clk); + + /* Turn off the NPU GDSC */ + regulator_disable(npu_gdsc); + + return 0; +} + +static int npu_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct regulator *npu_gdsc; + int ret = 0; + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + npu_gdsc = devm_regulator_get(&pdev->dev, "npu_gdsc"); + if (IS_ERR(npu_gdsc)) { + if (!(PTR_ERR(npu_gdsc) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get npu_gdsc regulator\n"); + return PTR_ERR(npu_gdsc); + } + + regmap = qcom_cc_map(pdev, &npu_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the npu CC registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&npu_cc_pll0, regmap, &npu_cc_pll0_config); + clk_fabia_pll_configure(&npu_cc_pll1, regmap, &npu_cc_pll1_config); + + ret = qcom_cc_really_probe(pdev, &npu_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register NPU CC clocks\n"); + return ret; + } + + ret = enable_npu_crc(regmap, npu_gdsc); + if (ret) { + dev_err(&pdev->dev, "Failed to enable CRC for NPU cal RCG\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered NPU CC clocks\n"); + return ret; +} + +static struct platform_driver npu_cc_sdmmagpie_driver = { + .probe = npu_cc_sdmmagpie_probe, + .driver = { + .name = "npu_cc-sdmmagpie", + .of_match_table = npu_cc_sdmmagpie_match_table, + }, +}; + +static int __init npu_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&npu_cc_sdmmagpie_driver); +} +subsys_initcall(npu_cc_sdmmagpie_init); + +static void __exit npu_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&npu_cc_sdmmagpie_driver); +} +module_exit(npu_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI NPU_CC SDMMAGPIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:npu_cc-sdmmagpie"); diff --git a/drivers/clk/qcom/videocc-sdmmagpie.c b/drivers/clk/qcom/videocc-sdmmagpie.c new file mode 100644 index 0000000000000000000000000000000000000000..8d2d57f3104d54b6c7fa6eb73853f02a6dd15d84 --- /dev/null +++ b/drivers/clk/qcom/videocc-sdmmagpie.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "clk-alpha-pll.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_VIDEO_PLL0_OUT_EVEN, + P_VIDEO_PLL0_OUT_MAIN, + P_VIDEO_PLL0_OUT_ODD, +}; + +static const struct parent_map video_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_VIDEO_PLL0_OUT_MAIN, 1 }, + { P_VIDEO_PLL0_OUT_EVEN, 2 }, + { P_VIDEO_PLL0_OUT_ODD, 3 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const video_cc_parent_names_0[] = { + "bi_tcxo", + "video_pll0", + "video_pll0_out_even", + "video_pll0_out_odd", + "core_bi_pll_test_se", +}; + +static const struct parent_map video_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const video_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct alpha_pll_config video_pll0_config = { + .l = 0x19, + .frac = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll video_pll0 = { + .offset = 0x42c, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "video_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = { + F(240000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(338000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(365000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(444000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(533000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_iris_clk_src = { + .cmd_rcgr = 0x7f0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_0, + .freq_tbl = ftbl_video_cc_iris_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "video_cc_iris_clk_src", + .parent_names = video_cc_parent_names_0, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 240000000, + [VDD_LOW] = 338000000, + [VDD_LOW_L1] = 365000000, + [VDD_NOMINAL] = 444000000, + [VDD_HIGH] = 533000000}, + }, +}; + +static const struct freq_tbl ftbl_video_cc_xo_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_xo_clk_src = { + .cmd_rcgr = 0xa98, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_2, + .freq_tbl = ftbl_video_cc_xo_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "video_cc_xo_clk_src", + .parent_names = video_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch video_cc_iris_ahb_clk = { + .halt_reg = 0x8f4, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x8f4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_iris_ahb_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs0_axi_clk = { + .halt_reg = 0x9ec, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9ec, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs0_core_clk = { + .halt_reg = 0x890, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x890, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs0_core_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs1_axi_clk = { + .halt_reg = 0xa0c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa0c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs1_core_clk = { + .halt_reg = 0x8d0, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x8d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs1_core_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvsc_core_clk = { + .halt_reg = 0x850, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x850, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvsc_core_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvsc_ctl_axi_clk = { + .halt_reg = 0x9cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9cc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvsc_ctl_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_venus_ahb_clk = { + .halt_reg = 0xa6c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa6c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_venus_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_xo_clk = { + .halt_reg = 0x984, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x984, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_xo_clk", + .parent_names = (const char *[]){ + "video_cc_xo_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *video_cc_sdmmagpie_clocks[] = { + [VIDEO_PLL0] = &video_pll0.clkr, + [VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr, + [VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr, + [VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr, + [VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr, + [VIDEO_CC_MVS1_AXI_CLK] = &video_cc_mvs1_axi_clk.clkr, + [VIDEO_CC_MVS1_CORE_CLK] = &video_cc_mvs1_core_clk.clkr, + [VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr, + [VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr, + [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, + [VIDEO_CC_XO_CLK] = &video_cc_xo_clk.clkr, + [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, +}; + +static const struct regmap_config video_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xb94, + .fast_io = true, +}; + +static const struct qcom_cc_desc video_cc_sdmmagpie_desc = { + .config = &video_cc_sdmmagpie_regmap_config, + .clks = video_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(video_cc_sdmmagpie_clocks), +}; + +static const struct of_device_id video_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,videocc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, video_cc_sdmmagpie_match_table); + +static int video_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (PTR_ERR(vdd_cx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + regmap = qcom_cc_map(pdev, &video_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the video_cc registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); + + ret = qcom_cc_really_probe(pdev, &video_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Video CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Video CC clocks\n"); + return ret; +} + +static struct platform_driver video_cc_sdmmagpie_driver = { + .probe = video_cc_sdmmagpie_probe, + .driver = { + .name = "video_cc-sdmmagpie", + .of_match_table = video_cc_sdmmagpie_match_table, + }, +}; + +static int __init video_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&video_cc_sdmmagpie_driver); +} +subsys_initcall(video_cc_sdmmagpie_init); + +static void __exit video_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&video_cc_sdmmagpie_driver); +} +module_exit(video_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI VIDEO_CC SDMMAGPIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:video_cc-sdmmagpie"); diff --git a/drivers/clk/qcom/videocc-sm6150.c b/drivers/clk/qcom/videocc-sm6150.c index 844d78de958dca0f0ec3b05ad8c64aa066427af7..cc775411cba00b92918b539554d1e425a4fb0816 100644 --- a/drivers/clk/qcom/videocc-sm6150.c +++ b/drivers/clk/qcom/videocc-sm6150.c @@ -176,29 +176,6 @@ static struct clk_rcg2 video_cc_venus_clk_src = { }, }; -static const struct freq_tbl ftbl_video_cc_xo_clk_src[] = { - F(19200000, P_BI_TCXO, 1, 0, 0), - { } -}; - -static struct clk_rcg2 video_cc_xo_clk_src = { - .cmd_rcgr = 0xa98, - .mnd_width = 0, - .hid_width = 5, - .parent_map = video_cc_parent_map_2, - .freq_tbl = ftbl_video_cc_xo_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "video_cc_xo_clk_src", - .parent_names = video_cc_parent_names_2, - .num_parents = 2, - .ops = &clk_rcg2_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_LOWER] = 19200000}, - }, -}; - static struct clk_branch video_cc_apb_clk = { .halt_reg = 0x990, .halt_check = BRANCH_HALT, @@ -313,11 +290,7 @@ static struct clk_branch video_cc_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "video_cc_xo_clk", - .parent_names = (const char *[]){ - "video_cc_xo_clk_src", - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -334,7 +307,6 @@ static struct clk_regmap *video_cc_sm6150_clocks[] = { [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr, [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr, [VIDEO_CC_XO_CLK] = &video_cc_xo_clk.clkr, - [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, [VIDEO_PLL0_OUT_MAIN] = &video_pll0_out_main.clkr, }; diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 8b432d6e846d9677e03c21604b6e495f453a14fa..c9ce716247c1550b06ebcae6b35b11103f16edee 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -126,6 +126,49 @@ static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy) cpu->perf_caps.lowest_perf, cpu_num, ret); } +/* + * The PCC subspace describes the rate at which platform can accept commands + * on the shared PCC channel (including READs which do not count towards freq + * trasition requests), so ideally we need to use the PCC values as a fallback + * if we don't have a platform specific transition_delay_us + */ +#ifdef CONFIG_ARM64 +#include + +static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu) +{ + unsigned long implementor = read_cpuid_implementor(); + unsigned long part_num = read_cpuid_part_number(); + unsigned int delay_us = 0; + + switch (implementor) { + case ARM_CPU_IMP_QCOM: + switch (part_num) { + case QCOM_CPU_PART_FALKOR_V1: + case QCOM_CPU_PART_FALKOR: + delay_us = 10000; + break; + default: + delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC; + break; + } + break; + default: + delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC; + break; + } + + return delay_us; +} + +#else + +static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu) +{ + return cppc_get_transition_latency(cpu) / NSEC_PER_USEC; +} +#endif + static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) { struct cppc_cpudata *cpu; @@ -163,8 +206,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = cppc_dmi_max_khz; policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num); - policy->transition_delay_us = cppc_get_transition_latency(cpu_num) / - NSEC_PER_USEC; + policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu_num); policy->shared_type = cpu->shared_type; if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index a905bbb45667b55ed0ba9e1fa614e6e26c2c5ddb..114dfe67015b264ba1a998875f350724272637cf 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -2188,6 +2188,18 @@ static bool __init intel_pstate_no_acpi_pss(void) return true; } +static bool __init intel_pstate_no_acpi_pcch(void) +{ + acpi_status status; + acpi_handle handle; + + status = acpi_get_handle(NULL, "\\_SB", &handle); + if (ACPI_FAILURE(status)) + return true; + + return !acpi_has_method(handle, "PCCH"); +} + static bool __init intel_pstate_has_acpi_ppc(void) { int i; @@ -2247,7 +2259,10 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void) switch (plat_info[idx].data) { case PSS: - return intel_pstate_no_acpi_pss(); + if (!intel_pstate_no_acpi_pss()) + return false; + + return intel_pstate_no_acpi_pcch(); case PPC: return intel_pstate_has_acpi_ppc() && !force_load; } diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 3f0ce2ae35ee432637c28e7dddd2851a20e29f16..0c56c97596725edf323a2abf471bbaf69582b903 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -580,6 +580,10 @@ static int __init pcc_cpufreq_init(void) { int ret; + /* Skip initialization if another cpufreq driver is there. */ + if (cpufreq_get_current_driver()) + return 0; + if (acpi_disabled) return 0; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ebbd696f6c709e8e844123198aedade6f9d84bb5..235d21cda429b5acac0cdee0e1fc4cf0feb6a327 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -264,12 +264,18 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, * * @drv: the cpuidle driver * @dev: the cpuidle device + * @stop_tick: indication on whether or not to stop the tick * * Returns the index of the idle state. The return value must not be negative. + * + * The memory location pointed to by @stop_tick is expected to be written the + * 'false' boolean value if the scheduler tick should not be stopped before + * entering the returned state. */ -int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) +int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + bool *stop_tick) { - return cpuidle_curr_governor->select(drv, dev); + return cpuidle_curr_governor->select(drv, dev, stop_tick); } /** diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index ce1a2ffffb2a0f88ad9c43d89b34f9f553bc9009..0213e07abe9c2e969349da7cda454de92a316766 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -62,9 +62,10 @@ static inline void ladder_do_selection(struct ladder_device *ldev, * ladder_select_state - selects the next state to enter * @drv: cpuidle driver * @dev: the CPU + * @dummy: not used */ static int ladder_select_state(struct cpuidle_driver *drv, - struct cpuidle_device *dev) + struct cpuidle_device *dev, bool *dummy) { struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); struct ladder_device_state *last_state; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index a99d5620056d8803fe88de7ab272229eb92c6168..58c103b5892b2924976bf3d5cedfeecdbed4e932 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -123,6 +123,7 @@ struct menu_device { int last_state_idx; int needs_update; + int tick_wakeup; unsigned int next_timer_us; unsigned int predicted_us; @@ -284,8 +285,10 @@ static unsigned int get_typical_interval(struct menu_device *data) * menu_select - selects the next idle state to enter * @drv: cpuidle driver containing state data * @dev: the CPU + * @stop_tick: indication on whether or not to stop the tick */ -static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) +static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + bool *stop_tick) { struct menu_device *data = this_cpu_ptr(&menu_devices); struct device *device = get_cpu_device(dev->cpu); @@ -297,6 +300,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) unsigned int expected_interval; unsigned long nr_iowaiters, cpu_load; int resume_latency = dev_pm_qos_raw_read_value(device); + ktime_t delta_next; if (data->needs_update) { menu_update(drv, dev); @@ -308,11 +312,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) latency_req = resume_latency; /* Special case when user has set very strict latency requirement */ - if (unlikely(latency_req == 0)) + if (unlikely(latency_req == 0)) { + *stop_tick = false; return 0; + } /* determine the expected residency time, round up */ - data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length()); + data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length(&delta_next)); get_iowait_load(&nr_iowaiters, &cpu_load); data->bucket = which_bucket(data->next_timer_us, nr_iowaiters); @@ -351,14 +357,30 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) */ data->predicted_us = min(data->predicted_us, expected_interval); - /* - * Use the performance multiplier and the user-configurable - * latency_req to determine the maximum exit latency. - */ - interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load); - if (latency_req > interactivity_req) - latency_req = interactivity_req; + if (tick_nohz_tick_stopped()) { + /* + * If the tick is already stopped, the cost of possible short + * idle duration misprediction is much higher, because the CPU + * may be stuck in a shallow idle state for a long time as a + * result of it. In that case say we might mispredict and try + * to force the CPU into a state for which we would have stopped + * the tick, unless a timer is going to expire really soon + * anyway. + */ + if (data->predicted_us < TICK_USEC) + data->predicted_us = min_t(unsigned int, TICK_USEC, + ktime_to_us(delta_next)); + } else { + /* + * Use the performance multiplier and the user-configurable + * latency_req to determine the maximum exit latency. + */ + interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load); + if (latency_req > interactivity_req) + latency_req = interactivity_req; + } + expected_interval = data->predicted_us; /* * Find the idle state with the lowest power while satisfying * our constraints. @@ -374,15 +396,52 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) idx = i; /* first enabled state */ if (s->target_residency > data->predicted_us) break; - if (s->exit_latency > latency_req) + if (s->exit_latency > latency_req) { + /* + * If we break out of the loop for latency reasons, use + * the target residency of the selected state as the + * expected idle duration so that the tick is retained + * as long as that target residency is low enough. + */ + expected_interval = drv->states[idx].target_residency; break; - + } idx = i; } if (idx == -1) idx = 0; /* No states enabled. Must use 0. */ + /* + * Don't stop the tick if the selected state is a polling one or if the + * expected idle duration is shorter than the tick period length. + */ + if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || + expected_interval < TICK_USEC) { + unsigned int delta_next_us = ktime_to_us(delta_next); + + *stop_tick = false; + + if (!tick_nohz_tick_stopped() && idx > 0 && + drv->states[idx].target_residency > delta_next_us) { + /* + * The tick is not going to be stopped and the target + * residency of the state to be returned is not within + * the time until the next timer event including the + * tick, so try to correct that. + */ + for (i = idx - 1; i >= 0; i--) { + if (drv->states[i].disabled || + dev->states_usage[i].disable) + continue; + + idx = i; + if (drv->states[i].target_residency <= delta_next_us) + break; + } + } + } + data->last_state_idx = idx; return data->last_state_idx; @@ -402,6 +461,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index) data->last_state_idx = index; data->needs_update = 1; + data->tick_wakeup = tick_nohz_idle_got_tick(); } /** @@ -432,14 +492,27 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * assume the state was never reached and the exit latency is 0. */ - /* measured value */ - measured_us = cpuidle_get_last_residency(dev); - - /* Deduct exit latency */ - if (measured_us > 2 * target->exit_latency) - measured_us -= target->exit_latency; - else - measured_us /= 2; + if (data->tick_wakeup && data->next_timer_us > TICK_USEC) { + /* + * The nohz code said that there wouldn't be any events within + * the tick boundary (if the tick was stopped), but the idle + * duration predictor had a differing opinion. Since the CPU + * was woken up by a tick (that wasn't stopped after all), the + * predictor was not quite right, so assume that the CPU could + * have been idle long (but not forever) to help the idle + * duration predictor do a better job next time. + */ + measured_us = 9 * MAX_INTERESTING / 10; + } else { + /* measured value */ + measured_us = cpuidle_get_last_residency(dev); + + /* Deduct exit latency */ + if (measured_us > 2 * target->exit_latency) + measured_us -= target->exit_latency; + else + measured_us /= 2; + } /* Make sure our coefficients do not exceed unity */ if (measured_us > data->next_timer_us) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 4011f05e9676ebcd9cfb1b43877bd515b7b66fc6..a4da8c693647378f0bdf228b81faa27d2ff9cc95 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -592,7 +592,8 @@ static int cpu_power_select(struct cpuidle_device *dev, int best_level = 0; uint32_t latency_us = pm_qos_request_for_cpu(PM_QOS_CPU_DMA_LATENCY, dev->cpu); - s64 sleep_us = ktime_to_us(tick_nohz_get_sleep_length()); + ktime_t delta_next; + s64 sleep_us = ktime_to_us(tick_nohz_get_sleep_length(&delta_next)); uint32_t modified_time_us = 0; uint32_t next_event_us = 0; int i, idx_restrict; @@ -1316,7 +1317,7 @@ static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle) } static int lpm_cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev) + struct cpuidle_device *dev, bool *stop_tick) { struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0359f0c484fcb2157b538720db267675fef1a229..fe89328d3d99dfe837eec29611730c3eaaa2a236 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -773,4 +773,5 @@ config CRYPTO_DEV_ARTPEC6 if ARCH_QCOM source drivers/crypto/msm/Kconfig endif + endif # CRYPTO_HW diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 65dc78b91dea0147e454a5f9fdb20ed4bf024510..3f9eee7e555fe921a8e4af9d3d5fee7063e5a711 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -207,7 +207,7 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) dev->pdr_pa); return -ENOMEM; } - memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); + memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD, &dev->shadow_sa_pool_pa, @@ -240,13 +240,15 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev) { - if (dev->pdr != NULL) + if (dev->pdr) dma_free_coherent(dev->core_dev->device, sizeof(struct ce_pd) * PPC4XX_NUM_PD, dev->pdr, dev->pdr_pa); + if (dev->shadow_sa_pool) dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD, dev->shadow_sa_pool, dev->shadow_sa_pool_pa); + if (dev->shadow_sr_pool) dma_free_coherent(dev->core_dev->device, sizeof(struct sa_state_record) * PPC4XX_NUM_PD, @@ -416,12 +418,12 @@ static u32 crypto4xx_build_sdr(struct crypto4xx_device *dev) static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev) { - if (dev->sdr != NULL) + if (dev->sdr) dma_free_coherent(dev->core_dev->device, sizeof(struct ce_sd) * PPC4XX_NUM_SD, dev->sdr, dev->sdr_pa); - if (dev->scatter_buffer_va != NULL) + if (dev->scatter_buffer_va) dma_free_coherent(dev->core_dev->device, dev->scatter_buffer_size * PPC4XX_NUM_SD, dev->scatter_buffer_va, @@ -1033,12 +1035,10 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, break; } - if (rc) { - list_del(&alg->entry); + if (rc) kfree(alg); - } else { + else list_add_tail(&alg->entry, &sec_dev->alg_list); - } } return 0; @@ -1193,7 +1193,7 @@ static int crypto4xx_probe(struct platform_device *ofdev) rc = crypto4xx_build_gdr(core_dev->dev); if (rc) - goto err_build_gdr; + goto err_build_pdr; rc = crypto4xx_build_sdr(core_dev->dev); if (rc) @@ -1236,12 +1236,11 @@ static int crypto4xx_probe(struct platform_device *ofdev) err_request_irq: irq_dispose_mapping(core_dev->irq); tasklet_kill(&core_dev->tasklet); - crypto4xx_destroy_sdr(core_dev->dev); err_build_sdr: + crypto4xx_destroy_sdr(core_dev->dev); crypto4xx_destroy_gdr(core_dev->dev); -err_build_gdr: - crypto4xx_destroy_pdr(core_dev->dev); err_build_pdr: + crypto4xx_destroy_pdr(core_dev->dev); kfree(core_dev->dev); err_alloc_dev: kfree(core_dev); diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index e342d2af11094d314dc1b5f1c567603b800ebba0..4b37f69ef56f66450362a282d83c49f3481eeb38 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -57,6 +57,17 @@ #define QCOM_ICE_UFS 10 #define QCOM_ICE_SDCC 20 +#define QCOM_ICE_ENCRYPT 0x1 +#define QCOM_ICE_DECRYPT 0x2 +#define QCOM_SECT_LEN_IN_BYTE 512 +#define QCOM_UD_FOOTER_SIZE 0x4000 +#define QCOM_UD_FOOTER_SECS (QCOM_UD_FOOTER_SIZE / QCOM_SECT_LEN_IN_BYTE) + +#define ICE_CRYPTO_CXT_FDE 1 +#define ICE_CRYPTO_CXT_FBE 2 + +static int ice_fde_flag; + struct ice_clk_info { struct list_head list; struct clk *clk; @@ -108,16 +119,13 @@ struct ice_device { static int qti_ice_setting_config(struct request *req, struct platform_device *pdev, struct ice_crypto_setting *crypto_data, - struct ice_data_setting *setting) + struct ice_data_setting *setting, uint32_t cxt) { - struct ice_device *ice_dev = NULL; - - ice_dev = platform_get_drvdata(pdev); + struct ice_device *ice_dev = platform_get_drvdata(pdev); if (!ice_dev) { pr_debug("%s no ICE device\n", __func__); - - /* make the caller finish peacfully */ + /* make the caller finish peacefully */ return 0; } @@ -130,15 +138,20 @@ static int qti_ice_setting_config(struct request *req, return -EINVAL; if ((short)(crypto_data->key_index) >= 0) { - memcpy(&setting->crypto_data, crypto_data, sizeof(setting->crypto_data)); - if (rq_data_dir(req) == WRITE) - setting->encr_bypass = false; - else if (rq_data_dir(req) == READ) - setting->decr_bypass = false; - else { + if (rq_data_dir(req) == WRITE) { + if ((cxt == ICE_CRYPTO_CXT_FBE) || + ((cxt == ICE_CRYPTO_CXT_FDE) && + (ice_fde_flag & QCOM_ICE_ENCRYPT))) + setting->encr_bypass = false; + } else if (rq_data_dir(req) == READ) { + if ((cxt == ICE_CRYPTO_CXT_FBE) || + ((cxt == ICE_CRYPTO_CXT_FDE) && + (ice_fde_flag & QCOM_ICE_DECRYPT))) + setting->decr_bypass = false; + } else { /* Should I say BUG_ON */ setting->encr_bypass = true; setting->decr_bypass = true; @@ -148,6 +161,13 @@ static int qti_ice_setting_config(struct request *req, return 0; } +void qcom_ice_set_fde_flag(int flag) +{ + ice_fde_flag = flag; + pr_debug("%s read_write setting %d\n", __func__, ice_fde_flag); +} +EXPORT_SYMBOL(qcom_ice_set_fde_flag); + static int qcom_ice_enable_clocks(struct ice_device *, bool); #ifdef CONFIG_MSM_BUS_SCALING @@ -1431,8 +1451,11 @@ static int qcom_ice_config_start(struct platform_device *pdev, struct ice_data_setting *setting, bool async) { struct ice_crypto_setting pfk_crypto_data = {0}; + struct ice_crypto_setting ice_data = {0}; int ret = 0; bool is_pfe = false; + unsigned long sec_end = 0; + sector_t data_size; if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); @@ -1464,7 +1487,38 @@ static int qcom_ice_config_start(struct platform_device *pdev, } return qti_ice_setting_config(req, pdev, - &pfk_crypto_data, setting); + &pfk_crypto_data, setting, ICE_CRYPTO_CXT_FBE); + } + + if (ice_fde_flag && req->part && req->part->info + && req->part->info->volname[0]) { + if (!strcmp(req->part->info->volname, "userdata")) { + sec_end = req->part->start_sect + req->part->nr_sects - + QCOM_UD_FOOTER_SECS; + if ((req->__sector >= req->part->start_sect) && + (req->__sector < sec_end)) { + /* + * Ugly hack to address non-block-size aligned + * userdata end address in eMMC based devices. + * for eMMC based devices, since sector and + * block sizes are not same i.e. 4K, it is + * possible that partition is not a multiple of + * block size. For UFS based devices sector + * size and block size are same. Hence ensure + * that data is within userdata partition using + * sector based calculation + */ + data_size = req->__data_len / + QCOM_SECT_LEN_IN_BYTE; + + if ((req->__sector + data_size) > sec_end) + return 0; + else + return qti_ice_setting_config(req, pdev, + &ice_data, setting, + ICE_CRYPTO_CXT_FDE); + } + } } /* diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index c939f18f70cc0be197dc4c805b58d5d933cd7072..7685f557dcc0799a2a7869b0bf152d1eac8bcc9d 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -266,6 +266,8 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, return; } + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) @@ -273,7 +275,7 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) - : "d"(control_word), "b"(key), "c"(count - initial)); + : "d"(control_word), "b"(key), "c"(count)); } static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, @@ -284,6 +286,8 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, if (count < cbc_fetch_blocks) return cbc_crypt(input, output, key, iv, control_word, count); + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) @@ -291,7 +295,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) - : "d" (control_word), "b" (key), "c" (count-initial)); + : "d" (control_word), "b" (key), "c" (count)); return iv; } diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 346c4987b2848782336db887150b88db1a9b91a4..38983f56ad0ddd210703636088d5ccacac6ecbc7 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1106,7 +1106,7 @@ static void *ocram_alloc_mem(size_t size, void **other) static void ocram_free_mem(void *p, size_t size, void *other) { - gen_pool_free((struct gen_pool *)other, (u32)p, size); + gen_pool_free((struct gen_pool *)other, (unsigned long)p, size); } static const struct edac_device_prv_data ocramecc_data = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 1360a24d2ede1de8afa739a87f8405df5e768246..f08624f2f20945c60d5d6d82726fb1c9e707e691 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -683,8 +683,12 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return -EINVAL; /* A shared bo cannot be migrated to VRAM */ - if (bo->prime_shared_count && (domain == AMDGPU_GEM_DOMAIN_VRAM)) - return -EINVAL; + if (bo->prime_shared_count) { + if (domain & AMDGPU_GEM_DOMAIN_GTT) + domain = AMDGPU_GEM_DOMAIN_GTT; + else + return -EINVAL; + } if (bo->pin_count) { uint32_t mem_type = bo->tbo.mem.mem_type; diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 0d8a417e2cd67abd15f631ec4f54cead209d285b..bb5cc15fa0b927c09ac20d7ecb9dac9f1c154e2e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1355,7 +1355,9 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, { struct drm_plane *plane = plane_state->plane; struct drm_crtc_state *crtc_state; - + /* Nothing to do for same crtc*/ + if (plane_state->crtc == crtc) + return 0; if (plane_state->crtc) { crtc_state = drm_atomic_get_crtc_state(plane_state->state, plane_state->crtc); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0028591f3f959ced1ad520ee280fb481d7a52898..1f08d597b87af472b824cffd0ea858c362824f1b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2683,31 +2683,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, return 0; } -/** - * drm_atomic_helper_disable_all - disable all currently active outputs - * @dev: DRM device - * @ctx: lock acquisition context - * - * Loops through all connectors, finding those that aren't turned off and then - * turns them off by setting their DPMS mode to OFF and deactivating the CRTC - * that they are connected to. - * - * This is used for example in suspend/resume to disable all currently active - * functions when suspending. If you just want to shut down everything at e.g. - * driver unload, look at drm_atomic_helper_shutdown(). - * - * Note that if callers haven't already acquired all modeset locks this might - * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). - * - * Returns: - * 0 on success or a negative error code on failure. - * - * See also: - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and - * drm_atomic_helper_shutdown(). - */ -int drm_atomic_helper_disable_all(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx) +static int __drm_atomic_helper_disable_all(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx, + bool clean_old_fbs) { struct drm_atomic_state *state; struct drm_connector_state *conn_state; @@ -2759,8 +2737,11 @@ int drm_atomic_helper_disable_all(struct drm_device *dev, goto free; drm_atomic_set_fb_for_plane(plane_state, NULL); - plane_mask |= BIT(drm_plane_index(plane)); - plane->old_fb = plane->fb; + + if (clean_old_fbs) { + plane->old_fb = plane->fb; + plane_mask |= BIT(drm_plane_index(plane)); + } } ret = drm_atomic_commit(state); @@ -2771,6 +2752,34 @@ int drm_atomic_helper_disable_all(struct drm_device *dev, return ret; } +/** + * drm_atomic_helper_disable_all - disable all currently active outputs + * @dev: DRM device + * @ctx: lock acquisition context + * + * Loops through all connectors, finding those that aren't turned off and then + * turns them off by setting their DPMS mode to OFF and deactivating the CRTC + * that they are connected to. + * + * This is used for example in suspend/resume to disable all currently active + * functions when suspending. If you just want to shut down everything at e.g. + * driver unload, look at drm_atomic_helper_shutdown(). + * + * Note that if callers haven't already acquired all modeset locks this might + * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). + * + * Returns: + * 0 on success or a negative error code on failure. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and + * drm_atomic_helper_shutdown(). + */ +int drm_atomic_helper_disable_all(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + return __drm_atomic_helper_disable_all(dev, ctx, false); +} EXPORT_SYMBOL(drm_atomic_helper_disable_all); /** @@ -2793,7 +2802,7 @@ void drm_atomic_helper_shutdown(struct drm_device *dev) while (1) { ret = drm_modeset_lock_all_ctx(dev, &ctx); if (!ret) - ret = drm_atomic_helper_disable_all(dev, &ctx); + ret = __drm_atomic_helper_disable_all(dev, &ctx, true); if (ret != -EDEADLK) break; @@ -2897,16 +2906,11 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_connector_state *new_conn_state; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; - unsigned plane_mask = 0; - struct drm_device *dev = state->dev; - int ret; state->acquire_ctx = ctx; - for_each_new_plane_in_state(state, plane, new_plane_state, i) { - plane_mask |= BIT(drm_plane_index(plane)); + for_each_new_plane_in_state(state, plane, new_plane_state, i) state->planes[i].old_state = plane->state; - } for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) state->crtcs[i].old_state = crtc->state; @@ -2914,11 +2918,7 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, for_each_new_connector_in_state(state, connector, new_conn_state, i) state->connectors[i].old_state = connector->state; - ret = drm_atomic_commit(state); - if (plane_mask) - drm_atomic_clean_old_fb(dev, plane_mask, ret); - - return ret; + return drm_atomic_commit(state); } EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 41b492f99955f8d6778197e7102c854e41530b8f..c022ab6e84bdd714901a50bf539ddee849fabeff 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2862,12 +2862,14 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m, } } +#define DP_PAYLOAD_TABLE_SIZE 64 + static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, char *buf) { int i; - for (i = 0; i < 64; i += 16) { + for (i = 0; i < DP_PAYLOAD_TABLE_SIZE; i += 16) { if (drm_dp_dpcd_read(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS + i, &buf[i], 16) != 16) @@ -2936,7 +2938,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, mutex_lock(&mgr->lock); if (mgr->mst_primary) { - u8 buf[64]; + u8 buf[DP_PAYLOAD_TABLE_SIZE]; int ret; ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE); @@ -2954,8 +2956,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n", buf[0x9] >> 4, buf[0x9] & 0xf, buf[0xa], buf[0xb]); if (dump_dp_payload_table(mgr, buf)) - seq_printf(m, "payload table: %*ph\n", 63, buf); - + seq_printf(m, "payload table: %*ph\n", DP_PAYLOAD_TABLE_SIZE, buf); } mutex_unlock(&mgr->lock); diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index e8e4ea14b12ba4f2bb8474e7941b9eec858f7cfe..e05e5399af2db518959143992fbe21dc16dd0c11 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -255,7 +255,7 @@ extern int intelfb_remove(struct drm_device *dev, extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, +extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index be3eefec5152aa0cdf9dd891bf4d4fe423ff87d4..8baf6325c6e46cfbc7d839607f8536d27ee5e7c0 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -343,7 +343,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) } } -int psb_intel_lvds_mode_valid(struct drm_connector *connector, +enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_psb_private *dev_priv = connector->dev->dev_private; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b63893eeca73ddf78070bbecf055f6560f8636b7..20a471ad0ad27652447f9c6e33e957a4b2b43a2a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1786,10 +1786,38 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_status = 0, hotplug_status_mask; + int i; + + if (IS_G4X(dev_priv) || + IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + hotplug_status_mask = HOTPLUG_INT_STATUS_G4X | + DP_AUX_CHANNEL_MASK_INT_STATUS_G4X; + else + hotplug_status_mask = HOTPLUG_INT_STATUS_I915; - if (hotplug_status) + /* + * We absolutely have to clear all the pending interrupt + * bits in PORT_HOTPLUG_STAT. Otherwise the ISR port + * interrupt bit won't have an edge, and the i965/g4x + * edge triggered IIR will not notice that an interrupt + * is still pending. We can't use PORT_HOTPLUG_EN to + * guarantee the edge as the act of toggling the enable + * bits can itself generate a new hotplug interrupt :( + */ + for (i = 0; i < 10; i++) { + u32 tmp = I915_READ(PORT_HOTPLUG_STAT) & hotplug_status_mask; + + if (tmp == 0) + return hotplug_status; + + hotplug_status |= tmp; I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + } + + WARN_ONCE(1, + "PORT_HOTPLUG_STAT did not clear (0x%08x)\n", + I915_READ(PORT_HOTPLUG_STAT)); return hotplug_status; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 73f3e33ec86f8450fe14b94fdec37a4caba7939c..cd7ade6f8ae977cd2b3174c27263e86957b94e34 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1603,8 +1603,8 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, pr_debug("type=%d, name=%s, length=%d\n", type, cmd_set_prop_map[type], length); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, - 8, 1, data, length, false); + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 8, 1, data, length, false); rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count); if (rc) { diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 5b9d549aa791f5d02d1abef5e1c96e1aaf4bf2c6..e7926da59214fd6d919cde21f22e97a08f565883 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -55,6 +55,9 @@ nv04_display_create(struct drm_device *dev) nouveau_display(dev)->init = nv04_display_init; nouveau_display(dev)->fini = nv04_display_fini; + /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */ + dev->driver->driver_features &= ~DRIVER_ATOMIC; + nouveau_hw_save_vga_fonts(dev, 1); nv04_crtc_create(dev, 0); diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index debbbf0fd4bdda619732c67952c772f9957c4166..408b955e5c39a6b41043c18fb37ae8dc9de42c04 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->client.device; struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; INIT_LIST_HEAD(&drm->bl_connectors); @@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev) return 0; } - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && connector->connector_type != DRM_MODE_CONNECTOR_eDP) continue; @@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev) break; } } - + drm_connector_list_iter_end(&conn_iter); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c902a851eb5129b45bf1b21810a31c3da4f1d220..430830d63a33dcd7aad0ecf17ed40b8cd5051162 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; int type, ret = 0; bool dummy; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { nv_connector = nouveau_connector(connector); - if (nv_connector->index == index) + if (nv_connector->index == index) { + drm_connector_list_iter_end(&conn_iter); return connector; + } } + drm_connector_list_iter_end(&conn_iter); nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); if (!nv_connector) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index a4d1a059bd3d4f948c36c0a942150c68199ec974..dc7454e7f19aa0ec9f22e279015a0966eedbd531 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -33,6 +33,7 @@ #include #include #include "nouveau_crtc.h" +#include "nouveau_encoder.h" struct nvkm_i2c_port; @@ -60,19 +61,46 @@ static inline struct nouveau_connector *nouveau_connector( return container_of(con, struct nouveau_connector, base); } +static inline bool +nouveau_connector_is_mst(struct drm_connector *connector) +{ + const struct nouveau_encoder *nv_encoder; + const struct drm_encoder *encoder; + + if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + return false; + + nv_encoder = find_encoder(connector, DCB_OUTPUT_ANY); + if (!nv_encoder) + return false; + + encoder = &nv_encoder->base.base; + return encoder->encoder_type == DRM_MODE_ENCODER_DPMST; +} + +#define nouveau_for_each_non_mst_connector_iter(connector, iter) \ + drm_for_each_connector_iter(connector, iter) \ + for_each_if(!nouveau_connector_is_mst(connector)) + static inline struct nouveau_connector * nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) { struct drm_device *dev = nv_crtc->base.dev; struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct nouveau_connector *nv_connector = NULL; struct drm_crtc *crtc = to_drm_crtc(nv_crtc); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder && connector->encoder->crtc == crtc) - return nouveau_connector(connector); + drm_connector_list_iter_begin(dev, &conn_iter); + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { + if (connector->encoder && connector->encoder->crtc == crtc) { + nv_connector = nouveau_connector(connector); + break; + } } + drm_connector_list_iter_end(&conn_iter); - return NULL; + return nv_connector; } struct drm_connector * diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 2e7785f49e6d54c1c0941c69de2ff0a869cfd3f0..caf53503c0f7a5cea1265c2b333212f76e3b9014 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -405,6 +405,7 @@ nouveau_display_init(struct drm_device *dev) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; int ret; ret = disp->init(dev); @@ -412,10 +413,12 @@ nouveau_display_init(struct drm_device *dev) return ret; /* enable hotplug interrupts */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); nvif_notify_get(&conn->hpd); } + drm_connector_list_iter_end(&conn_iter); /* enable flip completion events */ nvif_notify_get(&drm->flip); @@ -428,6 +431,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; if (!suspend) { if (drm_drv_uses_atomic_modeset(dev)) @@ -440,10 +444,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) nvif_notify_put(&drm->flip); /* disable hotplug interrupts */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); nvif_notify_put(&conn->hpd); } + drm_connector_list_iter_end(&conn_iter); drm_kms_helper_poll_disable(dev); disp->fini(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 595630d1fb9e239b68e6ddc71d1269cafca5ae7b..362a34cb435db7ad2b8dd5810c9dd25a0d5b744e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -79,6 +79,10 @@ MODULE_PARM_DESC(modeset, "enable driver (default: auto, " int nouveau_modeset = -1; module_param_named(modeset, nouveau_modeset, int, 0400); +MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)"); +static int nouveau_atomic = 0; +module_param_named(atomic, nouveau_atomic, int, 0400); + MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1)"); static int nouveau_runtime_pm = -1; module_param_named(runpm, nouveau_runtime_pm, int, 0400); @@ -383,6 +387,9 @@ static int nouveau_drm_probe(struct pci_dev *pdev, pci_set_master(pdev); + if (nouveau_atomic) + driver_pci.driver_features |= DRIVER_ATOMIC; + ret = drm_get_pci_dev(pdev, pent, &driver_pci); if (ret) { nvkm_device_del(&device); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index a29474528e8506ed7b8c4ff4c5770adc63df30e2..926ec51ba5be19820c3ad0a703e84cfe16cd9236 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -4150,7 +4150,7 @@ nv50_disp_atomic_commit(struct drm_device *dev, nv50_disp_atomic_commit_tail(state); drm_for_each_crtc(crtc, dev) { - if (crtc->state->enable) { + if (crtc->state->active) { if (!drm->have_disp_power_ref) { drm->have_disp_power_ref = true; return 0; @@ -4398,10 +4398,6 @@ nv50_display_destroy(struct drm_device *dev) kfree(disp); } -MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)"); -static int nouveau_atomic = 0; -module_param_named(atomic, nouveau_atomic, int, 0400); - int nv50_display_create(struct drm_device *dev) { @@ -4426,8 +4422,6 @@ nv50_display_create(struct drm_device *dev) disp->disp = &nouveau_display(dev)->disp; dev->mode_config.funcs = &nv50_disp_func; dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP; - if (nouveau_atomic) - dev->driver->driver_features |= DRIVER_ATOMIC; /* small shared memory area we use for notifiers and semaphores */ ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index a7e55c422501cf9c4fc98bc7e7798d2b2213cfcf..0b632dc0cf7d4c6b40aee1226ca3e4f01f2485a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -155,10 +155,10 @@ gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl) (target << 28)); nvkm_wr32(device, 0x002274, (runl << 20) | nr); - if (wait_event_timeout(fifo->runlist[runl].wait, - !(nvkm_rd32(device, 0x002284 + (runl * 0x08)) - & 0x00100000), - msecs_to_jiffies(2000)) == 0) + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x002284 + (runl * 0x08)) & 0x00100000)) + break; + ) < 0) nvkm_error(subdev, "runlist %d update timeout\n", runl); unlock: mutex_unlock(&subdev->mutex); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 424cd1b665759bfb0033cdf8aefff77d863cab06..337d3a1c2a4099b54652b7c5b836f4826b1c1ee8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -853,7 +853,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) return ret; } -static int radeon_lvds_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -1013,7 +1013,7 @@ static int radeon_vga_get_modes(struct drm_connector *connector) return ret; } -static int radeon_vga_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1157,7 +1157,7 @@ static int radeon_tv_get_modes(struct drm_connector *connector) return 1; } -static int radeon_tv_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) @@ -1499,7 +1499,7 @@ static void radeon_dvi_force(struct drm_connector *connector) radeon_connector->use_digital = true; } -static int radeon_dvi_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1801,7 +1801,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) return ret; } -static int radeon_dp_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 77c56264c05bb2875cc662fb8d189bedf1abef41..17590cb2b80d952b4479dc14b00b26c6db7ae379 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -352,6 +352,9 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) vc4_state->x_scaling[0] = VC4_SCALING_TPZ; if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) vc4_state->y_scaling[0] = VC4_SCALING_TPZ; + } else { + vc4_state->x_scaling[1] = VC4_SCALING_NONE; + vc4_state->y_scaling[1] = VC4_SCALING_NONE; } vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 2547794bd78fa67aa45f9e8b44d8deb1c80dc884..9092d14168f89e06c345ca13f1a8b2949a54b3ed 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -387,7 +387,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .patchid = 0, .features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT | - ADRENO_IFPC, + ADRENO_IFPC | ADRENO_ACD, .sqefw_name = "a630_sqe.fw", .zap_name = "a640_zap", .gpudev = &adreno_a6xx_gpudev, @@ -408,7 +408,8 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .minor = 0, .patchid = ANY_ID, .features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_GPMU | - ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT, + ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT | + ADRENO_IFPC, .sqefw_name = "a630_sqe.fw", .zap_name = "a640_zap", .gpudev = &adreno_a6xx_gpudev, @@ -420,7 +421,6 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gpmu_minor = 0x000, .gpmu_tsens = 0x000C000D, .max_power = 5448, - .va_padding = SZ_64K, }, { .gpurev = ADRENO_REV_A680, @@ -447,8 +447,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .major = 0, .minor = 8, .patchid = ANY_ID, - .features = ADRENO_64BIT | ADRENO_CONTENT_PROTECTION | - ADRENO_PREEMPTION, + .features = ADRENO_64BIT | ADRENO_CONTENT_PROTECTION, .sqefw_name = "a630_sqe.fw", .zap_name = "a608_zap", .gpudev = &adreno_a6xx_gpudev, diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index df69aa95dc4920dbbc75003cdf66adf910caa219..e3cd9803dc88e9ba55702ff7d9f6261449e755cc 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -756,6 +756,7 @@ static struct { { ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW, "qcom,gpu-quirk-limit-uche-gbif-rw" }, { ADRENO_QUIRK_MMU_SECURE_CB_ALT, "qcom,gpu-quirk-mmu-secure-cb-alt" }, + { ADRENO_QUIRK_CX_GDSC, "qcom,gpu-quirk-cx-gdsc" }, }; static struct device_node * @@ -965,6 +966,10 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, if (of_property_read_u32(child, "qcom,bus-max", &level->bus_max)) level->bus_max = level->bus_freq; + + if (of_property_read_u32(child, "qcom,dvm-val", + &level->acd_dvm_val)) + level->acd_dvm_val = 0xFFFFFFFF; } return 0; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 0ffcc9eed2359f0797dd255aee3563bf33807dae..0131912811808c1cd8a64bf7e2b4ce079e35ab35 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -123,6 +123,11 @@ #define ADRENO_MIN_VOLT BIT(15) /* The core supports IO-coherent memory */ #define ADRENO_IOCOHERENT BIT(16) +/* + * The GMU supports Adaptive Clock Distribution (ACD) + * for droop mitigation + */ +#define ADRENO_ACD BIT(17) /* * Adreno GPU quirks - control bits for various workarounds @@ -152,6 +157,8 @@ #define ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW BIT(8) /* Select alternate secure context bank for mmu */ #define ADRENO_QUIRK_MMU_SECURE_CB_ALT BIT(9) +/* Do explicit mode control of cx gdsc */ +#define ADRENO_QUIRK_CX_GDSC BIT(10) /* Flags to control command packet settings */ #define KGSL_CMD_FLAGS_NONE 0 @@ -233,6 +240,7 @@ enum adreno_gpurev { #define ADRENO_LM_CTRL 2 #define ADRENO_HWCG_CTRL 3 #define ADRENO_THROTTLING_CTRL 4 +#define ADRENO_ACD_CTRL 5 /* VBIF, GBIF halt request and ack mask */ #define GBIF_HALT_REQUEST 0x1E0 diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index d1103cc4fe2ac397832c8a124c90c9d35f1ca51b..8c6ca7c9e0b20f8e3d8a3c5caa5e2bfd408d43f3 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2546,17 +2546,11 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - /* - * Both A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4 and - * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5 are owned - * by the GMU. Mark them as broken so there is no - * dual ownership. - */ - { KGSL_PERFCOUNTER_BROKEN, 0, 0, + { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, - { KGSL_PERFCOUNTER_BROKEN, 0, 0, + { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, @@ -2656,6 +2650,7 @@ static const struct { void (*func)(struct adreno_device *adreno_dev); } a6xx_efuse_funcs[] = { { adreno_is_a615, a6xx_efuse_speed_bin }, + { adreno_is_a608, a6xx_efuse_speed_bin }, }; static void a6xx_check_features(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index bbfab64bddf91b0cc51a01389b278ebb8ce79733..24a578d16d03441070d29600d78a3d9a396fe10d 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -301,12 +301,6 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) break; } - /* ACD feature enablement */ - if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && - test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - gmu_core_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0, - BIT(10)); - /* Enable RPMh GPU client */ if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH)) gmu_core_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, @@ -322,11 +316,6 @@ static int a6xx_gmu_start(struct kgsl_device *device) struct gmu_device *gmu = KGSL_GMU_DEVICE(device); kgsl_regwrite(device, A6XX_GMU_CX_GMU_WFI_CONFIG, 0x0); - /* Write 1 first to make sure the GMU is reset */ - gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); - - /* Make sure putting in reset doesn't happen after clearing */ - wmb(); /* Bring GMU out of reset */ gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); @@ -426,6 +415,10 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) if (test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags)) return 0; + gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); + /* Make sure M3 is in reset before going on */ + wmb(); + /* RSC sleep sequence is different on v1 */ if (adreno_is_a630v1(adreno_dev)) gmu_core_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); @@ -472,68 +465,51 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) return 0; } -/* - * Gmu FW header format: - * <32-bit start addr> <32-bit size> <32-bit pad0> <32-bit pad1> - */ -#define GMU_FW_HEADER_SIZE 4 - -#define GMU_ITCM_VA_START 0x0 -#define GMU_ITCM_VA_END (GMU_ITCM_VA_START + 0x4000) /* 16 KB */ - -#define GMU_DTCM_VA_START 0x40000 -#define GMU_DTCM_VA_END (GMU_DTCM_VA_START + 0x4000) /* 16 KB */ - -#define GMU_ICACHE_VA_START 0x4000 -#define GMU_ICACHE_VA_END (GMU_ICACHE_VA_START + 0x3C000) /* 240 KB */ - static int load_gmu_fw(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - uint32_t *fwptr = gmu->fw_image->hostptr; - int i, j; - int start_addr, size_in_bytes, num_dwords, tcm_slot, num_records; + uint8_t *fw = (uint8_t *)gmu->fw_image->data; + int j; + int tcm_addr; + struct gmu_block_header *blk; + struct gmu_memdesc *md; + + while (fw < (uint8_t *)gmu->fw_image->data + gmu->fw_image->size) { + blk = (struct gmu_block_header *)fw; + fw += sizeof(*blk); + + /* Don't deal with zero size blocks */ + if (blk->size == 0) + continue; + + md = gmu_get_memdesc(blk->addr, blk->size); + if (md == NULL) { + dev_err(&gmu->pdev->dev, + "No backing memory for 0x%8.8X\n", + blk->addr); + return -EINVAL; + } - /* - * Read first record. pad0 field of first record contains - * number of records in the image. - */ - num_records = fwptr[2]; - for (i = 0; i < num_records; i++) { - start_addr = fwptr[0]; - size_in_bytes = fwptr[1]; - num_dwords = size_in_bytes / sizeof(uint32_t); - fwptr += GMU_FW_HEADER_SIZE; - - if ((start_addr >= GMU_ITCM_VA_START) && - (start_addr < GMU_ITCM_VA_END)) { - tcm_slot = start_addr / sizeof(uint32_t); - - for (j = 0; j < num_dwords; j++) - gmu_core_regwrite(device, - A6XX_GMU_CM3_ITCM_START + tcm_slot + j, - fwptr[j]); - } else if ((start_addr >= GMU_DTCM_VA_START) && - (start_addr < GMU_DTCM_VA_END)) { - tcm_slot = (start_addr - GMU_DTCM_VA_START) - / sizeof(uint32_t); - - for (j = 0; j < num_dwords; j++) - gmu_core_regwrite(device, - A6XX_GMU_CM3_DTCM_START + tcm_slot + j, - fwptr[j]); - } else if ((start_addr >= GMU_ICACHE_VA_START) && - (start_addr < GMU_ICACHE_VA_END)) { - if (!is_cached_fw_size_valid(size_in_bytes)) { - dev_err(&gmu->pdev->dev, - "GMU firmware size too big\n"); - return -EINVAL; + if (md->mem_type == GMU_ITCM || md->mem_type == GMU_DTCM) { + uint32_t *fwptr = (uint32_t *)fw; + + tcm_addr = (blk->addr - (uint32_t)md->gmuaddr) / + sizeof(uint32_t); + + if (md->mem_type == GMU_ITCM) + tcm_addr += A6XX_GMU_CM3_ITCM_START; + else + tcm_addr += A6XX_GMU_CM3_DTCM_START; - } - memcpy(gmu->icache_mem->hostptr, fwptr, size_in_bytes); + for (j = 0; j < blk->size / sizeof(uint32_t); j++) + gmu_core_regwrite(device, tcm_addr + j, + fwptr[j]); + } else { + /* Copy the memory directly */ + memcpy(md->hostptr, fw, blk->size); } - fwptr += num_dwords; + fw += blk->size; } /* Proceed only after the FW is written */ @@ -1044,11 +1020,10 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, */ static int a6xx_gmu_load_firmware(struct kgsl_device *device) { - const struct firmware *fw = NULL; const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct gmu_device *gmu = KGSL_GMU_DEVICE(device); const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; - int image_size, ret = -EINVAL; + int ret = -EINVAL; /* there is no GMU */ if (!gmu_core_isenabled(device)) @@ -1061,22 +1036,11 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device) if (gpucore->gpmufw_name == NULL) return -EINVAL; - ret = request_firmware(&fw, gpucore->gpmufw_name, device->dev); - if (ret || fw == NULL) { + ret = request_firmware(&gmu->fw_image, gpucore->gpmufw_name, + device->dev); + if (ret || gmu->fw_image == NULL) KGSL_CORE_ERR("request_firmware (%s) failed: %d\n", gpucore->gpmufw_name, ret); - return ret; - } - - image_size = PAGE_ALIGN(fw->size); - - ret = allocate_gmu_image(gmu, image_size); - - /* load into shared memory with GMU */ - if (!ret) - memcpy(gmu->fw_image->hostptr, fw->data, fw->size); - - release_firmware(fw); return ret; } diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index a414e553cd7b028cefe18328c06f9bf02bea0049..55b0b73468eddb835f078d0aa1005287969765e1 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -312,6 +312,21 @@ static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) return preempt->count; } +static unsigned int _acd_show(struct adreno_device *adreno_dev) +{ + return test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); +} + +static int _acd_store(struct adreno_device *adreno_dev, unsigned int val) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag) == val) + return 0; + + return gmu_core_acd_set(device, val); +} + static ssize_t _sysfs_store_u32(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -416,7 +431,7 @@ static ADRENO_SYSFS_BOOL(hwcg); static ADRENO_SYSFS_BOOL(throttling); static ADRENO_SYSFS_BOOL(ifpc); static ADRENO_SYSFS_RO_U32(ifpc_count); - +static ADRENO_SYSFS_BOOL(acd); static const struct device_attribute *_attr_list[] = { @@ -439,6 +454,7 @@ static const struct device_attribute *_attr_list[] = { &adreno_attr_ifpc.attr, &adreno_attr_ifpc_count.attr, &adreno_attr_preempt_count.attr, + &adreno_attr_acd.attr, NULL, }; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e40c91a01742473422b316e92db17e5c186bf717..2ef9b45c3e8d2a21ba57e4be8f61a71319f4fdce 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -2352,6 +2353,7 @@ static long _gpuobj_map_dma_buf(struct kgsl_device *device, { struct kgsl_gpuobj_import_dma_buf buf; struct dma_buf *dmabuf; + unsigned long flags = 0; int ret; /* @@ -2382,6 +2384,16 @@ static long _gpuobj_map_dma_buf(struct kgsl_device *device, if (IS_ERR_OR_NULL(dmabuf)) return (dmabuf == NULL) ? -EINVAL : PTR_ERR(dmabuf); + /* + * ION cache ops are routed through kgsl, so record if the dmabuf is + * cached or not in the memdesc. Assume uncached if dma_buf_get_flags + * fails. + */ + dma_buf_get_flags(dmabuf, &flags); + if (flags & ION_FLAG_CACHED) + entry->memdesc.flags |= + KGSL_CACHEMODE_WRITEBACK << KGSL_CACHEMODE_SHIFT; + ret = kgsl_setup_dma_buf(device, pagetable, entry, dmabuf); if (ret) dma_buf_put(dmabuf); diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index b47246533d42e6bfbf7c96a89486e9e745e3615c..0ea075fb93ebd1097100d270c7d8cb8e3f6e0ca1 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -10,6 +10,7 @@ * GNU General Public License for more details. * */ +#include #include #include #include @@ -26,6 +27,13 @@ #include "kgsl_hfi.h" #include "adreno.h" +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "kgsl." + +static bool noacd; +module_param(noacd, bool, 0444); +MODULE_PARM_DESC(noacd, "Disable GPU ACD"); + #define GMU_CONTEXT_USER 0 #define GMU_CONTEXT_KERNEL 1 #define GMU_KERNEL_ENTRIES 16 @@ -40,16 +48,15 @@ struct gmu_iommu_context { #define DUMMY_SIZE SZ_4K -#define GMU_DCACHE_SIZE (SZ_256K - SZ_16K) /* GMU DCache VA size: 240KB */ -#define GMU_ICACHE_SIZE (SZ_256K - SZ_16K) /* GMU ICache VA size: 240KB */ - /* Define target specific GMU VMA configurations */ static const struct gmu_vma_entry { unsigned int start; unsigned int size; } gmu_vma[] = { - [GMU_CACHED_CODE] = { .start = 0x04000, .size = GMU_ICACHE_SIZE }, - [GMU_CACHED_DATA] = { .start = 0x44000, .size = GMU_DCACHE_SIZE }, + [GMU_ITCM] = { .start = 0x00000, .size = SZ_16K }, + [GMU_ICACHE] = { .start = 0x04000, .size = (SZ_256K - SZ_16K) }, + [GMU_DTCM] = { .start = 0x40000, .size = SZ_16K }, + [GMU_DCACHE] = { .start = 0x44000, .size = (SZ_256K - SZ_16K) }, [GMU_NONCACHED_KERNEL] = { .start = 0x60000000, .size = SZ_512M }, [GMU_NONCACHED_USER] = { .start = 0x80000000, .size = SZ_1G }, }; @@ -125,6 +132,9 @@ static int alloc_and_map(struct gmu_device *gmu, unsigned int ctx_id, int ret; struct iommu_domain *domain; + if (md->mem_type == GMU_ITCM || md->mem_type == GMU_DTCM) + return 0; + domain = gmu_ctx[ctx_id].domain; md->hostptr = dma_alloc_attrs(&gmu->pdev->dev, (size_t) md->size, @@ -145,6 +155,25 @@ static int alloc_and_map(struct gmu_device *gmu, unsigned int ctx_id, return ret; } +struct gmu_memdesc *gmu_get_memdesc(unsigned int addr, unsigned int size) +{ + int i; + struct gmu_memdesc *mem; + + for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { + if (!test_bit(i, &gmu_kmem_bitmap)) + continue; + + mem = &gmu_kmem_entries[i]; + + if (addr >= mem->gmuaddr && + (addr + size < mem->gmuaddr + mem->size)) + return mem; + } + + return NULL; +} + /* * allocate_gmu_kmem() - allocates and maps uncached GMU kernel shared memory * @gmu: Pointer to GMU device @@ -152,10 +181,12 @@ static int alloc_and_map(struct gmu_device *gmu, unsigned int ctx_id, * @attrs: IOMMU mapping attributes */ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, - uint32_t mem_type, unsigned int size, unsigned int attrs) + enum gmu_mem_type mem_type, unsigned int size, + unsigned int attrs) { struct gmu_memdesc *md; - int ret, entry_idx = find_first_zero_bit( + int ret = 0; + int entry_idx = find_first_zero_bit( &gmu_kmem_bitmap, GMU_KERNEL_ENTRIES); if (entry_idx >= GMU_KERNEL_ENTRIES) { @@ -174,55 +205,54 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, return ERR_PTR(-EINVAL); } - /* Allocate GMU virtual memory */ md = &gmu_kmem_entries[entry_idx]; md->gmuaddr = gmu_vma[mem_type].start + (num_uncached_entries * SZ_1M); set_bit(entry_idx, &gmu_kmem_bitmap); md->size = size; md->mem_type = mem_type; - break; - case GMU_CACHED_DATA: - if (size != GMU_DCACHE_SIZE) { - dev_err(&gmu->pdev->dev, - "Invalid cached GMU memory req %d\n", - size); - return ERR_PTR(-EINVAL); - } - /* Allocate GMU virtual memory */ + case GMU_DCACHE: md = &gmu_kmem_entries[entry_idx]; md->gmuaddr = gmu_vma[mem_type].start; set_bit(entry_idx, &gmu_kmem_bitmap); md->size = size; md->mem_type = mem_type; + break; + case GMU_ICACHE: + md = &gmu_kmem_entries[entry_idx]; + md->gmuaddr = gmu_vma[mem_type].start; + set_bit(entry_idx, &gmu_kmem_bitmap); + md->size = size; + md->mem_type = mem_type; break; - case GMU_CACHED_CODE: - if (size != GMU_ICACHE_SIZE) { - dev_err(&gmu->pdev->dev, - "Invalid cached GMU memory req %d\n", - size); - return ERR_PTR(-EINVAL); - } - /* Allocate GMU virtual memory */ + case GMU_ITCM: md = &gmu_kmem_entries[entry_idx]; md->gmuaddr = gmu_vma[mem_type].start; set_bit(entry_idx, &gmu_kmem_bitmap); md->size = size; md->mem_type = mem_type; + break; + case GMU_DTCM: + md = &gmu_kmem_entries[entry_idx]; + md->gmuaddr = gmu_vma[mem_type].start; + set_bit(entry_idx, &gmu_kmem_bitmap); + md->size = size; + md->mem_type = mem_type; break; + default: dev_err(&gmu->pdev->dev, - "Invalid memory type requested\n"); + "Invalid memory type (%d) requested\n", + mem_type); return ERR_PTR(-EINVAL); }; ret = alloc_and_map(gmu, GMU_CONTEXT_KERNEL, md, attrs); - if (ret) { clear_bit(entry_idx, &gmu_kmem_bitmap); md->gmuaddr = 0; @@ -235,35 +265,6 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, return md; } -/* - * allocate_gmu_image() - allocates & maps memory for FW image, the size - * shall come from the loaded f/w file. - * @gmu: Pointer to GMU device - * @size: Requested allocation size - */ -int allocate_gmu_image(struct gmu_device *gmu, unsigned int size) -{ - /* Allocates & maps memory for GMU FW */ - gmu->fw_image = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, size, - (IOMMU_READ | IOMMU_PRIV)); - if (IS_ERR(gmu->fw_image)) { - dev_err(&gmu->pdev->dev, - "GMU firmware image allocation failed\n"); - return -EINVAL; - } - - return 0; -} - -/* Checks if cached fw code size falls within the cached code segment range */ -bool is_cached_fw_size_valid(uint32_t size_in_bytes) -{ - if (size_in_bytes > gmu_vma[GMU_CACHED_CODE].size) - return false; - - return true; -} - static int gmu_iommu_cb_probe(struct gmu_device *gmu, struct gmu_iommu_context *ctx, struct device_node *node) @@ -360,21 +361,21 @@ static void gmu_kmem_close(struct gmu_device *gmu) gmu->hfi_mem = NULL; gmu->bw_mem = NULL; gmu->dump_mem = NULL; - gmu->fw_image = NULL; gmu->gmu_log = NULL; - /* Unmap all memories in GMU kernel memory pool */ + /* Unmap and free all memories in GMU kernel memory pool */ for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { + if (!test_bit(i, &gmu_kmem_bitmap)) + continue; + md = &gmu_kmem_entries[i]; - if (md->gmuaddr) + if (md->gmuaddr && md->mem_type != GMU_ITCM && + md->mem_type != GMU_DTCM) iommu_unmap(ctx->domain, md->gmuaddr, md->size); - } - /* Free GMU shared kernel memory */ - for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { - md = &gmu_kmem_entries[i]; free_gmu_mem(gmu, md); + clear_bit(i, &gmu_kmem_bitmap); } @@ -411,6 +412,20 @@ static int gmu_memory_probe(struct kgsl_device *device, if (ret) return ret; + /* Reserve a memdesc for ITCM. No actually memory allocated */ + md = allocate_gmu_kmem(gmu, GMU_ITCM, gmu_vma[GMU_ITCM].size, 0); + if (IS_ERR(md)) { + ret = PTR_ERR(md); + goto err_ret; + } + + /* Reserve a memdesc for DTCM. No actually memory allocated */ + md = allocate_gmu_kmem(gmu, GMU_DTCM, gmu_vma[GMU_DTCM].size, 0); + if (IS_ERR(md)) { + ret = PTR_ERR(md); + goto err_ret; + } + /* Allocates & maps memory for WB DUMMY PAGE */ /* Must be the first alloc */ md = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, @@ -421,7 +436,7 @@ static int gmu_memory_probe(struct kgsl_device *device, } /* Allocates & maps memory for DCACHE */ - md = allocate_gmu_kmem(gmu, GMU_CACHED_DATA, GMU_DCACHE_SIZE, + md = allocate_gmu_kmem(gmu, GMU_DCACHE, gmu_vma[GMU_DCACHE].size, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); if (IS_ERR(md)) { ret = PTR_ERR(md); @@ -429,11 +444,10 @@ static int gmu_memory_probe(struct kgsl_device *device, } /* Allocates & maps memory for ICACHE */ - gmu->icache_mem = allocate_gmu_kmem(gmu, GMU_CACHED_CODE, - GMU_ICACHE_SIZE, + md = allocate_gmu_kmem(gmu, GMU_ICACHE, gmu_vma[GMU_ICACHE].size, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(gmu->icache_mem)) { - ret = PTR_ERR(gmu->icache_mem); + if (IS_ERR(md)) { + ret = PTR_ERR(md); goto err_ret; } @@ -1166,6 +1180,103 @@ static int gmu_irq_probe(struct kgsl_device *device, struct gmu_device *gmu) return ret; } +struct mbox_message { + uint32_t len; + void *msg; +}; + +static void gmu_aop_send_acd_state(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct mbox_message msg; + char msg_buf[33]; + bool state = test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + int ret; + + if (!gmu->mailbox.client) + return; + + msg.len = scnprintf(msg_buf, sizeof(msg_buf), + "{class: gpu, res: acd, value: %d}", state); + msg.msg = msg_buf; + + ret = mbox_send_message(gmu->mailbox.channel, &msg); + if (ret < 0) + dev_err(&gmu->pdev->dev, + "AOP mbox send message failed: %d\n", ret); +} + +static void gmu_aop_mailbox_destroy(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct kgsl_mailbox *mailbox = &gmu->mailbox; + + if (!mailbox->client) + return; + + mbox_free_channel(mailbox->channel); + mailbox->channel = NULL; + + kfree(mailbox->client); + mailbox->client = NULL; + + clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); +} + +static int gmu_aop_mailbox_init(struct kgsl_device *device, + struct gmu_device *gmu) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_mailbox *mailbox = &gmu->mailbox; + + mailbox->client = kzalloc(sizeof(*mailbox->client), GFP_KERNEL); + if (!mailbox->client) + return -ENOMEM; + + mailbox->client->dev = &gmu->pdev->dev; + mailbox->client->tx_block = true; + mailbox->client->tx_tout = 1000; + mailbox->client->knows_txdone = false; + + mailbox->channel = mbox_request_channel(mailbox->client, 0); + if (IS_ERR(mailbox->channel)) { + kfree(mailbox->client); + mailbox->client = NULL; + return PTR_ERR(mailbox->channel); + } + + set_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + return 0; +} + +static int gmu_acd_set(struct kgsl_device *device, unsigned int val) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + if (!gmu->mailbox.client) + return -EINVAL; + + /* Don't do any unneeded work if ACD is already in the correct state */ + if (val == test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag)) + return 0; + + mutex_lock(&device->mutex); + + /* Power down the GPU before enabling or disabling ACD */ + kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (val) + set_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + else + clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + + mutex_unlock(&device->mutex); + return 0; +} + /* Do not access any GMU registers in GMU probe function */ static int gmu_probe(struct kgsl_device *device, struct device_node *node) { @@ -1240,6 +1351,7 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) int j = gmu->num_gpupwrlevels - 1 - i; gmu->gpu_freqs[i] = pwr->pwrlevels[j].gpu_freq; + gmu->acd_dvm_vals[i] = pwr->pwrlevels[j].acd_dvm_val; } /* Initializes GPU b/w levels configuration */ @@ -1271,6 +1383,13 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) else gmu->idle_level = GPU_HW_ACTIVE; + if (ADRENO_FEATURE(adreno_dev, ADRENO_ACD) && !noacd) { + ret = gmu_aop_mailbox_init(device, gmu); + if (ret) + dev_err(&gmu->pdev->dev, + "AOP mailbox init failed: %d\n", ret); + } + /* disable LM during boot time */ clear_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag); set_bit(GMU_ENABLED, &device->gmu_core.flags); @@ -1401,7 +1520,15 @@ static int gmu_suspend(struct kgsl_device *device) return -EINVAL; gmu_disable_clks(device); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) + regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_IDLE); + gmu_disable_gdsc(gmu); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) + regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); + dev_err(&gmu->pdev->dev, "Suspended GMU\n"); return 0; } @@ -1450,6 +1577,9 @@ static int gmu_start(struct kgsl_device *device) case KGSL_STATE_INIT: case KGSL_STATE_SUSPEND: WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + + gmu_aop_send_acd_state(device); + gmu_enable_gdsc(gmu); gmu_enable_clks(device); gmu_dev_ops->irq_enable(device); @@ -1477,6 +1607,9 @@ static int gmu_start(struct kgsl_device *device) case KGSL_STATE_SLUMBER: WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + + gmu_aop_send_acd_state(device); + gmu_enable_gdsc(gmu); gmu_enable_clks(device); gmu_dev_ops->irq_enable(device); @@ -1497,6 +1630,9 @@ static int gmu_start(struct kgsl_device *device) if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv) || test_bit(GMU_FAULT, &device->gmu_core.flags)) { gmu_suspend(device); + + gmu_aop_send_acd_state(device); + gmu_enable_gdsc(gmu); gmu_enable_clks(device); gmu_dev_ops->irq_enable(device); @@ -1517,6 +1653,8 @@ static int gmu_start(struct kgsl_device *device) /* GMU fast boot */ hfi_stop(gmu); + gmu_aop_send_acd_state(device); + ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) @@ -1602,6 +1740,8 @@ static void gmu_remove(struct kgsl_device *device) gmu_stop(device); + gmu_aop_mailbox_destroy(device); + while ((i < MAX_GMU_CLKS) && gmu->clks[i]) { gmu->clks[i] = NULL; i++; @@ -1629,6 +1769,11 @@ static void gmu_remove(struct kgsl_device *device) gmu->pcl = 0; } + if (gmu->fw_image) { + release_firmware(gmu->fw_image); + gmu->fw_image = NULL; + } + gmu_memory_close(gmu); for (i = 0; i < MAX_GMU_CLKS; i++) { @@ -1670,4 +1815,5 @@ struct gmu_core_ops gmu_ops = { .snapshot = gmu_snapshot, .regulator_isenabled = gmu_regulator_isenabled, .suspend = gmu_suspend, + .acd_set = gmu_acd_set, }; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 4b003a8a659e10686e27b3bc32b801736dc8e6c3..f6ca3d2c45d0391d868c5602f4571621520e46f0 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -13,7 +13,9 @@ #ifndef __KGSL_GMU_H #define __KGSL_GMU_H +#include #include "kgsl_gmu_core.h" +#include #include "kgsl_hfi.h" #define MAX_GMUFW_SIZE 0x2000 /* in bytes */ @@ -55,6 +57,14 @@ #define OOB_BOOT_OPTION 0 #define OOB_SLUMBER_OPTION 1 +/* Gmu FW block header format */ +struct gmu_block_header { + uint32_t addr; + uint32_t size; + uint32_t type; + uint32_t value; +}; + /* For GMU Logs*/ #define LOGMEM_SIZE SZ_4K @@ -62,10 +72,13 @@ extern struct gmu_dev_ops adreno_a6xx_gmudev; #define KGSL_GMU_DEVICE(_a) ((struct gmu_device *)((_a)->gmu_core.ptr)) enum gmu_mem_type { - GMU_CACHED_CODE = 0, - GMU_CACHED_DATA, + GMU_ITCM = 0, + GMU_ICACHE, + GMU_DTCM, + GMU_DCACHE, GMU_NONCACHED_KERNEL, - GMU_NONCACHED_USER + GMU_NONCACHED_USER, + GMU_MEM_TYPE_MAX, }; /** @@ -106,18 +119,22 @@ enum gmu_load_mode { INVALID_LOAD }; +struct kgsl_mailbox { + struct mbox_client *client; + struct mbox_chan *channel; +}; + /** * struct gmu_device - GMU device structure * @ver: GMU FW version, read from GMU * @reg_phys: GMU CSR physical address * @reg_len: GMU CSR range * @gmu_interrupt_num: GMU interrupt number - * @fw_image: descriptor of GMU memory that has GMU image in it + * @fw_image: GMU FW image * @hfi_mem: pointer to HFI shared memory * @bw_mem: pointer to BW data indirect buffer memory * @dump_mem: pointer to GMU debug dump memory * @gmu_log: gmu event log memory - * @icache_mem: gmu icache memory buffer * @hfi: HFI controller * @lm_config: GPU LM configuration data * @lm_dcvs_level: Minimal DCVS level that enable LM. LM disable in @@ -141,6 +158,8 @@ enum gmu_load_mode { * @ccl: CNOC BW scaling client * @idle_level: Minimal GPU idle power level * @fault_count: GMU fault count + * @acd_dvm_vals: Table of DVM values that correspond to frequency levels + * @mailbox: Messages to AOP for ACD enable/disable go through this */ struct gmu_device { unsigned int ver; @@ -148,12 +167,11 @@ struct gmu_device { unsigned long reg_phys; unsigned int reg_len; unsigned int gmu_interrupt_num; - struct gmu_memdesc *fw_image; + const struct firmware *fw_image; struct gmu_memdesc *hfi_mem; struct gmu_memdesc *bw_mem; struct gmu_memdesc *dump_mem; struct gmu_memdesc *gmu_log; - struct gmu_memdesc *icache_mem; struct kgsl_hfi hfi; unsigned int lm_config; unsigned int lm_dcvs_level; @@ -174,9 +192,10 @@ struct gmu_device { unsigned int ccl; unsigned int idle_level; unsigned int fault_count; + unsigned int acd_dvm_vals[MAX_GX_LEVELS]; + struct kgsl_mailbox mailbox; }; -bool is_cached_fw_size_valid(uint32_t size_in_bytes); -int allocate_gmu_image(struct gmu_device *gmu, unsigned int size); +struct gmu_memdesc *gmu_get_memdesc(unsigned int addr, unsigned int size); #endif /* __KGSL_GMU_H */ diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index e752c3231204d24d65cf8856b2f3609348bc1882..9421de861cb79124f645d5c5c1175f099e536e13 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -132,6 +132,16 @@ int gmu_core_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, return -EINVAL; } +int gmu_core_acd_set(struct kgsl_device *device, unsigned int val) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->acd_set) + return gmu_core_ops->acd_set(device, val); + + return -EINVAL; +} + bool gmu_core_regulator_isenabled(struct kgsl_device *device) { struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index b6a559d46fc4be045134297bceabe1669d2ab5b9..b2ecf2b1632ddb44bd1400ac40965eccbb1db3d7 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -127,6 +127,7 @@ struct gmu_core_ops { void (*snapshot)(struct kgsl_device *device); bool (*regulator_isenabled)(struct kgsl_device *device); int (*suspend)(struct kgsl_device *device); + int (*acd_set)(struct kgsl_device *device, unsigned int val); }; struct gmu_dev_ops { @@ -187,6 +188,7 @@ bool gmu_core_gpmu_isenabled(struct kgsl_device *device); bool gmu_core_isenabled(struct kgsl_device *device); int gmu_core_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, unsigned int bus_level); +int gmu_core_acd_set(struct kgsl_device *device, unsigned int val); bool gmu_core_regulator_isenabled(struct kgsl_device *device); bool gmu_core_is_register_offset(struct kgsl_device *device, unsigned int offsetwords); diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 6b2f77acc67e9082af7002f3292e3ba6236d60ff..b1516aefdf0c3c3c6f0914755a9050887df0556b 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -388,6 +388,7 @@ static int hfi_send_core_fw_start(struct gmu_device *gmu) static const char * const hfi_features[] = { [HFI_FEATURE_ECP] = "ECP", + [HFI_FEATURE_ACD] = "ACD", }; static const char *feature_to_string(uint32_t feature) @@ -474,11 +475,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu) for (i = 0; i < gmu->num_gpupwrlevels; i++) { cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i]; - /* - * Set ACD threshold to the maximum value as a default. - * At this level, ACD will never activate. - */ - cmd.gx_votes[i].acd = 0xFFFFFFFF; + cmd.gx_votes[i].acd = gmu->acd_dvm_vals[i]; /* Divide by 1000 to convert to kHz */ cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; } @@ -729,6 +726,10 @@ int hfi_start(struct kgsl_device *device, */ if (HFI_VER_MAJOR(&gmu->hfi) >= 2) { result = hfi_send_feature_ctrl(gmu, HFI_FEATURE_ECP, 0, 0); + if (test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag)) + result |= hfi_send_feature_ctrl(gmu, + HFI_FEATURE_ACD, 1, 0); + if (result) return result; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 1800d14c389db888796854479ee665203d89d213..8f700028351abc50d8299d661b237c9ed2109c1e 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -106,12 +106,14 @@ struct kgsl_pwr_constraint { * @bus_freq: Bus bandwidth vote index * @bus_min: Min bus index @gpu_freq * @bus_max: Max bus index @gpu_freq + * @acd_dvm_val: Register setting for ACD */ struct kgsl_pwrlevel { unsigned int gpu_freq; unsigned int bus_freq; unsigned int bus_min; unsigned int bus_max; + unsigned int acd_dvm_val; }; struct kgsl_regulator { diff --git a/drivers/hid/hid-plantronics.c b/drivers/hid/hid-plantronics.c index febb21ee190e99134ae995887ceeeb86721e1440..584b10d3fc3d84d026c56e4ae4b74fb7b2525d69 100644 --- a/drivers/hid/hid-plantronics.c +++ b/drivers/hid/hid-plantronics.c @@ -2,7 +2,7 @@ * Plantronics USB HID Driver * * Copyright (c) 2014 JD Cole - * Copyright (c) 2015 Terry Junge + * Copyright (c) 2015-2018 Terry Junge */ /* @@ -48,6 +48,10 @@ static int plantronics_input_mapping(struct hid_device *hdev, unsigned short mapped_key; unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev); + /* special case for PTT products */ + if (field->application == HID_GD_JOYSTICK) + goto defaulted; + /* handle volume up/down mapping */ /* non-standard types or multi-HID interfaces - plt_type is PID */ if (!(plt_type & HID_USAGE_PAGE)) { diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index d9282755638934331acf79f0fafe960b1122757a..136a34dc31b8e23fbea60fdda7968c81e65adfab 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1036,6 +1036,14 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_enable(&client->dev); device_enable_async_suspend(&client->dev); + /* Make sure there is something at this address */ + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", ret); + ret = -ENXIO; + goto err_pm; + } + ret = i2c_hid_fetch_hid_descriptor(ihid); if (ret < 0) goto err_pm; diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index 24796b026f55b2f24aed02ad2e04c1d31341123b..1a4c7419178909c4b33320a60e85d50366a87814 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -47,7 +47,8 @@ static void tmc_etr_sg_read_pos(loff_t *ppos, size_t bytes, bool noirq, size_t *len, char **bufpp) { - uint32_t rwp, i = 0; + uint32_t i = 0; + u64 rwp; uint32_t blk_num, sg_tbl_num, blk_num_loc, read_off; uint32_t *virt_pte, *virt_st_tbl; void *virt_blk; @@ -86,7 +87,7 @@ static void tmc_etr_sg_read_pos(loff_t *ppos, *bufpp = (char *)(virt_blk + read_off); if (noirq) { - rwp = readl_relaxed(tmcdrvdata->base + TMC_RWP); + rwp = tmc_read_rwp(tmcdrvdata); tmc_etr_sg_rwp_pos(tmcdrvdata, rwp); if (tmcdrvdata->sg_blk_num == blk_num && rwp >= (phys_pte + read_off)) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 0df879000532014a04043ffc15a764a6c60e1414..6aafdba979561b714c42403a8500de67603eb7f4 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -352,7 +352,7 @@ static void tmc_etr_sg_mem_reset(uint32_t *vaddr, uint32_t size) tmc_etr_sg_tbl_flush(vaddr, size); } -void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp) +void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, phys_addr_t rwp) { uint32_t i = 0, pte_n = 0, last_pte; uint32_t *virt_st_tbl, *virt_pte; @@ -447,7 +447,8 @@ void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) } axictl = (axictl & - ~(TMC_AXICTL_CACHE_CTL_B0 | TMC_AXICTL_CACHE_CTL_B1)) | + ~(TMC_AXICTL_CACHE_CTL_B0 | TMC_AXICTL_CACHE_CTL_B1 | + TMC_AXICTL_CACHE_CTL_B2 | TMC_AXICTL_CACHE_CTL_B3)) | TMC_AXICTL_CACHE_CTL_B0; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); tmc_write_dba(drvdata, drvdata->paddr); @@ -587,9 +588,10 @@ static void tmc_etr_free_mem(struct tmc_drvdata *drvdata) } } -static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) +static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; + dma_addr_t data_fifo_iova, desc_fifo_iova; get_qdss_bam_connection_info(&bamdata->dest, &bamdata->dest_pipe_idx, @@ -597,6 +599,28 @@ static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) &bamdata->desc_fifo, &bamdata->data_fifo, NULL); + + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + data_fifo_iova = dma_map_resource(drvdata->dev, + bamdata->data_fifo.phys_base, bamdata->data_fifo.size, + DMA_BIDIRECTIONAL, 0); + if (!data_fifo_iova) + return -ENOMEM; + dev_dbg(drvdata->dev, "%s:data p_addr:%pa,iova:%pad,size:%x\n", + __func__, &(bamdata->data_fifo.phys_base), + &data_fifo_iova, bamdata->data_fifo.size); + bamdata->data_fifo.iova = data_fifo_iova; + desc_fifo_iova = dma_map_resource(drvdata->dev, + bamdata->desc_fifo.phys_base, bamdata->desc_fifo.size, + DMA_BIDIRECTIONAL, 0); + if (!desc_fifo_iova) + return -ENOMEM; + dev_dbg(drvdata->dev, "%s:desc p_addr:%pa,iova:%pad,size:%x\n", + __func__, &(bamdata->desc_fifo.phys_base), + &desc_fifo_iova, bamdata->desc_fifo.size); + bamdata->desc_fifo.iova = desc_fifo_iova; + } + return 0; } static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) @@ -625,10 +649,17 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) axictl = (axictl & ~0x3) | 0x2; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); - writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + writel_relaxed((uint32_t)bamdata->data_fifo.iova, drvdata->base + TMC_DBALO); - writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) & 0xFF, - drvdata->base + TMC_DBAHI); + writel_relaxed((((uint64_t)bamdata->data_fifo.iova) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } else { + writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, + drvdata->base + TMC_DBALO); + writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } /* Set FOnFlIn for periodic flush */ writel_relaxed(0x133, drvdata->base + TMC_FFCR); writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); @@ -639,9 +670,29 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) drvdata->enable_to_bam = true; } +static int get_usb_bam_iova(struct device *dev, unsigned long usb_bam_handle, + unsigned long *iova) +{ + int ret = 0; + phys_addr_t p_addr; + u32 bam_size; + + ret = sps_get_bam_addr(usb_bam_handle, &p_addr, &bam_size); + if (ret) { + dev_err(dev, "sps_get_bam_addr failed at handle:%lx, err:%d\n", + usb_bam_handle, ret); + return ret; + } + *iova = dma_map_resource(dev, p_addr, bam_size, DMA_BIDIRECTIONAL, 0); + if (!(*iova)) + return -ENOMEM; + return 0; +} + static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; + unsigned long iova; int ret; if (bamdata->enable) @@ -673,6 +724,12 @@ static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) bamdata->connect.desc = bamdata->desc_fifo; bamdata->connect.data = bamdata->data_fifo; + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + ret = get_usb_bam_iova(drvdata->dev, bamdata->dest, &iova); + if (ret) + goto err1; + bamdata->connect.dest_iova = iova; + } ret = sps_connect(bamdata->pipe, &bamdata->connect); if (ret) goto err1; @@ -739,7 +796,9 @@ void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, mutex_lock(&drvdata->mem_lock); if (event == USB_QDSS_CONNECT) { - tmc_etr_fill_usb_bam_data(drvdata); + ret = tmc_etr_fill_usb_bam_data(drvdata); + if (ret) + dev_err(drvdata->dev, "ETR get usb bam data failed\n"); ret = tmc_etr_bam_enable(drvdata); if (ret) dev_err(drvdata->dev, "ETR BAM enable failed\n"); @@ -784,6 +843,12 @@ int tmc_etr_bam_init(struct amba_device *adev, bamdata->props.summing_threshold = 0x10; /* BAM event threshold */ bamdata->props.irq = 0; bamdata->props.num_pipes = TMC_ETR_BAM_NR_PIPES; + if (device_property_present(dev, "iommus") + && !device_property_present(dev, "qcom,smmu-s1-bypass")) { + pr_info("%s: setting SPS_BAM_SMMU_EN flag with (%s)\n", + __func__, dev_name(dev)); + bamdata->props.options |= SPS_BAM_SMMU_EN; + } return sps_register_bam_device(&bamdata->props, &bamdata->handle); } @@ -872,7 +937,6 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) tmc_etr_enable_hw(drvdata); drvdata->enable = true; - drvdata->sticky_enable = true; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index e9fe00d0438cc158a54b0f291f65f5713586784b..20dd35e71830379d914ee19d2554bdbd409d5b75 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -141,7 +141,6 @@ static void __tmc_reg_dump(struct tmc_drvdata *drvdata) void tmc_enable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = true; - drvdata->sticky_enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); if (drvdata->force_reg_dump) __tmc_reg_dump(drvdata); @@ -157,7 +156,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) { int ret = 0; - if (!drvdata->sticky_enable) + if (!drvdata->enable) return -EPERM; switch (drvdata->config_type) { @@ -544,10 +543,17 @@ static ssize_t mem_type_store(struct device *dev, } if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_CONTIG])) drvdata->mem_type = TMC_ETR_MEM_TYPE_CONTIG; - else if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_SG])) + else if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_SG])) { + if (device_property_present(dev->parent, "iommus") && + !device_property_present(dev->parent, "qcom,smmu-s1-bypass")) { + mutex_unlock(&drvdata->mem_lock); + pr_err("SMMU is enabled. Sg mode is not supported\n"); + return -EINVAL; + } drvdata->mem_type = TMC_ETR_MEM_TYPE_SG; - else + } else { size = -EINVAL; + } mutex_unlock(&drvdata->mem_lock); @@ -606,7 +612,7 @@ static int tmc_iommu_init(struct tmc_drvdata *drvdata) return 0; drvdata->iommu_mapping = arm_iommu_create_mapping(&amba_bustype, - 0, (SZ_1G * 4ULL)); + 0, (SZ_1G * 2ULL)); if (IS_ERR(drvdata->iommu_mapping)) { dev_err(drvdata->dev, "Create mapping failed, err = %d\n", ret); ret = PTR_ERR(drvdata->iommu_mapping); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index ffe2fde6d193121d907f72d164be34695009e529..7fa37cb663bfaca034acdb772c50718ba3f422a6 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -86,6 +86,8 @@ #define TMC_AXICTL_PROT_CTL_B1 BIT(1) #define TMC_AXICTL_CACHE_CTL_B0 BIT(2) #define TMC_AXICTL_CACHE_CTL_B1 BIT(3) +#define TMC_AXICTL_CACHE_CTL_B2 BIT(4) +#define TMC_AXICTL_CACHE_CTL_B3 BIT(5) #define TMC_AXICTL_SCT_GAT_MODE BIT(7) #define TMC_AXICTL_WR_BURST_16 0xF00 /* Write-back Read and Write-allocate */ @@ -271,7 +273,7 @@ int tmc_etr_bam_init(struct amba_device *adev, extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; -extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp); +extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, phys_addr_t rwp); extern const struct coresight_ops tmc_etr_cs_ops; diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index ef79c9efd8409adc432af692922a154c1cc81f8e..7f4d263bf7ea85b3aba4c420b6a7ea8ea4d5135c 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -206,8 +206,10 @@ static int coresight_enable_link(struct coresight_device *csdev, if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { ret = link_ops(csdev)->enable(csdev, inport, outport); - if (ret) + if (ret) { + atomic_dec(&csdev->refcnt[refport]); return ret; + } } } @@ -296,42 +298,66 @@ static bool coresight_disable_source(struct coresight_device *csdev) return !csdev->enable; } -void coresight_disable_path(struct list_head *path) +static void coresigh_disable_list_node(struct list_head *path, + struct coresight_node *nd) { u32 type; - struct coresight_node *nd; struct coresight_device *csdev, *parent, *child; - list_for_each_entry(nd, path, link) { - csdev = nd->csdev; - type = csdev->type; + csdev = nd->csdev; + type = csdev->type; - /* - * ETF devices are tricky... They can be a link or a sink, - * depending on how they are configured. If an ETF has been - * "activated" it will be configured as a sink, otherwise - * go ahead with the link configuration. - */ - if (type == CORESIGHT_DEV_TYPE_LINKSINK) - type = (csdev == coresight_get_sink(path)) ? - CORESIGHT_DEV_TYPE_SINK : - CORESIGHT_DEV_TYPE_LINK; + /* + * ETF devices are tricky... They can be a link or a sink, + * depending on how they are configured. If an ETF has been + * "activated" it will be configured as a sink, otherwise + * go ahead with the link configuration. + */ + if (type == CORESIGHT_DEV_TYPE_LINKSINK) + type = (csdev == coresight_get_sink(path)) ? + CORESIGHT_DEV_TYPE_SINK : + CORESIGHT_DEV_TYPE_LINK; + + switch (type) { + case CORESIGHT_DEV_TYPE_SINK: + coresight_disable_sink(csdev); + break; + case CORESIGHT_DEV_TYPE_SOURCE: + /* sources are disabled from either sysFS or Perf */ + break; + case CORESIGHT_DEV_TYPE_LINK: + parent = list_prev_entry(nd, link)->csdev; + child = list_next_entry(nd, link)->csdev; + coresight_disable_link(csdev, parent, child); + break; + default: + break; + } +} - switch (type) { - case CORESIGHT_DEV_TYPE_SINK: - coresight_disable_sink(csdev); - break; - case CORESIGHT_DEV_TYPE_SOURCE: - /* sources are disabled from either sysFS or Perf */ - break; - case CORESIGHT_DEV_TYPE_LINK: - parent = list_prev_entry(nd, link)->csdev; - child = list_next_entry(nd, link)->csdev; - coresight_disable_link(csdev, parent, child); - break; - default: - break; - } +/** + * During enabling path, if it is failed, then only those enabled + * devices need to be disabled. This function is to disable devices + * which is enabled before the failed device. + * + * @path the head of the list + * @nd the failed device node + */ +static void coresight_disable_previous_devs(struct list_head *path, + struct coresight_node *nd) +{ + + list_for_each_entry_continue(nd, path, link) { + coresigh_disable_list_node(path, nd); + } +} + +void coresight_disable_path(struct list_head *path) +{ + struct coresight_node *nd; + + list_for_each_entry(nd, path, link) { + coresigh_disable_list_node(path, nd); } } @@ -382,7 +408,7 @@ int coresight_enable_path(struct list_head *path, u32 mode) out: return ret; err: - coresight_disable_path(path); + coresight_disable_previous_devs(path, nd); goto out; } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f96830ffd9f1c1456965810fad723ab365a7f263..75c6b98585ba2e545ac0b3239e237796b68881b7 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -376,6 +376,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx, goto err_desc; } + reinit_completion(&dma->cmd_complete); txdesc->callback = i2c_imx_dma_callback; txdesc->callback_param = i2c_imx; if (dma_submit_error(dmaengine_submit(txdesc))) { @@ -619,7 +620,6 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, * The first byte must be transmitted by the CPU. */ imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); - reinit_completion(&i2c_imx->dma->cmd_complete); time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); @@ -678,7 +678,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, if (result) return result; - reinit_completion(&i2c_imx->dma->cmd_complete); time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db708ea669d168c4fcac68cfb05518fe728fbae8..ef358b234c9ce41de5849ac2c5b913f7bfc54827 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -77,6 +77,10 @@ #define I2C_AUTO_SUSPEND_DELAY 250 +#define I2C_TIMEOUT_SAFETY_COEFFICIENT 10 + +#define I2C_TIMEOUT_MIN_USEC 500000 + enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, @@ -89,6 +93,7 @@ struct geni_i2c_dev { unsigned int tx_wm; int irq; int err; + u32 xfer_timeout; struct i2c_adapter adap; struct completion xfer; struct i2c_msg *cur; @@ -192,12 +197,26 @@ static inline void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c, int dfs) mb(); } +static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) +{ + + struct geni_i2c_clk_fld *clk_itr = geni_i2c_clk_map + gi2c->clk_fld_idx; + size_t bit_cnt = gi2c->cur->len*9; + size_t bit_usec = (bit_cnt*USEC_PER_SEC)/clk_itr->clk_freq_out; + size_t xfer_max_usec = (bit_usec*I2C_TIMEOUT_SAFETY_COEFFICIENT) + + I2C_TIMEOUT_MIN_USEC; + + gi2c->xfer_timeout = usecs_to_jiffies(xfer_max_usec); + +} + static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { if (gi2c->cur) GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len, - gi2c->cur->addr, gi2c->cur->flags); + "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", + gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, + gi2c->xfer_timeout); if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", @@ -476,6 +495,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], struct device *tx_dev = gi2c->wrapper_dev; gi2c->cur = &msgs[i]; + qcom_geni_i2c_calc_timeout(gi2c); if (!gi2c->cfg_sent) { segs++; sg_init_table(gi2c->tx_sg, segs); @@ -506,8 +526,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (msgs[i].flags & I2C_M_RD) { sg_init_table(&gi2c->rx_sg, 1); - geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, msgs[i].buf, - msgs[i].len, DMA_FROM_DEVICE); + ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, + msgs[i].buf, msgs[i].len, + DMA_FROM_DEVICE); + if (ret) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "geni_se_iommu_map_buf for rx failed :%d\n", + ret); + goto geni_i2c_gsi_xfer_out; + + } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); gi2c->rx_t.dword[1] = @@ -528,7 +556,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "prep_slave_sg for rx failed\n"); gi2c->err = -ENOMEM; - goto geni_i2c_gsi_xfer_out; + goto geni_i2c_err_prep_sg; } gi2c->rx_desc->callback = gi2c_gsi_rx_cb; gi2c->rx_desc->callback_param = &gi2c->rx_cb; @@ -537,8 +565,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { - geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, msgs[i].buf, - msgs[i].len, DMA_TO_DEVICE); + ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, + msgs[i].buf, msgs[i].len, + DMA_TO_DEVICE); + if (ret) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "geni_se_iommu_map_buf for tx failed :%d\n", + ret); + goto geni_i2c_gsi_xfer_out; + + } gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = @@ -560,7 +596,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "prep_slave_sg for tx failed\n"); gi2c->err = -ENOMEM; - goto geni_i2c_gsi_xfer_out; + goto geni_i2c_err_prep_sg; } gi2c->tx_desc->callback = gi2c_gsi_tx_cb; gi2c->tx_desc->callback_param = &gi2c->tx_cb; @@ -569,7 +605,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], tx_cookie = dmaengine_submit(gi2c->tx_desc); dma_async_issue_pending(gi2c->tx_c); - timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); + timeout = wait_for_completion_timeout(&gi2c->xfer, + gi2c->xfer_timeout); + + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "GSI Txn timed out: %u len: %d\n", + gi2c->xfer_timeout, gi2c->cur->len); + gi2c->err = -ETIMEDOUT; + } +geni_i2c_err_prep_sg: if (msgs[i].flags & I2C_M_RD) geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, msgs[i].len, DMA_FROM_DEVICE); @@ -577,17 +622,13 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], geni_se_iommu_unmap_buf(tx_dev, &gi2c->tx_ph, msgs[i].len, DMA_TO_DEVICE); - if (!timeout) { - GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI Txn timed out\n"); - gi2c->err = -ETIMEDOUT; - } if (gi2c->err) { dmaengine_terminate_all(gi2c->tx_c); gi2c->cfg_sent = 0; goto geni_i2c_gsi_xfer_out; } } + geni_i2c_gsi_xfer_out: if (!ret && gi2c->err) ret = gi2c->err; @@ -635,6 +676,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT); gi2c->cur = &msgs[i]; + qcom_geni_i2c_calc_timeout(gi2c); mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); if (ret) { @@ -684,7 +726,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } /* Ensure FIFO write go through before waiting for Done evet */ mb(); - timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); + timeout = wait_for_completion_timeout(&gi2c->xfer, + gi2c->xfer_timeout); if (!timeout) { geni_i2c_err(gi2c, GENI_TIMEOUT); gi2c->cur = NULL; @@ -845,6 +888,15 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "could not set DMA mask\n"); + return ret; + } + } + gi2c->adap.algo = &geni_i2c_algo; init_completion(&gi2c->xfer); platform_set_drvdata(pdev, gi2c); diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e46581b84bdb03eeb07ddaa8d83cec1aa76341..6f2fe63e8f5aa80ade4daa76bdfe0b48516b2256 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -808,8 +808,11 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - if (client->dev.of_node) + if (client->dev.of_node) { of_node_clear_flag(client->dev.of_node, OF_POPULATED); + of_node_put(client->dev.of_node); + } + if (ACPI_COMPANION(&client->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_unregister(&client->dev); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index f0b06b14e782b5b926b5ba7876d827551ce4cfa9..16249b0953fff61e14f0c786decb4de6927a5e74 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1061,7 +1061,7 @@ static const struct idle_cpu idle_cpu_dnv = { }; #define ICPU(model, cpu) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu } + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&cpu } static const struct x86_cpu_id intel_idle_ids[] __initconst = { ICPU(INTEL_FAM6_NEHALEM_EP, idle_cpu_nehalem), @@ -1125,6 +1125,11 @@ static int __init intel_idle_probe(void) return -ENODEV; } + if (!boot_cpu_has(X86_FEATURE_MWAIT)) { + pr_debug("Please enable MWAIT in BIOS SETUP\n"); + return -ENODEV; + } + if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) return -ENODEV; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index d8efdc191c27f0cda1a5458d523b402811c87805..55252079faf65812ca5663a98be193543636150f 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1558,7 +1558,8 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, mad_reg_req->oui, 3)) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(!*method); + if (!*method) + goto error3; goto check_in_use; } } @@ -1568,10 +1569,12 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, vclass]->oui[i])) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(*method); /* Allocate method table for this OUI */ - if ((ret = allocate_method_table(method))) - goto error3; + if (!*method) { + ret = allocate_method_table(method); + if (ret) + goto error3; + } memcpy((*vendor_table)->vendor_class[vclass]->oui[i], mad_reg_req->oui, 3); goto check_in_use; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index e47baf0950e3dbe2039b5e0cf9d79e585839af53..a22b992cde38c2bdf586bcea56b2edb351b8bf89 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -218,7 +218,7 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) return NULL; mutex_lock(&mut); - mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); + mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL); mutex_unlock(&mut); if (mc->id < 0) goto error; @@ -1404,6 +1404,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, goto err3; } + mutex_lock(&mut); + idr_replace(&multicast_idr, mc, mc->id); + mutex_unlock(&mut); + mutex_unlock(&file->mut); ucma_put_ctx(ctx); return 0; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 186dce6bba8f3a212ccd87acb4b2c0f43ed37e4b..f836ed1dd300eb53a1e025bd29e293685482bea4 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1981,15 +1981,64 @@ static int modify_qp(struct ib_uverbs_file *file, goto release_qp; } - if ((cmd->base.attr_mask & IB_QP_AV) && - !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { - ret = -EINVAL; - goto release_qp; + if ((cmd->base.attr_mask & IB_QP_AV)) { + if (!rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { + ret = -EINVAL; + goto release_qp; + } + + if (cmd->base.attr_mask & IB_QP_STATE && + cmd->base.qp_state == IB_QPS_RTR) { + /* We are in INIT->RTR TRANSITION (if we are not, + * this transition will be rejected in subsequent checks). + * In the INIT->RTR transition, we cannot have IB_QP_PORT set, + * but the IB_QP_STATE flag is required. + * + * Since kernel 3.14 (commit dbf727de7440), the uverbs driver, + * when IB_QP_AV is set, has required inclusion of a valid + * port number in the primary AV. (AVs are created and handled + * differently for infiniband and ethernet (RoCE) ports). + * + * Check the port number included in the primary AV against + * the port number in the qp struct, which was set (and saved) + * in the RST->INIT transition. + */ + if (cmd->base.dest.port_num != qp->real_qp->port) { + ret = -EINVAL; + goto release_qp; + } + } else { + /* We are in SQD->SQD. (If we are not, this transition will + * be rejected later in the verbs layer checks). + * Check for both IB_QP_PORT and IB_QP_AV, these can be set + * together in the SQD->SQD transition. + * + * If only IP_QP_AV was set, add in IB_QP_PORT as well (the + * verbs layer driver does not track primary port changes + * resulting from path migration. Thus, in SQD, if the primary + * AV is modified, the primary port should also be modified). + * + * Note that in this transition, the IB_QP_STATE flag + * is not allowed. + */ + if (((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT)) + == (IB_QP_AV | IB_QP_PORT)) && + cmd->base.port_num != cmd->base.dest.port_num) { + ret = -EINVAL; + goto release_qp; + } + if ((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT)) + == IB_QP_AV) { + cmd->base.attr_mask |= IB_QP_PORT; + cmd->base.port_num = cmd->base.dest.port_num; + } + } } if ((cmd->base.attr_mask & IB_QP_ALT_PATH) && (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) || - !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) { + !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num) || + cmd->base.alt_port_num != cmd->base.alt_dest.port_num)) { ret = -EINVAL; goto release_qp; } @@ -3376,6 +3425,11 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, goto err_uobj; } + if (qp->qp_type != IB_QPT_UD && qp->qp_type != IB_QPT_RAW_PACKET) { + err = -EINVAL; + goto err_put; + } + flow_attr = kzalloc(sizeof(*flow_attr) + cmd.flow_attr.num_of_specs * sizeof(union ib_flow_spec), GFP_KERNEL); if (!flow_attr) { diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 9032f77cc38d259e08f8ccaff34bd7808d7ff785..feb80dbb59487124778ced1734a53bda1ee448cb 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2115,10 +2115,16 @@ static void __ib_drain_sq(struct ib_qp *qp) struct ib_cq *cq = qp->send_cq; struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; struct ib_drain_cqe sdrain; - struct ib_send_wr swr = {}, *bad_swr; + struct ib_send_wr *bad_swr; + struct ib_rdma_wr swr = { + .wr = { + .next = NULL, + { .wr_cqe = &sdrain.cqe, }, + .opcode = IB_WR_RDMA_WRITE, + }, + }; int ret; - swr.wr_cqe = &sdrain.cqe; sdrain.cqe.done = ib_drain_qp_done; init_completion(&sdrain.done); @@ -2128,7 +2134,7 @@ static void __ib_drain_sq(struct ib_qp *qp) return; } - ret = ib_post_send(qp, &swr, &bad_swr); + ret = ib_post_send(qp, &swr.wr, &bad_swr); if (ret) { WARN_ONCE(ret, "failed to drain send queue: %d\n", ret); return; diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c index f661b387e916ccb09e83cd29fc438ff9ac7756ec..8ab2c40b13b271fba24de26b997c4d3839098dc2 100644 --- a/drivers/infiniband/hw/hfi1/debugfs.c +++ b/drivers/infiniband/hw/hfi1/debugfs.c @@ -71,13 +71,13 @@ static ssize_t hfi1_seq_read( loff_t *ppos) { struct dentry *d = file->f_path.dentry; - int srcu_idx; ssize_t r; - r = debugfs_use_file_start(d, &srcu_idx); - if (likely(!r)) - r = seq_read(file, buf, size, ppos); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); + if (unlikely(r)) + return r; + r = seq_read(file, buf, size, ppos); + debugfs_file_put(d); return r; } @@ -87,13 +87,13 @@ static loff_t hfi1_seq_lseek( int whence) { struct dentry *d = file->f_path.dentry; - int srcu_idx; loff_t r; - r = debugfs_use_file_start(d, &srcu_idx); - if (likely(!r)) - r = seq_lseek(file, offset, whence); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); + if (unlikely(r)) + return r; + r = seq_lseek(file, offset, whence); + debugfs_file_put(d); return r; } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 7b1d7e58671ed5674ec49a13d2e050e3c3116b24..2e7982042fe59e94efbb8870ed2bc414a3748374 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -787,13 +787,17 @@ static int srpt_post_recv(struct srpt_device *sdev, */ static int srpt_zerolength_write(struct srpt_rdma_ch *ch) { - struct ib_send_wr wr, *bad_wr; + struct ib_send_wr *bad_wr; + struct ib_rdma_wr wr = { + .wr = { + .next = NULL, + { .wr_cqe = &ch->zw_cqe, }, + .opcode = IB_WR_RDMA_WRITE, + .send_flags = IB_SEND_SIGNALED, + } + }; - memset(&wr, 0, sizeof(wr)); - wr.opcode = IB_WR_RDMA_WRITE; - wr.wr_cqe = &ch->zw_cqe; - wr.send_flags = IB_SEND_SIGNALED; - return ib_post_send(ch->qp, &wr, &bad_wr); + return ib_post_send(ch->qp, &wr.wr, &bad_wr); } static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc) diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index 310eb4162af045ed7b16b467272396be7f0ab1e7..f60e835af89cc4d797a99f2b524a69d3b6220a20 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -175,6 +175,7 @@ struct qti_hap_effect { u8 *pattern; int pattern_length; u16 play_rate_us; + u16 vmax_mv; u8 wf_repeat_n; u8 wf_s_repeat_n; u8 brake[HAP_BRAKE_PATTERN_MAX]; @@ -527,7 +528,6 @@ static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake) { u8 addr, mask, val; int i, rc; - bool en = true; addr = REG_HAP_BRAKE; for (val = 0, i = 0; i < HAP_BRAKE_PATTERN_MAX; i++) @@ -539,14 +539,12 @@ static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake) dev_err(chip->dev, "write brake pattern failed, rc=%d\n", rc); return rc; } - - if (val == 0) - en = false; - - /* Set BRAKE_EN only if brake pattern is non-zero */ + /* + * Set BRAKE_EN regardless of the brake pattern, this helps to stop + * playing immediately once the valid values in WF_Sx are played. + */ addr = REG_HAP_EN_CTL2; - mask = HAP_BRAKE_EN_BIT; - val = en; + val = mask = HAP_BRAKE_EN_BIT; rc = qti_haptics_masked_write(chip, addr, mask, val); if (rc < 0) dev_err(chip->dev, "set EN_CTL2 failed, rc=%d\n", rc); @@ -579,6 +577,9 @@ static int qti_haptics_load_constant_waveform(struct qti_hap_chip *chip) if (rc < 0) return rc; + rc = qti_haptics_config_play_rate_us(chip, config->play_rate_us); + if (rc < 0) + return rc; /* * Using VMAX waveform source if playing length is >= 20ms, * otherwise using buffer waveform source and calculate the @@ -696,7 +697,6 @@ static irqreturn_t qti_haptics_play_irq_handler(int irq, void *data) dev_dbg(chip->dev, "play_irq triggered\n"); if (play->playing_pos == effect->pattern_length) { dev_dbg(chip->dev, "waveform playing done\n"); - qti_haptics_play(chip, false); if (chip->play_irq_en) { disable_irq_nosync(chip->play_irq); chip->play_irq_en = false; @@ -830,10 +830,6 @@ static int qti_haptics_upload_effect(struct input_dev *dev, goto disable_vdd; } - level = effect->u.periodic.magnitude; - tmp = level * config->vmax_mv; - play->vmax_mv = tmp / 0x7fff; - if (copy_from_user(data, effect->u.periodic.custom_data, sizeof(s16) * CUSTOM_DATA_LEN)) { rc = -EFAULT; @@ -852,6 +848,10 @@ static int qti_haptics_upload_effect(struct input_dev *dev, goto disable_vdd; } + level = effect->u.periodic.magnitude; + tmp = level * chip->predefined[i].vmax_mv; + play->vmax_mv = tmp / 0x7fff; + dev_dbg(chip->dev, "upload effect %d, vmax_mv=%d\n", chip->predefined[i].id, play->vmax_mv); rc = qti_haptics_load_predefined_effect(chip, i); @@ -918,6 +918,10 @@ static int qti_haptics_playback(struct input_dev *dev, int effect_id, int val) enable_irq(chip->play_irq); chip->play_irq_en = true; } + /* Toggle PLAY when playing pattern */ + rc = qti_haptics_play(chip, false); + if (rc < 0) + return rc; } else { if (chip->play_irq_en) { disable_irq_nosync(chip->play_irq); @@ -966,6 +970,22 @@ static int qti_haptics_erase(struct input_dev *dev, int effect_id) return rc; } +static void qti_haptics_set_gain(struct input_dev *dev, u16 gain) +{ + struct qti_hap_chip *chip = input_get_drvdata(dev); + struct qti_hap_config *config = &chip->config; + struct qti_hap_play_info *play = &chip->play; + + if (gain == 0) + return; + + if (gain > 0x7fff) + gain = 0x7fff; + + play->vmax_mv = ((u32)(gain * config->vmax_mv)) / 0x7fff; + qti_haptics_config_vmax(chip, play->vmax_mv); +} + static int qti_haptics_hw_init(struct qti_hap_chip *chip) { struct qti_hap_config *config = &chip->config; @@ -1092,7 +1112,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) struct device_node *child_node; struct qti_hap_effect *effect; const char *str; - int rc = 0, tmp, i = 0, j; + int rc = 0, tmp, i = 0, j, m; u8 val; rc = of_property_read_u32(node, "reg", &tmp); @@ -1234,6 +1254,15 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) return rc; } + effect->vmax_mv = config->vmax_mv; + rc = of_property_read_u32(child_node, "qcom,wf-vmax-mv", &tmp); + if (rc < 0) + dev_dbg(chip->dev, "Read qcom,wf-vmax-mv failed, rc=%d\n", + rc); + else + effect->vmax_mv = (tmp > HAP_VMAX_MV_MAX) ? + HAP_VMAX_MV_MAX : tmp; + rc = of_property_count_elems_of_size(child_node, "qcom,wf-pattern", sizeof(u8)); if (rc < 0) { @@ -1301,7 +1330,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) effect->wf_s_repeat_n = j; } - effect->lra_auto_res_disable = of_property_read_bool(node, + effect->lra_auto_res_disable = of_property_read_bool(child_node, "qcom,lra-auto-resonance-disable"); tmp = of_property_count_elems_of_size(child_node, @@ -1337,6 +1366,28 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) effect->brake_en = (val != 0); } + for (j = 0; j < i; j++) { + dev_dbg(chip->dev, "effect: %d\n", chip->predefined[j].id); + dev_dbg(chip->dev, " vmax: %d mv\n", + chip->predefined[j].vmax_mv); + dev_dbg(chip->dev, " play_rate: %d us\n", + chip->predefined[j].play_rate_us); + for (m = 0; m < chip->predefined[j].pattern_length; m++) + dev_dbg(chip->dev, " pattern[%d]: 0x%x\n", + m, chip->predefined[j].pattern[m]); + for (m = 0; m < chip->predefined[j].brake_pattern_length; m++) + dev_dbg(chip->dev, " brake_pattern[%d]: 0x%x\n", + m, chip->predefined[j].brake[m]); + dev_dbg(chip->dev, " brake_en: %d\n", + chip->predefined[j].brake_en); + dev_dbg(chip->dev, " wf_repeat_n: %d\n", + chip->predefined[j].wf_repeat_n); + dev_dbg(chip->dev, " wf_s_repeat_n: %d\n", + chip->predefined[j].wf_s_repeat_n); + dev_dbg(chip->dev, " lra_auto_res_disable: %d\n", + chip->predefined[j].lra_auto_res_disable); + } + return 0; } @@ -1404,6 +1455,7 @@ static int qti_haptics_probe(struct platform_device *pdev) chip->input_dev = input_dev; input_set_capability(input_dev, EV_FF, FF_CONSTANT); + input_set_capability(input_dev, EV_FF, FF_GAIN); if (chip->effects_count != 0) { input_set_capability(input_dev, EV_FF, FF_PERIODIC); input_set_capability(input_dev, EV_FF, FF_CUSTOM); @@ -1424,6 +1476,7 @@ static int qti_haptics_probe(struct platform_device *pdev) ff->upload = qti_haptics_upload_effect; ff->playback = qti_haptics_playback; ff->erase = qti_haptics_erase; + ff->set_gain = qti_haptics_set_gain; rc = input_register_device(input_dev); if (rc < 0) { diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 7b5fa501bbcf6651886cb16a2bcdbede026f382e..696e540304fd91231126557892f5222261ee0db2 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1262,6 +1262,8 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0611", 0 }, { "ELAN0612", 0 }, { "ELAN0618", 0 }, + { "ELAN061D", 0 }, + { "ELAN0622", 0 }, { "ELAN1000", 0 }, { } }; diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index b353d494ad404888bd2884527fe771937cb1416f..136f6e7bf797767256e66c1c083cb80c55cd7a1b 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -527,6 +527,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), }, }, + { + /* Lenovo LaVie Z */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), + }, + }, { } }; diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index b04e1c77eb5775af69afb37561d4e61e3f7dca95..fbc7fdbaf3f023f7b430bc782a09f9453b4192df 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -106,4 +106,4 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_ST) += st/ -obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET)» += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index 43ea1829c4afe96fde0ab7189ad1f27d67508239..980ceeb685bb035ee804196eb04e8196d4dc1150 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -986,7 +986,7 @@ static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, int ts_path, || (HX_ESD_RESET_ACTIVATE) #endif ) { - if (!g_core_fp.fp_read_event_stack(buf, 128)) { + if (!g_core_fp.fp_read_event_stack(buf, HX_REPORT_SZ)) { E("%s: can't read data from chip!\n", __func__); ts_status = HX_TS_GET_DATA_FAIL; goto END_FUNCTION; @@ -1013,7 +1013,7 @@ static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, int ts_path, break; #endif case HX_REPORT_COORD_RAWDATA: - if (!g_core_fp.fp_read_event_stack(buf, 128)) { + if (!g_core_fp.fp_read_event_stack(buf, HX_REPORT_SZ)) { E("%s: can't read data from chip!\n", __func__); ts_status = HX_TS_GET_DATA_FAIL; goto END_FUNCTION; @@ -1750,7 +1750,7 @@ int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status) static int himax_ts_operation(struct himax_ts_data *ts, int ts_path, int ts_status) { uint8_t hw_reset_check[2]; - uint8_t buf[128]; + uint8_t buf[HX_REPORT_SZ]; memset(buf, 0x00, sizeof(buf)); memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); @@ -1890,23 +1890,23 @@ static void himax_update_register(struct work_struct *work) #endif #ifdef CONFIG_DRM -static void himax_fb_register(struct work_struct *work) +int himax_fb_register(struct himax_ts_data *ts) { int ret = 0; - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work_att.work); I(" %s in\n", __func__); - ts->fb_notif.notifier_call = fb_notifier_callback; + ts->fb_notif.notifier_call = drm_notifier_callback; ret = msm_drm_register_client(&ts->fb_notif); if (ret) E(" Unable to register fb_notifier: %d\n", ret); + + return ret; } #elif defined CONFIG_FB -static void himax_fb_register(struct work_struct *work) +int himax_fb_register(struct himax_ts_data *ts) { int ret = 0; - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work_att.work); I(" %s in\n", __func__); ts->fb_notif.notifier_call = fb_notifier_callback; @@ -1914,6 +1914,8 @@ static void himax_fb_register(struct work_struct *work) if (ret) E(" Unable to register fb_notifier: %d\n", ret); + + return ret; } #endif @@ -1957,6 +1959,7 @@ int himax_chip_common_init(void) if (himax_parse_dt(ts, pdata) < 0) { I(" pdata is NULL for DT\n"); + err = -ECANCELED; goto err_alloc_dt_pdata_failed; } @@ -1971,6 +1974,7 @@ int himax_chip_common_init(void) if (ret < 0) { E("%s: power on failed\n", __func__); + err = ret; goto err_power_failed; } } @@ -1982,10 +1986,12 @@ int himax_chip_common_init(void) g_core_fp.fp_chip_init(); } else { E("%s: chip detect failed!\n", __func__); + err = -ECANCELED; goto error_ic_detect_failed; } } else { E("%s: function point is NULL!\n", __func__); + err = -ECANCELED; goto error_ic_detect_failed; } @@ -2026,6 +2032,7 @@ int himax_chip_common_init(void) /* Himax Power On and Load Config */ if (himax_loadSensorConfig(pdata)) { E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + err = -ECANCELED; goto err_detect_failed; } @@ -2067,23 +2074,10 @@ int himax_chip_common_init(void) if (ret) { E("%s: Unable to register %s input device\n", __func__, ts->input_dev->name); + err = ret; goto err_input_register_device_failed; } -#if defined(CONFIG_DRM) || defined(CONFIG_FB) - - ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_request"); - - if (!ts->himax_att_wq) { - E(" allocate syn_att_wq failed\n"); - err = -ENOMEM; - goto err_get_intr_bit_failed; - } - - INIT_DELAYED_WORK(&ts->work_att, himax_fb_register); - queue_delayed_work(ts->himax_att_wq, &ts->work_att, msecs_to_jiffies(15000)); -#endif - #ifdef HX_SMART_WAKEUP ts->SMWP_enable = 0; wakeup_source_init(&ts->ts_SMWP_wake_src, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); @@ -2110,6 +2104,7 @@ int himax_chip_common_init(void) if (himax_common_proc_init()) { E(" %s: himax_common proc_init failed!\n", __func__); + err = -ECANCELED; goto err_creat_proc_file_failed; } @@ -2148,11 +2143,6 @@ remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); #ifdef HX_SMART_WAKEUP wakeup_source_trash(&ts->ts_SMWP_wake_src); #endif -#if defined(CONFIG_FB) || defined(CONFIG_DRM) -err_get_intr_bit_failed: - cancel_delayed_work_sync(&ts->work_att); - destroy_workqueue(ts->himax_att_wq); -#endif err_input_register_device_failed: input_free_device(ts->input_dev); err_detect_failed: @@ -2217,13 +2207,9 @@ void himax_chip_common_deinit(void) #ifdef CONFIG_DRM if (msm_drm_unregister_client(&ts->fb_notif)) E("Error occurred while unregistering fb_notifier.\n"); - cancel_delayed_work_sync(&ts->work_att); - destroy_workqueue(ts->himax_att_wq); #elif defined(CONFIG_FB) if (fb_unregister_client(&ts->fb_notif)) E("Error occurred while unregistering fb_notifier.\n"); - cancel_delayed_work_sync(&ts->work_att); - destroy_workqueue(ts->himax_att_wq); #endif input_free_device(ts->input_dev); #ifdef HX_ZERO_FLASH @@ -2244,6 +2230,7 @@ void himax_chip_common_deinit(void) kfree(hx_touch_data); kfree(ic_data); kfree(ts->pdata); + kfree(ts->report_i2c_data); kfree(ts); probe_fail_flag = 0; } diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h index e190490d469c650b00b84414201e0c3ae8778ae8..45bd140f94a94e8175b4314402e9d1fe5144b9fa 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -142,6 +142,7 @@ #define HX_FINGER_ON 1 #define HX_FINGER_LEAVE 2 +#define HX_REPORT_SZ 128 enum HX_TS_PATH { HX_REPORT_COORD = 1, @@ -259,6 +260,7 @@ struct himax_report_data { }; struct himax_ts_data { + bool initialized; bool suspended; atomic_t suspend_mode; uint8_t x_channel; @@ -320,10 +322,8 @@ struct himax_ts_data { int in_self_test; -#if defined(CONFIG_FB) +#if defined(CONFIG_FB) || defined(CONFIG_DRM) struct notifier_block fb_notif; - struct workqueue_struct *himax_att_wq; - struct delayed_work work_att; #elif defined(CONFIG_HAS_EARLYSUSPEND) struct early_suspend early_suspend; #endif @@ -364,6 +364,7 @@ struct himax_ts_data { struct work_struct ito_test_work; #endif + uint8_t *report_i2c_data; }; struct himax_debug { @@ -474,6 +475,7 @@ extern int himax_chip_common_suspend(struct himax_ts_data *ts); extern int himax_chip_common_resume(struct himax_ts_data *ts); extern int himax_chip_common_init(void); extern void himax_chip_common_deinit(void); +extern int himax_fb_register(struct himax_ts_data *ts); extern int himax_input_register(struct himax_ts_data *ts); extern void himax_ts_work(struct himax_ts_data *ts); extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c b/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c index a95fb26a3bc25d30d561121bc5eae6d29cfb6215..b720826e59e27033b9fc0d59c118dbe04ae5e00a 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c +++ b/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c @@ -464,7 +464,10 @@ static void himax_mcu_resume_ic_action(void) static void himax_mcu_suspend_ic_action(void) { - /* Nothing to do */ + /* Keep TS_RESET PIN to LOW, to avoid leakage during suspend */ +#ifdef HX_RST_PIN_FUNC + himax_rst_gpio_set(private_ts->rst_gpio, 0); +#endif } static void himax_mcu_power_on_init(void) diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index 95564672112b1c4c015a33e774dfda3908dd01ec..8672e95d240d013b20d6b90be973cd57616f4683 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -168,7 +168,10 @@ int himax_parse_dt(struct himax_ts_data *ts, struct himax_i2c_platform_data *pda int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRetry) { int retry; - struct i2c_client *client = private_ts->client; + bool reallocate = false; + struct himax_ts_data *ts = private_ts; + uint8_t *buf = ts->report_i2c_data; + struct i2c_client *client = ts->client; struct i2c_msg msg[] = { { .addr = client->addr, @@ -180,11 +183,22 @@ int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRe .addr = client->addr, .flags = I2C_M_RD, .len = length, - .buf = data, + .buf = buf, } }; - mutex_lock(&private_ts->rw_lock); + if (length > HX_REPORT_SZ * 2) { + E("%s: data length too large %d!\n", __func__, length); + buf = kmalloc(length, GFP_KERNEL); + if (!buf) { + E("%s: failed realloc buf %d\n", __func__, length); + return -EIO; + } + reallocate = true; + msg[1].buf = buf; + } + + mutex_lock(&ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 2) == 2) @@ -196,19 +210,26 @@ int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRe if (retry == toRetry) { E("%s: i2c_read_block retry over %d\n", __func__, toRetry); i2c_error_count = toRetry; - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); return -EIO; } - mutex_unlock(&private_ts->rw_lock); + memcpy(data, buf, length); + mutex_unlock(&ts->rw_lock); + + if (reallocate) + kfree(buf); + return 0; } int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRetry) { int retry; - uint8_t buf[length + 1]; - struct i2c_client *client = private_ts->client; + bool reallocate = false; + struct himax_ts_data *ts = private_ts; + uint8_t *buf = ts->report_i2c_data; + struct i2c_client *client = ts->client; struct i2c_msg msg[] = { { .addr = client->addr, @@ -218,7 +239,17 @@ int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toR } }; - mutex_lock(&private_ts->rw_lock); + if (length + 1 > HX_REPORT_SZ * 2) { + E("%s: data length too large %d!\n", __func__, length + 1); + buf = kmalloc(length + 1, GFP_KERNEL); + if (!buf) { + E("%s: failed realloc buf %d\n", __func__, length + 1); + return -EIO; + } + reallocate = true; + } + + mutex_lock(&ts->rw_lock); buf[0] = command; memcpy(buf + 1, data, length); @@ -232,11 +263,15 @@ int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toR if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); i2c_error_count = toRetry; - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); return -EIO; } - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); + + if (reallocate) + kfree(buf); + return 0; } @@ -248,7 +283,9 @@ int himax_bus_write_command(uint8_t command, uint8_t toRetry) int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) { int retry; - uint8_t buf[length]; + bool reallocate = false; + struct himax_ts_data *ts = private_ts; + uint8_t *buf = ts->report_i2c_data; struct i2c_client *client = private_ts->client; struct i2c_msg msg[] = { { @@ -259,7 +296,17 @@ int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) } }; - mutex_lock(&private_ts->rw_lock); + if (length > HX_REPORT_SZ * 2) { + E("%s: data length too large %d!\n", __func__, length); + buf = kmalloc(length, GFP_KERNEL); + if (!buf) { + E("%s: failed realloc buf %d\n", __func__, length); + return -EIO; + } + reallocate = true; + } + + mutex_lock(&ts->rw_lock); memcpy(buf, data, length); for (retry = 0; retry < toRetry; retry++) { @@ -272,11 +319,15 @@ int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); i2c_error_count = toRetry; - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); return -EIO; } - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); + + if (reallocate) + kfree(buf); + return 0; } @@ -641,7 +692,8 @@ static int himax_common_resume(struct device *dev) #if defined(CONFIG_DRM) -int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) { struct msm_drm_notifier *evdata = data; int *blank; @@ -658,6 +710,11 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void switch (*blank) { case MSM_DRM_BLANK_UNBLANK: + if (!ts->initialized) { + if (himax_chip_common_init()) + return -ECANCELED; + ts->initialized = true; + } himax_common_resume(&ts->client->dev); break; case MSM_DRM_BLANK_POWERDOWN: @@ -671,7 +728,8 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void #elif defined(CONFIG_FB) -int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) { struct fb_event *evdata = data; int *blank; @@ -689,6 +747,11 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void switch (*blank) { case FB_BLANK_UNBLANK: + if (!ts->initialized) { + if (himax_chip_common_init()) + return 0; + ts->initialized = true; + } himax_common_resume(&ts->client->dev); break; case FB_BLANK_POWERDOWN: @@ -731,8 +794,30 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i mutex_init(&ts->rw_lock); private_ts = ts; - ret = himax_chip_common_init(); + ts->report_i2c_data = kmalloc(HX_REPORT_SZ * 2, GFP_KERNEL); + if (ts->report_i2c_data == NULL) { + E("%s: allocate report_i2c_data failed\n", __func__); + ret = -ENOMEM; + goto err_report_i2c_data; + } + + /* + * ts chip initialization is deferred till FB_UNBLACK event; + * probe is considered pending till then. + */ + ts->initialized = false; +#if defined(CONFIG_FB) || defined(CONFIG_DRM) + ret = himax_fb_register(ts); + if (ret) + goto err_fb_notify_reg_failed; +#endif + + return ret; +err_fb_notify_reg_failed: + kfree(ts->report_i2c_data); +err_report_i2c_data: + kfree(ts); err_alloc_data_failed: err_check_functionality_failed: @@ -742,7 +827,6 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i int himax_chip_common_remove(struct i2c_client *client) { himax_chip_common_deinit(); - return 0; } diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h index ac6e37d55dce5b869458a0d6c2f81351b60f2326..9e83f4212c5c14a953a8304f7aa7be6ab8481d44 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.h +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -125,8 +125,12 @@ extern uint8_t himax_int_gpio_read(int pinnum); extern int himax_gpio_power_config(struct himax_i2c_platform_data *pdata); -#if defined(CONFIG_DRM) || defined(CONFIG_FB) - extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#if defined(CONFIG_DRM) + extern int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_FB) + extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); #endif #if defined(HX_PLATFOME_DEFINE_KEY) diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c index 1f45adddec76b28387f1aaf17820c51455d7b8e7..0d1453873d739507874bd52ebb6003580e01320d 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c @@ -147,6 +147,8 @@ static int synaptics_rmi4_suspend(struct device *dev); static int synaptics_rmi4_resume(struct device *dev); +static int synaptics_rmi4_defer_probe(struct platform_device *pdev); + static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); @@ -4226,7 +4228,6 @@ EXPORT_SYMBOL(synaptics_rmi4_new_function); static int synaptics_rmi4_probe(struct platform_device *pdev) { int retval; - unsigned char attr_count; struct synaptics_rmi4_data *rmi4_data; const struct synaptics_dsx_hw_interface *hw_if; const struct synaptics_dsx_board_data *bdata; @@ -4277,6 +4278,31 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) vir_button_map = bdata->vir_button_map; + rmi4_data->initialized = false; +#ifdef CONFIG_FB + rmi4_data->fb_notifier.notifier_call = + synaptics_rmi4_dsi_panel_notifier_cb; + retval = msm_drm_register_client(&rmi4_data->fb_notifier); + if (retval < 0) { + dev_err(&pdev->dev, + "%s: Failed to register fb notifier client\n", + __func__); + } +#endif + return retval; +} + +static int synaptics_rmi4_defer_probe(struct platform_device *pdev) +{ + int retval; + struct synaptics_rmi4_data *rmi4_data; + const struct synaptics_dsx_hw_interface *hw_if; + const struct synaptics_dsx_board_data *bdata; + unsigned char attr_count; + + rmi4_data = platform_get_drvdata(pdev); + hw_if = rmi4_data->hw_if; + bdata = hw_if->board_data; retval = synaptics_rmi4_get_reg(rmi4_data, true); if (retval < 0) { dev_err(&pdev->dev, @@ -4335,18 +4361,6 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) goto err_set_input_dev; } -#ifdef CONFIG_FB - rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_dsi_panel_notifier_cb; - retval = msm_drm_register_client(&rmi4_data->fb_notifier); - if (retval < 0) { - - - dev_err(&pdev->dev, - "%s: Failed to register fb notifier client\n", - __func__); - } -#endif - #ifdef USE_EARLYSUSPEND rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend; @@ -4594,6 +4608,12 @@ static int synaptics_rmi4_dsi_panel_notifier_cb(struct notifier_block *self, synaptics_rmi4_suspend(&rmi4_data->pdev->dev); rmi4_data->fb_ready = false; } else if (transition == MSM_DRM_BLANK_UNBLANK) { + if (rmi4_data->initialized == false) { + if (synaptics_rmi4_defer_probe( + rmi4_data->pdev)) + return -ECANCELED; + rmi4_data->initialized = true; + } synaptics_rmi4_resume(&rmi4_data->pdev->dev); rmi4_data->fb_ready = true; } diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h index 34170708a96b61ef3a5b9fb7d2710d26d6f6638a..423db092f9767e68c76844d8b2ed3e110355f97a 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h @@ -353,6 +353,7 @@ struct synaptics_rmi4_device_info { * @report_touch: pointer to touch reporting function */ struct synaptics_rmi4_data { + bool initialized; struct platform_device *pdev; struct input_dev *input_dev; struct input_dev *stylus_dev; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4181c15cc9385eafad3a2ce7676936704638fe4a..ea26ce6a66845bd5afd0c78db008a09f948da191 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -255,6 +255,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5) #define ARM_SMMU_OPT_STATIC_CB (1 << 6) #define ARM_SMMU_OPT_DISABLE_ATOS (1 << 7) +#define ARM_SMMU_OPT_MIN_IOVA_ALIGN (1 << 8) u32 options; enum arm_smmu_arch_version version; enum arm_smmu_implementation model; @@ -394,6 +395,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" }, { ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"}, { ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" }, + { ARM_SMMU_OPT_MIN_IOVA_ALIGN, "qcom,min-iova-align" }, { 0, NULL}, }; @@ -976,7 +978,7 @@ static void arm_smmu_domain_power_off(struct iommu_domain *domain, } /* Wait for any pending TLB invalidations to complete */ -static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, +static int __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, void __iomem *sync, void __iomem *status) { unsigned int spin_cnt, delay; @@ -985,7 +987,7 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) { for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) { if (!(readl_relaxed(status) & sTLBGSTATUS_GSACTIVE)) - return; + return 0; cpu_relax(); } udelay(delay); @@ -993,6 +995,7 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, trace_tlbsync_timeout(smmu->dev, 0); dev_err_ratelimited(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n"); + return -EINVAL; } static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) @@ -1001,8 +1004,10 @@ static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) unsigned long flags; spin_lock_irqsave(&smmu->global_sync_lock, flags); - __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC, - base + ARM_SMMU_GR0_sTLBGSTATUS); + if (__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC, + base + ARM_SMMU_GR0_sTLBGSTATUS)) + dev_err_ratelimited(smmu->dev, + "TLB global sync failed!\n"); spin_unlock_irqrestore(&smmu->global_sync_lock, flags); } @@ -1014,8 +1019,12 @@ static void arm_smmu_tlb_sync_context(void *cookie) unsigned long flags; spin_lock_irqsave(&smmu_domain->sync_lock, flags); - __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC, - base + ARM_SMMU_CB_TLBSTATUS); + if (__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC, + base + ARM_SMMU_CB_TLBSTATUS)) + dev_err_ratelimited(smmu->dev, + "TLB sync on cb%d failed for device %s\n", + smmu_domain->cfg.cbndx, + dev_name(smmu_domain->dev)); spin_unlock_irqrestore(&smmu_domain->sync_lock, flags); } @@ -1635,6 +1644,9 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx, reg |= SCTLR_HUPCF; } + if (attributes & (1 << DOMAIN_ATTR_NO_CFRE)) + reg &= ~SCTLR_CFRE; + if ((!(attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) && !(attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) || !stage1) reg |= SCTLR_M; @@ -2706,10 +2718,6 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, if (arm_smmu_is_slave_side_secure(smmu_domain)) return msm_secure_smmu_map_sg(domain, iova, sg, nents, prot); - ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu); - if (ret) - return ret; - arm_smmu_prealloc_memory_sg(smmu_domain, sg, nents, &nonsecure_pool); arm_smmu_secure_domain_lock(smmu_domain); @@ -2754,7 +2762,6 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, iova = __saved_iova_start; } arm_smmu_secure_domain_unlock(smmu_domain); - arm_smmu_domain_power_off(domain, smmu_domain->smmu); arm_smmu_release_prealloc_memory(smmu_domain, &nonsecure_pool); return iova - __saved_iova_start; } @@ -3206,6 +3213,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, & (1 << DOMAIN_ATTR_CB_STALL_DISABLE)); ret = 0; break; + case DOMAIN_ATTR_NO_CFRE: + *((int *)data) = !!(smmu_domain->attributes + & (1 << DOMAIN_ATTR_NO_CFRE)); + ret = 0; + break; case DOMAIN_ATTR_QCOM_MMU500_ERRATA_MIN_IOVA_ALIGN: *((int *)data) = smmu_domain->qsmmuv500_errata1_min_iova_align; ret = 0; @@ -3422,6 +3434,12 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, 1 << DOMAIN_ATTR_CB_STALL_DISABLE; ret = 0; break; + case DOMAIN_ATTR_NO_CFRE: + if (*((int *)data)) + smmu_domain->attributes |= + 1 << DOMAIN_ATTR_NO_CFRE; + ret = 0; + break; default: ret = -ENODEV; } @@ -4963,6 +4981,12 @@ static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu, u32 halt, fsr, sctlr_orig, sctlr, status; void __iomem *base, *cb_base; + if (of_property_read_bool(tbu->dev->of_node, + "qcom,opt-out-tbu-halting")) { + dev_notice(tbu->dev, "TBU opted-out for halting!\n"); + return -EBUSY; + } + spin_lock_irqsave(&tbu->halt_lock, flags); if (tbu->halt_count) { tbu->halt_count++; @@ -5322,8 +5346,9 @@ static void qsmmuv500_init_cb(struct arm_smmu_domain *smmu_domain, * Prefetch only works properly if the start and end of all * buffers in the page table are aligned to ARM_SMMU_MIN_IOVA_ALIGN. */ - if ((iommudata->actlr >> QSMMUV500_ACTLR_DEEP_PREFETCH_SHIFT) & - QSMMUV500_ACTLR_DEEP_PREFETCH_MASK) + if (((iommudata->actlr >> QSMMUV500_ACTLR_DEEP_PREFETCH_SHIFT) & + QSMMUV500_ACTLR_DEEP_PREFETCH_MASK) && + (smmu->options & ARM_SMMU_OPT_MIN_IOVA_ALIGN)) smmu_domain->qsmmuv500_errata1_min_iova_align = true; } diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 119f4ef0d42175b01ea8247728e303b8697fc1b7..b7f943f96068d116b2ee86217013f6cdc44e3655 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MSI_IRQS_PER_MSIR 32 #define MSI_MSIR_OFFSET 4 @@ -94,6 +95,8 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) if (msi_affinity_flag) msg->data |= cpumask_first(data->common->affinity); + + iommu_dma_map_msi_msg(data->irq, msg); } static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index da8b46f9ec7f248b27ff72159968f3b0571e1511..1ab5f21c0a0cfffaeb03eb68f4a04e76d80f669e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -406,6 +406,15 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 +config LEDS_PCA9956B + tristate "LED support for PCA9956B I2C chip" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to the PCA9956B + LED driver chip accessed via the I2C bus. Supported + devices include PCA9956B + config LEDS_QPNP_FLASH_V2 tristate "Support for QPNP V2 Flash LEDs" depends on LEDS_CLASS && MFD_SPMI_PMIC diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index e8e7a2ec587cd1b9fd924c7f143821fe95488d4c..9ea6d8a1cd6de6a53f2eead8f66a5417a8f55fa8 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o +obj-$(CONFIG_LEDS_PCA9956B) += leds-pca9956b.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o diff --git a/drivers/leds/leds-pca9956b.c b/drivers/leds/leds-pca9956b.c new file mode 100644 index 0000000000000000000000000000000000000000..b54e7a21635e342d46c2c8b8d2fd86f4b8138e5e --- /dev/null +++ b/drivers/leds/leds-pca9956b.c @@ -0,0 +1,528 @@ +/* + * leds-pca9956b.c - NXP PCA9956B LED segment driver + * + * Copyright (C) 2017 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include "leds-pca9956b.h" + +#define PCA9956B_LED_NUM 24 +#define MAX_DEVICES 32 + +#define DRIVER_NAME "nxp-ledseg" +#define DRIVER_VERSION "17.11.28" + +struct pca9956b_chip { + struct i2c_client *client; + struct mutex lock; + struct pca9956b_led *leds; +}; + +struct pca9956b_led { + struct led_classdev led_cdev; + struct pca9956b_chip *chip; + int led_num; + char name[32]; +}; + +static struct device *pca9956b_dev; + +/* + * Read one byte from given register address. + */ +static int pca9956b_read_reg(struct pca9956b_chip *chip, int reg, uint8_t *val) +{ + int ret = i2c_smbus_read_byte_data(chip->client, reg); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed reading register\n"); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + +/* + * Write one byte to the given register address. + */ +static int pca9956b_write_reg(struct pca9956b_chip *chip, int reg, uint8_t val) +{ + int ret = i2c_smbus_write_byte_data(chip->client, reg, val); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed writing register\n"); + return ret; + } + + return 0; +} + +/* + * Read string from device tree property and write it to the register. + */ +static int pca9956b_readWrite_reg(struct pca9956b_chip *chip, + char *readStr, int writeRegAddr) +{ + struct device_node *np = chip->client->dev.of_node; + uint32_t reg_value; + int ret; + + ret = of_property_read_u32(np, readStr, ®_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to read %s\n", + __func__, readStr); + return ret; + } + + mutex_lock(&chip->lock); + + ret = pca9956b_write_reg(chip, writeRegAddr, (uint8_t)reg_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to write %s , value = 0x%x\n", + __func__, readStr, reg_value); + mutex_unlock(&chip->lock); + return ret; + } + + mutex_unlock(&chip->lock); + + return ret; +} + +/* + * Store one byte to given register address. + */ +static ssize_t pca9956b_storeReg(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + unsigned int ret, reg_value, reg_addr; + + ret = sscanf(buf, "%x %x", ®_addr, ®_value); + if (ret == 0) { + dev_err(&chip->client->dev, + "[%s] fail to pca9956b out.\n", + __func__); + return count; + } + + if (reg_addr < PCA9956B_MODE1 || reg_addr > PCA9956B_IREFALL) { + dev_err(&chip->client->dev, + "[%s] Out of range. Reg = 0x%x\n", + __func__, reg_addr); + return count; + } + + mutex_lock(&chip->lock); + + ret = pca9956b_write_reg(chip, reg_addr, (uint8_t)reg_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Operation [0x%x , %d] is failed.\n", + __func__, reg_addr, reg_value); + + mutex_unlock(&chip->lock); + + return count; +} + +/* + * Show all registers + */ +static ssize_t pca9956b_showReg(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + uint8_t reg_value = 0; + int ret, i; + char *bufp = buf; + + mutex_lock(&chip->lock); + + for (i = PCA9956B_MODE1; i < PCA9956B_IREFALL; i++) { + ret = pca9956b_read_reg(chip, i, ®_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Reading reg[0x%x] is failed.\n", + __func__, i); + + bufp += snprintf(bufp, PAGE_SIZE, + "Addr[0x%x] = 0x%x\n", i, reg_value); + } + + mutex_unlock(&chip->lock); + + return strlen(buf); +} + +static DEVICE_ATTR(reg, 0664, + pca9956b_showReg, pca9956b_storeReg); + +/* + * Show error register. + */ +static ssize_t pca9956_showErr(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + uint8_t reg_value = 0; + int ret, i; + char *bufp = buf; + + mutex_lock(&chip->lock); + + for (i = PCA9956B_EFLAG0 ; i <= PCA9956B_EFLAG4 ; i++) { + ret = pca9956b_read_reg(chip, i, ®_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Reading [0x%x] is failed.\n", + __func__, i); + + bufp += snprintf(bufp, PAGE_SIZE, "PCA9956B_EFLAG[%d] = 0x%x\n", + i - PCA9956B_EFLAG0, reg_value); + } + + mutex_unlock(&chip->lock); + + return strlen(buf); +} +static DEVICE_ATTR(err, 0664, + pca9956_showErr, NULL); + +static struct attribute *attrs[] = { + &dev_attr_err.attr, + &dev_attr_reg.attr, + NULL, /* Need to NULL terminate the list of attributes */ +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +/* + * Individual PWM set function + */ +static void pca9956b_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct pca9956b_led *pca9956b; + struct pca9956b_chip *chip; + int ret; + + pca9956b = container_of(led_cdev, struct pca9956b_led, led_cdev); + chip = pca9956b->chip; + + mutex_lock(&chip->lock); + ret = pca9956b_write_reg(chip, + PCA9956B_PWM0 + pca9956b->led_num, + value); + if (ret != 0) + dev_err(&chip->client->dev, "[%s] is failed = %d.\n", + __func__, ret); + + mutex_unlock(&chip->lock); +} + +/* + * Individual PWM get function + */ +static enum led_brightness pca9956b_brightness_get( + struct led_classdev *led_cdev) +{ + struct pca9956b_led *pca9956b; + struct pca9956b_chip *chip; + int ret; + uint8_t reg_value; + + pca9956b = container_of(led_cdev, struct pca9956b_led, led_cdev); + chip = pca9956b->chip; + + mutex_lock(&chip->lock); + ret = pca9956b_read_reg(chip, PCA9956B_PWM0 + pca9956b->led_num, + ®_value); + if (ret != 0) + dev_err(&chip->client->dev, "[%s] is failed = %d.\n", + __func__, ret); + + mutex_unlock(&chip->lock); + + return reg_value; +} + +static int pca9956b_registerClassDevice(struct i2c_client *client, + struct pca9956b_chip *chip) +{ + int i = 0, err, reg; + struct device_node *np = client->dev.of_node, *child; + struct pca9956b_led *led; + + for_each_child_of_node(np, child) { + err = of_property_read_u32(child, "reg", ®); + if (err) { + of_node_put(child); + pr_err(DRIVER_NAME": Failed to get child node"); + return err; + } + if (reg < 0 || reg >= PCA9956B_LED_NUM) { + of_node_put(child); + pr_err(DRIVER_NAME": Invalid reg value"); + return -EINVAL; + } + + led = &chip->leds[reg]; + led->led_cdev.name = + of_get_property(child, "label", NULL) ? : child->name; + led->led_cdev.default_trigger = + of_get_property(child, "linux,default-trigger", NULL); + led->led_cdev.brightness_set = pca9956b_brightness_set; + led->led_cdev.brightness_get = pca9956b_brightness_get; + led->chip = chip; + led->led_num = reg; + i++; + + err = led_classdev_register(&client->dev, + &led->led_cdev); + if (err < 0) { + pr_err(DRIVER_NAME": Failed to register LED class dev"); + goto exit; + } + } + + return 0; +exit: + while (i--) + led_classdev_unregister(&chip->leds[i].led_cdev); + + return err; +} + +/* + * Read properties and write it to register. + */ +static int pca9956b_setup(struct pca9956b_chip *chip) +{ + struct device_node *np = chip->client->dev.of_node; + int ret; + uint32_t reg_value; + + ret = of_property_read_u32(np, "pca9956b,support_initialize", + ®_value); + if (ret < 0) { + pr_err("[%s]: Unable to pca9956b,support_initialize\n", + __func__); + return ret; + } + + if (reg_value == 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,mode1", + PCA9956B_MODE1); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,mode2", + PCA9956B_MODE2); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout0", + PCA9956B_LEDOUT0); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout1", + PCA9956B_LEDOUT1); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout2", + PCA9956B_LEDOUT2); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout3", + PCA9956B_LEDOUT3); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout4", + PCA9956B_LEDOUT4); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout5", + PCA9956B_LEDOUT5); + if (ret < 0) + return ret; + + /* set default IREF to all IREF */ + { + int reg_addr; + + ret = of_property_read_u32(np, "pca9956b,defaultiref", + ®_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to read pca9956b,defaultiref\n", + __func__); + return ret; + } + mutex_lock(&chip->lock); + + for (reg_addr = PCA9956B_IREF0; + reg_addr <= PCA9956B_IREF23; reg_addr++) { + ret = pca9956b_write_reg(chip, reg_addr, + (uint8_t)reg_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to write reg0x%x[0x%x]\n", + __func__, reg_addr, reg_value); + mutex_unlock(&chip->lock); + return ret; + } + } + mutex_unlock(&chip->lock); + } + + /* set IREF0 ~ IREF23 if required */ + + return ret; +} + + +static int pca9956b_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pca9956b_chip *chip; + struct pca9956b_led *led; + int ret; + int i; + + pr_info(DRIVER_NAME": (I2C) "DRIVER_VERSION"\n"); + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); + return -EIO; + } + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->leds = devm_kzalloc(&client->dev, sizeof(*led)*PCA9956B_LED_NUM, + GFP_KERNEL); + if (!chip->leds) { + devm_kfree(&client->dev, chip); + return -ENOMEM; + } + + i2c_set_clientdata(client, chip); + + mutex_init(&chip->lock); + chip->client = client; + + /* LED device class registration */ + ret = pca9956b_registerClassDevice(client, chip); + if (ret < 0) + goto exit; + + /* Configuration setup */ + ret = pca9956b_setup(chip); + if (ret < 0) + goto err_setup; + + pca9956b_dev = &client->dev; + + ret = sysfs_create_group(&pca9956b_dev->kobj, &attr_group); + if (ret) { + dev_err(&client->dev, + "Failed to create sysfs group for pca9956b\n"); + goto err_setup; + } + + return 0; + +err_setup: + for (i = 0; i < PCA9956B_LED_NUM; i++) + led_classdev_unregister(&chip->leds[i].led_cdev); +exit: + mutex_destroy(&chip->lock); + devm_kfree(&client->dev, chip->leds); + devm_kfree(&client->dev, chip); + return ret; +} + +static int pca9956b_remove(struct i2c_client *client) +{ + struct pca9956b_chip *dev = i2c_get_clientdata(client); + int i; + + for (i = 0; i < PCA9956B_LED_NUM; i++) + led_classdev_unregister(&dev->leds[i].led_cdev); + + sysfs_remove_group(&pca9956b_dev->kobj, &attr_group); + + mutex_destroy(&dev->lock); + devm_kfree(&client->dev, dev->leds); + devm_kfree(&client->dev, dev); + return 0; +} + +static const struct of_device_id pca9956b_dt_ids[] = { + { .compatible = "nxp,pca9956b",}, +}; + +static const struct i2c_device_id pca9956b_id[] = { + {DRIVER_NAME"-i2c", 0, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pca9956b_id); + +static struct i2c_driver pca9956b_driver = { + .driver = { + .name = DRIVER_NAME"-i2c", + .of_match_table = of_match_ptr(pca9956b_dt_ids), + }, + .probe = pca9956b_probe, + .remove = pca9956b_remove, + .id_table = pca9956b_id, +}; + +static int __init pca9956b_init(void) +{ + return i2c_add_driver(&pca9956b_driver); +} + +static void __exit pca9956b_exit(void) +{ + i2c_del_driver(&pca9956b_driver); +} +module_init(pca9956b_init); +module_exit(pca9956b_exit); +MODULE_AUTHOR("NXP Semiconductors"); +MODULE_DESCRIPTION("PCA9956B : 24-channel constant current LED driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/leds/leds-pca9956b.h b/drivers/leds/leds-pca9956b.h new file mode 100644 index 0000000000000000000000000000000000000000..af50a134e5f7bbc1bd6166e8b4b653518b61972c --- /dev/null +++ b/drivers/leds/leds-pca9956b.h @@ -0,0 +1,111 @@ +/* + * leds-pca9956b.h - NXP PCA9956B LED segment driver + * + * Copyright (C) 2017 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PCA9956B_H + +/* Register address */ +enum { + PCA9956B_MODE1 = 0x00, /* AIF, SLEEP, SUBn, ALLCALL */ + PCA9956B_MODE2, /* OVERTEMP, ERROR, DMBLNK, CLRERR, OCH */ + PCA9956B_LEDOUT0, /* LED driver output state */ + PCA9956B_LEDOUT1, + PCA9956B_LEDOUT2, + PCA9956B_LEDOUT3, + PCA9956B_LEDOUT4, + PCA9956B_LEDOUT5, + PCA9956B_GRPPWM, /* DMBLINK set 0, then GRPPWM controls */ + /* global brightness */ + PCA9956B_GRPFREQ, /* DMBLINK set 1, then GRPFREQ controls */ + /* global blinking period */ + + /* 10 : 0x0A */ + PCA9956B_PWM0, /* Brightness control */ + PCA9956B_PWM1, + PCA9956B_PWM2, + PCA9956B_PWM3, + PCA9956B_PWM4, + PCA9956B_PWM5, + PCA9956B_PWM6, + PCA9956B_PWM7, + PCA9956B_PWM8, + PCA9956B_PWM9, + + /* 20 : 0x14 */ + PCA9956B_PWM10, + PCA9956B_PWM11, + PCA9956B_PWM12, + PCA9956B_PWM13, + PCA9956B_PWM14, + PCA9956B_PWM15, + PCA9956B_PWM16, + PCA9956B_PWM17, + PCA9956B_PWM18, + PCA9956B_PWM19, + + /* 30 : 0x1E */ + PCA9956B_PWM20, + PCA9956B_PWM21, + PCA9956B_PWM22, + PCA9956B_PWM23, + PCA9956B_IREF0, /* Output current control */ + PCA9956B_IREF1, + PCA9956B_IREF2, + PCA9956B_IREF3, + PCA9956B_IREF4, + PCA9956B_IREF5, + + /* 40 : 0x28 */ + PCA9956B_IREF6, + PCA9956B_IREF7, + PCA9956B_IREF8, + PCA9956B_IREF9, + PCA9956B_IREF10, + PCA9956B_IREF11, + PCA9956B_IREF12, + PCA9956B_IREF13, + PCA9956B_IREF14, + PCA9956B_IREF15, + + /* 50 : 0x32 */ + PCA9956B_IREF16, + PCA9956B_IREF17, + PCA9956B_IREF18, + PCA9956B_IREF19, + PCA9956B_IREF20, + PCA9956B_IREF21, + PCA9956B_IREF22, + PCA9956B_IREF23, + PCA9956B_OFFSET, /* led turn-on delay */ + PCA9956B_SUBADR1, /* I2C bus subaddress */ + + /* 60 : 0x3C */ + PCA9956B_SUBADR2, + PCA9956B_SUBADR3, + PCA9956B_ALLCALLADR, /* Allows all the PCA9956Bs on the bus to be */ + /* programmed at the same time */ + PCA9956B_PWMALL, /* brightness control for all LEDn outputs */ + PCA9956B_IREFALL, /* output current value for all LED outputs */ + PCA9956B_EFLAG0, /* LED error detection */ + PCA9956B_EFLAG1, + PCA9956B_EFLAG2, + PCA9956B_EFLAG3, + PCA9956B_EFLAG4, + + /* 70 : 0x46 */ + PCA9956B_EFLAG5, +}; + +#endif /* PCA9956B_H */ diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index 9bc32578a766e1581d315dc23337214d75fd38d3..c0dd17a821709d8959a06e2ca3674b4e733da806 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -142,10 +142,9 @@ static void clean_wctx(struct pblk_w_ctx *w_ctx) { int flags; -try: flags = READ_ONCE(w_ctx->flags); - if (!(flags & PBLK_SUBMITTED_ENTRY)) - goto try; + WARN_ONCE(!(flags & PBLK_SUBMITTED_ENTRY), + "pblk: overwriting unsubmitted data\n"); /* Release flags on context. Protect from writes and reads */ smp_store_release(&w_ctx->flags, PBLK_WRITABLE_ENTRY); diff --git a/drivers/mailbox/qcom-rpmh-mailbox.c b/drivers/mailbox/qcom-rpmh-mailbox.c index 94bd6f99395e069e8633430c72778da5f562206b..8f4b3f780f33eed0c7539232a5f5933fa96d2d35 100644 --- a/drivers/mailbox/qcom-rpmh-mailbox.c +++ b/drivers/mailbox/qcom-rpmh-mailbox.c @@ -30,6 +30,7 @@ #include #include +#include #include #include diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index e4a0eced8950a4a42b60bccef5a1918ed29a6aaf..888c9020ca067a9334904ff73bb3c50170fb6879 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -286,6 +286,24 @@ config DM_CRYPT If unsure, say N. +config DM_DEFAULT_KEY + tristate "Default-key crypt target support" + depends on BLK_DEV_DM + depends on PFK + ---help--- + This (currently Android-specific) device-mapper target allows you to + create a device that assigns a default encryption key to bios that + don't already have one. This can sit between inline cryptographic + acceleration hardware and filesystems that use it. This ensures that + where the filesystem doesn't explicitly specify a key, such as for + filesystem metadata, a default key will be used instead, leaving no + sectors unencrypted. + + To compile this code as a module, choose M here: the module will be + called dm-default-key. + + If unsure, say N. + config DM_SNAPSHOT tristate "Snapshot target" depends on BLK_DEV_DM @@ -557,10 +575,11 @@ config DM_ZONED config DM_ANDROID_VERITY bool "Android verity target support" + depends on BLK_DEV_DM=y depends on DM_VERITY=y depends on X509_CERTIFICATE_PARSER depends on SYSTEM_TRUSTED_KEYRING - depends on PUBLIC_KEY_ALGO_RSA + depends on CRYPTO_RSA depends on KEYS depends on ASYMMETRIC_KEY_TYPE depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE @@ -576,8 +595,8 @@ config DM_ANDROID_VERITY config DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED bool "Verity will validate blocks at most once" - depends on DM_VERITY - ---help--- + depends on DM_VERITY + ---help--- Default enables at_most_once option for dm-verity Verify data blocks only the first time they are read from the diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 26c2f8f28ec0011e6e74b3851d4b7b347cd019f4..bfd027659aafe63ba22adaeede557c0e600ac873 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o obj-$(CONFIG_DM_BUFIO) += dm-bufio.o obj-$(CONFIG_DM_BIO_PRISON) += dm-bio-prison.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o +obj-$(CONFIG_DM_DEFAULT_KEY) += dm-default-key.o obj-$(CONFIG_DM_DELAY) += dm-delay.o obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index 0dd69244f77cce1cf38565fa1390b43ef20f4ef2..20e05936551fd593793c758589aeeabb0d303910 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -122,75 +123,6 @@ static inline bool is_unlocked(void) return !strncmp(verifiedbootstate, unlocked, sizeof(unlocked)); } -static int table_extract_mpi_array(struct public_key_signature *pks, - const void *data, size_t len) -{ - MPI mpi = mpi_read_raw_data(data, len); - - if (!mpi) { - DMERR("Error while allocating mpi array"); - return -ENOMEM; - } - - pks->mpi[0] = mpi; - pks->nr_mpi = 1; - return 0; -} - -static struct public_key_signature *table_make_digest( - enum hash_algo hash, - const void *table, - unsigned long table_len) -{ - struct public_key_signature *pks = NULL; - struct crypto_shash *tfm; - struct shash_desc *desc; - size_t digest_size, desc_size; - int ret; - - /* Allocate the hashing algorithm we're going to need and find out how - * big the hash operational data will be. - */ - tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); - if (IS_ERR(tfm)) - return ERR_CAST(tfm); - - desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); - digest_size = crypto_shash_digestsize(tfm); - - /* We allocate the hash operational data storage on the end of out - * context data and the digest output buffer on the end of that. - */ - ret = -ENOMEM; - pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); - if (!pks) - goto error; - - pks->pkey_hash_algo = hash; - pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; - pks->digest_size = digest_size; - - desc = (struct shash_desc *)(pks + 1); - desc->tfm = tfm; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - - ret = crypto_shash_init(desc); - if (ret < 0) - goto error; - - ret = crypto_shash_finup(desc, table, table_len, pks->digest); - if (ret < 0) - goto error; - - crypto_free_shash(tfm); - return pks; - -error: - kfree(pks); - crypto_free_shash(tfm); - return ERR_PTR(ret); -} - static int read_block_dev(struct bio_read *payload, struct block_device *bdev, sector_t offset, int length) { @@ -205,8 +137,9 @@ static int read_block_dev(struct bio_read *payload, struct block_device *bdev, return -ENOMEM; } - bio->bi_bdev = bdev; + bio_set_dev(bio, bdev); bio->bi_iter.bi_sector = offset; + bio_set_op_attrs(bio, REQ_OP_READ, 0); payload->page_io = kzalloc(sizeof(struct page *) * payload->number_of_pages, GFP_KERNEL); @@ -230,7 +163,7 @@ static int read_block_dev(struct bio_read *payload, struct block_device *bdev, } } - if (!submit_bio_wait(READ, bio)) + if (!submit_bio_wait(bio)) /* success */ goto free_bio; DMERR("bio read failed"); @@ -567,28 +500,85 @@ static int verity_mode(void) return DM_VERITY_MODE_EIO; } +static void handle_error(void) +{ + int mode = verity_mode(); + if (mode == DM_VERITY_MODE_RESTART) { + DMERR("triggering restart"); + kernel_restart("dm-verity device corrupted"); + } else { + DMERR("Mounting verity root failed"); + } +} + +static struct public_key_signature *table_make_digest( + enum hash_algo hash, + const void *table, + unsigned long table_len) +{ + struct public_key_signature *pks = NULL; + struct crypto_shash *tfm; + struct shash_desc *desc; + size_t digest_size, desc_size; + int ret; + + /* Allocate the hashing algorithm we're going to need and find out how + * big the hash operational data will be. + */ + tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); + if (IS_ERR(tfm)) + return ERR_CAST(tfm); + + desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); + digest_size = crypto_shash_digestsize(tfm); + + /* We allocate the hash operational data storage on the end of out + * context data and the digest output buffer on the end of that. + */ + ret = -ENOMEM; + pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); + if (!pks) + goto error; + + pks->pkey_algo = "rsa"; + pks->hash_algo = hash_algo_name[hash]; + pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; + pks->digest_size = digest_size; + + desc = (struct shash_desc *)(pks + 1); + desc->tfm = tfm; + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_init(desc); + if (ret < 0) + goto error; + + ret = crypto_shash_finup(desc, table, table_len, pks->digest); + if (ret < 0) + goto error; + + crypto_free_shash(tfm); + return pks; + +error: + kfree(pks); + crypto_free_shash(tfm); + return ERR_PTR(ret); +} + + static int verify_verity_signature(char *key_id, struct android_metadata *metadata) { - key_ref_t key_ref; - struct key *key; struct public_key_signature *pks = NULL; int retval = -EINVAL; - key_ref = keyring_search(make_key_ref(system_trusted_keyring, 1), - &key_type_asymmetric, key_id); - - if (IS_ERR(key_ref)) { - DMERR("keyring: key not found"); - return -ENOKEY; - } - - key = key_ref_to_ptr(key_ref); + if (!key_id) + goto error; pks = table_make_digest(HASH_ALGO_SHA256, (const void *)metadata->verity_table, le32_to_cpu(metadata->header->table_length)); - if (IS_ERR(pks)) { DMERR("hashing failed"); retval = PTR_ERR(pks); @@ -596,33 +586,20 @@ static int verify_verity_signature(char *key_id, goto error; } - retval = table_extract_mpi_array(pks, &metadata->header->signature[0], - RSANUMBYTES); - if (retval < 0) { - DMERR("Error extracting mpi %d", retval); + pks->s = kmemdup(&metadata->header->signature[0], RSANUMBYTES, GFP_KERNEL); + if (!pks->s) { + DMERR("Error allocating memory for signature"); goto error; } + pks->s_size = RSANUMBYTES; - retval = verify_signature(key, pks); - mpi_free(pks->rsa.s); + retval = verify_signature_one(pks, NULL, key_id); + kfree(pks->s); error: kfree(pks); - key_put(key); - return retval; } -static void handle_error(void) -{ - int mode = verity_mode(); - if (mode == DM_VERITY_MODE_RESTART) { - DMERR("triggering restart"); - kernel_restart("dm-verity device corrupted"); - } else { - DMERR("Mounting verity root failed"); - } -} - static inline bool test_mult_overflow(sector_t a, u32 b) { sector_t r = (sector_t)~0ULL; @@ -696,8 +673,8 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) dev_t uninitialized_var(dev); struct android_metadata *metadata = NULL; int err = 0, i, mode; - char *key_id, *table_ptr, dummy, *target_device, - *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS]; + char *key_id = NULL, *table_ptr, dummy, *target_device; + char *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS]; /* One for specifying number of opt args and one for mode */ sector_t data_sectors; u32 data_block_size; @@ -716,16 +693,16 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) handle_error(); return -EINVAL; } - } else if (argc == 2) - key_id = argv[1]; - else { + target_device = argv[0]; + } else if (argc == 2) { + key_id = argv[0]; + target_device = argv[1]; + } else { DMERR("Incorrect number of arguments"); handle_error(); return -EINVAL; } - target_device = argv[0]; - dev = name_to_dev_t(target_device); if (!dev) { DMERR("no dev found for %s", target_device); @@ -879,12 +856,11 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } err = verity_ctr(ti, no_of_args, verity_table_args); - - if (err) - DMERR("android-verity failed to mount as verity target"); - else { + if (err) { + DMERR("android-verity failed to create a verity target"); + } else { target_added = true; - DMINFO("android-verity mounted as verity target"); + DMINFO("android-verity created as verity target"); } free_metadata: diff --git a/drivers/md/dm-android-verity.h b/drivers/md/dm-android-verity.h index ed67d567f3eeb8c2757a4230c563931e3a290fab..ef406c136fcd1eccd877a51fa78cf2dd6fb71ed5 100644 --- a/drivers/md/dm-android-verity.h +++ b/drivers/md/dm-android-verity.h @@ -120,8 +120,9 @@ extern int dm_linear_prepare_ioctl(struct dm_target *ti, extern int dm_linear_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data); extern int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv); -extern long dm_linear_dax_direct_access(struct dm_target *ti, sector_t sector, - void **kaddr, pfn_t *pfn, long size); +extern long dm_linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, + long nr_pages, void **kaddr, + pfn_t *pfn); extern size_t dm_linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i); #endif /* DM_ANDROID_VERITY_H */ diff --git a/drivers/md/dm-default-key.c b/drivers/md/dm-default-key.c new file mode 100644 index 0000000000000000000000000000000000000000..23e91d8af0bd90006919327199457860ba7d0a7f --- /dev/null +++ b/drivers/md/dm-default-key.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#define DM_MSG_PREFIX "default-key" + +struct default_key_c { + struct dm_dev *dev; + sector_t start; + struct blk_encryption_key key; +}; + +static void default_key_dtr(struct dm_target *ti) +{ + struct default_key_c *dkc = ti->private; + + if (dkc->dev) + dm_put_device(ti, dkc->dev); + kzfree(dkc); +} + +/* + * Construct a default-key mapping: + */ +static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct default_key_c *dkc; + size_t key_size; + unsigned long long tmp; + char dummy; + int err; + + if (argc != 4) { + ti->error = "Invalid argument count"; + return -EINVAL; + } + + dkc = kzalloc(sizeof(*dkc), GFP_KERNEL); + if (!dkc) { + ti->error = "Out of memory"; + return -ENOMEM; + } + ti->private = dkc; + + if (strcmp(argv[0], "AES-256-XTS") != 0) { + ti->error = "Unsupported encryption mode"; + err = -EINVAL; + goto bad; + } + + key_size = strlen(argv[1]); + if (key_size != 2 * BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS) { + ti->error = "Unsupported key size"; + err = -EINVAL; + goto bad; + } + key_size /= 2; + + if (hex2bin(dkc->key.raw, argv[1], key_size) != 0) { + ti->error = "Malformed key string"; + err = -EINVAL; + goto bad; + } + + err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table), + &dkc->dev); + if (err) { + ti->error = "Device lookup failed"; + goto bad; + } + + if (sscanf(argv[3], "%llu%c", &tmp, &dummy) != 1) { + ti->error = "Invalid start sector"; + err = -EINVAL; + goto bad; + } + dkc->start = tmp; + + if (!blk_queue_inlinecrypt(bdev_get_queue(dkc->dev->bdev))) { + ti->error = "Device does not support inline encryption"; + err = -EINVAL; + goto bad; + } + + /* Pass flush requests through to the underlying device. */ + ti->num_flush_bios = 1; + + /* + * We pass discard requests through to the underlying device, although + * the discarded blocks will be zeroed, which leaks information about + * unused blocks. It's also impossible for dm-default-key to know not + * to decrypt discarded blocks, so they will not be read back as zeroes + * and we must set discard_zeroes_data_unsupported. + */ + ti->num_discard_bios = 1; + + /* + * It's unclear whether WRITE_SAME would work with inline encryption; it + * would depend on whether the hardware duplicates the data before or + * after encryption. But since the internal storage in some devices + * (MSM8998-based) doesn't claim to support WRITE_SAME anyway, we don't + * currently have a way to test it. Leave it disabled it for now. + */ + /*ti->num_write_same_bios = 1;*/ + + return 0; + +bad: + default_key_dtr(ti); + return err; +} + +static int default_key_map(struct dm_target *ti, struct bio *bio) +{ + const struct default_key_c *dkc = ti->private; + + bio_set_dev(bio, dkc->dev->bdev); + if (bio_sectors(bio)) { + bio->bi_iter.bi_sector = dkc->start + + dm_target_offset(ti, bio->bi_iter.bi_sector); + } + + if (!bio->bi_crypt_key && !bio->bi_crypt_skip) + bio->bi_crypt_key = &dkc->key; + + return DM_MAPIO_REMAPPED; +} + +static void default_key_status(struct dm_target *ti, status_type_t type, + unsigned int status_flags, char *result, + unsigned int maxlen) +{ + const struct default_key_c *dkc = ti->private; + unsigned int sz = 0; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + + /* encryption mode */ + DMEMIT("AES-256-XTS"); + + /* reserved for key; dm-crypt shows it, but we don't for now */ + DMEMIT(" -"); + + /* name of underlying device, and the start sector in it */ + DMEMIT(" %s %llu", dkc->dev->name, + (unsigned long long)dkc->start); + break; + } +} + +static int default_key_prepare_ioctl(struct dm_target *ti, + struct block_device **bdev, fmode_t *mode) +{ + struct default_key_c *dkc = ti->private; + struct dm_dev *dev = dkc->dev; + + *bdev = dev->bdev; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (dkc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + return 1; + return 0; +} + +static int default_key_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, + void *data) +{ + struct default_key_c *dkc = ti->private; + + return fn(ti, dkc->dev, dkc->start, ti->len, data); +} + +static struct target_type default_key_target = { + .name = "default-key", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = default_key_ctr, + .dtr = default_key_dtr, + .map = default_key_map, + .status = default_key_status, + .prepare_ioctl = default_key_prepare_ioctl, + .iterate_devices = default_key_iterate_devices, +}; + +static int __init dm_default_key_init(void) +{ + return dm_register_target(&default_key_target); +} + +static void __exit dm_default_key_exit(void) +{ + dm_unregister_target(&default_key_target); +} + +module_init(dm_default_key_init); +module_exit(dm_default_key_exit); + +MODULE_AUTHOR("Paul Lawrence "); +MODULE_AUTHOR("Paul Crowley "); +MODULE_AUTHOR("Eric Biggers "); +MODULE_DESCRIPTION(DM_NAME " target for encrypting filesystem metadata"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 23e8bde4c500a8e98a650471858642159962e016..52a695f065e1c988ef77ef62766afe6c2b934e3e 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1686,6 +1686,16 @@ static int queue_supports_sg_merge(struct dm_target *ti, struct dm_dev *dev, return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); } +static int queue_supports_inline_encryption(struct dm_target *ti, + struct dm_dev *dev, + sector_t start, sector_t len, + void *data) +{ + struct request_queue *q = bdev_get_queue(dev->bdev); + + return q && blk_queue_inlinecrypt(q); +} + static bool dm_table_all_devices_attribute(struct dm_table *t, iterate_devices_callout_fn func) { @@ -1836,6 +1846,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, else queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); + if (dm_table_all_devices_attribute(t, queue_supports_inline_encryption)) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); + else + queue_flag_clear_unlocked(QUEUE_FLAG_INLINECRYPT, q); + dm_table_verify_integrity(t); /* diff --git a/drivers/md/md.c b/drivers/md/md.c index 861e764ec169bef84ff8a2fe54a57409f8eed8b6..24f0f7c0d5becd3c2c37331212900480fa86c926 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6498,6 +6498,9 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev) char b[BDEVNAME_SIZE]; struct md_rdev *rdev; + if (!mddev->pers) + return -ENODEV; + rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 029ecba607272cdabc315e83ddf21780b356b26a..78d8307637045f3b797d7f6954732268a82b9c82 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2462,6 +2462,8 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio) fix_read_error(conf, r1_bio->read_disk, r1_bio->sector, r1_bio->sectors); unfreeze_array(conf); + } else if (mddev->ro == 0 && test_bit(FailFast, &rdev->flags)) { + md_error(mddev, rdev); } else { r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED; } diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index bfe831c10b1c46ccabf4efd41a49a8550b04ab70..b95a631f23f9ab3f34d7f323997afbfe9b30d542 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -35,7 +35,7 @@ void smsendian_handle_tx_message(void *buffer) switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { - msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); + msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0])); break; } @@ -44,7 +44,7 @@ void smsendian_handle_tx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -64,7 +64,7 @@ void smsendian_handle_rx_message(void *buffer) { struct sms_version_res *ver = (struct sms_version_res *) msg; - ver->chip_model = le16_to_cpu(ver->chip_model); + ver->chip_model = le16_to_cpu((__force __le16)ver->chip_model); break; } @@ -81,7 +81,7 @@ void smsendian_handle_rx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -95,9 +95,9 @@ void smsendian_handle_message_header(void *msg) #ifdef __BIG_ENDIAN struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; - phdr->msg_type = le16_to_cpu(phdr->msg_type); - phdr->msg_length = le16_to_cpu(phdr->msg_length); - phdr->msg_flags = le16_to_cpu(phdr->msg_flags); + phdr->msg_type = le16_to_cpu((__force __le16)phdr->msg_type); + phdr->msg_length = le16_to_cpu((__force __le16)phdr->msg_length); + phdr->msg_flags = le16_to_cpu((__force __le16)phdr->msg_flags); #endif /* __BIG_ENDIAN */ } EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index c4df6cee48e6ab41520d73d4a9e12a7be76b0f07..e14a29c33518b336d674fcf02fabac57e7da6c6e 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -36,6 +36,8 @@ * Common definitions */ +#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */ + /* * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. */ @@ -56,6 +58,108 @@ #define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) #endif +/* + * enum dmx_success: Success codes for the Demux Callback API. + */ +enum dmx_success { + DMX_OK = 0, /* Received Ok */ + DMX_OK_PES_END, /* Received OK, data reached end of PES packet */ + DMX_OK_PCR, /* Received OK, data with new PCR/STC pair */ + DMX_OK_EOS, /* Received OK, reached End-of-Stream (EOS) */ + DMX_OK_MARKER, /* Received OK, reached a data Marker */ + DMX_LENGTH_ERROR, /* Incorrect length */ + DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ + DMX_CRC_ERROR, /* Incorrect CRC */ + DMX_FRAME_ERROR, /* Frame alignment error */ + DMX_FIFO_ERROR, /* Receiver FIFO overrun */ + DMX_MISSED_ERROR, /* Receiver missed packet */ + DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */ + DMX_OK_IDX, /* Received OK, new index event */ + DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */ +}; + +struct ion_dma_buff_info { + struct dma_buf *dmabuf; + struct sg_table *sgt; + struct dma_buf_attachment *attach; + phys_addr_t pa; + void *va; + size_t len; +}; + +/* + * struct dmx_data_ready: Parameters for event notification callback. + * Event notification notifies demux device that data is written + * and available in the device's output buffer or provides + * notification on errors and other events. In the latter case + * data_length is zero. + */ +struct dmx_data_ready { + enum dmx_success status; + + /* + * data_length may be 0 in case of DMX_OK_PES_END or DMX_OK_EOS + * and in non-DMX_OK_XXX events. In DMX_OK_PES_END, + * data_length is for data coming after the end of PES. + */ + int data_length; + + union { + struct { + int start_gap; + int actual_length; + int disc_indicator_set; + int pes_length_mismatch; + u64 stc; + u32 tei_counter; + u32 cont_err_counter; + u32 ts_packets_num; + } pes_end; + + struct { + u64 pcr; + u64 stc; + int disc_indicator_set; + } pcr; + + struct { + int handle; + int cookie; + u32 offset; + u32 len; + int pts_exists; + u64 pts; + int dts_exists; + u64 dts; + u32 tei_counter; + u32 cont_err_counter; + u32 ts_packets_num; + u32 ts_dropped_bytes; + u64 stc; + } buf; + + struct { + u64 id; + } marker; + + struct dmx_index_event_info idx_event; + struct dmx_scrambling_status_event_info scrambling_bits; + }; +}; + +/* + * struct data_buffer: Parameters of buffer allocated by + * demux device for input/output. Can be used to directly map the + * demux-device buffer to HW output if HW supports it. + */ +struct data_buffer { + /* dvb_ringbuffer managed by demux-device */ + const struct dvb_ringbuffer *ringbuff; + + /* ion_dma_buff_info managed by demux-device */ + struct ion_dma_buff_info buff_dma_info; + +}; /* * TS packet reception */ @@ -91,17 +195,54 @@ enum ts_filter_type { * Using this API, the client can set the filtering properties to start/stop * filtering TS packets on a particular TS feed. */ +struct dmx_ts_feed; + +typedef int (*dmx_ts_data_ready_cb)( + struct dmx_ts_feed *source, + struct dmx_data_ready *dmx_data_ready); + struct dmx_ts_feed { int is_filtering; struct dmx_demux *parent; + struct data_buffer buffer; void *priv; + struct dmx_decoder_buffers *decoder_buffers; int (*set)(struct dmx_ts_feed *feed, u16 pid, int type, enum dmx_ts_pes pes_type, + size_t circular_buffer_size, ktime_t timeout); int (*start_filtering)(struct dmx_ts_feed *feed); int (*stop_filtering)(struct dmx_ts_feed *feed); + int (*set_video_codec)(struct dmx_ts_feed *feed, + enum dmx_video_codec video_codec); + int (*set_idx_params)(struct dmx_ts_feed *feed, + struct dmx_indexing_params *idx_params); + int (*get_decoder_buff_status)( + struct dmx_ts_feed *feed, + struct dmx_buffer_status *dmx_buffer_status); + int (*reuse_decoder_buffer)( + struct dmx_ts_feed *feed, + int cookie); + int (*data_ready_cb)(struct dmx_ts_feed *feed, + dmx_ts_data_ready_cb callback); + int (*notify_data_read)(struct dmx_ts_feed *feed, + u32 bytes_num); + int (*set_tsp_out_format)(struct dmx_ts_feed *feed, + enum dmx_tsp_format_t tsp_format); + int (*set_secure_mode)(struct dmx_ts_feed *feed, + struct dmx_secure_mode *sec_mode); + int (*set_cipher_ops)(struct dmx_ts_feed *feed, + struct dmx_cipher_operations *cipher_ops); + int (*oob_command)(struct dmx_ts_feed *feed, + struct dmx_oob_command *cmd); + int (*ts_insertion_init)(struct dmx_ts_feed *feed); + int (*ts_insertion_terminate)(struct dmx_ts_feed *feed); + int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed, + char *data, size_t size); + int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value); + int (*flush_buffer)(struct dmx_ts_feed *feed, size_t length); }; /* @@ -126,14 +267,21 @@ struct dmx_ts_feed { * corresponding bits are compared. The filter only accepts sections that are * equal to filter_value in all the tested bit positions. */ + +struct dmx_section_feed; struct dmx_section_filter { u8 filter_value[DMX_MAX_FILTER_SIZE]; u8 filter_mask[DMX_MAX_FILTER_SIZE]; u8 filter_mode[DMX_MAX_FILTER_SIZE]; struct dmx_section_feed *parent; /* Back-pointer */ + struct data_buffer buffer; void *priv; /* Pointer to private data of the API client */ }; +typedef int (*dmx_section_data_ready_cb)( + struct dmx_section_filter *source, + struct dmx_data_ready *dmx_data_ready); + /** * struct dmx_section_feed - Structure that contains a section feed filter * @@ -176,6 +324,7 @@ struct dmx_section_feed { /* public: */ int (*set)(struct dmx_section_feed *feed, u16 pid, + size_t circular_buffer_size, int check_crc); int (*allocate_filter)(struct dmx_section_feed *feed, struct dmx_section_filter **filter); @@ -183,6 +332,18 @@ struct dmx_section_feed { struct dmx_section_filter *filter); int (*start_filtering)(struct dmx_section_feed *feed); int (*stop_filtering)(struct dmx_section_feed *feed); + int (*data_ready_cb)(struct dmx_section_feed *feed, + dmx_section_data_ready_cb callback); + int (*notify_data_read)(struct dmx_section_filter *filter, + u32 bytes_num); + int (*set_secure_mode)(struct dmx_section_feed *feed, + struct dmx_secure_mode *sec_mode); + int (*set_cipher_ops)(struct dmx_section_feed *feed, + struct dmx_cipher_operations *cipher_ops); + int (*oob_command)(struct dmx_section_feed *feed, + struct dmx_oob_command *cmd); + int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value); + int (*flush_buffer)(struct dmx_section_feed *feed, size_t length); }; /** @@ -288,9 +449,19 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, size_t buffer2_len, struct dmx_section_filter *source); -/* - * DVB Front-End - */ +typedef int (*dmx_ts_fullness) ( + struct dmx_ts_feed *source, + int required_space, + int wait); + +typedef int (*dmx_section_fullness) ( + struct dmx_section_filter *source, + int required_space, + int wait); + +/*--------------------------------------------------------------------------*/ +/* DVB Front-End */ +/*--------------------------------------------------------------------------*/ /** * enum dmx_frontend_source - Used to identify the type of frontend @@ -305,6 +476,13 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, enum dmx_frontend_source { DMX_MEMORY_FE, DMX_FRONTEND_0, + DMX_FRONTEND_1, + DMX_FRONTEND_2, + DMX_FRONTEND_3, + DMX_STREAM_0, /* external stream input, e.g. LVDS */ + DMX_STREAM_1, + DMX_STREAM_2, + DMX_STREAM_3 }; /** @@ -338,8 +516,11 @@ struct dmx_frontend { */ enum dmx_demux_caps { DMX_TS_FILTERING = 1, + DMX_PES_FILTERING = 2, DMX_SECTION_FILTERING = 4, DMX_MEMORY_BASED_FILTERING = 8, + DMX_CRC_CHECKING = 16, + DMX_TS_DESCRAMBLING = 32 }; /* @@ -550,6 +731,10 @@ struct dmx_demux { enum dmx_demux_caps capabilities; struct dmx_frontend *frontend; void *priv; + struct data_buffer dvr_input; /* DVR input buffer */ + int dvr_input_protected; + struct dentry *debugfs_demux_dir; /* debugfs dir */ + int (*open)(struct dmx_demux *demux); int (*close)(struct dmx_demux *demux); int (*write)(struct dmx_demux *demux, const char __user *buf, @@ -575,7 +760,19 @@ struct dmx_demux { int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids); - /* private: */ + int (*get_caps)(struct dmx_demux *demux, struct dmx_caps *caps); + + int (*set_source)(struct dmx_demux *demux, const dmx_source_t *src); + + int (*set_tsp_format)(struct dmx_demux *demux, + enum dmx_tsp_format_t tsp_format); + + int (*set_playback_mode)(struct dmx_demux *demux, + enum dmx_playback_mode_t mode, + dmx_ts_fullness ts_fullness_callback, + dmx_section_fullness sec_fullness_callback); + + int (*write_cancel)(struct dmx_demux *demux); /* * Only used at av7110, to read some data from firmware. @@ -584,6 +781,15 @@ struct dmx_demux { */ int (*get_stc)(struct dmx_demux *demux, unsigned int num, u64 *stc, unsigned int *base); + + int (*map_buffer)(struct dmx_demux *demux, + struct dmx_buffer *dmx_buffer, + struct ion_dma_buff_info *dma_buffer, void **mem); + + int (*unmap_buffer)(struct dmx_demux *demux, + struct ion_dma_buff_info *dma_buffer); + + int (*get_tsp_size)(struct dmx_demux *demux); }; #endif /* #ifndef __DEMUX_H */ diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 51009b2718a3e0c9ce5f865f1a4bcab5737498ca..ff6a5cf93eb86cb7f0119f16ddb0dc25ba03d469 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -27,18 +27,73 @@ #include #include #include +#include +#include +#include +#include #include "dmxdev.h" -static int debug; +static int overflow_auto_flush = 1; +module_param(overflow_auto_flush, int, 0644); +MODULE_PARM_DESC(overflow_auto_flush, + "Automatically flush buffer on overflow (default: on)"); -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +#define DMX_DEFAULT_DECODER_BUFFER_SIZE (32768) -#define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_DEBUG pr_fmt("%s: " fmt), \ - __func__, ##arg); \ -} while (0) +static inline int dvb_dmxdev_verify_buffer_size(u32 size, u32 max_size, + u32 size_align) +{ + if (size_align) + return size <= max_size && !(size % size_align); + else + return size <= max_size; +} + +static int dvb_filter_verify_buffer_size(struct dmxdev_filter *filter) +{ + struct dmx_caps caps; + size_t size = filter->buffer.size; + + /* + * For backward compatibility, if no demux capabilities can + * be retrieved assume size is ok. + * Decoder filter buffer size is verified when decoder buffer is set. + */ + if (filter->dev->demux->get_caps) { + filter->dev->demux->get_caps(filter->dev->demux, &caps); + + if (filter->type == DMXDEV_TYPE_SEC) + return dvb_dmxdev_verify_buffer_size( + size, + caps.section.max_size, + caps.section.size_alignment); + + if (filter->params.pes.output == DMX_OUT_TAP) + return dvb_dmxdev_verify_buffer_size( + size, + caps.pes.max_size, + caps.pes.size_alignment); + + size = (filter->params.pes.output == DMX_OUT_TS_TAP) ? + filter->dev->dvr_buffer.size : size; + + if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP || + filter->params.pes.output == DMX_OUT_TS_TAP) { + if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188) + return dvb_dmxdev_verify_buffer_size( + size, + caps.recording_188_tsp.max_size, + caps.recording_188_tsp.size_alignment); + + return dvb_dmxdev_verify_buffer_size( + size, + caps.recording_192_tsp.max_size, + caps.recording_192_tsp.size_alignment); + } + } + + return 1; +} static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, const u8 *src, size_t len) @@ -52,16 +107,401 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, free = dvb_ringbuffer_free(buf); if (len > free) { - dprintk("buffer overflow\n"); + pr_debug("dmxdev: buffer overflow\n"); return -EOVERFLOW; } return dvb_ringbuffer_write(buf, src, len); } -static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, - int non_blocking, char __user *buf, - size_t count, loff_t *ppos) +static inline void dvb_dmxdev_notify_data_read(struct dmxdev_filter *filter, + int bytes_read) +{ + if (!filter) + return; + + if (filter->type == DMXDEV_TYPE_SEC) { + if (filter->feed.sec.feed->notify_data_read) + filter->feed.sec.feed->notify_data_read( + filter->filter.sec, + bytes_read); + } else { + struct dmxdev_feed *feed; + + /* + * All feeds of same demux-handle share the same output + * buffer, it is enough to notify on the buffer status + * on one of the feeds + */ + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + + if (feed->ts->notify_data_read) + feed->ts->notify_data_read( + feed->ts, + bytes_read); + } +} + +static inline u32 dvb_dmxdev_advance_event_idx(u32 index) +{ + index++; + if (index >= DMX_EVENT_QUEUE_SIZE) + index = 0; + + return index; +} + +static inline int dvb_dmxdev_events_is_full(struct dmxdev_events_queue *events) +{ + int new_write_index; + + new_write_index = dvb_dmxdev_advance_event_idx(events->write_index); + if (new_write_index == events->read_index) + return 1; + + return 0; + +} + +static inline void dvb_dmxdev_flush_events(struct dmxdev_events_queue *events) +{ + events->read_index = 0; + events->write_index = 0; + events->notified_index = 0; + events->bytes_read_no_event = 0; + events->current_event_data_size = 0; + events->wakeup_events_counter = 0; +} + +static inline void dvb_dmxdev_flush_output(struct dvb_ringbuffer *buffer, + struct dmxdev_events_queue *events) +{ + dvb_dmxdev_flush_events(events); + dvb_ringbuffer_flush(buffer); +} + +static int dvb_dmxdev_update_pes_event(struct dmx_filter_event *event, + int bytes_read) +{ + int start_delta; + + if (event->params.pes.total_length <= bytes_read) + return event->params.pes.total_length; + + /* + * only part of the data relevant to this event was read. + * Update the event's information to reflect the new state. + */ + event->params.pes.total_length -= bytes_read; + + start_delta = event->params.pes.start_offset - + event->params.pes.base_offset; + + if (bytes_read <= start_delta) { + event->params.pes.base_offset += + bytes_read; + } else { + start_delta = + bytes_read - start_delta; + + event->params.pes.start_offset += start_delta; + event->params.pes.actual_length -= start_delta; + + event->params.pes.base_offset = + event->params.pes.start_offset; + } + + return 0; +} + +static int dvb_dmxdev_update_section_event(struct dmx_filter_event *event, + int bytes_read) +{ + int start_delta; + + if (event->params.section.total_length <= bytes_read) + return event->params.section.total_length; + + /* + * only part of the data relevant to this event was read. + * Update the event's information to reflect the new state. + */ + + event->params.section.total_length -= bytes_read; + + start_delta = event->params.section.start_offset - + event->params.section.base_offset; + + if (bytes_read <= start_delta) { + event->params.section.base_offset += + bytes_read; + } else { + start_delta = + bytes_read - start_delta; + + event->params.section.start_offset += start_delta; + event->params.section.actual_length -= start_delta; + + event->params.section.base_offset = + event->params.section.start_offset; + } + + return 0; +} + +static int dvb_dmxdev_update_rec_event(struct dmx_filter_event *event, + int bytes_read) +{ + if (event->params.recording_chunk.size <= bytes_read) + return event->params.recording_chunk.size; + + /* + * only part of the data relevant to this event was read. + * Update the event's information to reflect the new state. + */ + event->params.recording_chunk.size -= bytes_read; + event->params.recording_chunk.offset += bytes_read; + + return 0; +} + +static int dvb_dmxdev_add_event(struct dmxdev_events_queue *events, + struct dmx_filter_event *event) +{ + int res; + int new_write_index; + int data_event; + + /* Check if the event is disabled */ + if (events->event_mask.disable_mask & event->type) + return 0; + + /* Check if we are adding an event that user already read its data */ + if (events->bytes_read_no_event) { + data_event = 1; + + if (event->type == DMX_EVENT_NEW_PES) + res = dvb_dmxdev_update_pes_event(event, + events->bytes_read_no_event); + else if (event->type == DMX_EVENT_NEW_SECTION) + res = dvb_dmxdev_update_section_event(event, + events->bytes_read_no_event); + else if (event->type == DMX_EVENT_NEW_REC_CHUNK) + res = dvb_dmxdev_update_rec_event(event, + events->bytes_read_no_event); + else + data_event = 0; + + if (data_event) { + if (res) { + /* + * Data relevant to this event was fully + * consumed already, discard event. + */ + events->bytes_read_no_event -= res; + return 0; + } + events->bytes_read_no_event = 0; + } else { + /* + * data was read beyond the non-data event, + * making it not relevant anymore + */ + return 0; + } + } + + new_write_index = dvb_dmxdev_advance_event_idx(events->write_index); + if (new_write_index == events->read_index) { + pr_err("dmxdev: events overflow\n"); + return -EOVERFLOW; + } + + events->queue[events->write_index] = *event; + events->write_index = new_write_index; + + if (!(events->event_mask.no_wakeup_mask & event->type)) + events->wakeup_events_counter++; + + return 0; +} + +static int dvb_dmxdev_remove_event(struct dmxdev_events_queue *events, + struct dmx_filter_event *event) +{ + if (events->notified_index == events->write_index) + return -ENODATA; + + *event = events->queue[events->notified_index]; + + events->notified_index = + dvb_dmxdev_advance_event_idx(events->notified_index); + + if (!(events->event_mask.no_wakeup_mask & event->type)) + events->wakeup_events_counter--; + + return 0; +} + +static int dvb_dmxdev_update_events(struct dmxdev_events_queue *events, + int bytes_read) +{ + struct dmx_filter_event *event; + int res; + int data_event; + + /* + * If data events are not enabled on this filter, + * there's nothing to update. + */ + if (events->data_read_event_masked) + return 0; + + /* + * Go through all events that were notified and + * remove them from the events queue if their respective + * data was read. + */ + while ((events->read_index != events->notified_index) && + (bytes_read)) { + event = events->queue + events->read_index; + + data_event = 1; + + if (event->type == DMX_EVENT_NEW_PES) + res = dvb_dmxdev_update_pes_event(event, bytes_read); + else if (event->type == DMX_EVENT_NEW_SECTION) + res = dvb_dmxdev_update_section_event(event, + bytes_read); + else if (event->type == DMX_EVENT_NEW_REC_CHUNK) + res = dvb_dmxdev_update_rec_event(event, bytes_read); + else + data_event = 0; + + if (data_event) { + if (res) { + /* + * Data relevant to this event was + * fully consumed, remove it from the queue. + */ + bytes_read -= res; + events->read_index = + dvb_dmxdev_advance_event_idx( + events->read_index); + } else { + bytes_read = 0; + } + } else { + /* + * non-data event was already notified, + * no need to keep it + */ + events->read_index = dvb_dmxdev_advance_event_idx( + events->read_index); + } + } + + if (!bytes_read) + return 0; + + /* + * If we reached here it means: + * bytes_read != 0 + * events->read_index == events->notified_index + * Check if there are pending events in the queue + * which the user didn't read while their relevant data + * was read. + */ + while ((events->notified_index != events->write_index) && + (bytes_read)) { + event = events->queue + events->notified_index; + + data_event = 1; + + if (event->type == DMX_EVENT_NEW_PES) + res = dvb_dmxdev_update_pes_event(event, bytes_read); + else if (event->type == DMX_EVENT_NEW_SECTION) + res = dvb_dmxdev_update_section_event(event, + bytes_read); + else if (event->type == DMX_EVENT_NEW_REC_CHUNK) + res = dvb_dmxdev_update_rec_event(event, bytes_read); + else + data_event = 0; + + if (data_event) { + if (res) { + /* + * Data relevant to this event was + * fully consumed, remove it from the queue. + */ + bytes_read -= res; + events->notified_index = + dvb_dmxdev_advance_event_idx( + events->notified_index); + if (!(events->event_mask.no_wakeup_mask & + event->type)) + events->wakeup_events_counter--; + } else { + bytes_read = 0; + } + } else { + if (bytes_read) { + /* + * data was read beyond the non-data event, + * making it not relevant anymore + */ + events->notified_index = + dvb_dmxdev_advance_event_idx( + events->notified_index); + if (!(events->event_mask.no_wakeup_mask & + event->type)) + events->wakeup_events_counter--; + } + } + + events->read_index = events->notified_index; + } + + /* + * Check if data was read without having a respective + * event in the events-queue + */ + if (bytes_read) + events->bytes_read_no_event += bytes_read; + + return 0; +} + +static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter, + struct dvb_ringbuffer *src) +{ + int data_status_change; + + if (filter) + if (mutex_lock_interruptible(&filter->mutex)) + return -ERESTARTSYS; + + if (!src->data || + !dvb_ringbuffer_empty(src) || + src->error || + (filter && + (filter->state != DMXDEV_STATE_GO) && + (filter->state != DMXDEV_STATE_DONE))) + data_status_change = 1; + else + data_status_change = 0; + + if (filter) + mutex_unlock(&filter->mutex); + + return data_status_change; +} + +static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter, + struct dvb_ringbuffer *src, + int non_blocking, char __user *buf, + size_t count, loff_t *ppos) { size_t todo; ssize_t avail; @@ -72,7 +512,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, if (src->error) { ret = src->error; - dvb_ringbuffer_flush(src); + src->error = 0; return ret; } @@ -82,15 +522,35 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, break; } + if (filter) { + if ((filter->state == DMXDEV_STATE_DONE) && + dvb_ringbuffer_empty(src)) + break; + + mutex_unlock(&filter->mutex); + } + ret = wait_event_interruptible(src->queue, - !dvb_ringbuffer_empty(src) || - (src->error != 0)); + dvb_dmxdev_check_data(filter, src)); + + if (filter) { + if (mutex_lock_interruptible(&filter->mutex)) + return -ERESTARTSYS; + + if ((filter->state != DMXDEV_STATE_GO) && + (filter->state != DMXDEV_STATE_DONE)) + return -ENODEV; + } + if (ret < 0) break; + if (!src->data) + return 0; + if (src->error) { ret = src->error; - dvb_ringbuffer_flush(src); + src->error = 0; break; } @@ -105,6 +565,9 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, buf += ret; } + if (count - todo) /* some data was read? */ + wake_up_all(&src->queue); + return (count - todo) ? (count - todo) : ret; } @@ -122,13 +585,238 @@ static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) return NULL; } +static void dvb_dvr_oob_cmd(struct dmxdev *dmxdev, struct dmx_oob_command *cmd) +{ + int i; + struct dmxdev_filter *filter; + struct dmxdev_feed *feed; + + for (i = 0; i < dmxdev->filternum; i++) { + filter = &dmxdev->filter[i]; + if (!filter || filter->state != DMXDEV_STATE_GO) + continue; + + switch (filter->type) { + case DMXDEV_TYPE_SEC: + filter->feed.sec.feed->oob_command( + filter->feed.sec.feed, cmd); + break; + case DMXDEV_TYPE_PES: + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + feed->ts->oob_command(feed->ts, cmd); + break; + case DMXDEV_TYPE_NONE: + break; + default: + break; + } + } +} + +static int dvb_dvr_feed_cmd(struct dmxdev *dmxdev, struct dvr_command *dvr_cmd) +{ + int ret = 0; + size_t todo; + int bytes_written = 0; + size_t split; + size_t tsp_size; + u8 *data_start; + struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer; + + todo = dvr_cmd->cmd.data_feed_count; + + if (dmxdev->demux->get_tsp_size) + tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux); + else + tsp_size = 188; + + while (todo >= tsp_size) { + /* wait for input */ + ret = wait_event_interruptible( + src->queue, + (dvb_ringbuffer_avail(src) >= tsp_size) || + dmxdev->dvr_in_exit || src->error); + + if (ret < 0) + break; + + spin_lock(&dmxdev->dvr_in_lock); + + if (dmxdev->exit || dmxdev->dvr_in_exit) { + spin_unlock(&dmxdev->dvr_in_lock); + ret = -ENODEV; + break; + } + + if (src->error) { + spin_unlock(&dmxdev->dvr_in_lock); + wake_up_all(&src->queue); + ret = -EINVAL; + break; + } + + dmxdev->dvr_processing_input = 1; + + split = (src->pread + todo > src->size) ? + src->size - src->pread : 0; + + /* + * In DVR PULL mode, write might block. + * Lock on DVR buffer is released before calling to + * write, if DVR was released meanwhile, dvr_in_exit is + * prompted. Lock is acquired when updating the read pointer + * again to preserve read/write pointers consistency. + * + * In protected input mode, DVR input buffer is not mapped + * to kernel memory. Underlying demux implementation + * should trigger HW to read from DVR input buffer + * based on current read offset. + */ + if (split > 0) { + data_start = (dmxdev->demux->dvr_input_protected) ? + NULL : (src->data + src->pread); + + spin_unlock(&dmxdev->dvr_in_lock); + ret = dmxdev->demux->write(dmxdev->demux, + data_start, + split); + + if (ret < 0) { + pr_err("dmxdev: dvr write error %d\n", ret); + continue; + } + + if (dmxdev->dvr_in_exit) { + ret = -ENODEV; + break; + } + + spin_lock(&dmxdev->dvr_in_lock); + + todo -= ret; + bytes_written += ret; + DVB_RINGBUFFER_SKIP(src, ret); + if (ret < split) { + dmxdev->dvr_processing_input = 0; + spin_unlock(&dmxdev->dvr_in_lock); + wake_up_all(&src->queue); + continue; + } + } + + data_start = (dmxdev->demux->dvr_input_protected) ? + NULL : (src->data + src->pread); + + spin_unlock(&dmxdev->dvr_in_lock); + ret = dmxdev->demux->write(dmxdev->demux, + data_start, todo); + + if (ret < 0) { + pr_err("dmxdev: dvr write error %d\n", ret); + continue; + } + + if (dmxdev->dvr_in_exit) { + ret = -ENODEV; + break; + } + + spin_lock(&dmxdev->dvr_in_lock); + + todo -= ret; + bytes_written += ret; + DVB_RINGBUFFER_SKIP(src, ret); + dmxdev->dvr_processing_input = 0; + spin_unlock(&dmxdev->dvr_in_lock); + + wake_up_all(&src->queue); + } + + if (ret < 0) + return ret; + + return bytes_written; +} + +static int dvr_input_thread_entry(void *arg) +{ + struct dmxdev *dmxdev = arg; + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + struct dvr_command dvr_cmd; + int leftover = 0; + int ret; + + while (1) { + /* wait for input */ + ret = wait_event_interruptible( + cmdbuf->queue, + (!cmdbuf->data) || + (dvb_ringbuffer_avail(cmdbuf) >= sizeof(dvr_cmd)) || + (dmxdev->dvr_in_exit)); + + if (ret < 0) + break; + + spin_lock(&dmxdev->dvr_in_lock); + + if (!cmdbuf->data || dmxdev->exit || dmxdev->dvr_in_exit) { + spin_unlock(&dmxdev->dvr_in_lock); + break; + } + + dvb_ringbuffer_read(cmdbuf, (u8 *)&dvr_cmd, sizeof(dvr_cmd)); + + spin_unlock(&dmxdev->dvr_in_lock); + + if (dvr_cmd.type == DVR_DATA_FEED_CMD) { + dvr_cmd.cmd.data_feed_count += leftover; + + ret = dvb_dvr_feed_cmd(dmxdev, &dvr_cmd); + if (ret < 0) { + pr_debug("%s: DVR data feed failed, ret=%d\n", + __func__, ret); + continue; + } + + leftover = dvr_cmd.cmd.data_feed_count - ret; + } else { + /* + * For EOS, try to process leftover data in the input + * buffer. + */ + if (dvr_cmd.cmd.oobcmd.type == DMX_OOB_CMD_EOS) { + struct dvr_command feed_cmd; + + feed_cmd.type = DVR_DATA_FEED_CMD; + feed_cmd.cmd.data_feed_count = + dvb_ringbuffer_avail( + &dmxdev->dvr_input_buffer); + dvb_dvr_feed_cmd(dmxdev, &feed_cmd); + } + + dvb_dvr_oob_cmd(dmxdev, &dvr_cmd.cmd.oobcmd); + } + } + + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + + return 0; +} + static int dvb_dvr_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; + void *mem; - dprintk("%s\n", __func__); + pr_debug("function : %s(%X)\n", __func__, (file->f_flags & O_ACCMODE)); if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -146,22 +834,29 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - void *mem; - if (!dvbdev->readers) { mutex_unlock(&dmxdev->mutex); return -EBUSY; } - mem = vmalloc(DVR_BUFFER_SIZE); + mem = vmalloc_user(DVR_BUFFER_SIZE); if (!mem) { mutex_unlock(&dmxdev->mutex); return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); - dvbdev->readers--; - } + dvb_dmxdev_flush_events(&dmxdev->dvr_output_events); + dmxdev->dvr_output_events.event_mask.disable_mask = 0; + dmxdev->dvr_output_events.event_mask.no_wakeup_mask = 0; + dmxdev->dvr_output_events.event_mask.wakeup_threshold = 1; + dmxdev->dvr_feeds_count = 0; + dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL; + memset(&dmxdev->dvr_buff_dma_info, 0, + sizeof(dmxdev->dvr_buff_dma_info)); - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + dvbdev->readers--; + } else if (!dvbdev->writers) { + dmxdev->dvr_in_exit = 0; + dmxdev->dvr_processing_input = 0; dmxdev->dvr_orig_fe = dmxdev->demux->frontend; if (!dmxdev->demux->write) { @@ -175,9 +870,52 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) mutex_unlock(&dmxdev->mutex); return -EINVAL; } + + mem = vmalloc_user(DVR_BUFFER_SIZE); + if (!mem) { + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } + dmxdev->demux->disconnect_frontend(dmxdev->demux); dmxdev->demux->connect_frontend(dmxdev->demux, front); + dmxdev->dvr_input_buffer_mode = DMX_BUFFER_MODE_INTERNAL; + + dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, + mem, + DVR_BUFFER_SIZE); + + memset(&dmxdev->demux->dvr_input.buff_dma_info, 0, + sizeof(struct ion_dma_buff_info)); + dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer; + dmxdev->demux->dvr_input_protected = 0; + mem = vmalloc(DVR_CMDS_BUFFER_SIZE); + if (!mem) { + vfree(dmxdev->dvr_input_buffer.data); + dmxdev->dvr_input_buffer.data = NULL; + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } + dvb_ringbuffer_init(&dmxdev->dvr_cmd_buffer, mem, + DVR_CMDS_BUFFER_SIZE); + dvbdev->writers--; + + dmxdev->dvr_input_thread = + kthread_run( + dvr_input_thread_entry, + (void *)dmxdev, + "dvr_input"); + + if (IS_ERR(dmxdev->dvr_input_thread)) { + vfree(dmxdev->dvr_input_buffer.data); + vfree(dmxdev->dvr_cmd_buffer.data); + dmxdev->dvr_input_buffer.data = NULL; + dmxdev->dvr_cmd_buffer.data = NULL; + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } } + dvbdev->users++; mutex_unlock(&dmxdev->mutex); return 0; @@ -190,11 +928,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) mutex_lock(&dmxdev->mutex); - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - dmxdev->demux->disconnect_frontend(dmxdev->demux); - dmxdev->demux->connect_frontend(dmxdev->demux, - dmxdev->dvr_orig_fe); - } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { dvbdev->readers++; if (dmxdev->dvr_buffer.data) { @@ -204,140 +937,1657 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) spin_lock_irq(&dmxdev->lock); dmxdev->dvr_buffer.data = NULL; spin_unlock_irq(&dmxdev->lock); - vfree(mem); + wake_up_all(&dmxdev->dvr_buffer.queue); + + if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL) + vfree(mem); } - } - /* TODO */ - dvbdev->users--; - if (dvbdev->users == 1 && dmxdev->exit == 1) { - mutex_unlock(&dmxdev->mutex); - wake_up(&dvbdev->wait_queue); - } else - mutex_unlock(&dmxdev->mutex); + + if ((dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_EXTERNAL) && + dmxdev->dvr_buff_dma_info.va) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdev->dvr_buff_dma_info); + } + } else { + int i; + + spin_lock(&dmxdev->dvr_in_lock); + dmxdev->dvr_in_exit = 1; + spin_unlock(&dmxdev->dvr_in_lock); + + wake_up_all(&dmxdev->dvr_cmd_buffer.queue); + + /* + * There might be dmx filters reading now from DVR + * device, in PULL mode, they might be also stalled + * on output, signal to them that DVR is exiting. + */ + if (dmxdev->playback_mode == DMX_PB_MODE_PULL) { + wake_up_all(&dmxdev->dvr_buffer.queue); + + for (i = 0; i < dmxdev->filternum; i++) + if (dmxdev->filter[i].state == DMXDEV_STATE_GO) + wake_up_all( + &dmxdev->filter[i].buffer.queue); + } + + /* notify kernel demux that we are canceling */ + if (dmxdev->demux->write_cancel) + dmxdev->demux->write_cancel(dmxdev->demux); + + /* + * Now stop dvr-input thread so that no one + * would process data from dvr input buffer any more + * before it gets freed. + */ + kthread_stop(dmxdev->dvr_input_thread); + + dvbdev->writers++; + dmxdev->demux->disconnect_frontend(dmxdev->demux); + dmxdev->demux->connect_frontend(dmxdev->demux, + dmxdev->dvr_orig_fe); + + if (dmxdev->dvr_input_buffer.data) { + void *mem = dmxdev->dvr_input_buffer.data; + /* + * Ensure all the operations on the DVR input buffer + * are completed before it gets freed. + */ + mb(); + spin_lock_irq(&dmxdev->dvr_in_lock); + dmxdev->dvr_input_buffer.data = NULL; + spin_unlock_irq(&dmxdev->dvr_in_lock); + + if (dmxdev->dvr_input_buffer_mode == + DMX_BUFFER_MODE_INTERNAL) + vfree(mem); + } + + if ((dmxdev->dvr_input_buffer_mode == + DMX_BUFFER_MODE_EXTERNAL) && + (dmxdev->demux->dvr_input.buff_dma_info.va)) { + if (!dmxdev->demux->dvr_input_protected) + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdev->demux->dvr_input.buff_dma_info); + } + + if (dmxdev->dvr_cmd_buffer.data) { + void *mem = dmxdev->dvr_cmd_buffer.data; + /* + * Ensure all the operations on the DVR command buffer + * are completed before it gets freed. + */ + mb(); + spin_lock_irq(&dmxdev->dvr_in_lock); + dmxdev->dvr_cmd_buffer.data = NULL; + spin_unlock_irq(&dmxdev->dvr_in_lock); + vfree(mem); + } + } + /* TODO */ + dvbdev->users--; + if (dvbdev->users == 1 && dmxdev->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + mutex_unlock(&dmxdev->mutex); + wake_up(&dvbdev->wait_queue); + } else + mutex_unlock(&dmxdev->mutex); + + return 0; +} + + +static int dvb_dvr_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct dvb_device *dvbdev = filp->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + struct dvb_ringbuffer *buffer; + enum dmx_buffer_mode buffer_mode; + int vma_size; + int buffer_size; + int ret; + + if (((filp->f_flags & O_ACCMODE) == O_RDONLY) && + (vma->vm_flags & VM_WRITE)) + return -EINVAL; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (dmxdev->exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + + if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { + buffer = &dmxdev->dvr_buffer; + buffer_mode = dmxdev->dvr_buffer_mode; + } else { + buffer = &dmxdev->dvr_input_buffer; + buffer_mode = dmxdev->dvr_input_buffer_mode; + } + + if (buffer_mode == DMX_BUFFER_MODE_EXTERNAL) { + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + vma_size = vma->vm_end - vma->vm_start; + + /* Make sure requested mapping is not larger than buffer size */ + buffer_size = buffer->size + (PAGE_SIZE-1); + buffer_size = buffer_size & ~(PAGE_SIZE-1); + + if (vma_size != buffer_size) { + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + ret = remap_vmalloc_range(vma, buffer->data, 0); + if (ret) { + mutex_unlock(&dmxdev->mutex); + return ret; + } + + vma->vm_flags |= VM_DONTDUMP; + vma->vm_flags |= VM_DONTEXPAND; + + mutex_unlock(&dmxdev->mutex); + return ret; +} + +static void dvb_dvr_queue_data_feed(struct dmxdev *dmxdev, size_t count) +{ + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + struct dvr_command *dvr_cmd; + int last_dvr_cmd; + + spin_lock(&dmxdev->dvr_in_lock); + + /* Peek at the last DVR command queued, try to coalesce FEED commands */ + if (dvb_ringbuffer_avail(cmdbuf) >= sizeof(*dvr_cmd)) { + last_dvr_cmd = cmdbuf->pwrite - sizeof(*dvr_cmd); + if (last_dvr_cmd < 0) + last_dvr_cmd += cmdbuf->size; + + dvr_cmd = (struct dvr_command *)&cmdbuf->data[last_dvr_cmd]; + if (dvr_cmd->type == DVR_DATA_FEED_CMD) { + dvr_cmd->cmd.data_feed_count += count; + spin_unlock(&dmxdev->dvr_in_lock); + return; + } + } + + /* + * We assume command buffer is large enough so that overflow should not + * happen. Overflow to the command buffer means data previously written + * to the input buffer is 'orphan' - does not have a matching FEED + * command. Issue a warning if this ever happens. + * Orphan data might still be processed if EOS is issued. + */ + if (dvb_ringbuffer_free(cmdbuf) < sizeof(*dvr_cmd)) { + pr_err("%s: DVR command buffer overflow\n", __func__); + spin_unlock(&dmxdev->dvr_in_lock); + return; + } + + dvr_cmd = (struct dvr_command *)&cmdbuf->data[cmdbuf->pwrite]; + dvr_cmd->type = DVR_DATA_FEED_CMD; + dvr_cmd->cmd.data_feed_count = count; + DVB_RINGBUFFER_PUSH(cmdbuf, sizeof(*dvr_cmd)); + spin_unlock(&dmxdev->dvr_in_lock); + + wake_up_all(&cmdbuf->queue); +} + +static int dvb_dvr_external_input_only(struct dmxdev *dmxdev) +{ + struct dmx_caps caps; + int is_external_only; + int flags; + size_t tsp_size; + + if (dmxdev->demux->get_tsp_size) + tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux); + else + tsp_size = 188; + + /* + * For backward compatibility, default assumes that + * external only buffers are not supported. + */ + flags = 0; + if (dmxdev->demux->get_caps) { + dmxdev->demux->get_caps(dmxdev->demux, &caps); + + if (tsp_size == 188) + flags = caps.playback_188_tsp.flags; + else + flags = caps.playback_192_tsp.flags; + } + + if (!(flags & DMX_BUFFER_INTERNAL_SUPPORT) && + (flags & DMX_BUFFER_EXTERNAL_SUPPORT)) + is_external_only = 1; + else + is_external_only = 0; + + return is_external_only; +} + +static int dvb_dvr_verify_buffer_size(struct dmxdev *dmxdev, + unsigned int f_flags, + unsigned long size) +{ + struct dmx_caps caps; + int tsp_size; + + if (!dmxdev->demux->get_caps) + return 1; + + if (dmxdev->demux->get_tsp_size) + tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux); + else + tsp_size = 188; + + dmxdev->demux->get_caps(dmxdev->demux, &caps); + if ((f_flags & O_ACCMODE) == O_RDONLY) + return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size, + caps.recording_188_tsp.max_size, + caps.recording_188_tsp.size_alignment)) || + (tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size, + caps.recording_192_tsp.max_size, + caps.recording_192_tsp.size_alignment)); + + return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size, + caps.playback_188_tsp.max_size, + caps.playback_188_tsp.size_alignment)) || + (tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size, + caps.playback_192_tsp.max_size, + caps.playback_192_tsp.size_alignment)); +} + +static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer; + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + int ret; + size_t todo; + ssize_t free_space; + + if (!dmxdev->demux->write) + return -EOPNOTSUPP; + + if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags, src->size) || + ((file->f_flags & O_ACCMODE) == O_RDONLY) || + !src->data || !cmdbuf->data || + (dvb_dvr_external_input_only(dmxdev) && + (dmxdev->dvr_input_buffer_mode == DMX_BUFFER_MODE_INTERNAL))) + return -EINVAL; + + if ((file->f_flags & O_NONBLOCK) && + (dvb_ringbuffer_free(src) == 0)) + return -EWOULDBLOCK; + + ret = 0; + for (todo = count; todo > 0; todo -= ret) { + ret = wait_event_interruptible(src->queue, + (dvb_ringbuffer_free(src)) || + !src->data || !cmdbuf->data || + (src->error != 0) || dmxdev->dvr_in_exit); + + if (ret < 0) + return ret; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if ((!src->data) || (!cmdbuf->data)) { + mutex_unlock(&dmxdev->mutex); + return 0; + } + + if (dmxdev->exit || dmxdev->dvr_in_exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + + if (src->error) { + ret = src->error; + dvb_ringbuffer_flush(src); + mutex_unlock(&dmxdev->mutex); + wake_up_all(&src->queue); + return ret; + } + + free_space = dvb_ringbuffer_free(src); + + if (free_space > todo) + free_space = todo; + + ret = dvb_ringbuffer_write_user(src, buf, free_space); + + if (ret < 0) { + mutex_unlock(&dmxdev->mutex); + return ret; + } + + buf += ret; + + dvb_dvr_queue_data_feed(dmxdev, ret); + + mutex_unlock(&dmxdev->mutex); + } + + return (count - todo) ? (count - todo) : ret; +} + +static int dvb_dmxdev_flush_data(struct dmxdev_filter *filter, size_t length) +{ + int ret = 0; + unsigned long flags; + + struct dvb_ringbuffer *buffer = &filter->buffer; + struct dmxdev_events_queue *events = &filter->events; + + if (filter->type == DMXDEV_TYPE_PES && + filter->params.pes.output == DMX_OUT_TS_TAP) { + buffer = &filter->dev->dvr_buffer; + events = &filter->dev->dvr_output_events; + } + + /* + * Drop 'length' pending data bytes from the ringbuffer and update + * event queue accordingly, similarly to dvb_dmxdev_release_data(). + */ + spin_lock_irqsave(&filter->dev->lock, flags); + DVB_RINGBUFFER_SKIP(buffer, length); + buffer->error = 0; + dvb_dmxdev_flush_events(events); + events->current_event_start_offset = buffer->pwrite; + spin_unlock_irqrestore(&filter->dev->lock, flags); + + if (filter->type == DMXDEV_TYPE_PES) { + struct dmxdev_feed *feed; + + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + + if (feed->ts->flush_buffer) + return feed->ts->flush_buffer(feed->ts, length); + } else if (filter->type == DMXDEV_TYPE_SEC && + filter->feed.sec.feed->flush_buffer) { + return filter->feed.sec.feed->flush_buffer( + filter->feed.sec.feed, length); + } + + return ret; +} + +static inline void dvb_dmxdev_auto_flush_buffer(struct dmxdev_filter *filter, + struct dvb_ringbuffer *buf) +{ + size_t flush_len; + + /* + * When buffer overflowed, demux-dev marked the buffer in + * error state. If auto-flush is enabled discard current + * pending data in buffer. + */ + if (overflow_auto_flush) { + flush_len = dvb_ringbuffer_avail(buf); + dvb_dmxdev_flush_data(filter, flush_len); + } +} + +static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + ssize_t res; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + unsigned long flags; + + if (dmxdev->exit) + return -ENODEV; + + if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags, + dmxdev->dvr_buffer.size)) + return -EINVAL; + + res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + + if (res > 0) { + dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res); + spin_lock_irqsave(&dmxdev->lock, flags); + dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res); + spin_unlock_irqrestore(&dmxdev->lock, flags); + + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdev->dvr_buffer.queue); + } else if (res == -EOVERFLOW) { + dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, + &dmxdev->dvr_buffer); + } + + return res; +} + +/* + * dvb_dvr_push_oob_cmd + * + * Note: this function assume dmxdev->mutex was taken, so command buffer cannot + * be released during its operation. + */ +static int dvb_dvr_push_oob_cmd(struct dmxdev *dmxdev, unsigned int f_flags, + struct dmx_oob_command *cmd) +{ + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + struct dvr_command *dvr_cmd; + + if ((f_flags & O_ACCMODE) == O_RDONLY || + dmxdev->source < DMX_SOURCE_DVR0) + return -EPERM; + + if (dvb_ringbuffer_free(cmdbuf) < sizeof(*dvr_cmd)) + return -ENOMEM; + + dvr_cmd = (struct dvr_command *)&cmdbuf->data[cmdbuf->pwrite]; + dvr_cmd->type = DVR_OOB_CMD; + dvr_cmd->cmd.oobcmd = *cmd; + DVB_RINGBUFFER_PUSH(cmdbuf, sizeof(*dvr_cmd)); + wake_up_all(&cmdbuf->queue); + + return 0; +} + +static int dvb_dvr_flush_buffer(struct dmxdev *dmxdev, unsigned int f_flags) +{ + size_t flush_len; + int ret; + + if ((f_flags & O_ACCMODE) != O_RDONLY) + return -EINVAL; + + flush_len = dvb_ringbuffer_avail(&dmxdev->dvr_buffer); + ret = dvb_dmxdev_flush_data(dmxdev->dvr_feed, flush_len); + + return ret; +} + +static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, + unsigned int f_flags, + unsigned long size) +{ + struct dvb_ringbuffer *buf; + void *newmem; + void *oldmem; + spinlock_t *lock; + enum dmx_buffer_mode buffer_mode; + + pr_debug("function : %s\n", __func__); + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + buffer_mode = dmxdev->dvr_buffer_mode; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + buffer_mode = dmxdev->dvr_input_buffer_mode; + } + + if (buf->size == size) + return 0; + if (!size || (buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + + newmem = vmalloc_user(size); + if (!newmem) + return -ENOMEM; + + oldmem = buf->data; + + spin_lock_irq(lock); + + if (((f_flags & O_ACCMODE) != O_RDONLY) && + (dmxdev->dvr_processing_input)) { + spin_unlock_irq(lock); + vfree(oldmem); + return -EBUSY; + } + + buf->data = newmem; + buf->size = size; + + /* reset and not flush in case the buffer shrinks */ + dvb_ringbuffer_reset(buf); + + spin_unlock_irq(lock); + + vfree(oldmem); + + return 0; +} + +static int dvb_dvr_set_buffer_mode(struct dmxdev *dmxdev, + unsigned int f_flags, enum dmx_buffer_mode mode) +{ + struct dvb_ringbuffer *buf; + spinlock_t *lock; + enum dmx_buffer_mode *buffer_mode; + struct ion_dma_buff_info *dma_info; + void *oldmem; + int *is_protected; + + if ((mode != DMX_BUFFER_MODE_INTERNAL) && + (mode != DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + + if ((mode == DMX_BUFFER_MODE_EXTERNAL) && + (!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer)) + return -EINVAL; + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + buffer_mode = &dmxdev->dvr_buffer_mode; + dma_info = &dmxdev->dvr_buff_dma_info; + is_protected = NULL; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + buffer_mode = &dmxdev->dvr_input_buffer_mode; + dma_info = &dmxdev->demux->dvr_input.buff_dma_info; + is_protected = &dmxdev->demux->dvr_input_protected; + } + + if (mode == *buffer_mode) + return 0; + + oldmem = buf->data; + spin_lock_irq(lock); + buf->data = NULL; + spin_unlock_irq(lock); + + *buffer_mode = mode; + + if (mode == DMX_BUFFER_MODE_INTERNAL) { + /* switched from external to internal */ + if (dma_info->dmabuf) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + dma_info); + } + + if (is_protected) + *is_protected = 0; + + /* set default internal buffer */ + dvb_dvr_set_buffer_size(dmxdev, f_flags, DVR_BUFFER_SIZE); + } else if (oldmem) { + /* switched from internal to external */ + vfree(oldmem); + } + + return 0; +} + +static int dvb_dvr_set_buffer(struct dmxdev *dmxdev, + unsigned int f_flags, struct dmx_buffer *dmx_buffer) +{ + struct dvb_ringbuffer *buf; + spinlock_t *lock; + enum dmx_buffer_mode buffer_mode; + struct ion_dma_buff_info *dma_info; + void *newmem; + void *oldmem = NULL; + int *is_protected; + struct dmx_caps caps; + + if (dmxdev->demux->get_caps) + dmxdev->demux->get_caps(dmxdev->demux, &caps); + else + caps.caps = 0; + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + buffer_mode = dmxdev->dvr_buffer_mode; + dma_info = &dmxdev->dvr_buff_dma_info; + is_protected = NULL; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + buffer_mode = dmxdev->dvr_input_buffer_mode; + dma_info = &dmxdev->demux->dvr_input.buff_dma_info; + is_protected = &dmxdev->demux->dvr_input_protected; + if (!(caps.caps & DMX_CAP_SECURED_INPUT_PLAYBACK) && + dmx_buffer->is_protected) + return -EINVAL; + } + + if (!dmx_buffer->size || + (buffer_mode == DMX_BUFFER_MODE_INTERNAL)) + return -EINVAL; + + if (dmxdev->demux->dvr_input.buff_dma_info.va) + oldmem = dmxdev->demux->dvr_input.buff_dma_info.va; + + /* + * Protected buffer is relevant only for DVR input buffer + * when DVR device is opened for write. In such case, + * buffer is mapped only if the buffer is not protected one. + */ + if (!is_protected || !dmx_buffer->is_protected) { + if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer, + dma_info, &newmem)) + return -ENOMEM; + } else { + newmem = NULL; + } + + spin_lock_irq(lock); + buf->data = newmem; + buf->size = dmx_buffer->size; + if (is_protected) + *is_protected = dmx_buffer->is_protected; + dvb_ringbuffer_reset(buf); + spin_unlock_irq(lock); + + if (oldmem) + dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem); + + return 0; +} + +static int dvb_dvr_get_event(struct dmxdev *dmxdev, + unsigned int f_flags, + struct dmx_filter_event *event) +{ + int res = 0; + + if (!((f_flags & O_ACCMODE) == O_RDONLY)) + return -EINVAL; + + spin_lock_irq(&dmxdev->lock); + + if (dmxdev->dvr_buffer.error == -EOVERFLOW) { + event->type = DMX_EVENT_BUFFER_OVERFLOW; + dmxdev->dvr_buffer.error = 0; + } else { + res = dvb_dmxdev_remove_event(&dmxdev->dvr_output_events, + event); + if (res) { + spin_unlock_irq(&dmxdev->lock); + return res; + } + } + + spin_unlock_irq(&dmxdev->lock); + + if (event->type == DMX_EVENT_BUFFER_OVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, + &dmxdev->dvr_buffer); + + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdev->dvr_buffer.queue); + + return res; +} + +static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev, + unsigned int f_flags, + struct dmx_buffer_status *dmx_buffer_status) +{ + struct dvb_ringbuffer *buf; + spinlock_t *lock; + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + } + + spin_lock_irq(lock); + + dmx_buffer_status->error = buf->error; + dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf); + dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf); + dmx_buffer_status->read_offset = buf->pread; + dmx_buffer_status->write_offset = buf->pwrite; + dmx_buffer_status->size = buf->size; + buf->error = 0; + + spin_unlock_irq(lock); + + if (dmx_buffer_status->error == -EOVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, buf); + + return 0; +} + +static int dvb_dvr_release_data(struct dmxdev *dmxdev, + unsigned int f_flags, + u32 bytes_count) +{ + ssize_t buff_fullness; + + if (!((f_flags & O_ACCMODE) == O_RDONLY)) + return -EINVAL; + + if (!bytes_count) + return 0; + + buff_fullness = dvb_ringbuffer_avail(&dmxdev->dvr_buffer); + + if (bytes_count > buff_fullness) + return -EINVAL; + + DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count); + + dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, bytes_count); + spin_lock_irq(&dmxdev->lock); + dvb_dmxdev_update_events(&dmxdev->dvr_output_events, bytes_count); + spin_unlock_irq(&dmxdev->lock); + + wake_up_all(&dmxdev->dvr_buffer.queue); + return 0; +} + +/* + * dvb_dvr_feed_data - Notify new data in DVR input buffer + * + * @dmxdev - demux device instance + * @f_flags - demux device file flag (access mode) + * @bytes_count - how many bytes were written to the input buffer + * + * Note: this function assume dmxdev->mutex was taken, so buffer cannot + * be released during its operation. + */ +static int dvb_dvr_feed_data(struct dmxdev *dmxdev, + unsigned int f_flags, + u32 bytes_count) +{ + ssize_t free_space; + struct dvb_ringbuffer *buffer = &dmxdev->dvr_input_buffer; + + if ((f_flags & O_ACCMODE) == O_RDONLY) + return -EINVAL; + + if (!bytes_count) + return 0; + + free_space = dvb_ringbuffer_free(buffer); + + if (bytes_count > free_space) + return -EINVAL; + + DVB_RINGBUFFER_PUSH(buffer, bytes_count); + + dvb_dvr_queue_data_feed(dmxdev, bytes_count); + + return 0; +} + +static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter + *dmxdevfilter, int state) +{ + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state = state; + spin_unlock_irq(&dmxdevfilter->dev->lock); +} + +static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, + unsigned long size) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + void *newmem; + void *oldmem; + + if (buf->size == size) + return 0; + if (!size || + (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + newmem = vmalloc_user(size); + if (!newmem) + return -ENOMEM; + + oldmem = buf->data; + + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = newmem; + buf->size = size; + + /* reset and not flush in case the buffer shrinks */ + dvb_ringbuffer_reset(buf); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + vfree(oldmem); + + return 0; +} + +static int dvb_dmxdev_set_buffer_mode(struct dmxdev_filter *dmxdevfilter, + enum dmx_buffer_mode mode) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + struct dmxdev *dmxdev = dmxdevfilter->dev; + void *oldmem; + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + if ((mode != DMX_BUFFER_MODE_INTERNAL) && + (mode != DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + + if ((mode == DMX_BUFFER_MODE_EXTERNAL) && + (!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer)) + return -EINVAL; + + if (mode == dmxdevfilter->buffer_mode) + return 0; + + oldmem = buf->data; + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = NULL; + spin_unlock_irq(&dmxdevfilter->dev->lock); + + dmxdevfilter->buffer_mode = mode; + + if (mode == DMX_BUFFER_MODE_INTERNAL) { + /* switched from external to internal */ + if (dmxdevfilter->buff_dma_info.va) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdevfilter->buff_dma_info); + } + } else if (oldmem) { + /* switched from internal to external */ + vfree(oldmem); + } + + return 0; +} + +static int dvb_dmxdev_set_buffer(struct dmxdev_filter *dmxdevfilter, + struct dmx_buffer *buffer) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + struct dmxdev *dmxdev = dmxdevfilter->dev; + void *newmem; + void *oldmem; + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + if ((!buffer->size) || + (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL)) + return -EINVAL; + + oldmem = dmxdevfilter->buff_dma_info.va; + if (oldmem) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdevfilter->buff_dma_info); + } + + + if (dmxdev->demux->map_buffer(dmxdev->demux, buffer, + &dmxdevfilter->buff_dma_info, &newmem)) + return -ENOMEM; + + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = newmem; + buf->size = buffer->size; + dvb_ringbuffer_reset(buf); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + return 0; +} + +static int dvb_dmxdev_set_tsp_out_format(struct dmxdev_filter *dmxdevfilter, + enum dmx_tsp_format_t dmx_tsp_format) +{ + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + if ((dmx_tsp_format > DMX_TSP_FORMAT_192_HEAD) || + (dmx_tsp_format < DMX_TSP_FORMAT_188)) + return -EINVAL; + + dmxdevfilter->dmx_tsp_format = dmx_tsp_format; + + return 0; +} + +static int dvb_dmxdev_set_decoder_buffer_size( + struct dmxdev_filter *dmxdevfilter, + unsigned long size) +{ + struct dmx_caps caps; + struct dmx_demux *demux = dmxdevfilter->dev->demux; + + if (demux->get_caps) { + demux->get_caps(demux, &caps); + if (!dvb_dmxdev_verify_buffer_size(size, caps.decoder.max_size, + caps.decoder.size_alignment)) + return -EINVAL; + } + + if (size == 0) + return -EINVAL; + + if (dmxdevfilter->decoder_buffers.buffers_size == size) + return 0; + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + /* + * In case decoder buffers were already set before to some external + * buffers, setting the decoder buffer size alone implies transition + * to internal buffer mode. + */ + dmxdevfilter->decoder_buffers.buffers_size = size; + dmxdevfilter->decoder_buffers.buffers_num = 0; + dmxdevfilter->decoder_buffers.is_linear = 0; + return 0; +} + +static int dvb_dmxdev_set_source(struct dmxdev_filter *dmxdevfilter, + dmx_source_t *source) +{ + int ret = 0; + struct dmxdev *dev; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) + return -EBUSY; + + dev = dmxdevfilter->dev; + if (dev->demux->set_source) + ret = dev->demux->set_source(dev->demux, source); + + if (!ret) + dev->source = *source; + + return ret; +} + +static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter, + int cookie) +{ + struct dmxdev_feed *feed; + + if (dmxdevfilter->state != DMXDEV_STATE_GO || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + (dmxdevfilter->params.pes.output != DMX_OUT_DECODER) || + (dmxdevfilter->events.event_mask.disable_mask & + DMX_EVENT_NEW_ES_DATA)) + return -EPERM; + + /* Only one feed should be in the list in case of decoder */ + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + if (feed && feed->ts && feed->ts->reuse_decoder_buffer) + return feed->ts->reuse_decoder_buffer(feed->ts, cookie); + + return -ENODEV; +} + +static int dvb_dmxdev_set_event_mask(struct dmxdev_filter *dmxdevfilter, + struct dmx_events_mask *event_mask) +{ + if (!event_mask || + (event_mask->wakeup_threshold >= DMX_EVENT_QUEUE_SIZE)) + return -EINVAL; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) + return -EBUSY; + + /* + * Overflow event is not allowed to be masked. + * This is because if overflow occurs, demux stops outputting data + * until user is notified. If user is using events to read the data, + * the overflow event must be always enabled or otherwise we would + * never recover from overflow state. + */ + event_mask->disable_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW; + event_mask->no_wakeup_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW; + + dmxdevfilter->events.event_mask = *event_mask; + + return 0; +} + +static int dvb_dmxdev_get_event_mask(struct dmxdev_filter *dmxdevfilter, + struct dmx_events_mask *event_mask) +{ + if (!event_mask) + return -EINVAL; + + *event_mask = dmxdevfilter->events.event_mask; return 0; } -static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter, + struct dmx_indexing_params *idx_params) +{ + int found_pid; + struct dmxdev_feed *feed; + struct dmxdev_feed *ts_feed = NULL; + struct dmx_caps caps; + int ret = 0; + + if (!dmxdevfilter->dev->demux->get_caps) + return -EINVAL; + + dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps); + + if (!idx_params || + !(caps.caps & DMX_CAP_VIDEO_INDEXING) || + (dmxdevfilter->state < DMXDEV_STATE_SET) || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) && + (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP))) + return -EINVAL; + + if (idx_params->enable && !idx_params->types) + return -EINVAL; + + found_pid = 0; + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + if (feed->pid == idx_params->pid) { + found_pid = 1; + ts_feed = feed; + ts_feed->idx_params = *idx_params; + if ((dmxdevfilter->state == DMXDEV_STATE_GO) && + ts_feed->ts->set_idx_params) + ret = ts_feed->ts->set_idx_params( + ts_feed->ts, idx_params); + break; + } + } + + if (!found_pid) + return -EINVAL; + + return ret; +} + +static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter, + struct dmx_scrambling_bits *scrambling_bits) +{ + struct dmxdev_feed *feed; + + if (!scrambling_bits || + (filter->state != DMXDEV_STATE_GO)) + return -EINVAL; + + if (filter->type == DMXDEV_TYPE_SEC) { + if (filter->feed.sec.feed->get_scrambling_bits) + return filter->feed.sec.feed->get_scrambling_bits( + filter->feed.sec.feed, + &scrambling_bits->value); + return -EINVAL; + } + + list_for_each_entry(feed, &filter->feed.ts, next) { + if (feed->pid == scrambling_bits->pid) { + if (feed->ts->get_scrambling_bits) + return feed->ts->get_scrambling_bits(feed->ts, + &scrambling_bits->value); + return -EINVAL; + } + } + + return -EINVAL; +} + +static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker) +{ + struct ts_insertion_buffer *ts_buffer = + container_of(to_delayed_work(worker), + struct ts_insertion_buffer, dwork); + struct dmxdev_feed *feed; + size_t free_bytes; + struct dmx_ts_feed *ts; + + mutex_lock(&ts_buffer->dmxdevfilter->mutex); + + if (ts_buffer->abort || + (ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) { + mutex_unlock(&ts_buffer->dmxdevfilter->mutex); + return; + } + + feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + ts = feed->ts; + free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer); + + mutex_unlock(&ts_buffer->dmxdevfilter->mutex); + + if (ts_buffer->size < free_bytes) + ts->ts_insertion_insert_buffer(ts, + ts_buffer->buffer, ts_buffer->size); + + if (ts_buffer->repetition_time && !ts_buffer->abort) + schedule_delayed_work(&ts_buffer->dwork, + msecs_to_jiffies(ts_buffer->repetition_time)); +} + +static void dvb_dmxdev_queue_ts_insertion( + struct ts_insertion_buffer *ts_buffer) +{ + size_t tsp_size; + + if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188) + tsp_size = 188; + else + tsp_size = 192; + + if (ts_buffer->size % tsp_size) { + pr_err("%s: Wrong buffer alignment, size=%zu, tsp_size=%zu\n", + __func__, ts_buffer->size, tsp_size); + return; + } + + ts_buffer->abort = 0; + schedule_delayed_work(&ts_buffer->dwork, 0); +} + +static void dvb_dmxdev_cancel_ts_insertion( + struct ts_insertion_buffer *ts_buffer) +{ + /* + * This function assumes it is called while mutex + * of demux filter is taken. Since work in workqueue + * captures the filter's mutex to protect against the DB, + * mutex needs to be released before waiting for the work + * to get finished otherwise work in workqueue will + * never be finished. + */ + if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) { + pr_err("%s: mutex is not locked!\n", __func__); + return; + } + + ts_buffer->abort = 1; + + mutex_unlock(&ts_buffer->dmxdevfilter->mutex); + cancel_delayed_work_sync(&ts_buffer->dwork); + mutex_lock(&ts_buffer->dmxdevfilter->mutex); +} + +static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter, + struct dmx_set_ts_insertion *params) +{ + int ret = 0; + int first_buffer; + struct dmxdev_feed *feed; + struct ts_insertion_buffer *ts_buffer; + struct dmx_caps caps; + + if (!dmxdevfilter->dev->demux->get_caps) + return -EINVAL; + + dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps); + + if (!params || + !params->size || + !(caps.caps & DMX_CAP_TS_INSERTION) || + (dmxdevfilter->state < DMXDEV_STATE_SET) || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) && + (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP))) + return -EINVAL; + + ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer)); + if (!ts_buffer) + return -ENOMEM; + + ts_buffer->buffer = vmalloc(params->size); + if (!ts_buffer->buffer) { + vfree(ts_buffer); + return -ENOMEM; + } + + if (copy_from_user(ts_buffer->buffer, + params->ts_packets, params->size)) { + vfree(ts_buffer->buffer); + vfree(ts_buffer); + return -EFAULT; + } + + if (params->repetition_time && + params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME) + params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME; + + ts_buffer->size = params->size; + ts_buffer->identifier = params->identifier; + ts_buffer->repetition_time = params->repetition_time; + ts_buffer->dmxdevfilter = dmxdevfilter; + INIT_DELAYED_WORK(&ts_buffer->dwork, dvb_dmxdev_ts_insertion_work); + + first_buffer = list_empty(&dmxdevfilter->insertion_buffers); + list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers); + + if (dmxdevfilter->state != DMXDEV_STATE_GO) + return 0; + + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + + if (first_buffer && feed->ts->ts_insertion_init) + ret = feed->ts->ts_insertion_init(feed->ts); + + if (!ret) { + dvb_dmxdev_queue_ts_insertion(ts_buffer); + } else { + list_del(&ts_buffer->next); + vfree(ts_buffer->buffer); + vfree(ts_buffer); + } + + return ret; +} + +static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter, + struct dmx_abort_ts_insertion *params) +{ + int ret = 0; + int found_buffer; + struct dmxdev_feed *feed; + struct ts_insertion_buffer *ts_buffer, *tmp; + struct dmx_caps caps; + + if (!dmxdevfilter->dev->demux->get_caps) + return -EINVAL; + + dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps); + + if (!params || + !(caps.caps & DMX_CAP_TS_INSERTION) || + (dmxdevfilter->state < DMXDEV_STATE_SET) || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) && + (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP))) + return -EINVAL; + + found_buffer = 0; + list_for_each_entry_safe(ts_buffer, tmp, + &dmxdevfilter->insertion_buffers, next) { + if (ts_buffer->identifier == params->identifier) { + list_del(&ts_buffer->next); + found_buffer = 1; + break; + } + } + + if (!found_buffer) + return -EINVAL; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) { + dvb_dmxdev_cancel_ts_insertion(ts_buffer); + if (list_empty(&dmxdevfilter->insertion_buffers)) { + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + if (feed->ts->ts_insertion_terminate) + ret = feed->ts->ts_insertion_terminate( + feed->ts); + } + } + + vfree(ts_buffer->buffer); + vfree(ts_buffer); + + return ret; +} + +static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter, + int required_space, int wait) +{ + struct dmxdev_filter *dmxdevfilter = filter->priv; + struct dvb_ringbuffer *src; + struct dmxdev_events_queue *events; + int ret; + + if (!dmxdevfilter) { + pr_err("%s: NULL demux filter object!\n", __func__); + return -ENODEV; + } + + if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) { + src = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + } else { + src = &dmxdevfilter->dev->dvr_buffer; + events = &dmxdevfilter->dev->dvr_output_events; + } + + do { + ret = 0; + + if (dmxdevfilter->dev->dvr_in_exit) + return -ENODEV; + + spin_lock(&dmxdevfilter->dev->lock); + + if ((!src->data) || + (dmxdevfilter->state != DMXDEV_STATE_GO)) + ret = -EINVAL; + else if (src->error) + ret = src->error; + + if (ret) { + spin_unlock(&dmxdevfilter->dev->lock); + return ret; + } + + if ((required_space <= dvb_ringbuffer_free(src)) && + (!dvb_dmxdev_events_is_full(events))) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + spin_unlock(&dmxdevfilter->dev->lock); + + if (!wait) + return -ENOSPC; + + ret = wait_event_interruptible(src->queue, + (!src->data) || + ((dvb_ringbuffer_free(src) >= required_space) && + (!dvb_dmxdev_events_is_full(events))) || + (src->error != 0) || + (dmxdevfilter->state != DMXDEV_STATE_GO) || + dmxdevfilter->dev->dvr_in_exit); + + if (ret < 0) + return ret; + } while (1); +} + +static int dvb_dmxdev_sec_fullness_callback( + struct dmx_section_filter *filter, + int required_space, int wait) +{ + struct dmxdev_filter *dmxdevfilter = filter->priv; + struct dvb_ringbuffer *src; + struct dmxdev_events_queue *events; + int ret; + + if (!dmxdevfilter) { + pr_err("%s: NULL demux filter object!\n", __func__); + return -ENODEV; + } + + src = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + + do { + ret = 0; + + if (dmxdevfilter->dev->dvr_in_exit) + return -ENODEV; + + spin_lock(&dmxdevfilter->dev->lock); + + if ((!src->data) || + (dmxdevfilter->state != DMXDEV_STATE_GO)) + ret = -EINVAL; + else if (src->error) + ret = src->error; + + if (ret) { + spin_unlock(&dmxdevfilter->dev->lock); + return ret; + } + + if ((required_space <= dvb_ringbuffer_free(src)) && + (!dvb_dmxdev_events_is_full(events))) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + spin_unlock(&dmxdevfilter->dev->lock); + + if (!wait) + return -ENOSPC; + + ret = wait_event_interruptible(src->queue, + (!src->data) || + ((dvb_ringbuffer_free(src) >= required_space) && + (!dvb_dmxdev_events_is_full(events))) || + (src->error != 0) || + (dmxdevfilter->state != DMXDEV_STATE_GO) || + dmxdevfilter->dev->dvr_in_exit); + + if (ret < 0) + return ret; + } while (1); +} + +static int dvb_dmxdev_set_playback_mode(struct dmxdev_filter *dmxdevfilter, + enum dmx_playback_mode_t playback_mode) { - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - int ret; + struct dmxdev *dmxdev = dmxdevfilter->dev; + struct dmx_caps caps; - if (!dmxdev->demux->write) - return -EOPNOTSUPP; - if ((file->f_flags & O_ACCMODE) != O_WRONLY) + if (dmxdev->demux->get_caps) + dmxdev->demux->get_caps(dmxdev->demux, &caps); + else + caps.caps = 0; + + if ((playback_mode != DMX_PB_MODE_PUSH) && + (playback_mode != DMX_PB_MODE_PULL)) return -EINVAL; - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } - ret = dmxdev->demux->write(dmxdev->demux, buf, count); - mutex_unlock(&dmxdev->mutex); - return ret; + if (dmxdev->demux->set_playback_mode == NULL) + return -EINVAL; + + if (((dmxdev->source < DMX_SOURCE_DVR0) || + !(caps.caps & DMX_CAP_PULL_MODE)) && + (playback_mode == DMX_PB_MODE_PULL)) + return -EPERM; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) + return -EBUSY; + + dmxdev->playback_mode = playback_mode; + + return dmxdev->demux->set_playback_mode( + dmxdev->demux, + dmxdev->playback_mode, + dvb_dmxdev_ts_fullness_callback, + dvb_dmxdev_sec_fullness_callback); } -static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) +static int dvb_dmxdev_flush_buffer(struct dmxdev_filter *filter) { - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; + size_t flush_len; + int ret; - if (dmxdev->exit) - return -ENODEV; + if (filter->state != DMXDEV_STATE_GO) + return -EINVAL; + + flush_len = dvb_ringbuffer_avail(&filter->buffer); + ret = dvb_dmxdev_flush_data(filter, flush_len); - return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); + return ret; } -static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, - unsigned long size) +static int dvb_dmxdev_get_buffer_status( + struct dmxdev_filter *dmxdevfilter, + struct dmx_buffer_status *dmx_buffer_status) { - struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; - void *newmem; - void *oldmem; + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; - dprintk("%s\n", __func__); + /* + * Note: Taking the dmxdevfilter->dev->lock spinlock is required only + * when getting the status of the Demux-userspace data ringbuffer . + * In case we are getting the status of a decoder buffer, taking this + * spinlock is not required and in fact might lead to a deadlock. + */ + if ((dmxdevfilter->type == DMXDEV_TYPE_PES) && + (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) { + struct dmxdev_feed *feed; + int ret; + + /* Only one feed should be in the list in case of decoder */ + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + + /* Ask for status of decoder's buffer from underlying HW */ + if (feed->ts->get_decoder_buff_status) + ret = feed->ts->get_decoder_buff_status( + feed->ts, + dmx_buffer_status); + else + ret = -ENODEV; - if (buf->size == size) - return 0; - if (!size) - return -EINVAL; + return ret; + } - newmem = vmalloc(size); - if (!newmem) - return -ENOMEM; + spin_lock_irq(&dmxdevfilter->dev->lock); - oldmem = buf->data; + if (!buf->data) { + spin_unlock_irq(&dmxdevfilter->dev->lock); + return -EINVAL; + } - spin_lock_irq(&dmxdev->lock); - buf->data = newmem; - buf->size = size; + dmx_buffer_status->error = buf->error; + dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf); + dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf); + dmx_buffer_status->read_offset = buf->pread; + dmx_buffer_status->write_offset = buf->pwrite; + dmx_buffer_status->size = buf->size; + buf->error = 0; - /* reset and not flush in case the buffer shrinks */ - dvb_ringbuffer_reset(buf); - spin_unlock_irq(&dmxdev->lock); + spin_unlock_irq(&dmxdevfilter->dev->lock); - vfree(oldmem); + if (dmx_buffer_status->error == -EOVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdevfilter, buf); return 0; } -static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter - *dmxdevfilter, int state) +static int dvb_dmxdev_release_data(struct dmxdev_filter *dmxdevfilter, + u32 bytes_count) { + ssize_t buff_fullness; + + if (!dmxdevfilter->buffer.data) + return -EINVAL; + + if (!bytes_count) + return 0; + + buff_fullness = dvb_ringbuffer_avail(&dmxdevfilter->buffer); + + if (bytes_count > buff_fullness) + return -EINVAL; + + DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count); + + dvb_dmxdev_notify_data_read(dmxdevfilter, bytes_count); spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state = state; + dvb_dmxdev_update_events(&dmxdevfilter->events, bytes_count); spin_unlock_irq(&dmxdevfilter->dev->lock); + + wake_up_all(&dmxdevfilter->buffer.queue); + + return 0; } -static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, - unsigned long size) +static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter, + struct dmx_filter_event *event) { - struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; - void *newmem; - void *oldmem; + int res = 0; - if (buf->size == size) - return 0; - if (!size) - return -EINVAL; - if (dmxdevfilter->state >= DMXDEV_STATE_GO) - return -EBUSY; + spin_lock_irq(&dmxdevfilter->dev->lock); - newmem = vmalloc(size); - if (!newmem) - return -ENOMEM; + /* Check first for filter overflow */ + if (dmxdevfilter->buffer.error == -EOVERFLOW) { + event->type = DMX_EVENT_BUFFER_OVERFLOW; + } else { + res = dvb_dmxdev_remove_event(&dmxdevfilter->events, event); + if (res) { + spin_unlock_irq(&dmxdevfilter->dev->lock); + return res; + } + } - oldmem = buf->data; + /* clear buffer error now that user was notified */ + if (event->type == DMX_EVENT_BUFFER_OVERFLOW || + event->type == DMX_EVENT_SECTION_TIMEOUT) + dmxdevfilter->buffer.error = 0; + + spin_unlock_irq(&dmxdevfilter->dev->lock); + + if (event->type == DMX_EVENT_BUFFER_OVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdevfilter, + &dmxdevfilter->buffer); spin_lock_irq(&dmxdevfilter->dev->lock); - buf->data = newmem; - buf->size = size; - /* reset and not flush in case the buffer shrinks */ - dvb_ringbuffer_reset(buf); + /* + * If no-data events are enabled on this filter, + * the events can be removed from the queue when + * user gets them. + * For filters with data events enabled, the event is removed + * from the queue only when the respective data is read. + */ + if (event->type != DMX_EVENT_BUFFER_OVERFLOW && + dmxdevfilter->events.data_read_event_masked) + dmxdevfilter->events.read_index = + dvb_dmxdev_advance_event_idx( + dmxdevfilter->events.read_index); + spin_unlock_irq(&dmxdevfilter->dev->lock); - vfree(oldmem); + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdevfilter->buffer.queue); - return 0; + return res; } static void dvb_dmxdev_filter_timeout(unsigned long data) { struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; + struct dmx_filter_event event; dmxdevfilter->buffer.error = -ETIMEDOUT; spin_lock_irq(&dmxdevfilter->dev->lock); dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; + event.type = DMX_EVENT_SECTION_TIMEOUT; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); spin_unlock_irq(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); + wake_up_all(&dmxdevfilter->buffer.queue); } static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) @@ -359,65 +2609,481 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, struct dmx_section_filter *filter) { struct dmxdev_filter *dmxdevfilter = filter->priv; - int ret; + struct dmx_filter_event event; + ssize_t free; - if (dmxdevfilter->buffer.error) { - wake_up(&dmxdevfilter->buffer.queue); - return 0; + + if (!dmxdevfilter) { + pr_err("%s: null filter.\n", __func__); + return -EINVAL; } + spin_lock(&dmxdevfilter->dev->lock); - if (dmxdevfilter->state != DMXDEV_STATE_GO) { + + if (dmxdevfilter->buffer.error || + dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + /* Discard section data if event cannot be notified */ + if (!(dmxdevfilter->events.event_mask.disable_mask & + DMX_EVENT_NEW_SECTION) && + dvb_dmxdev_events_is_full(&dmxdevfilter->events)) { spin_unlock(&dmxdevfilter->dev->lock); return 0; } + + if ((buffer1_len + buffer2_len) == 0) { + if (buffer1 == NULL && buffer2 == NULL) { + /* Section was dropped due to CRC error */ + event.type = DMX_EVENT_SECTION_CRC_ERROR; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else { + spin_unlock(&dmxdevfilter->dev->lock); + } + + return 0; + } + + event.params.section.base_offset = dmxdevfilter->buffer.pwrite; + event.params.section.start_offset = dmxdevfilter->buffer.pwrite; + del_timer(&dmxdevfilter->timer); - dprintk("section callback %*ph\n", 6, buffer1); - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, - buffer1_len); - if (ret == buffer1_len) { - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, - buffer2_len); + + /* Verify output buffer has sufficient space, or report overflow */ + free = dvb_ringbuffer_free(&dmxdevfilter->buffer); + if (free < (buffer1_len + buffer2_len)) { + pr_debug("%s: section filter overflow (pid=%u)\n", + __func__, dmxdevfilter->params.sec.pid); + dmxdevfilter->buffer.error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + return 0; } - if (ret < 0) - dmxdevfilter->buffer.error = ret; + + dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); + dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); + + event.type = DMX_EVENT_NEW_SECTION; + event.params.section.total_length = buffer1_len + buffer2_len; + event.params.section.actual_length = + event.params.section.total_length; + + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) dmxdevfilter->state = DMXDEV_STATE_DONE; spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); + wake_up_all(&dmxdevfilter->buffer.queue); + return 0; +} + +static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, + struct dmx_ts_feed *feed) +{ + struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; + struct dmxdev_events_queue *events; + struct dmx_filter_event event; + ssize_t free; + + if (!dmxdevfilter) { + pr_err("%s: null filter (feed->is_filtering=%d)\n", + __func__, feed->is_filtering); + return -EINVAL; + } + spin_lock(&dmxdevfilter->dev->lock); + + if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER || + dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) { + buffer = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + } else { + buffer = &dmxdevfilter->dev->dvr_buffer; + events = &dmxdevfilter->dev->dvr_output_events; + } + + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return buffer->error; + } + + if (!events->current_event_data_size) + events->current_event_start_offset = buffer->pwrite; + + /* Verify output buffer has sufficient space, or report overflow */ + free = dvb_ringbuffer_free(buffer); + if (free < (buffer1_len + buffer2_len)) { + pr_debug("%s: buffer overflow error, pid=%u\n", + __func__, dmxdevfilter->params.pes.pid); + buffer->error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + + return -EOVERFLOW; + } + + if (buffer1_len + buffer2_len) { + dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); + + events->current_event_data_size += (buffer1_len + buffer2_len); + + if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + && events->current_event_data_size >= + dmxdevfilter->params.pes.rec_chunk_size) { + event.type = DMX_EVENT_NEW_REC_CHUNK; + event.params.recording_chunk.offset = + events->current_event_start_offset; + event.params.recording_chunk.size = + events->current_event_data_size; + + dvb_dmxdev_add_event(events, &event); + events->current_event_data_size = 0; + } + } + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); return 0; } -static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed) -{ - struct dmxdev_filter *dmxdevfilter = feed->priv; - struct dvb_ringbuffer *buffer; - int ret; +static int dvb_dmxdev_section_event_cb(struct dmx_section_filter *filter, + struct dmx_data_ready *dmx_data_ready) +{ + int res = 0; + struct dmxdev_filter *dmxdevfilter = filter->priv; + struct dmx_filter_event event; + ssize_t free; + + if (!dmxdevfilter) { + pr_err("%s: null filter. event type=%d (length=%d) will be discarded\n", + __func__, dmx_data_ready->status, + dmx_data_ready->data_length); + return -EINVAL; + } + + spin_lock(&dmxdevfilter->dev->lock); + + if (dmxdevfilter->buffer.error == -ETIMEDOUT || + dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmx_data_ready->data_length == 0) { + if (dmx_data_ready->status == DMX_CRC_ERROR) { + /* Section was dropped due to CRC error */ + event.type = DMX_EVENT_SECTION_CRC_ERROR; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_EOS) { + event.type = DMX_EVENT_EOS; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_MARKER) { + event.type = DMX_EVENT_MARKER; + event.params.marker.id = dmx_data_ready->marker.id; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) { + event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE; + event.params.scrambling_status = + dmx_data_ready->scrambling_bits; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OVERRUN_ERROR) { + pr_debug("dmxdev: section filter overflow (pid=%u)\n", + dmxdevfilter->params.sec.pid); + /* Set buffer error to notify user overflow occurred */ + dmxdevfilter->buffer.error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else { + spin_unlock(&dmxdevfilter->dev->lock); + } + return 0; + } + + event.type = DMX_EVENT_NEW_SECTION; + event.params.section.base_offset = dmxdevfilter->buffer.pwrite; + event.params.section.start_offset = dmxdevfilter->buffer.pwrite; + event.params.section.total_length = dmx_data_ready->data_length; + event.params.section.actual_length = dmx_data_ready->data_length; + + if (dmx_data_ready->status == DMX_MISSED_ERROR) + event.params.section.flags = DMX_FILTER_CC_ERROR; + else + event.params.section.flags = 0; + + free = dvb_ringbuffer_free(&dmxdevfilter->buffer); + if (free < dmx_data_ready->data_length) { + pr_err("%s: invalid data length: data_length=%d > free=%zd\n", + __func__, dmx_data_ready->data_length, free); + } else { + res = dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + DVB_RINGBUFFER_PUSH(&dmxdevfilter->buffer, + dmx_data_ready->data_length); + } + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + + return res; +} + +static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed, + struct dmx_data_ready *dmx_data_ready) +{ + struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; + struct dmxdev_events_queue *events; + struct dmx_filter_event event; + ssize_t free; + + if (!dmxdevfilter) { + pr_err("%s: null filter (feed->is_filtering=%d) event type=%d (length=%d) will be discarded\n", + __func__, feed->is_filtering, + dmx_data_ready->status, + dmx_data_ready->data_length); + return -EINVAL; + } + + spin_lock(&dmxdevfilter->dev->lock); + + if (dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) { + buffer = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + } else { + buffer = &dmxdevfilter->dev->dvr_buffer; + events = &dmxdevfilter->dev->dvr_output_events; + } + + if (!buffer->error && dmx_data_ready->status == DMX_OVERRUN_ERROR) { + pr_debug("dmxdev: %s filter buffer overflow (pid=%u)\n", + dmxdevfilter->params.pes.output == DMX_OUT_DECODER ? + "decoder" : "", + dmxdevfilter->params.pes.pid); + /* Set buffer error to notify user overflow occurred */ + buffer->error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_EOS) { + /* Report partial recording chunk */ + if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + && events->current_event_data_size) { + event.type = DMX_EVENT_NEW_REC_CHUNK; + event.params.recording_chunk.offset = + events->current_event_start_offset; + event.params.recording_chunk.size = + events->current_event_data_size; + events->current_event_start_offset = + (events->current_event_start_offset + + events->current_event_data_size) % + buffer->size; + events->current_event_data_size = 0; + dvb_dmxdev_add_event(events, &event); + } + + dmxdevfilter->eos_state = 1; + pr_debug("dmxdev: DMX_OK_EOS - entering EOS state\n"); + event.type = DMX_EVENT_EOS; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_MARKER) { + pr_debug("dmxdev: DMX_OK_MARKER - id=%llu\n", + dmx_data_ready->marker.id); + event.type = DMX_EVENT_MARKER; + event.params.marker.id = dmx_data_ready->marker.id; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_PCR) { + pr_debug("dmxdev: event callback DMX_OK_PCR\n"); + event.type = DMX_EVENT_NEW_PCR; + event.params.pcr.pcr = dmx_data_ready->pcr.pcr; + event.params.pcr.stc = dmx_data_ready->pcr.stc; + if (dmx_data_ready->pcr.disc_indicator_set) + event.params.pcr.flags = + DMX_FILTER_DISCONTINUITY_INDICATOR; + else + event.params.pcr.flags = 0; + + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_IDX) { + pr_debug("dmxdev: event callback DMX_OK_IDX\n"); + event.type = DMX_EVENT_NEW_INDEX_ENTRY; + event.params.index = dmx_data_ready->idx_event; + + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) { + event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE; + event.params.scrambling_status = + dmx_data_ready->scrambling_bits; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_DECODER_BUF) { + event.type = DMX_EVENT_NEW_ES_DATA; + event.params.es_data.buf_handle = dmx_data_ready->buf.handle; + event.params.es_data.cookie = dmx_data_ready->buf.cookie; + event.params.es_data.offset = dmx_data_ready->buf.offset; + event.params.es_data.data_len = dmx_data_ready->buf.len; + event.params.es_data.pts_valid = dmx_data_ready->buf.pts_exists; + event.params.es_data.pts = dmx_data_ready->buf.pts; + event.params.es_data.dts_valid = dmx_data_ready->buf.dts_exists; + event.params.es_data.dts = dmx_data_ready->buf.dts; + event.params.es_data.stc = dmx_data_ready->buf.stc; + event.params.es_data.transport_error_indicator_counter = + dmx_data_ready->buf.tei_counter; + event.params.es_data.continuity_error_counter = + dmx_data_ready->buf.cont_err_counter; + event.params.es_data.ts_packets_num = + dmx_data_ready->buf.ts_packets_num; + event.params.es_data.ts_dropped_bytes = + dmx_data_ready->buf.ts_dropped_bytes; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } - spin_lock(&dmxdevfilter->dev->lock); if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); return 0; } - if (dmxdevfilter->params.pes.output == DMX_OUT_TAP - || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) - buffer = &dmxdevfilter->buffer; - else - buffer = &dmxdevfilter->dev->dvr_buffer; - if (buffer->error) { + free = dvb_ringbuffer_free(buffer); + if (free < dmx_data_ready->data_length) { + pr_err("%s: invalid data length: data_length=%d > free=%zd\n", + __func__, dmx_data_ready->data_length, free); + spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); + wake_up_all(&buffer->queue); return 0; } - ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret == buffer1_len) - ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); - if (ret < 0) - buffer->error = ret; + + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) { + if (dmx_data_ready->status == DMX_OK && + !events->current_event_data_size) { + events->current_event_start_offset = buffer->pwrite; + } else if (dmx_data_ready->status == DMX_OK_PES_END) { + event.type = DMX_EVENT_NEW_PES; + + event.params.pes.base_offset = + events->current_event_start_offset; + event.params.pes.start_offset = + (events->current_event_start_offset + + dmx_data_ready->pes_end.start_gap) % + buffer->size; + + event.params.pes.actual_length = + dmx_data_ready->pes_end.actual_length; + event.params.pes.total_length = + events->current_event_data_size; + + event.params.pes.flags = 0; + if (dmx_data_ready->pes_end.disc_indicator_set) + event.params.pes.flags |= + DMX_FILTER_DISCONTINUITY_INDICATOR; + if (dmx_data_ready->pes_end.pes_length_mismatch) + event.params.pes.flags |= + DMX_FILTER_PES_LENGTH_ERROR; + + event.params.pes.stc = dmx_data_ready->pes_end.stc; + event.params.pes.transport_error_indicator_counter = + dmx_data_ready->pes_end.tei_counter; + event.params.pes.continuity_error_counter = + dmx_data_ready->pes_end.cont_err_counter; + event.params.pes.ts_packets_num = + dmx_data_ready->pes_end.ts_packets_num; + + /* Do not report zero length PES */ + if (event.params.pes.total_length) + dvb_dmxdev_add_event(events, &event); + + events->current_event_data_size = 0; + } + } else if (!events->current_event_data_size) { + events->current_event_start_offset = buffer->pwrite; + } + + events->current_event_data_size += dmx_data_ready->data_length; + DVB_RINGBUFFER_PUSH(buffer, dmx_data_ready->data_length); + + if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) || + (dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) { + while (events->current_event_data_size >= + dmxdevfilter->params.pes.rec_chunk_size) { + event.type = DMX_EVENT_NEW_REC_CHUNK; + event.params.recording_chunk.offset = + events->current_event_start_offset; + event.params.recording_chunk.size = + dmxdevfilter->params.pes.rec_chunk_size; + events->current_event_data_size = + events->current_event_data_size - + dmxdevfilter->params.pes.rec_chunk_size; + events->current_event_start_offset = + (events->current_event_start_offset + + dmxdevfilter->params.pes.rec_chunk_size) % + buffer->size; + + dvb_dmxdev_add_event(events, &event); + } + } spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); + wake_up_all(&buffer->queue); return 0; } @@ -431,11 +3097,18 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: del_timer(&dmxdevfilter->timer); - dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); + dmxdevfilter->feed.sec.feed->stop_filtering( + dmxdevfilter->feed.sec.feed); break; case DMXDEV_TYPE_PES: - list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + if (dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) { + dmxdevfilter->dev->dvr_feeds_count--; + if (!dmxdevfilter->dev->dvr_feeds_count) + dmxdevfilter->dev->dvr_feed = NULL; + } feed->ts->stop_filtering(feed->ts); + } break; default: return -EINVAL; @@ -453,7 +3126,8 @@ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) switch (filter->type) { case DMXDEV_TYPE_SEC: - return filter->feed.sec->start_filtering(filter->feed.sec); + return filter->feed.sec.feed->start_filtering( + filter->feed.sec.feed); case DMXDEV_TYPE_PES: list_for_each_entry(feed, &filter->feed.ts, next) { ret = feed->ts->start_filtering(feed->ts); @@ -487,7 +3161,7 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) } filter->dev->demux->release_section_feed(dmxdev->demux, - filter->feed.sec); + filter->feed.sec.feed); return 0; } @@ -496,25 +3170,38 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) { struct dmxdev_feed *feed; struct dmx_demux *demux; + struct ts_insertion_buffer *ts_buffer; if (dmxdevfilter->state < DMXDEV_STATE_GO) return 0; switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: - if (!dmxdevfilter->feed.sec) + if (!dmxdevfilter->feed.sec.feed) break; dvb_dmxdev_feed_stop(dmxdevfilter); if (dmxdevfilter->filter.sec) - dmxdevfilter->feed.sec-> - release_filter(dmxdevfilter->feed.sec, - dmxdevfilter->filter.sec); + dmxdevfilter->feed.sec.feed->release_filter( + dmxdevfilter->feed.sec.feed, + dmxdevfilter->filter.sec); dvb_dmxdev_feed_restart(dmxdevfilter); - dmxdevfilter->feed.sec = NULL; + dmxdevfilter->feed.sec.feed = NULL; break; case DMXDEV_TYPE_PES: dvb_dmxdev_feed_stop(dmxdevfilter); demux = dmxdevfilter->dev->demux; + + if (!list_empty(&dmxdevfilter->insertion_buffers)) { + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + + list_for_each_entry(ts_buffer, + &dmxdevfilter->insertion_buffers, next) + dvb_dmxdev_cancel_ts_insertion(ts_buffer); + if (feed->ts->ts_insertion_terminate) + feed->ts->ts_insertion_terminate(feed->ts); + } + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { demux->release_ts_feed(demux, feed->ts); feed->ts = NULL; @@ -526,7 +3213,13 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) return -EINVAL; } - dvb_ringbuffer_flush(&dmxdevfilter->buffer); + spin_lock_irq(&dmxdevfilter->dev->lock); + dvb_dmxdev_flush_output(&dmxdevfilter->buffer, &dmxdevfilter->events); + dvb_ringbuffer_reset(&dmxdevfilter->buffer); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + wake_up_all(&dmxdevfilter->buffer.queue); + return 0; } @@ -560,7 +3253,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, struct dmxdev_filter *filter, struct dmxdev_feed *feed) { - ktime_t timeout = 0; + ktime_t timeout = ktime_set(0, 0); struct dmx_pes_filter_params *para = &filter->params.pes; enum dmx_output otype; int ret; @@ -593,12 +3286,84 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, tsfeed = feed->ts; tsfeed->priv = filter; - ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout); + if (filter->params.pes.output == DMX_OUT_TS_TAP) { + tsfeed->buffer.ringbuff = &dmxdev->dvr_buffer; + memcpy(&tsfeed->buffer.buff_dma_info, + &dmxdev->dvr_buff_dma_info, + sizeof(struct ion_dma_buff_info)); + + if (!dmxdev->dvr_feeds_count) + dmxdev->dvr_feed = filter; + dmxdev->dvr_feeds_count++; + } else if (filter->params.pes.output == DMX_OUT_DECODER) { + tsfeed->buffer.ringbuff = &filter->buffer; + tsfeed->decoder_buffers = &filter->decoder_buffers; + memcpy(&tsfeed->buffer.buff_dma_info, + &filter->buff_dma_info, + sizeof(struct ion_dma_buff_info)); + + } else { + tsfeed->buffer.ringbuff = &filter->buffer; + memcpy(&tsfeed->buffer.buff_dma_info, + &filter->buff_dma_info, + sizeof(struct ion_dma_buff_info)); + } + + if (tsfeed->data_ready_cb) { + ret = tsfeed->data_ready_cb(tsfeed, dvb_dmxdev_ts_event_cb); + + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + } + + ret = tsfeed->set(tsfeed, feed->pid, + ts_type, ts_pes, + filter->decoder_buffers.buffers_size, + timeout); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); return ret; } + if (tsfeed->set_tsp_out_format) + tsfeed->set_tsp_out_format(tsfeed, filter->dmx_tsp_format); + + if (tsfeed->set_secure_mode) + tsfeed->set_secure_mode(tsfeed, &filter->sec_mode); + + if (tsfeed->set_cipher_ops) + tsfeed->set_cipher_ops(tsfeed, &feed->cipher_ops); + + if ((para->pes_type == DMX_PES_VIDEO0) || + (para->pes_type == DMX_PES_VIDEO1) || + (para->pes_type == DMX_PES_VIDEO2) || + (para->pes_type == DMX_PES_VIDEO3)) { + if (tsfeed->set_video_codec) { + ret = tsfeed->set_video_codec(tsfeed, + para->video_codec); + + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, + tsfeed); + return ret; + } + } + } + + if ((filter->params.pes.output == DMX_OUT_TS_TAP) || + (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) + if (tsfeed->set_idx_params) { + ret = tsfeed->set_idx_params( + tsfeed, &feed->idx_params); + if (ret) { + dmxdev->demux->release_ts_feed(dmxdev->demux, + tsfeed); + return ret; + } + } + ret = tsfeed->start_filtering(tsfeed); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); @@ -608,12 +3373,50 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, return 0; } +static int dvb_filter_external_buffer_only(struct dmxdev *dmxdev, + struct dmxdev_filter *filter) +{ + struct dmx_caps caps; + int is_external_only; + int flags; + + /* + * For backward compatibility, default assumes that + * external only buffers are not supported. + */ + flags = 0; + if (dmxdev->demux->get_caps) { + dmxdev->demux->get_caps(dmxdev->demux, &caps); + + if (filter->type == DMXDEV_TYPE_SEC) + flags = caps.section.flags; + else if (filter->params.pes.output == DMX_OUT_DECODER) + /* For decoder filters dmxdev buffer is not required */ + flags = 0; + else if (filter->params.pes.output == DMX_OUT_TAP) + flags = caps.pes.flags; + else if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188) + flags = caps.recording_188_tsp.flags; + else + flags = caps.recording_192_tsp.flags; + } + + if (!(flags & DMX_BUFFER_INTERNAL_SUPPORT) && + (flags & DMX_BUFFER_EXTERNAL_SUPPORT)) + is_external_only = 1; + else + is_external_only = 0; + + return is_external_only; +} + static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) { struct dmxdev *dmxdev = filter->dev; struct dmxdev_feed *feed; void *mem; int ret, i; + size_t tsp_size; if (filter->state < DMXDEV_STATE_SET) return -EINVAL; @@ -621,34 +3424,64 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) if (filter->state >= DMXDEV_STATE_GO) dvb_dmxdev_filter_stop(filter); + if (!dvb_filter_verify_buffer_size(filter)) + return -EINVAL; + if (!filter->buffer.data) { - mem = vmalloc(filter->buffer.size); + /* + * dmxdev buffer in decoder filters is not really used + * to exchange data with applications. Decoder buffers + * can be set using DMX_SET_DECODER_BUFFER, which + * would not update the filter->buffer.data at all. + * Therefore we should not treat this filter as + * other regular filters and should not fail here + * even if user sets the buffer in deocder + * filter as external buffer. + */ + if (filter->type == DMXDEV_TYPE_PES && + (filter->params.pes.output == DMX_OUT_DECODER || + filter->params.pes.output == DMX_OUT_TS_TAP)) + filter->buffer_mode = DMX_BUFFER_MODE_INTERNAL; + + if (!(filter->type == DMXDEV_TYPE_PES && + filter->params.pes.output == DMX_OUT_TS_TAP) && + (filter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL || + dvb_filter_external_buffer_only(dmxdev, filter))) + return -ENOMEM; + + mem = vmalloc_user(filter->buffer.size); if (!mem) return -ENOMEM; spin_lock_irq(&filter->dev->lock); filter->buffer.data = mem; spin_unlock_irq(&filter->dev->lock); + } else if ((filter->buffer_mode == DMX_BUFFER_MODE_INTERNAL) && + dvb_filter_external_buffer_only(dmxdev, filter)) { + return -ENOMEM; } - dvb_ringbuffer_flush(&filter->buffer); + filter->eos_state = 0; + + spin_lock_irq(&filter->dev->lock); + dvb_dmxdev_flush_output(&filter->buffer, &filter->events); + spin_unlock_irq(&filter->dev->lock); switch (filter->type) { case DMXDEV_TYPE_SEC: { struct dmx_sct_filter_params *para = &filter->params.sec; struct dmx_section_filter **secfilter = &filter->filter.sec; - struct dmx_section_feed **secfeed = &filter->feed.sec; + struct dmx_section_feed **secfeed = &filter->feed.sec.feed; *secfilter = NULL; *secfeed = NULL; - /* find active filter/feed with same PID */ for (i = 0; i < dmxdev->filternum; i++) { if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && dmxdev->filter[i].type == DMXDEV_TYPE_SEC && dmxdev->filter[i].params.sec.pid == para->pid) { - *secfeed = dmxdev->filter[i].feed.sec; + *secfeed = dmxdev->filter[i].feed.sec.feed; break; } } @@ -656,22 +3489,44 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) /* if no feed found, try to allocate new one */ if (!*secfeed) { ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, - secfeed, - dvb_dmxdev_section_callback); + secfeed, + dvb_dmxdev_section_callback); if (ret < 0) { pr_err("DVB (%s): could not alloc feed\n", __func__); return ret; } - ret = (*secfeed)->set(*secfeed, para->pid, + if ((*secfeed)->data_ready_cb) { + ret = (*secfeed)->data_ready_cb( + *secfeed, + dvb_dmxdev_section_event_cb); + + if (ret < 0) { + pr_err( + "DVB (%s): could not set event cb\n", + __func__); + dvb_dmxdev_feed_restart(filter); + return ret; + } + } + + ret = (*secfeed)->set(*secfeed, para->pid, 32768, (para->flags & DMX_CHECK_CRC) ? 1 : 0); if (ret < 0) { pr_err("DVB (%s): could not set feed\n", - __func__); + __func__); dvb_dmxdev_feed_restart(filter); return ret; } + + if ((*secfeed)->set_secure_mode) + (*secfeed)->set_secure_mode(*secfeed, + &filter->sec_mode); + + if ((*secfeed)->set_cipher_ops) + (*secfeed)->set_cipher_ops(*secfeed, + &filter->feed.sec.cipher_ops); } else { dvb_dmxdev_feed_stop(filter); } @@ -679,12 +3534,15 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) ret = (*secfeed)->allocate_filter(*secfeed, secfilter); if (ret < 0) { dvb_dmxdev_feed_restart(filter); - filter->feed.sec->start_filtering(*secfeed); - dprintk("could not get filter\n"); + filter->feed.sec.feed->start_filtering(*secfeed); + pr_debug("could not get filter\n"); return ret; } (*secfilter)->priv = filter; + (*secfilter)->buffer.ringbuff = &filter->buffer; + memcpy(&(*secfilter)->buffer.buff_dma_info, + &filter->buff_dma_info, sizeof(struct ion_dma_buff_info)); memcpy(&((*secfilter)->filter_value[3]), &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); @@ -700,8 +3558,12 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) (*secfilter)->filter_mask[2] = 0; filter->todo = 0; + filter->events.data_read_event_masked = + filter->events.event_mask.disable_mask & + DMX_EVENT_NEW_SECTION; - ret = filter->feed.sec->start_filtering(filter->feed.sec); + ret = filter->feed.sec.feed->start_filtering( + filter->feed.sec.feed); if (ret < 0) return ret; @@ -709,19 +3571,93 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) break; } case DMXDEV_TYPE_PES: + if (filter->params.pes.rec_chunk_size < + DMX_REC_BUFF_CHUNK_MIN_SIZE) + filter->params.pes.rec_chunk_size = + DMX_REC_BUFF_CHUNK_MIN_SIZE; + + if (filter->params.pes.rec_chunk_size >= + filter->buffer.size) + filter->params.pes.rec_chunk_size = + filter->buffer.size >> 2; + + /* Align rec-chunk based on output format */ + if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188) + tsp_size = 188; + else + tsp_size = 192; + + filter->params.pes.rec_chunk_size /= tsp_size; + filter->params.pes.rec_chunk_size *= tsp_size; + + if (filter->params.pes.output == DMX_OUT_TS_TAP) + dmxdev->dvr_output_events.data_read_event_masked = + dmxdev->dvr_output_events.event_mask.disable_mask & + DMX_EVENT_NEW_REC_CHUNK; + else if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + filter->events.data_read_event_masked = + filter->events.event_mask.disable_mask & + DMX_EVENT_NEW_REC_CHUNK; + else if (filter->params.pes.output == DMX_OUT_TAP) + filter->events.data_read_event_masked = + filter->events.event_mask.disable_mask & + DMX_EVENT_NEW_PES; + else + filter->events.data_read_event_masked = 1; + + ret = 0; list_for_each_entry(feed, &filter->feed.ts, next) { ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); - if (ret < 0) { - dvb_dmxdev_filter_stop(filter); - return ret; + if (ret) + break; + } + + if (!ret) + break; + + /* cleanup feeds that were started before the failure */ + list_for_each_entry(feed, &filter->feed.ts, next) { + if (!feed->ts) + continue; + feed->ts->stop_filtering(feed->ts); + dmxdev->demux->release_ts_feed(dmxdev->demux, feed->ts); + feed->ts = NULL; + + if (filter->params.pes.output == DMX_OUT_TS_TAP) { + filter->dev->dvr_feeds_count--; + if (!filter->dev->dvr_feeds_count) + filter->dev->dvr_feed = NULL; } } - break; + return ret; + default: return -EINVAL; } dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); + + if ((filter->type == DMXDEV_TYPE_PES) && + !list_empty(&filter->insertion_buffers)) { + struct ts_insertion_buffer *ts_buffer; + + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + + ret = 0; + if (feed->ts->ts_insertion_init) + ret = feed->ts->ts_insertion_init(feed->ts); + if (!ret) { + list_for_each_entry(ts_buffer, + &filter->insertion_buffers, next) + dvb_dmxdev_queue_ts_insertion( + ts_buffer); + } else { + pr_err("%s: ts_insertion_init failed, err %d\n", + __func__, ret); + } + } + return 0; } @@ -751,11 +3687,29 @@ static int dvb_demux_open(struct inode *inode, struct file *file) mutex_init(&dmxdevfilter->mutex); file->private_data = dmxdevfilter; + memset(&dmxdevfilter->decoder_buffers, + 0, + sizeof(dmxdevfilter->decoder_buffers)); + dmxdevfilter->decoder_buffers.buffers_size = + DMX_DEFAULT_DECODER_BUFFER_SIZE; + dmxdevfilter->buffer_mode = DMX_BUFFER_MODE_INTERNAL; + memset(&dmxdevfilter->buff_dma_info, 0, + sizeof(struct ion_dma_buff_info)); dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); + dvb_dmxdev_flush_events(&dmxdevfilter->events); + dmxdevfilter->events.event_mask.disable_mask = DMX_EVENT_NEW_ES_DATA; + dmxdevfilter->events.event_mask.no_wakeup_mask = 0; + dmxdevfilter->events.event_mask.wakeup_threshold = 1; + dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); init_timer(&dmxdevfilter->timer); + dmxdevfilter->sec_mode.is_secured = 0; + + INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers); + + dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188; dvbdev->users++; mutex_unlock(&dmxdev->mutex); @@ -765,23 +3719,39 @@ static int dvb_demux_open(struct inode *inode, struct file *file) static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter) { + struct ts_insertion_buffer *ts_buffer, *tmp; + mutex_lock(&dmxdev->mutex); mutex_lock(&dmxdevfilter->mutex); dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter); + list_for_each_entry_safe(ts_buffer, tmp, + &dmxdevfilter->insertion_buffers, next) { + list_del(&ts_buffer->next); + vfree(ts_buffer->buffer); + vfree(ts_buffer); + } + if (dmxdevfilter->buffer.data) { void *mem = dmxdevfilter->buffer.data; spin_lock_irq(&dmxdev->lock); dmxdevfilter->buffer.data = NULL; spin_unlock_irq(&dmxdev->lock); - vfree(mem); + if (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL) + vfree(mem); + } + + if ((dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) && + dmxdevfilter->buff_dma_info.va) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdevfilter->buff_dma_info); } dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); - wake_up(&dmxdevfilter->buffer.queue); + wake_up_all(&dmxdevfilter->buffer.queue); mutex_unlock(&dmxdevfilter->mutex); mutex_unlock(&dmxdev->mutex); return 0; @@ -799,6 +3769,7 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, struct dmxdev_filter *filter, u16 pid) { struct dmxdev_feed *feed; + int ret = 0; if ((filter->type != DMXDEV_TYPE_PES) || (filter->state < DMXDEV_STATE_SET)) @@ -814,28 +3785,45 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, return -ENOMEM; feed->pid = pid; - list_add(&feed->next, &filter->feed.ts); + feed->cipher_ops.operations_count = 0; + feed->idx_params.enable = 0; if (filter->state >= DMXDEV_STATE_GO) - return dvb_dmxdev_start_feed(dmxdev, filter, feed); + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); - return 0; + if (!ret) + list_add(&feed->next, &filter->feed.ts); + else + kfree(feed); + + return ret; } static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, struct dmxdev_filter *filter, u16 pid) { + int feed_count; struct dmxdev_feed *feed, *tmp; if ((filter->type != DMXDEV_TYPE_PES) || (filter->state < DMXDEV_STATE_SET)) return -EINVAL; + feed_count = 0; + list_for_each_entry(tmp, &filter->feed.ts, next) + feed_count++; + + if (feed_count <= 1) + return -EINVAL; + list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { - if ((feed->pid == pid) && (feed->ts != NULL)) { - feed->ts->stop_filtering(feed->ts); - filter->dev->demux->release_ts_feed(filter->dev->demux, - feed->ts); + if (feed->pid == pid) { + if (feed->ts != NULL) { + feed->ts->stop_filtering(feed->ts); + filter->dev->demux->release_ts_feed( + filter->dev->demux, + feed->ts); + } list_del(&feed->next); kfree(feed); } @@ -848,7 +3836,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_sct_filter_params *params) { - dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n", + pr_debug("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n", __func__, params->pid, params->flags, params->timeout); dvb_dmxdev_filter_stop(dmxdevfilter); @@ -857,6 +3845,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, memcpy(&dmxdevfilter->params.sec, params, sizeof(struct dmx_sct_filter_params)); invert_mode(&dmxdevfilter->params.sec.filter); + dmxdevfilter->feed.sec.cipher_ops.operations_count = 0; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); if (params->flags & DMX_IMMEDIATE_START) @@ -865,6 +3854,99 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, return 0; } +static int dvb_dmxdev_set_secure_mode( + struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmx_secure_mode *sec_mode) +{ + if (!dmxdev || !filter || !sec_mode) + return -EINVAL; + + if (filter->state == DMXDEV_STATE_GO) { + pr_err("%s: invalid filter state\n", __func__); + return -EBUSY; + } + + pr_debug("%s: secure=%d\n", __func__, sec_mode->is_secured); + + filter->sec_mode = *sec_mode; + + return 0; +} + +static int dvb_dmxdev_set_cipher(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmx_cipher_operations *cipher_ops) +{ + struct dmxdev_feed *feed; + struct dmxdev_feed *ts_feed = NULL; + struct dmxdev_sec_feed *sec_feed = NULL; + struct dmx_caps caps; + + if (!dmxdev || !dmxdev->demux->get_caps) + return -EINVAL; + + dmxdev->demux->get_caps(dmxdev->demux, &caps); + + if (!filter || !cipher_ops || + (cipher_ops->operations_count > caps.num_cipher_ops) || + (cipher_ops->operations_count > + DMX_MAX_CIPHER_OPERATIONS_COUNT)) + return -EINVAL; + + pr_debug("%s: pid=%d, operations=%d\n", __func__, + cipher_ops->pid, cipher_ops->operations_count); + + if (filter->state < DMXDEV_STATE_SET || + filter->state > DMXDEV_STATE_GO) { + pr_err("%s: invalid filter state\n", __func__); + return -EPERM; + } + + if (!filter->sec_mode.is_secured && cipher_ops->operations_count) { + pr_err("%s: secure mode must be enabled to set cipher ops\n", + __func__); + return -EPERM; + } + + switch (filter->type) { + case DMXDEV_TYPE_PES: + list_for_each_entry(feed, &filter->feed.ts, next) { + if (feed->pid == cipher_ops->pid) { + ts_feed = feed; + ts_feed->cipher_ops = *cipher_ops; + if (filter->state == DMXDEV_STATE_GO && + ts_feed->ts->set_cipher_ops) + ts_feed->ts->set_cipher_ops( + ts_feed->ts, cipher_ops); + break; + } + } + break; + case DMXDEV_TYPE_SEC: + if (filter->params.sec.pid == cipher_ops->pid) { + sec_feed = &filter->feed.sec; + sec_feed->cipher_ops = *cipher_ops; + if (filter->state == DMXDEV_STATE_GO && + sec_feed->feed->set_cipher_ops) + sec_feed->feed->set_cipher_ops(sec_feed->feed, + cipher_ops); + } + break; + + default: + return -EINVAL; + } + + if (!ts_feed && !sec_feed) { + pr_err("%s: pid %d is undefined for this filter\n", + __func__, cipher_ops->pid); + return -EINVAL; + } + + return 0; +} + static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_pes_filter_params *params) @@ -895,6 +3977,55 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, return 0; } +static int dvb_dmxdev_set_decoder_buffer(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmx_decoder_buffers *buffs) +{ + int i; + struct dmx_decoder_buffers *dec_buffs; + struct dmx_caps caps; + + if (!dmxdev || !filter || !buffs) + return -EINVAL; + + dec_buffs = &filter->decoder_buffers; + if (!dmxdev->demux->get_caps) + return -EINVAL; + + dmxdev->demux->get_caps(dmxdev->demux, &caps); + if (!dvb_dmxdev_verify_buffer_size(buffs->buffers_size, + caps.decoder.max_size, caps.decoder.size_alignment)) + return -EINVAL; + + if ((buffs->buffers_size == 0) || + (buffs->is_linear && + ((buffs->buffers_num <= 1) || + (buffs->buffers_num > DMX_MAX_DECODER_BUFFER_NUM)))) + return -EINVAL; + + if (buffs->buffers_num == 0) { + /* Internal mode - linear buffers not supported in this mode */ + if (!(caps.decoder.flags & DMX_BUFFER_INTERNAL_SUPPORT) || + buffs->is_linear) + return -EINVAL; + } else { + /* External buffer(s) mode */ + if ((!(caps.decoder.flags & DMX_BUFFER_LINEAR_GROUP_SUPPORT) && + buffs->buffers_num > 1) || + !(caps.decoder.flags & DMX_BUFFER_EXTERNAL_SUPPORT) || + buffs->buffers_num > caps.decoder.max_buffer_num) + return -EINVAL; + + dec_buffs->is_linear = buffs->is_linear; + dec_buffs->buffers_num = buffs->buffers_num; + dec_buffs->buffers_size = buffs->buffers_size; + for (i = 0; i < dec_buffs->buffers_num; i++) + dec_buffs->handles[i] = buffs->handles[i]; + } + + return 0; +} + static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -906,7 +4037,10 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, hcount = 3 + dfil->todo; if (hcount > count) hcount = count; - result = dvb_dmxdev_buffer_read(&dfil->buffer, + if (hcount == 0) + return done; + + result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer, file->f_flags & O_NONBLOCK, buf, hcount, ppos); if (result < 0) { @@ -927,7 +4061,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, } if (count > dfil->todo) count = dfil->todo; - result = dvb_dmxdev_buffer_read(&dfil->buffer, + result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer, file->f_flags & O_NONBLOCK, buf, count, ppos); if (result < 0) @@ -946,12 +4080,36 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count, if (mutex_lock_interruptible(&dmxdevfilter->mutex)) return -ERESTARTSYS; + if (dmxdevfilter->eos_state && + dvb_ringbuffer_empty(&dmxdevfilter->buffer)) { + mutex_unlock(&dmxdevfilter->mutex); + return 0; + } + if (dmxdevfilter->type == DMXDEV_TYPE_SEC) ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); else - ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); + ret = dvb_dmxdev_buffer_read(dmxdevfilter, + &dmxdevfilter->buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + + if (ret > 0) { + dvb_dmxdev_notify_data_read(dmxdevfilter, ret); + spin_lock_irq(&dmxdevfilter->dev->lock); + dvb_dmxdev_update_events(&dmxdevfilter->events, ret); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (ret == -EOVERFLOW) { + dvb_dmxdev_auto_flush_buffer(dmxdevfilter, + &dmxdevfilter->buffer); + } mutex_unlock(&dmxdevfilter->mutex); return ret; @@ -974,55 +4132,161 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - if (dmxdevfilter->state < DMXDEV_STATE_SET) - ret = -EINVAL; - else - ret = dvb_dmxdev_filter_start(dmxdevfilter); + if (dmxdevfilter->state < DMXDEV_STATE_SET) + ret = -EINVAL; + else + ret = dvb_dmxdev_filter_start(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_STOP: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_filter_stop(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_FILTER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_PES_FILTER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER_SIZE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER_MODE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer_mode(dmxdevfilter, + *(enum dmx_buffer_mode *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_BUFFER_STATUS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_buffer_status(dmxdevfilter, parg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_STOP: + case DMX_RELEASE_DATA: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_filter_stop(dmxdevfilter); + ret = dvb_dmxdev_release_data(dmxdevfilter, arg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_SET_FILTER: + case DMX_GET_PES_PIDS: + if (!dmxdev->demux->get_pes_pids) { + ret = -EINVAL; + break; + } + dmxdev->demux->get_pes_pids(dmxdev->demux, parg); + break; + + case DMX_GET_CAPS: + if (!dmxdev->demux->get_caps) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->get_caps(dmxdev->demux, parg); + break; + + case DMX_SET_SOURCE: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); + ret = dvb_dmxdev_set_source(dmxdevfilter, parg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_SET_PES_FILTER: + case DMX_SET_TS_PACKET_FORMAT: + if (!dmxdev->demux->set_tsp_format) { + ret = -EINVAL; + break; + } + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) { + ret = -EBUSY; + break; + } + ret = dmxdev->demux->set_tsp_format( + dmxdev->demux, + *(enum dmx_tsp_format_t *)parg); + break; + + case DMX_SET_TS_OUT_FORMAT: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); + + ret = dvb_dmxdev_set_tsp_out_format(dmxdevfilter, + *(enum dmx_tsp_format_t *)parg); + mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_SET_BUFFER_SIZE: + case DMX_SET_DECODER_BUFFER_SIZE: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); + + ret = dvb_dmxdev_set_decoder_buffer_size(dmxdevfilter, arg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_GET_PES_PIDS: - if (!dmxdev->demux->get_pes_pids) { - ret = -EINVAL; - break; + case DMX_SET_PLAYBACK_MODE: + ret = dvb_dmxdev_set_playback_mode( + dmxdevfilter, + *(enum dmx_playback_mode_t *)parg); + break; + + case DMX_GET_EVENT: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; } - dmxdev->demux->get_pes_pids(dmxdev->demux, parg); + ret = dvb_dmxdev_get_event(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); break; case DMX_GET_STC: @@ -1054,8 +4318,109 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; + case DMX_SET_DECODER_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_set_decoder_buffer(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_SECURE_MODE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_set_secure_mode(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_CIPHER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_set_cipher(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_REUSE_DECODER_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_reuse_decoder_buf(dmxdevfilter, arg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_EVENTS_MASK: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_event_mask(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_EVENTS_MASK: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_event_mask(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_INDEXING_PARAMS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_indexing_params(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_TS_INSERTION: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_ABORT_TS_INSERTION: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_SCRAMBLING_BITS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_FLUSH_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_flush_buffer(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + default: - ret = -ENOTTY; + pr_err("%s: unknown ioctl code (0x%x)\n", + __func__, cmd); + ret = -ENOIOCTLCMD; break; } mutex_unlock(&dmxdev->mutex); @@ -1068,13 +4433,78 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd, return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); } +#ifdef CONFIG_COMPAT + +struct dmx_set_ts_insertion32 { + __u32 identifier; + __u32 repetition_time; + compat_uptr_t ts_packets; + compat_size_t size; +}; + +static long dmx_set_ts_insertion32_wrapper(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct dmx_set_ts_insertion32 dmx_ts_insert32; + struct dmx_set_ts_insertion dmx_ts_insert; + + ret = copy_from_user(&dmx_ts_insert32, (void __user *)arg, + sizeof(dmx_ts_insert32)); + if (ret) { + pr_err( + "%s: copy dmx_set_ts_insertion32 from user failed, ret=%d\n", + __func__, ret); + return -EFAULT; + } + + memset(&dmx_ts_insert, 0, sizeof(dmx_ts_insert)); + dmx_ts_insert.identifier = dmx_ts_insert32.identifier; + dmx_ts_insert.repetition_time = dmx_ts_insert32.repetition_time; + dmx_ts_insert.ts_packets = compat_ptr(dmx_ts_insert32.ts_packets); + dmx_ts_insert.size = dmx_ts_insert32.size; + + ret = dvb_demux_do_ioctl(file, DMX_SET_TS_INSERTION, &dmx_ts_insert); + + return ret; +} + +#define DMX_SET_TS_INSERTION32 _IOW('o', 70, struct dmx_set_ts_insertion32) + +/* + * compat ioctl is called whenever compatibility is required, i.e when a 32bit + * process calls an ioctl for a 64bit kernel. + */ +static long dvb_demux_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long ret = 0; + + switch (cmd) { + case DMX_SET_TS_INSERTION32: + ret = dmx_set_ts_insertion32_wrapper(file, cmd, arg); + break; + case DMX_SET_TS_INSERTION: + pr_err("%s: 64bit ioctl code (0x%lx) used by 32bit userspace\n", + __func__, DMX_SET_TS_INSERTION); + ret = -ENOIOCTLCMD; + break; + default: + /* use regular ioctl */ + ret = dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); + } + + return ret; +} +#endif + static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) { struct dmxdev_filter *dmxdevfilter = file->private_data; unsigned int mask = 0; - if ((!dmxdevfilter) || dmxdevfilter->dev->exit) - return POLLERR; + if (!dmxdevfilter) + return -EINVAL; poll_wait(file, &dmxdevfilter->buffer.queue, wait); @@ -1083,20 +4513,80 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) return 0; - if (dmxdevfilter->buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + if (dmxdevfilter->buffer.error) { + mask |= (POLLIN | POLLRDNORM | POLLERR); + if (dmxdevfilter->buffer.error == -EOVERFLOW) + mask |= POLLPRI; + } if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); + mask |= (POLLIN | POLLRDNORM); + + if (dmxdevfilter->events.wakeup_events_counter >= + dmxdevfilter->events.event_mask.wakeup_threshold) + mask |= POLLPRI; return mask; } +static int dvb_demux_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct dmxdev_filter *dmxdevfilter = filp->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; + int ret; + int vma_size; + int buffer_size; + + vma_size = vma->vm_end - vma->vm_start; + + if (vma->vm_flags & VM_WRITE) + return -EINVAL; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + + if ((!dmxdevfilter->buffer.data) || + (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) { + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + /* Make sure requested mapping is not larger than buffer size */ + buffer_size = dmxdevfilter->buffer.size + (PAGE_SIZE-1); + buffer_size = buffer_size & ~(PAGE_SIZE-1); + + if (vma_size != buffer_size) { + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + ret = remap_vmalloc_range(vma, dmxdevfilter->buffer.data, 0); + if (ret) { + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return ret; + } + + vma->vm_flags |= VM_DONTDUMP; + vma->vm_flags |= VM_DONTEXPAND; + + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + + return 0; +} + static int dvb_demux_release(struct inode *inode, struct file *file) { struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev = dmxdevfilter->dev; - int ret; ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); @@ -1104,6 +4594,8 @@ static int dvb_demux_release(struct inode *inode, struct file *file) mutex_lock(&dmxdev->mutex); dmxdev->dvbdev->users--; if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; mutex_unlock(&dmxdev->mutex); wake_up(&dmxdev->dvbdev->wait_queue); } else @@ -1120,6 +4612,10 @@ static const struct file_operations dvb_demux_fops = { .release = dvb_demux_release, .poll = dvb_demux_poll, .llseek = default_llseek, + .mmap = dvb_demux_mmap, +#ifdef CONFIG_COMPAT + .compat_ioctl = dvb_demux_compat_ioctl, +#endif }; static const struct dvb_device dvbdev_demux = { @@ -1145,7 +4641,40 @@ static int dvb_dvr_do_ioctl(struct file *file, switch (cmd) { case DMX_SET_BUFFER_SIZE: - ret = dvb_dvr_set_buffer_size(dmxdev, arg); + ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg); + break; + + case DMX_SET_BUFFER_MODE: + ret = dvb_dvr_set_buffer_mode(dmxdev, file->f_flags, + *(enum dmx_buffer_mode *)parg); + break; + + case DMX_SET_BUFFER: + ret = dvb_dvr_set_buffer(dmxdev, file->f_flags, parg); + break; + + case DMX_GET_BUFFER_STATUS: + ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg); + break; + + case DMX_RELEASE_DATA: + ret = dvb_dvr_release_data(dmxdev, file->f_flags, arg); + break; + + case DMX_FEED_DATA: + ret = dvb_dvr_feed_data(dmxdev, file->f_flags, arg); + break; + + case DMX_GET_EVENT: + ret = dvb_dvr_get_event(dmxdev, file->f_flags, parg); + break; + + case DMX_PUSH_OOB_COMMAND: + ret = dvb_dvr_push_oob_cmd(dmxdev, file->f_flags, parg); + break; + + case DMX_FLUSH_BUFFER: + ret = dvb_dvr_flush_buffer(dmxdev, file->f_flags); break; default: @@ -1157,10 +4686,18 @@ static int dvb_dvr_do_ioctl(struct file *file, } static long dvb_dvr_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) +{ + return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); +} + +#ifdef CONFIG_COMPAT +static long dvb_dvr_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); } +#endif static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) { @@ -1168,21 +4705,29 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) struct dmxdev *dmxdev = dvbdev->priv; unsigned int mask = 0; - dprintk("%s\n", __func__); - - if (dmxdev->exit) - return POLLERR; - - poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if (dmxdev->dvr_buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); + + if (dmxdev->dvr_buffer.error) { + mask |= (POLLIN | POLLRDNORM | POLLERR); + if (dmxdev->dvr_buffer.error == -EOVERFLOW) + mask |= POLLPRI; + } if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); - } else - mask |= (POLLOUT | POLLWRNORM | POLLPRI); + mask |= (POLLIN | POLLRDNORM); + + if (dmxdev->dvr_output_events.wakeup_events_counter >= + dmxdev->dvr_output_events.event_mask.wakeup_threshold) + mask |= POLLPRI; + } else { + poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait); + if (dmxdev->dvr_input_buffer.error) + mask |= (POLLOUT | POLLRDNORM | POLLPRI | POLLERR); + + if (dvb_ringbuffer_free(&dmxdev->dvr_input_buffer)) + mask |= (POLLOUT | POLLRDNORM | POLLPRI); + } return mask; } @@ -1191,7 +4736,11 @@ static const struct file_operations dvb_dvr_fops = { .owner = THIS_MODULE, .read = dvb_dvr_read, .write = dvb_dvr_write, + .mmap = dvb_dvr_mmap, .unlocked_ioctl = dvb_dvr_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dvb_dvr_compat_ioctl, +#endif .open = dvb_dvr_open, .release = dvb_dvr_release, .poll = dvb_dvr_poll, @@ -1207,9 +4756,94 @@ static const struct dvb_device dvbdev_dvr = { #endif .fops = &dvb_dvr_fops }; + + +/** + * debugfs service to print active filters information. + */ +static int dvb_dmxdev_dbgfs_print(struct seq_file *s, void *p) +{ + int i; + struct dmxdev *dmxdev = s->private; + struct dmxdev_filter *filter; + int active_count = 0; + struct dmx_buffer_status buffer_status; + struct dmx_scrambling_bits scrambling_bits; + static const char * const pes_feeds[] = {"DEC", "PES", "DVR", "REC"}; + int ret; + + if (!dmxdev) + return 0; + + for (i = 0; i < dmxdev->filternum; i++) { + filter = &dmxdev->filter[i]; + if (filter->state >= DMXDEV_STATE_GO) { + active_count++; + + seq_printf(s, "filter_%02d - ", i); + + if (filter->type == DMXDEV_TYPE_SEC) { + seq_puts(s, "type: SEC, "); + seq_printf(s, "PID %04d ", + filter->params.sec.pid); + scrambling_bits.pid = filter->params.sec.pid; + } else { + seq_printf(s, "type: %s, ", + pes_feeds[filter->params.pes.output]); + seq_printf(s, "PID: %04d ", + filter->params.pes.pid); + scrambling_bits.pid = filter->params.pes.pid; + } + + dvb_dmxdev_get_scrambling_bits(filter, + &scrambling_bits); + + if (filter->type == DMXDEV_TYPE_PES && + filter->params.pes.output == DMX_OUT_TS_TAP) + ret = dvb_dvr_get_buffer_status(dmxdev, + O_RDONLY, &buffer_status); + else + ret = dvb_dmxdev_get_buffer_status(filter, + &buffer_status); + if (!ret) { + seq_printf(s, "size: %08d, ", + buffer_status.size); + seq_printf(s, "fullness: %08d, ", + buffer_status.fullness); + seq_printf(s, "error: %d, ", + buffer_status.error); + } + + seq_printf(s, "scramble: %d, ", + scrambling_bits.value); + seq_printf(s, "secured: %d\n", + filter->sec_mode.is_secured); + } + } + + if (!active_count) + seq_puts(s, "No active filters\n"); + + return 0; +} + +static int dvb_dmxdev_dbgfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, dvb_dmxdev_dbgfs_print, inode->i_private); +} + +static const struct file_operations dbgfs_filters_fops = { + .open = dvb_dmxdev_dbgfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { int i; + struct dmx_caps caps; if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; @@ -1218,8 +4852,12 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) if (!dmxdev->filter) return -ENOMEM; + dmxdev->playback_mode = DMX_PB_MODE_PUSH; + dmxdev->demux->dvr_input_protected = 0; + mutex_init(&dmxdev->mutex); spin_lock_init(&dmxdev->lock); + spin_lock_init(&dmxdev->dvr_in_lock); for (i = 0; i < dmxdev->filternum; i++) { dmxdev->filter[i].dev = dmxdev; dmxdev->filter[i].buffer.data = NULL; @@ -1233,6 +4871,19 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) dmxdev, DVB_DEVICE_DVR, dmxdev->filternum); dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); + dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, NULL, 8192); + + /* Disable auto buffer flushing if plugin does not allow it */ + if (dmxdev->demux->get_caps) { + dmxdev->demux->get_caps(dmxdev->demux, &caps); + if (!(caps.caps & DMX_CAP_AUTO_BUFFER_FLUSH)) + overflow_auto_flush = 0; + } + + if (dmxdev->demux->debugfs_demux_dir) + debugfs_create_file("filters", 0444, + dmxdev->demux->debugfs_demux_dir, dmxdev, + &dbgfs_filters_fops); return 0; } diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h index 054fd4eb6192f6048573f6c6dbd1e7d8fdc2f019..88d17c2292c398958abcb3103e19615e25474218 100644 --- a/drivers/media/dvb-core/dmxdev.h +++ b/drivers/media/dvb-core/dmxdev.h @@ -29,7 +29,7 @@ #include #include #include - +#include #include #include "dvbdev.h" @@ -53,10 +53,87 @@ enum dmxdev_state { struct dmxdev_feed { u16 pid; + struct dmx_indexing_params idx_params; + struct dmx_cipher_operations cipher_ops; struct dmx_ts_feed *ts; struct list_head next; }; +struct dmxdev_sec_feed { + struct dmx_section_feed *feed; + struct dmx_cipher_operations cipher_ops; +}; + +struct dmxdev_events_queue { + /* + * indices used to manage events queue. + * read_index advanced when relevant data is read + * from the buffer. + * notified_index is the index from which next events + * are returned. + * read_index <= notified_index <= write_index + * + * If user reads the data without getting the respective + * event first, the read/notified indices are updated + * automatically to reflect the actual data that exist + * in the buffer. + */ + u32 read_index; + u32 write_index; + u32 notified_index; + + /* Bytes read by user without having respective event in the queue */ + u32 bytes_read_no_event; + + /* internal tracking of PES and recording events */ + u32 current_event_data_size; + u32 current_event_start_offset; + + /* current setting of the events masking */ + struct dmx_events_mask event_mask; + + /* + * indicates if an event used for data-reading from demux + * filter is enabled or not. These are events on which + * user may wait for before calling read() on the demux filter. + */ + int data_read_event_masked; + + /* + * holds the current number of pending events in the + * events queue that are considered as a wake-up source + */ + u32 wakeup_events_counter; + + struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE]; +}; + +#define DMX_MIN_INSERTION_REPETITION_TIME 25 /* in msec */ +struct ts_insertion_buffer { + /* work scheduled for insertion of this buffer */ + struct delayed_work dwork; + + struct list_head next; + + /* buffer holding TS packets for insertion */ + char *buffer; + + /* buffer size */ + size_t size; + + /* buffer ID from user */ + u32 identifier; + + /* repetition time for the buffer insertion */ + u32 repetition_time; + + /* the recording filter to which this buffer belongs */ + struct dmxdev_filter *dmxdevfilter; + + /* indication whether insertion should be aborted */ + int abort; +}; + struct dmxdev_filter { union { struct dmx_section_filter *sec; @@ -65,7 +142,7 @@ struct dmxdev_filter { union { /* list of TS and PES feeds (struct dmxdev_feed) */ struct list_head ts; - struct dmx_section_feed *sec; + struct dmxdev_sec_feed sec; } feed; union { @@ -73,19 +150,37 @@ struct dmxdev_filter { struct dmx_pes_filter_params pes; } params; + struct dmxdev_events_queue events; + enum dmxdev_type type; enum dmxdev_state state; struct dmxdev *dev; struct dvb_ringbuffer buffer; + struct ion_dma_buff_info buff_dma_info; + enum dmx_buffer_mode buffer_mode; struct mutex mutex; + /* for recording output */ + enum dmx_tsp_format_t dmx_tsp_format; + u32 rec_chunk_size; + + /* list of buffers used for insertion (struct ts_insertion_buffer) */ + struct list_head insertion_buffers; + + /* End-of-stream indication has been received */ + int eos_state; + /* only for sections */ struct timer_list timer; int todo; u8 secheader[3]; -}; + struct dmx_secure_mode sec_mode; + + /* Decoder buffer(s) related */ + struct dmx_decoder_buffers decoder_buffers; +}; struct dmxdev { struct dvb_device *dvbdev; @@ -96,18 +191,52 @@ struct dmxdev { int filternum; int capabilities; +#define DMXDEV_CAP_DUPLEX 0x01 + + enum dmx_playback_mode_t playback_mode; + dmx_source_t source; unsigned int exit:1; -#define DMXDEV_CAP_DUPLEX 1 + unsigned int dvr_in_exit:1; + unsigned int dvr_processing_input:1; + struct dmx_frontend *dvr_orig_fe; struct dvb_ringbuffer dvr_buffer; + struct ion_dma_buff_info dvr_buff_dma_info; + enum dmx_buffer_mode dvr_buffer_mode; + struct dmxdev_events_queue dvr_output_events; + struct dmxdev_filter *dvr_feed; + int dvr_feeds_count; + + struct dvb_ringbuffer dvr_input_buffer; + enum dmx_buffer_mode dvr_input_buffer_mode; + struct task_struct *dvr_input_thread; + /* DVR commands (data feed / OOB command) queue */ + struct dvb_ringbuffer dvr_cmd_buffer; + #define DVR_BUFFER_SIZE (10*188*1024) struct mutex mutex; spinlock_t lock; + spinlock_t dvr_in_lock; +}; + +enum dvr_cmd { + DVR_DATA_FEED_CMD, + DVR_OOB_CMD }; +struct dvr_command { + enum dvr_cmd type; + union { + struct dmx_oob_command oobcmd; + size_t data_feed_count; + } cmd; +}; + +#define DVR_CMDS_BUFFER_SIZE (sizeof(struct dvr_command)*500) + int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); void dvb_dmxdev_release(struct dmxdev *dmxdev); diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 6628f80d184fd42e4447daf0417f933908fd1119..48c670bccc99d9a9174751a6e7dde7d8fa2ba723 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -17,8 +17,6 @@ * */ -#define pr_fmt(fmt) "dvb_demux: " fmt - #include #include #include @@ -29,9 +27,16 @@ #include #include #include +#include #include "dvb_demux.h" +#define NOBUFS +/* + * #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog + */ +// #define DVB_DEMUX_SECTION_LOSS_LOG + static int dvb_demux_tscheck; module_param(dvb_demux_tscheck, int, 0644); MODULE_PARM_DESC(dvb_demux_tscheck, @@ -47,13 +52,117 @@ module_param(dvb_demux_feed_err_pkts, int, 0644); MODULE_PARM_DESC(dvb_demux_feed_err_pkts, "when set to 0, drop packets with the TEI bit set (1 by default)"); -#define dprintk(fmt, arg...) \ - printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg) +/* counter advancing for each new dvb-demux device */ +static int dvb_demux_index; + +static int dvb_demux_performancecheck; +module_param(dvb_demux_performancecheck, int, 0644); +MODULE_PARM_DESC(dvb_demux_performancecheck, + "enable transport stream performance check, reported through debugfs"); + +#define dprintk_tscheck(x...) do { \ + if (dvb_demux_tscheck) \ + pr_debug_ratelimited(x); \ + } while (0) + +static const struct dvb_dmx_video_patterns mpeg2_seq_hdr = { + {0x00, 0x00, 0x01, 0xB3}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_MPEG_SEQ_HEADER +}; + +static const struct dvb_dmx_video_patterns mpeg2_gop = { + {0x00, 0x00, 0x01, 0xB8}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_MPEG_GOP +}; + +static const struct dvb_dmx_video_patterns mpeg2_iframe = { + {0x00, 0x00, 0x01, 0x00, 0x00, 0x08}, + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, + 6, + DMX_IDX_MPEG_I_FRAME_START +}; + +static const struct dvb_dmx_video_patterns mpeg2_pframe = { + {0x00, 0x00, 0x01, 0x00, 0x00, 0x10}, + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, + 6, + DMX_IDX_MPEG_P_FRAME_START +}; + +static const struct dvb_dmx_video_patterns mpeg2_bframe = { + {0x00, 0x00, 0x01, 0x00, 0x00, 0x18}, + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, + 6, + DMX_IDX_MPEG_B_FRAME_START +}; + +static const struct dvb_dmx_video_patterns h264_sps = { + {0x00, 0x00, 0x01, 0x07}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_SPS +}; + +static const struct dvb_dmx_video_patterns h264_pps = { + {0x00, 0x00, 0x01, 0x08}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_PPS +}; + +static const struct dvb_dmx_video_patterns h264_idr = { + {0x00, 0x00, 0x01, 0x05, 0x80}, + {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, + 5, + DMX_IDX_H264_IDR_START +}; + +static const struct dvb_dmx_video_patterns h264_non_idr = { + {0x00, 0x00, 0x01, 0x01, 0x80}, + {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, + 5, + DMX_IDX_H264_NON_IDR_START +}; + +static const struct dvb_dmx_video_patterns h264_non_access_unit_del = { + {0x00, 0x00, 0x01, 0x09}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_ACCESS_UNIT_DEL +}; + +static const struct dvb_dmx_video_patterns h264_non_sei = { + {0x00, 0x00, 0x01, 0x06}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_SEI +}; + +static const struct dvb_dmx_video_patterns vc1_seq_hdr = { + {0x00, 0x00, 0x01, 0x0F}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_VC1_SEQ_HEADER +}; + +static const struct dvb_dmx_video_patterns vc1_entry_point = { + {0x00, 0x00, 0x01, 0x0E}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_VC1_ENTRY_POINT +}; + +static const struct dvb_dmx_video_patterns vc1_frame = { + {0x00, 0x00, 0x01, 0x0D}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_VC1_FRAME_START +}; -#define dprintk_tscheck(x...) do { \ - if (dvb_demux_tscheck && printk_ratelimit()) \ - dprintk(x); \ -} while (0) /****************************************************************************** * static inlined helper functions @@ -64,9 +173,9 @@ static inline u16 section_length(const u8 *buf) return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; } -static inline u16 ts_pid(const u8 *buf) +static inline u8 ts_scrambling_ctrl(const u8 *buf) { - return ((buf[1] & 0x1f) << 8) + buf[2]; + return (buf[3] >> 6) & 0x3; } static inline u8 payload(const u8 *tsp) @@ -95,39 +204,358 @@ static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, memcpy(d, s, len); } +static u32 dvb_dmx_calc_time_delta(ktime_t past_time) +{ + ktime_t curr_time = ktime_get(); + s64 delta_time_us = ktime_us_delta(curr_time, past_time); + + return (u32)delta_time_us; +} + /****************************************************************************** * Software filter functions ******************************************************************************/ +/* + * Check if two patterns are identical, taking mask into consideration. + * @pattern1: the first byte pattern to compare. + * @pattern2: the second byte pattern to compare. + * @mask: the bit mask to use. + * @pattern_size: the length of both patterns and the mask, in bytes. + * + * Return: 1 if patterns match, 0 otherwise. + */ +static inline int dvb_dmx_patterns_match(const u8 *pattern1, const u8 *pattern2, + const u8 *mask, size_t pattern_size) +{ + int i; + + /* + * Assumption: it is OK to access pattern1, pattern2 and mask. + * This function performs no sanity checks to keep things fast. + */ + + for (i = 0; i < pattern_size; i++) + if ((pattern1[i] & mask[i]) != (pattern2[i] & mask[i])) + return 0; + + return 1; +} + +/* + * dvb_dmx_video_pattern_search - + * search for framing patterns in a given buffer. + * + * Optimized version: first search for a common substring, e.g. 0x00 0x00 0x01. + * If this string is found, go over all the given patterns (all must start + * with this string) and search for their ending in the buffer. + * + * Assumption: the patterns we look for do not spread over more than two + * buffers. + * + * @paterns: the full patterns information to look for. + * @patterns_num: the number of patterns to look for. + * @buf: the buffer to search. + * @buf_size: the size of the buffer to search. we search the entire buffer. + * @prefix_size_masks: a bit mask (per pattern) of possible prefix sizes to use + * when searching for a pattern that started at the last buffer. + * Updated in this function for use in the next lookup. + * @results: lookup results (offset, type, used_prefix_size) per found pattern, + * up to DVB_DMX_MAX_FOUND_PATTERNS. + * + * Return: + * Number of patterns found (up to DVB_DMX_MAX_FOUND_PATTERNS). + * 0 if pattern was not found. + * error value on failure. + */ +int dvb_dmx_video_pattern_search( + const struct dvb_dmx_video_patterns + *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM], + int patterns_num, + const u8 *buf, + size_t buf_size, + struct dvb_dmx_video_prefix_size_masks *prefix_size_masks, + struct dvb_dmx_video_patterns_results *results) +{ + int i, j; + unsigned int current_size; + u32 prefix; + int found = 0; + int start_offset = 0; + /* the starting common substring to look for */ + u8 string[] = {0x00, 0x00, 0x01}; + /* the mask for the starting string */ + u8 string_mask[] = {0xFF, 0xFF, 0xFF}; + /* the size of the starting string (in bytes) */ + size_t string_size = 3; + + if ((patterns == NULL) || (patterns_num <= 0) || (buf == NULL)) + return -EINVAL; + + memset(results, 0, sizeof(struct dvb_dmx_video_patterns_results)); + + /* + * handle prefix - disregard string, simply check all patterns, + * looking for a matching suffix at the very beginning of the buffer. + */ + for (j = 0; (j < patterns_num) && !found; j++) { + prefix = prefix_size_masks->size_mask[j]; + current_size = 32; + while (prefix) { + if (prefix & (0x1 << (current_size - 1))) { + /* + * check that we don't look further + * than buf_size boundary + */ + if ((int)(patterns[j]->size - current_size) > + buf_size) + break; + + if (current_size >= DVB_DMX_MAX_PATTERN_LEN) + break; + + if (dvb_dmx_patterns_match( + (patterns[j]->pattern + current_size), + buf, (patterns[j]->mask + current_size), + (patterns[j]->size - current_size))) { + + /* + * pattern found using prefix at the + * very beginning of the buffer, so + * offset is 0, but we already zeroed + * everything in the beginning of the + * function. that's why the next line + * is commented. + */ + /* results->info[found].offset = 0; */ + results->info[found].type = + patterns[j]->type; + results->info[found].used_prefix_size = + current_size; + found++; + /* + * save offset to start looking from + * in the buffer, to avoid reusing the + * data of a pattern we already found. + */ + start_offset = (patterns[j]->size - + current_size); + + if (found >= DVB_DMX_MAX_FOUND_PATTERNS) + goto next_prefix_lookup; + /* + * we don't want to search for the same + * pattern with several possible prefix + * sizes if we have already found it, + * so we break from the inner loop. + * since we incremented 'found', we + * will not search for additional + * patterns using a prefix - that would + * imply ambiguous patterns where one + * pattern can be included in another. + * the for loop will exit. + */ + break; + } + } + prefix &= ~(0x1 << (current_size - 1)); + current_size--; + } + } + + /* + * Search buffer for entire pattern, starting with the string. + * Note the external for loop does not execute if buf_size is + * smaller than string_size (the cast to int is required, since + * size_t is unsigned). + */ + for (i = start_offset; i < (int)(buf_size - string_size + 1); i++) { + if (dvb_dmx_patterns_match(string, (buf + i), string_mask, + string_size)) { + /* now search for patterns: */ + for (j = 0; j < patterns_num; j++) { + /* avoid overflow to next buffer */ + if ((i + patterns[j]->size) > buf_size) + continue; + + if (dvb_dmx_patterns_match( + (patterns[j]->pattern + string_size), + (buf + i + string_size), + (patterns[j]->mask + string_size), + (patterns[j]->size - string_size))) { + + results->info[found].offset = i; + results->info[found].type = + patterns[j]->type; + /* + * save offset to start next prefix + * lookup, to avoid reusing the data + * of any pattern we already found. + */ + if ((i + patterns[j]->size) > + start_offset) + start_offset = (i + + patterns[j]->size); + /* + * did not use a prefix to find this + * pattern, but we zeroed everything + * in the beginning of the function. + * So no need to zero used_prefix_size + * for results->info[found] + */ + + found++; + if (found >= DVB_DMX_MAX_FOUND_PATTERNS) + goto next_prefix_lookup; + /* + * theoretically we don't have to break + * here, but we don't want to search + * for the other matching patterns on + * the very same same place in the + * buffer. That would mean the + * (pattern & mask) combinations are + * not unique. So we break from inner + * loop and move on to the next place + * in the buffer. + */ + break; + } + } + } + } + +next_prefix_lookup: + /* check for possible prefix sizes for the next buffer */ + for (j = 0; j < patterns_num; j++) { + prefix_size_masks->size_mask[j] = 0; + for (i = 1; i < patterns[j]->size; i++) { + /* + * avoid looking outside of the buffer + * or reusing previously used data. + */ + if (i > (buf_size - start_offset)) + break; + + if (dvb_dmx_patterns_match(patterns[j]->pattern, + (buf + buf_size - i), + patterns[j]->mask, i)) { + prefix_size_masks->size_mask[j] |= + (1 << (i - 1)); + } + } + } + + return found; +} +EXPORT_SYMBOL(dvb_dmx_video_pattern_search); + +/** + * dvb_dmx_notify_section_event() - Notify demux event for all filters of a + * specified section feed. + * + * @feed: dvb_demux_feed object + * @event: demux event to notify + * @should_lock: specifies whether the function should lock the demux + * + * Caller is responsible for locking the demux properly, either by doing the + * locking itself and setting 'should_lock' to 0, or have the function do it + * by setting 'should_lock' to 1. + */ +int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed, + struct dmx_data_ready *event, int should_lock) +{ + struct dvb_demux_filter *f; + + if (feed == NULL || event == NULL || feed->type != DMX_TYPE_SEC) + return -EINVAL; + + if (!should_lock && !spin_is_locked(&feed->demux->lock)) + return -EINVAL; + + if (should_lock) + spin_lock(&feed->demux->lock); + + f = feed->filter; + while (f && feed->feed.sec.is_filtering) { + feed->data_ready_cb.sec(&f->filter, event); + f = f->next; + } + + if (should_lock) + spin_unlock(&feed->demux->lock); + + return 0; +} +EXPORT_SYMBOL(dvb_dmx_notify_section_event); + +static int dvb_dmx_check_pes_end(struct dvb_demux_feed *feed) +{ + struct dmx_data_ready data; + + if (!feed->pusi_seen) + return 0; + + data.status = DMX_OK_PES_END; + data.data_length = 0; + data.pes_end.start_gap = 0; + data.pes_end.actual_length = feed->peslen; + data.pes_end.disc_indicator_set = 0; + data.pes_end.pes_length_mismatch = 0; + data.pes_end.stc = 0; + data.pes_end.tei_counter = feed->pes_tei_counter; + data.pes_end.cont_err_counter = feed->pes_cont_err_counter; + data.pes_end.ts_packets_num = feed->pes_ts_packets_num; + + return feed->data_ready_cb.ts(&feed->feed.ts, &data); +} + static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, const u8 *buf) { int count = payload(buf); int p; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG int ccok; u8 cc; -#endif + int ret; if (count == 0) return -1; p = 188 - count; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG cc = buf[3] & 0x0f; - ccok = ((feed->cc + 1) & 0x0f) == cc; + if (feed->first_cc) + ccok = 1; + else + ccok = ((feed->cc + 1) & 0x0f) == cc; + + feed->first_cc = 0; feed->cc = cc; - if (!ccok) - dprintk("missed packet!\n"); -#endif - if (buf[1] & 0x40) // PUSI ? - feed->peslen = 0xfffa; + /* PUSI ? */ + if (buf[1] & 0x40) { + dvb_dmx_check_pes_end(feed); + feed->pusi_seen = 1; + feed->peslen = 0; + feed->pes_tei_counter = 0; + feed->pes_cont_err_counter = 0; + feed->pes_ts_packets_num = 0; + } + + if (feed->pusi_seen == 0) + return 0; + + ret = feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); - feed->peslen += count; + /* Verify TS packet was copied successfully */ + if (!ret) { + feed->pes_cont_err_counter += !ccok; + feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0; + feed->pes_ts_packets_num++; + feed->peslen += count; + } - return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); + return ret; } static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, @@ -166,10 +594,28 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) return 0; if (sec->check_crc) { + ktime_t pre_crc_time = ktime_set(0, 0); + + if (dvb_demux_performancecheck) + pre_crc_time = ktime_get(); + section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); if (section_syntax_indicator && - demux->check_crc32(feed, sec->secbuf, sec->seclen)) + demux->check_crc32(feed, sec->secbuf, sec->seclen)) { + if (dvb_demux_performancecheck) + demux->total_crc_time += + dvb_dmx_calc_time_delta(pre_crc_time); + + /* Notify on CRC error */ + feed->cb.sec(NULL, 0, NULL, 0, + &f->filter); + return -1; + } + + if (dvb_demux_performancecheck) + demux->total_crc_time += + dvb_dmx_calc_time_delta(pre_crc_time); } do { @@ -186,7 +632,7 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +#ifdef DVB_DEMUX_SECTION_LOSS_LOG if (sec->secbufp < sec->tsfeedp) { int i, n = sec->tsfeedp - sec->secbufp; @@ -196,12 +642,12 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * but just first and last. */ if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { - dprintk("dvb_demux.c section ts padding loss: %d/%d\n", + pr_debug("dvb_demux.c section ts padding loss: %d/%d\n", n, sec->tsfeedp); - dprintk("dvb_demux.c pad data:"); + pr_debug("dvb_demux.c pad data:"); for (i = 0; i < n; i++) - pr_cont(" %02x", sec->secbuf[i]); - pr_cont("\n"); + pr_debug(" %02x", sec->secbuf[i]); + pr_debug("\n"); } } #endif @@ -239,8 +685,8 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("dvb_demux.c section buffer full loss: %d/%d\n", +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + pr_err("dvb_demux.c section buffer full loss: %d/%d\n", sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); #endif @@ -273,9 +719,9 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, /* dump [secbuf .. secbuf+seclen) */ if (feed->pusi_seen) dvb_dmx_swfilter_section_feed(feed); -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +#ifdef DVB_DEMUX_SECTION_LOSS_LOG else - dprintk("dvb_demux.c pusi not seen, discarding section data\n"); + pr_err("dvb_demux.c pusi not seen, discarding section data\n"); #endif sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ @@ -284,7 +730,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; } -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, +static int dvb_dmx_swfilter_section_one_packet(struct dvb_demux_feed *feed, const u8 *buf) { u8 p, count; @@ -299,7 +745,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, p = 188 - count; /* payload start */ cc = buf[3] & 0x0f; - ccok = ((feed->cc + 1) & 0x0f) == cc; + if (feed->first_cc) + ccok = 1; + else + ccok = ((feed->cc + 1) & 0x0f) == cc; + + /* discard TS packets holding sections with TEI bit set */ + if (buf[1] & 0x80) + return -EINVAL; + + feed->first_cc = 0; feed->cc = cc; if (buf[3] & 0x20) { @@ -309,9 +764,9 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, } if (!ccok || dc_i) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("dvb_demux.c discontinuity detected %d bytes lost\n", - count); +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + pr_err("dvb_demux.c discontinuity detected %d bytes lost\n", + count); /* * those bytes under sume circumstances will again be reported * in the following dvb_dmx_swfilter_section_new @@ -341,10 +796,9 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); } -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +#ifdef DVB_DEMUX_SECTION_LOSS_LOG else if (count > 0) - dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n", - count); + pr_err("dvb_demux.c PUSI=1 but %d bytes lost\n", count); #endif } else { /* PUSI=0 (is not set), no section boundary */ @@ -354,408 +808,1773 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, return 0; } -static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, - const u8 *buf) +/* + * dvb_dmx_swfilter_section_packet - wrapper for section filtering of single + * TS packet. + * + * @feed: dvb demux feed + * @buf: buffer containing the TS packet + * @should_lock: specifies demux locking semantics: if not set, proper demux + * locking is expected to have been done by the caller. + * + * Return error status + */ +int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + const u8 *buf, int should_lock) { - switch (feed->type) { - case DMX_TYPE_TS: - if (!feed->feed.ts.is_filtering) - break; - if (feed->ts_type & TS_PACKET) { - if (feed->ts_type & TS_PAYLOAD_ONLY) - dvb_dmx_swfilter_payload(feed, buf); - else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); - } - if (feed->ts_type & TS_DECODER) - if (feed->demux->write_to_decoder) - feed->demux->write_to_decoder(feed, buf, 188); - break; - - case DMX_TYPE_SEC: - if (!feed->feed.sec.is_filtering) - break; - if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) - feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; - break; + int ret; - default: - break; + if (!should_lock && !spin_is_locked(&feed->demux->lock)) { + pr_err("%s: demux spinlock should have been locked\n", + __func__); + return -EINVAL; } -} -#define DVR_FEED(f) \ - (((f)->type == DMX_TYPE_TS) && \ - ((f)->feed.ts.is_filtering) && \ - (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) + if (should_lock) + spin_lock(&feed->demux->lock); -static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) -{ - struct dvb_demux_feed *feed; - u16 pid = ts_pid(buf); - int dvr_done = 0; + ret = dvb_dmx_swfilter_section_one_packet(feed, buf); - if (dvb_demux_speedcheck) { - ktime_t cur_time; - u64 speed_bytes, speed_timedelta; + if (should_lock) + spin_unlock(&feed->demux->lock); - demux->speed_pkts_cnt++; + return ret; +} +EXPORT_SYMBOL(dvb_dmx_swfilter_section_packet); - /* show speed every SPEED_PKTS_INTERVAL packets */ - if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { - cur_time = ktime_get(); +static int dvb_demux_idx_event_sort(struct dmx_index_event_info *curr, + struct dmx_index_event_info *new) +{ + if (curr->match_tsp_num > new->match_tsp_num) + return 0; - if (ktime_to_ns(demux->speed_last_time) != 0) { - speed_bytes = (u64)demux->speed_pkts_cnt - * 188 * 8; - /* convert to 1024 basis */ - speed_bytes = 1000 * div64_u64(speed_bytes, - 1024); - speed_timedelta = ktime_ms_delta(cur_time, - demux->speed_last_time); - dprintk("TS speed %llu Kbits/sec \n", - div64_u64(speed_bytes, - speed_timedelta)); - } + if (curr->match_tsp_num < new->match_tsp_num) + return 1; + /* + * In case TSP numbers are equal, sort according to event type giving + * priority to PUSI events first, then RAI and finally framing events. + */ + if ((curr->type & DMX_IDX_RAI && new->type & DMX_IDX_PUSI) || + (!(curr->type & DMX_IDX_PUSI) && !(curr->type & DMX_IDX_RAI) && + new->type & (DMX_IDX_PUSI | DMX_IDX_RAI))) + return 0; - demux->speed_last_time = cur_time; - demux->speed_pkts_cnt = 0; - } + return 1; +} + +static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed, + struct dmx_index_event_info *idx_event, + int traverse_from_tail) +{ + struct dmx_index_entry *idx_entry; + struct dmx_index_entry *curr_entry; + struct list_head *pos; + + /* get entry from free list */ + if (list_empty(&feed->rec_info->idx_info.free_list)) { + pr_err("%s: index free list is empty\n", __func__); + return -ENOMEM; } - if (buf[1] & 0x80) { - dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", - pid, buf[1]); - /* data in this packet can't be trusted - drop it unless - * module option dvb_demux_feed_err_pkts is set */ - if (!dvb_demux_feed_err_pkts) - return; - } else /* if TEI bit is set, pid may be wrong- skip pkt counter */ - if (demux->cnt_storage && dvb_demux_tscheck) { - /* check pkt counter */ - if (pid < MAX_PID) { - if (buf[3] & 0x10) - demux->cnt_storage[pid] = - (demux->cnt_storage[pid] + 1) & 0xf; + idx_entry = list_first_entry(&feed->rec_info->idx_info.free_list, + struct dmx_index_entry, next); + list_del(&idx_entry->next); - if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { - dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", - pid, demux->cnt_storage[pid], - buf[3] & 0xf); - demux->cnt_storage[pid] = buf[3] & 0xf; - } + idx_entry->event = *idx_event; + + pos = &feed->rec_info->idx_info.ready_list; + if (traverse_from_tail) { + list_for_each_entry_reverse(curr_entry, + &feed->rec_info->idx_info.ready_list, next) { + if (dvb_demux_idx_event_sort(&curr_entry->event, + idx_event)) { + pos = &curr_entry->next; + break; } - /* end check */ } + } else { + list_for_each_entry(curr_entry, + &feed->rec_info->idx_info.ready_list, next) { + if (!dvb_demux_idx_event_sort(&curr_entry->event, + idx_event)) { + pos = &curr_entry->next; + break; + } + } + } - list_for_each_entry(feed, &demux->feed_list, list_head) { - if ((feed->pid != pid) && (feed->pid != 0x2000)) - continue; - - /* copy each packet only once to the dvr device, even - * if a PID is in multiple filters (e.g. video + PCR) */ - if ((DVR_FEED(feed)) && (dvr_done++)) - continue; + if (traverse_from_tail) + list_add(&idx_entry->next, pos); + else + list_add_tail(&idx_entry->next, pos); - if (feed->pid == pid) - dvb_dmx_swfilter_packet_type(feed, buf); - else if (feed->pid == 0x2000) - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); - } + return 0; } -void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, - size_t count) +int dvb_demux_push_idx_event(struct dvb_demux_feed *feed, + struct dmx_index_event_info *idx_event, int should_lock) { - unsigned long flags; + int ret; - spin_lock_irqsave(&demux->lock, flags); + if (!should_lock && !spin_is_locked(&feed->demux->lock)) + return -EINVAL; - while (count--) { - if (buf[0] == 0x47) - dvb_dmx_swfilter_packet(demux, buf); - buf += 188; - } + if (should_lock) + spin_lock(&feed->demux->lock); + ret = dvb_demux_save_idx_event(feed, idx_event, 1); + if (should_lock) + spin_unlock(&feed->demux->lock); - spin_unlock_irqrestore(&demux->lock, flags); + return ret; } +EXPORT_SYMBOL(dvb_demux_push_idx_event); -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); - -static inline int find_next_packet(const u8 *buf, int pos, size_t count, - const int pktsize) +static inline void dvb_dmx_notify_indexing(struct dvb_demux_feed *feed) { - int start = pos, lost; - - while (pos < count) { - if (buf[pos] == 0x47 || - (pktsize == 204 && buf[pos] == 0xB8)) - break; - pos++; - } - - lost = pos - start; - if (lost) { - /* This garbage is part of a valid packet? */ - int backtrack = pos - pktsize; - if (backtrack >= 0 && (buf[backtrack] == 0x47 || - (pktsize == 204 && buf[backtrack] == 0xB8))) - return backtrack; + struct dmx_data_ready dmx_data_ready; + struct dmx_index_entry *curr_entry; + struct list_head *n, *pos; + + dmx_data_ready.status = DMX_OK_IDX; + + list_for_each_safe(pos, n, &feed->rec_info->idx_info.ready_list) { + curr_entry = list_entry(pos, struct dmx_index_entry, next); + + if ((feed->rec_info->idx_info.min_pattern_tsp_num == (u64)-1) || + (curr_entry->event.match_tsp_num <= + feed->rec_info->idx_info.min_pattern_tsp_num)) { + dmx_data_ready.idx_event = curr_entry->event; + feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready); + list_del(&curr_entry->next); + list_add_tail(&curr_entry->next, + &feed->rec_info->idx_info.free_list); + } } - - return pos; } -/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ -static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, - size_t count, const int pktsize) +void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock) { - int p = 0, i, j; - const u8 *q; - unsigned long flags; + if (!should_lock && !spin_is_locked(&feed->demux->lock)) + return; - spin_lock_irqsave(&demux->lock, flags); + if (should_lock) + spin_lock(&feed->demux->lock); + dvb_dmx_notify_indexing(feed); + if (should_lock) + spin_unlock(&feed->demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_notify_idx_events); - if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ - i = demux->tsbufp; - j = pktsize - i; - if (count < j) { - memcpy(&demux->tsbuf[i], buf, count); - demux->tsbufp += count; - goto bailout; - } - memcpy(&demux->tsbuf[i], buf, j); - if (demux->tsbuf[0] == 0x47) /* double check */ - dvb_dmx_swfilter_packet(demux, demux->tsbuf); - demux->tsbufp = 0; - p += j; +static void dvb_dmx_process_pattern_result(struct dvb_demux_feed *feed, + struct dvb_dmx_video_patterns_results *patterns, int pattern, + u64 curr_stc, u64 prev_stc, + u64 curr_match_tsp, u64 prev_match_tsp, + u64 curr_pusi_tsp, u64 prev_pusi_tsp) +{ + int mpeg_frame_start; + int h264_frame_start; + int vc1_frame_start; + int seq_start; + u64 frame_end_in_seq; + struct dmx_index_event_info idx_event; + + idx_event.pid = feed->pid; + if (patterns->info[pattern].used_prefix_size) { + idx_event.match_tsp_num = prev_match_tsp; + idx_event.last_pusi_tsp_num = prev_pusi_tsp; + idx_event.stc = prev_stc; + } else { + idx_event.match_tsp_num = curr_match_tsp; + idx_event.last_pusi_tsp_num = curr_pusi_tsp; + idx_event.stc = curr_stc; } - while (1) { - p = find_next_packet(buf, p, count, pktsize); - if (p >= count) - break; - if (count - p < pktsize) - break; + /* notify on frame-end if needed */ + if (feed->prev_frame_valid) { + if (feed->prev_frame_type & DMX_IDX_MPEG_I_FRAME_START) { + idx_event.type = DMX_IDX_MPEG_I_FRAME_END; + frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_MPEG_P_FRAME_START) { + idx_event.type = DMX_IDX_MPEG_P_FRAME_END; + frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_MPEG_B_FRAME_START) { + idx_event.type = DMX_IDX_MPEG_B_FRAME_END; + frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_H264_IDR_START) { + idx_event.type = DMX_IDX_H264_IDR_END; + frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_H264_NON_IDR_START) { + idx_event.type = DMX_IDX_H264_NON_IDR_END; + frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END; + } else { + idx_event.type = DMX_IDX_VC1_FRAME_END; + frame_end_in_seq = DMX_IDX_VC1_FIRST_SEQ_FRAME_END; + } - q = &buf[p]; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); - if (pktsize == 204 && (*q == 0xB8)) { - memcpy(demux->tsbuf, q, 188); - demux->tsbuf[0] = 0x47; - q = demux->tsbuf; + if (feed->first_frame_in_seq_notified && + feed->idx_params.types & frame_end_in_seq) { + idx_event.type = frame_end_in_seq; + dvb_demux_save_idx_event(feed, &idx_event, 1); + feed->first_frame_in_seq_notified = 0; } - dvb_dmx_swfilter_packet(demux, q); - p += pktsize; } - i = count - p; - if (i) { - memcpy(demux->tsbuf, &buf[p], i); - demux->tsbufp = i; - if (pktsize == 204 && demux->tsbuf[0] == 0xB8) - demux->tsbuf[0] = 0x47; + seq_start = patterns->info[pattern].type & + (DMX_IDX_MPEG_SEQ_HEADER | DMX_IDX_H264_SPS | + DMX_IDX_VC1_SEQ_HEADER); + + /* did we find start of sequence/SPS? */ + if (seq_start) { + feed->first_frame_in_seq = 1; + feed->first_frame_in_seq_notified = 0; + feed->prev_frame_valid = 0; + idx_event.type = patterns->info[pattern].type; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + return; } -bailout: - spin_unlock_irqrestore(&demux->lock, flags); -} + mpeg_frame_start = patterns->info[pattern].type & + (DMX_IDX_MPEG_I_FRAME_START | + DMX_IDX_MPEG_P_FRAME_START | + DMX_IDX_MPEG_B_FRAME_START); -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) + h264_frame_start = patterns->info[pattern].type & + (DMX_IDX_H264_IDR_START | DMX_IDX_H264_NON_IDR_START); + + vc1_frame_start = patterns->info[pattern].type & + DMX_IDX_VC1_FRAME_START; + + if (!mpeg_frame_start && !h264_frame_start && !vc1_frame_start) { + /* neither sequence nor frame, notify on the entry if needed */ + idx_event.type = patterns->info[pattern].type; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + feed->prev_frame_valid = 0; + return; + } + + /* notify on first frame in sequence/sps if needed */ + if (feed->first_frame_in_seq) { + feed->first_frame_in_seq = 0; + feed->first_frame_in_seq_notified = 1; + if (mpeg_frame_start) + idx_event.type = DMX_IDX_MPEG_FIRST_SEQ_FRAME_START; + else if (h264_frame_start) + idx_event.type = DMX_IDX_H264_FIRST_SPS_FRAME_START; + else + idx_event.type = DMX_IDX_VC1_FIRST_SEQ_FRAME_START; + + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + } + + /* notify on frame start if needed */ + idx_event.type = patterns->info[pattern].type; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + + feed->prev_frame_valid = 1; + feed->prev_frame_type = patterns->info[pattern].type; +} + +void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed, + struct dvb_dmx_video_patterns_results *patterns, int pattern, + u64 curr_stc, u64 prev_stc, + u64 curr_match_tsp, u64 prev_match_tsp, + u64 curr_pusi_tsp, u64 prev_pusi_tsp) +{ + spin_lock(&feed->demux->lock); + dvb_dmx_process_pattern_result(feed, + patterns, pattern, + curr_stc, prev_stc, + curr_match_tsp, prev_match_tsp, + curr_pusi_tsp, prev_pusi_tsp); + spin_unlock(&feed->demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_process_idx_pattern); + +static void dvb_dmx_index(struct dvb_demux_feed *feed, + const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + int i; + int p; + u64 stc; + int found_patterns; + int count = payload(buf); + u64 min_pattern_tsp_num; + struct dvb_demux_feed *tmp_feed; + struct dvb_demux *demux = feed->demux; + struct dmx_index_event_info idx_event; + struct dvb_dmx_video_patterns_results patterns; + + if (feed->demux->convert_ts) + feed->demux->convert_ts(feed, timestamp, &stc); + else + stc = 0; + + idx_event.pid = feed->pid; + idx_event.stc = stc; + idx_event.match_tsp_num = feed->rec_info->ts_output_count; + + /* PUSI ? */ + if (buf[1] & 0x40) { + feed->curr_pusi_tsp_num = feed->rec_info->ts_output_count; + if (feed->idx_params.types & DMX_IDX_PUSI) { + idx_event.type = DMX_IDX_PUSI; + idx_event.last_pusi_tsp_num = + feed->curr_pusi_tsp_num; + dvb_demux_save_idx_event(feed, &idx_event, 1); + } + } + + /* + * if we still did not encounter a TS packet with PUSI indication, + * we cannot report index entries yet as we need to provide + * the TS packet number with PUSI indication preceding the TS + * packet pointed by the reported index entry. + */ + if (feed->curr_pusi_tsp_num == (u64)-1) { + dvb_dmx_notify_indexing(feed); + return; + } + + if ((feed->idx_params.types & DMX_IDX_RAI) && /* index RAI? */ + (buf[3] & 0x20) && /* adaptation field exists? */ + (buf[4] > 0) && /* adaptation field len > 0 ? */ + (buf[5] & 0x40)) { /* RAI is set? */ + idx_event.type = DMX_IDX_RAI; + idx_event.last_pusi_tsp_num = + feed->curr_pusi_tsp_num; + dvb_demux_save_idx_event(feed, &idx_event, 1); + } + + /* + * if no pattern search is required, or the TS packet has no payload, + * pattern search is not executed. + */ + if (!feed->pattern_num || !count) { + dvb_dmx_notify_indexing(feed); + return; + } + + p = 188 - count; /* payload start */ + + found_patterns = + dvb_dmx_video_pattern_search(feed->patterns, + feed->pattern_num, &buf[p], count, + &feed->prefix_size, &patterns); + + for (i = 0; i < found_patterns; i++) + dvb_dmx_process_pattern_result(feed, &patterns, i, + stc, feed->prev_stc, + feed->rec_info->ts_output_count, feed->prev_tsp_num, + feed->curr_pusi_tsp_num, feed->prev_pusi_tsp_num); + + feed->prev_tsp_num = feed->rec_info->ts_output_count; + feed->prev_pusi_tsp_num = feed->curr_pusi_tsp_num; + feed->prev_stc = stc; + feed->last_pattern_tsp_num = feed->rec_info->ts_output_count; + + /* + * it is possible to have a TS packet that has a prefix of + * a video pattern but the video pattern is not identified yet + * until we get the next TS packet of that PID. When we get + * the next TS packet of that PID, pattern-search would + * detect that we have a new index entry that starts in the + * previous TS packet. + * In order to notify the user on index entries with match_tsp_num + * in ascending order, index events with match_tsp_num up to + * the last_pattern_tsp_num are notified now to the user, + * the rest can't be notified now as we might hit the above + * scenario and cause the events not to be notified with + * ascending order of match_tsp_num. + */ + if (feed->rec_info->idx_info.pattern_search_feeds_num == 1) { + /* + * optimization for case we have only one PID + * with video pattern search, in this case + * min_pattern_tsp_num is simply updated to the new + * TS packet number of the PID with pattern search. + */ + feed->rec_info->idx_info.min_pattern_tsp_num = + feed->last_pattern_tsp_num; + dvb_dmx_notify_indexing(feed); + return; + } + + /* + * if we have more than one PID with pattern search, + * min_pattern_tsp_num needs to be updated now based on + * last_pattern_tsp_num of all PIDs with pattern search. + */ + min_pattern_tsp_num = (u64)-1; + i = feed->rec_info->idx_info.pattern_search_feeds_num; + list_for_each_entry(tmp_feed, &demux->feed_list, list_head) { + if ((tmp_feed->state != DMX_STATE_GO) || + (tmp_feed->type != DMX_TYPE_TS) || + (tmp_feed->feed.ts.buffer.ringbuff != + feed->feed.ts.buffer.ringbuff)) + continue; + + if ((tmp_feed->last_pattern_tsp_num != (u64)-1) && + ((min_pattern_tsp_num == (u64)-1) || + (tmp_feed->last_pattern_tsp_num < + min_pattern_tsp_num))) + min_pattern_tsp_num = tmp_feed->last_pattern_tsp_num; + + if (tmp_feed->pattern_num) { + i--; + if (i == 0) + break; + } + } + + feed->rec_info->idx_info.min_pattern_tsp_num = min_pattern_tsp_num; + + /* notify all index entries up to min_pattern_tsp_num */ + dvb_dmx_notify_indexing(feed); +} + +static inline void dvb_dmx_swfilter_output_packet( + struct dvb_demux_feed *feed, + const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + /* + * if we output 192 packet with timestamp at head of packet, + * output the timestamp now before the 188 TS packet + */ + if (feed->tsp_out_format == DMX_TSP_FORMAT_192_HEAD) + feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL, + 0, &feed->feed.ts); + + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); + + /* + * if we output 192 packet with timestamp at tail of packet, + * output the timestamp now after the 188 TS packet + */ + if (feed->tsp_out_format == DMX_TSP_FORMAT_192_TAIL) + feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL, + 0, &feed->feed.ts); + + if (feed->idx_params.enable) + dvb_dmx_index(feed, buf, timestamp); + + feed->rec_info->ts_output_count++; +} + +static inline void dvb_dmx_configure_decoder_fullness( + struct dvb_demux *demux, + int initialize) +{ + struct dvb_demux_feed *feed; + int j; + + for (j = 0; j < demux->feednum; j++) { + feed = &demux->feed[j]; + + if ((feed->state != DMX_STATE_GO) || + (feed->type != DMX_TYPE_TS) || + !(feed->ts_type & TS_DECODER)) + continue; + + if (initialize) { + if (demux->decoder_fullness_init) + demux->decoder_fullness_init(feed); + } else { + if (demux->decoder_fullness_abort) + demux->decoder_fullness_abort(feed); + } + } +} + +static inline int dvb_dmx_swfilter_buffer_check( + struct dvb_demux *demux, + u16 pid) +{ + int desired_space; + int ret; + struct dmx_ts_feed *ts; + struct dvb_demux_filter *f; + struct dvb_demux_feed *feed; + int was_locked; + int i, j; + + if (likely(spin_is_locked(&demux->lock))) + was_locked = 1; + else + was_locked = 0; + + /* + * Check that there's enough free space for data output. + * If there no space, wait for it (block). + * Since this function is called while spinlock + * is acquired, the lock should be released first. + * Once we get control back, lock is acquired back + * and checks that the filter is still valid. + */ + for (j = 0; j < demux->feednum; j++) { + feed = &demux->feed[j]; + + if (demux->sw_filter_abort) + return -ENODEV; + + if ((feed->state != DMX_STATE_GO) || + ((feed->pid != pid) && (feed->pid != 0x2000))) + continue; + + if (feed->secure_mode.is_secured && + !dvb_dmx_is_rec_feed(feed)) + return 0; + + if (feed->type == DMX_TYPE_TS) { + desired_space = 192; /* upper bound */ + ts = &feed->feed.ts; + + if (feed->ts_type & TS_PACKET) { + if (likely(was_locked)) + spin_unlock(&demux->lock); + + ret = demux->buffer_ctrl.ts(ts, + desired_space, 1); + + if (likely(was_locked)) + spin_lock(&demux->lock); + + if (ret < 0) + continue; + } + + if (demux->sw_filter_abort) + return -ENODEV; + + if (!ts->is_filtering) + continue; + + if ((feed->ts_type & TS_DECODER) && + (demux->decoder_fullness_wait)) { + if (likely(was_locked)) + spin_unlock(&demux->lock); + + ret = demux->decoder_fullness_wait( + feed, + desired_space); + + if (likely(was_locked)) + spin_lock(&demux->lock); + + if (ret < 0) + continue; + } + + continue; + } + + /* else - section case */ + desired_space = feed->feed.sec.tsfeedp + 188; /* upper bound */ + for (i = 0; i < demux->filternum; i++) { + if (demux->sw_filter_abort) + return -EPERM; + + if (!feed->feed.sec.is_filtering) + continue; + + f = &demux->filter[i]; + if (f->feed != feed) + continue; + + if (likely(was_locked)) + spin_unlock(&demux->lock); + + ret = demux->buffer_ctrl.sec(&f->filter, + desired_space, 1); + + if (likely(was_locked)) + spin_lock(&demux->lock); + + if (ret < 0) + break; + } + } + + return 0; +} + +static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, + const u8 *buf, const u8 timestamp[TIMESTAMP_LEN]) +{ + u16 pid = ts_pid(buf); + u8 scrambling_bits = ts_scrambling_ctrl(buf); + struct dmx_data_ready dmx_data_ready; + + /* + * Notify on scrambling status change only when we move + * from clear (0) to non-clear and vise-versa + */ + if ((scrambling_bits && !feed->scrambling_bits) || + (!scrambling_bits && feed->scrambling_bits)) { + dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS; + dmx_data_ready.data_length = 0; + dmx_data_ready.scrambling_bits.pid = pid; + dmx_data_ready.scrambling_bits.old_value = + feed->scrambling_bits; + dmx_data_ready.scrambling_bits.new_value = scrambling_bits; + + if (feed->type == DMX_TYPE_SEC) + dvb_dmx_notify_section_event(feed, &dmx_data_ready, 0); + else if (feed->feed.ts.is_filtering) + feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready); + } + + feed->scrambling_bits = scrambling_bits; + + switch (feed->type) { + case DMX_TYPE_TS: + if (!feed->feed.ts.is_filtering) + break; + if (feed->ts_type & TS_PACKET) { + if (feed->ts_type & TS_PAYLOAD_ONLY) { + if (!feed->secure_mode.is_secured) + dvb_dmx_swfilter_payload(feed, buf); + } else { + dvb_dmx_swfilter_output_packet(feed, + buf, timestamp); + } + } + if ((feed->ts_type & TS_DECODER) && + !feed->secure_mode.is_secured) + if (feed->demux->write_to_decoder) + feed->demux->write_to_decoder(feed, buf, 188); + break; + + case DMX_TYPE_SEC: + if (!feed->feed.sec.is_filtering || + feed->secure_mode.is_secured) + break; + if (dvb_dmx_swfilter_section_one_packet(feed, buf) < 0) + feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; + break; + + default: + break; + } +} + +#define DVR_FEED(f) \ + (((f)->type == DMX_TYPE_TS) && \ + ((f)->feed.ts.is_filtering) && \ + (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) + +static void dvb_dmx_swfilter_one_packet(struct dvb_demux *demux, const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + struct dvb_demux_feed *feed; + u16 pid = ts_pid(buf); + int dvr_done = 0; + + if (dvb_demux_speedcheck) { + ktime_t cur_time; + u64 speed_bytes, speed_timedelta; + + demux->speed_pkts_cnt++; + + /* show speed every SPEED_PKTS_INTERVAL packets */ + if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { + cur_time = ktime_get(); + + if (ktime_to_ns(demux->speed_last_time) != 0) { + speed_bytes = (u64)demux->speed_pkts_cnt + * 188 * 8; + /* convert to 1024 basis */ + speed_bytes = 1000 * div64_u64(speed_bytes, + 1024); + speed_timedelta = ktime_ms_delta(cur_time, + demux->speed_last_time); + pr_info("TS speed %llu Kbits/sec\n", + div64_u64(speed_bytes, speed_timedelta)); + } + + demux->speed_last_time = cur_time; + demux->speed_pkts_cnt = 0; + } + } + + if (buf[1] & 0x80) { + dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", pid, + buf[1]); + /* + * data in this packet can't be trusted - drop it unless + * module option dvb_demux_feed_err_pkts is set + */ + if (!dvb_demux_feed_err_pkts) + return; + } else /* if TEI bit is set, pid may be wrong- skip pkt counter */ + if (demux->cnt_storage && dvb_demux_tscheck) { + /* check pkt counter */ + if (pid < MAX_PID) { + if (buf[3] & 0x10) + demux->cnt_storage[pid] = + (demux->cnt_storage[pid] + 1) & + 0xf; + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { + dprintk_tscheck( + "TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", + pid, demux->cnt_storage[pid], + buf[3] & 0xf); + demux->cnt_storage[pid] = buf[3] & 0xf; + } + } + /* end check */ + } + + if (demux->playback_mode == DMX_PB_MODE_PULL) + if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0) + return; + + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + + /* + * copy each packet only once to the dvr device, even + * if a PID is in multiple filters (e.g. video + PCR) + */ + if ((DVR_FEED(feed)) && (dvr_done++)) + continue; + + if (feed->pid == pid) + dvb_dmx_swfilter_packet_type(feed, buf, timestamp); + else if ((feed->pid == 0x2000) && + (feed->feed.ts.is_filtering)) + dvb_dmx_swfilter_output_packet(feed, buf, timestamp); + } +} + +void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + spin_lock(&demux->lock); + dvb_dmx_swfilter_one_packet(demux, buf, timestamp); + spin_unlock(&demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_packet); + +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, + size_t count) +{ + ktime_t pre_time = ktime_set(0, 0); + u8 timestamp[TIMESTAMP_LEN] = {0}; + + if (dvb_demux_performancecheck) + pre_time = ktime_get(); + + spin_lock(&demux->lock); + + demux->sw_filter_abort = 0; + dvb_dmx_configure_decoder_fullness(demux, 1); + + while (count--) { + if (buf[0] == 0x47) + dvb_dmx_swfilter_one_packet(demux, buf, timestamp); + buf += 188; + } + + spin_unlock(&demux->lock); + + if (dvb_demux_performancecheck) + demux->total_process_time += dvb_dmx_calc_time_delta(pre_time); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); + +static inline int find_next_packet(const u8 *buf, int pos, size_t count, + const int pktsize, const int leadingbytes) +{ + int start = pos, lost; + + while (pos < count) { + if ((buf[pos] == 0x47 && !leadingbytes) || + (pktsize == 204 && buf[pos] == 0xB8) || + (pktsize == 192 && leadingbytes && + (pos+leadingbytes < count) && + buf[pos+leadingbytes] == 0x47)) + break; + pos++; + } + + lost = pos - start; + if (lost) { + /* This garbage is part of a valid packet? */ + int backtrack = pos - pktsize; + + if (backtrack >= 0 && (buf[backtrack] == 0x47 || + (pktsize == 204 && buf[backtrack] == 0xB8) || + (pktsize == 192 && + buf[backtrack+leadingbytes] == 0x47))) + return backtrack; + } + + return pos; +} + +/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ +static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, + size_t count, const int pktsize, const int leadingbytes) +{ + int p = 0, i = 0, j = 0; + const u8 *q; + ktime_t pre_time; + u8 timestamp[TIMESTAMP_LEN]; + + if (dvb_demux_performancecheck) + pre_time = ktime_get(); + + spin_lock(&demux->lock); + + demux->sw_filter_abort = 0; + dvb_dmx_configure_decoder_fullness(demux, 1); + + if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ + i = demux->tsbufp; + j = pktsize - i; + if (count < j) { + memcpy(&demux->tsbuf[i], buf, count); + demux->tsbufp += count; + goto bailout; + } + memcpy(&demux->tsbuf[i], buf, j); + + if (pktsize == 192) { + if (leadingbytes) + memcpy(timestamp, &demux->tsbuf[p], + TIMESTAMP_LEN); + else + memcpy(timestamp, &demux->tsbuf[188], + TIMESTAMP_LEN); + } else { + memset(timestamp, 0, TIMESTAMP_LEN); + } + + if (pktsize == 192 && + leadingbytes && + demux->tsbuf[leadingbytes] == 0x47) /* double check */ + dvb_dmx_swfilter_one_packet(demux, + demux->tsbuf + TIMESTAMP_LEN, timestamp); + else if (demux->tsbuf[0] == 0x47) /* double check */ + dvb_dmx_swfilter_one_packet(demux, + demux->tsbuf, timestamp); + demux->tsbufp = 0; + p += j; + } + + while (1) { + p = find_next_packet(buf, p, count, pktsize, leadingbytes); + + if (demux->sw_filter_abort) + goto bailout; + + if (p >= count) + break; + if (count - p < pktsize) + break; + + q = &buf[p]; + + if (pktsize == 204 && (*q == 0xB8)) { + memcpy(demux->tsbuf, q, 188); + demux->tsbuf[0] = 0x47; + q = demux->tsbuf; + } + + if (pktsize == 192) { + if (leadingbytes) { + q = &buf[p+leadingbytes]; + memcpy(timestamp, &buf[p], TIMESTAMP_LEN); + } else { + memcpy(timestamp, &buf[p+188], TIMESTAMP_LEN); + } + } else { + memset(timestamp, 0, TIMESTAMP_LEN); + } + + dvb_dmx_swfilter_one_packet(demux, q, timestamp); + p += pktsize; + } + + i = count - p; + if (i) { + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; + if (pktsize == 204 && demux->tsbuf[0] == 0xB8) + demux->tsbuf[0] = 0x47; + } + +bailout: + spin_unlock(&demux->lock); + + if (dvb_demux_performancecheck) + demux->total_process_time += dvb_dmx_calc_time_delta(pre_time); +} + +void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + _dvb_dmx_swfilter(demux, buf, count, 188, 0); +} +EXPORT_SYMBOL(dvb_dmx_swfilter); + +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + _dvb_dmx_swfilter(demux, buf, count, 204, 0); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_204); + +void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + spin_lock(&demux->lock); + + demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); + + spin_unlock(&demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_raw); + +void dvb_dmx_swfilter_format( + struct dvb_demux *demux, + const u8 *buf, + size_t count, + enum dmx_tsp_format_t tsp_format) +{ + switch (tsp_format) { + case DMX_TSP_FORMAT_188: + _dvb_dmx_swfilter(demux, buf, count, 188, 0); + break; + + case DMX_TSP_FORMAT_192_TAIL: + _dvb_dmx_swfilter(demux, buf, count, 192, 0); + break; + + case DMX_TSP_FORMAT_192_HEAD: + _dvb_dmx_swfilter(demux, buf, count, 192, TIMESTAMP_LEN); + break; + + case DMX_TSP_FORMAT_204: + _dvb_dmx_swfilter(demux, buf, count, 204, 0); + break; + + default: + pr_err("%s: invalid TS packet format (format=%d)\n", __func__, + tsp_format); + break; + } +} +EXPORT_SYMBOL(dvb_dmx_swfilter_format); + +static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) +{ + int i; + + for (i = 0; i < demux->filternum; i++) + if (demux->filter[i].state == DMX_STATE_FREE) + break; + + if (i == demux->filternum) + return NULL; + + demux->filter[i].state = DMX_STATE_ALLOCATED; + + return &demux->filter[i]; +} + +static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) +{ + int i; + + for (i = 0; i < demux->feednum; i++) + if (demux->feed[i].state == DMX_STATE_FREE) + break; + + if (i == demux->feednum) + return NULL; + + demux->feed[i].state = DMX_STATE_ALLOCATED; + + return &demux->feed[i]; +} + +const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern) +{ + switch (dmx_idx_pattern) { + case DMX_IDX_MPEG_SEQ_HEADER: + return &mpeg2_seq_hdr; + + case DMX_IDX_MPEG_GOP: + return &mpeg2_gop; + + case DMX_IDX_MPEG_I_FRAME_START: + return &mpeg2_iframe; + + case DMX_IDX_MPEG_P_FRAME_START: + return &mpeg2_pframe; + + case DMX_IDX_MPEG_B_FRAME_START: + return &mpeg2_bframe; + + case DMX_IDX_H264_SPS: + return &h264_sps; + + case DMX_IDX_H264_PPS: + return &h264_pps; + + case DMX_IDX_H264_IDR_START: + return &h264_idr; + + case DMX_IDX_H264_NON_IDR_START: + return &h264_non_idr; + + case DMX_IDX_H264_ACCESS_UNIT_DEL: + return &h264_non_access_unit_del; + + case DMX_IDX_H264_SEI: + return &h264_non_sei; + + case DMX_IDX_VC1_SEQ_HEADER: + return &vc1_seq_hdr; + + case DMX_IDX_VC1_ENTRY_POINT: + return &vc1_entry_point; + + case DMX_IDX_VC1_FRAME_START: + return &vc1_frame; + + default: + return NULL; + } +} +EXPORT_SYMBOL(dvb_dmx_get_pattern); + +static void dvb_dmx_init_idx_state(struct dvb_demux_feed *feed) +{ + feed->prev_tsp_num = (u64)-1; + feed->curr_pusi_tsp_num = (u64)-1; + feed->prev_pusi_tsp_num = (u64)-1; + feed->prev_frame_valid = 0; + feed->first_frame_in_seq = 0; + feed->first_frame_in_seq_notified = 0; + feed->last_pattern_tsp_num = (u64)-1; + feed->pattern_num = 0; + memset(&feed->prefix_size, 0, + sizeof(struct dvb_dmx_video_prefix_size_masks)); + + if (feed->idx_params.types & + (DMX_IDX_MPEG_SEQ_HEADER | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_MPEG_GOP)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP); + feed->pattern_num++; + } + + /* MPEG2 I-frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_MPEG_I_FRAME_START | DMX_IDX_MPEG_I_FRAME_END | + DMX_IDX_MPEG_P_FRAME_END | DMX_IDX_MPEG_B_FRAME_END | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START); + feed->pattern_num++; + } + + /* MPEG2 P-frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_MPEG_P_FRAME_START | DMX_IDX_MPEG_P_FRAME_END | + DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_B_FRAME_END | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START); + feed->pattern_num++; + } + + /* MPEG2 B-frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_MPEG_B_FRAME_START | DMX_IDX_MPEG_B_FRAME_END | + DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_P_FRAME_END | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_H264_SPS | + DMX_IDX_H264_FIRST_SPS_FRAME_START | + DMX_IDX_H264_FIRST_SPS_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_SPS); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_H264_PPS)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_PPS); + feed->pattern_num++; + } + + /* H264 IDR */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_H264_IDR_START | DMX_IDX_H264_IDR_END | + DMX_IDX_H264_NON_IDR_END | + DMX_IDX_H264_FIRST_SPS_FRAME_START | + DMX_IDX_H264_FIRST_SPS_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START); + feed->pattern_num++; + } + + /* H264 non-IDR */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_H264_NON_IDR_START | DMX_IDX_H264_NON_IDR_END | + DMX_IDX_H264_IDR_END | + DMX_IDX_H264_FIRST_SPS_FRAME_START | + DMX_IDX_H264_FIRST_SPS_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_H264_ACCESS_UNIT_DEL)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_ACCESS_UNIT_DEL); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_H264_SEI)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_SEI); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_VC1_SEQ_HEADER | + DMX_IDX_VC1_FIRST_SEQ_FRAME_START | + DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_VC1_ENTRY_POINT)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT); + feed->pattern_num++; + } + + /* VC1 frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_VC1_FRAME_START | DMX_IDX_VC1_FRAME_END | + DMX_IDX_VC1_FIRST_SEQ_FRAME_START | + DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START); + feed->pattern_num++; + } + + if (feed->pattern_num) + feed->rec_info->idx_info.pattern_search_feeds_num++; +} + +static struct dvb_demux_rec_info *dvb_dmx_alloc_rec_info( + struct dmx_ts_feed *ts_feed) +{ + int i; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + struct dvb_demux_rec_info *rec_info; + struct dvb_demux_feed *tmp_feed; + + /* check if this feed share recording buffer with other active feeds */ + list_for_each_entry(tmp_feed, &demux->feed_list, list_head) { + if ((tmp_feed->state == DMX_STATE_GO) && + (tmp_feed->type == DMX_TYPE_TS) && + (tmp_feed != feed) && + (tmp_feed->feed.ts.buffer.ringbuff == + ts_feed->buffer.ringbuff)) { + /* indexing information is shared between the feeds */ + tmp_feed->rec_info->ref_count++; + return tmp_feed->rec_info; + } + } + + /* Need to allocate a new indexing info */ + for (i = 0; i < demux->feednum; i++) + if (!demux->rec_info_pool[i].ref_count) + break; + + if (i == demux->feednum) + return NULL; + + rec_info = &demux->rec_info_pool[i]; + rec_info->ref_count++; + INIT_LIST_HEAD(&rec_info->idx_info.free_list); + INIT_LIST_HEAD(&rec_info->idx_info.ready_list); + + for (i = 0; i < DMX_IDX_EVENT_QUEUE_SIZE; i++) + list_add(&rec_info->idx_info.events[i].next, + &rec_info->idx_info.free_list); + + rec_info->ts_output_count = 0; + rec_info->idx_info.min_pattern_tsp_num = (u64)-1; + rec_info->idx_info.pattern_search_feeds_num = 0; + rec_info->idx_info.indexing_feeds_num = 0; + + return rec_info; +} + +static void dvb_dmx_free_rec_info(struct dmx_ts_feed *ts_feed) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + + if (!feed->rec_info || !feed->rec_info->ref_count) { + pr_err("%s: invalid idx info state\n", __func__); + return; + } + + feed->rec_info->ref_count--; +} + +static int dvb_demux_feed_find(struct dvb_demux_feed *feed) +{ + struct dvb_demux_feed *entry; + + list_for_each_entry(entry, &feed->demux->feed_list, list_head) + if (entry == feed) + return 1; + + return 0; +} + +static void dvb_demux_feed_add(struct dvb_demux_feed *feed) +{ + spin_lock_irq(&feed->demux->lock); + if (dvb_demux_feed_find(feed)) { + pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n", + __func__, feed->type, feed->state, feed->pid); + goto out; + } + + list_add(&feed->list_head, &feed->demux->feed_list); +out: + spin_unlock_irq(&feed->demux->lock); +} + +static void dvb_demux_feed_del(struct dvb_demux_feed *feed) +{ + spin_lock_irq(&feed->demux->lock); + if (!(dvb_demux_feed_find(feed))) { + pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n", + __func__, feed->type, feed->state, feed->pid); + goto out; + } + + list_del(&feed->list_head); +out: + spin_unlock_irq(&feed->demux->lock); +} + +static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, + enum dmx_ts_pes pes_type, + size_t circular_buffer_size, ktime_t timeout) { - _dvb_dmx_swfilter(demux, buf, count, 188); + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + + if (pid > DMX_MAX_PID) + return -EINVAL; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (ts_type & TS_DECODER) { + if (pes_type >= DMX_PES_OTHER) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (demux->pesfilter[pes_type] && + demux->pesfilter[pes_type] != feed) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + demux->pesfilter[pes_type] = feed; + demux->pids[pes_type] = pid; + } + + dvb_demux_feed_add(feed); + + feed->pid = pid; + feed->buffer_size = circular_buffer_size; + feed->timeout = timeout; + feed->ts_type = ts_type; + feed->pes_type = pes_type; + + if (feed->buffer_size) { +#ifdef NOBUFS + feed->buffer = NULL; +#else + feed->buffer = vmalloc(feed->buffer_size); + if (!feed->buffer) { + mutex_unlock(&demux->mutex); + return -ENOMEM; + } +#endif + } + + feed->state = DMX_STATE_READY; + mutex_unlock(&demux->mutex); + + return 0; } -EXPORT_SYMBOL(dvb_dmx_swfilter); -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) +static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) { - _dvb_dmx_swfilter(demux, buf, count, 204); + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (!demux->start_feed) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } + + feed->first_cc = 1; + feed->scrambling_bits = 0; + + if ((feed->ts_type & TS_PACKET) && + !(feed->ts_type & TS_PAYLOAD_ONLY)) { + feed->rec_info = dvb_dmx_alloc_rec_info(ts_feed); + if (!feed->rec_info) { + mutex_unlock(&demux->mutex); + return -ENOMEM; + } + if (feed->idx_params.enable) { + dvb_dmx_init_idx_state(feed); + feed->rec_info->idx_info.indexing_feeds_num++; + if (demux->set_indexing) + demux->set_indexing(feed); + } + } else { + feed->pattern_num = 0; + feed->rec_info = NULL; + } + + ret = demux->start_feed(feed); + if (ret < 0) { + if ((feed->ts_type & TS_PACKET) && + !(feed->ts_type & TS_PAYLOAD_ONLY)) { + dvb_dmx_free_rec_info(ts_feed); + feed->rec_info = NULL; + } + mutex_unlock(&demux->mutex); + return ret; + } + + spin_lock_irq(&demux->lock); + ts_feed->is_filtering = 1; + feed->state = DMX_STATE_GO; + spin_unlock_irq(&demux->lock); + mutex_unlock(&demux->mutex); + + return 0; } -EXPORT_SYMBOL(dvb_dmx_swfilter_204); -void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) +static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) { - unsigned long flags; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; - spin_lock_irqsave(&demux->lock, flags); + mutex_lock(&demux->mutex); - demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (!demux->stop_feed) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } + + ret = demux->stop_feed(feed); + + spin_lock_irq(&demux->lock); + ts_feed->is_filtering = 0; + feed->state = DMX_STATE_ALLOCATED; + spin_unlock_irq(&demux->lock); + + if (feed->rec_info) { + if (feed->pattern_num) + feed->rec_info->idx_info.pattern_search_feeds_num--; + if (feed->idx_params.enable) + feed->rec_info->idx_info.indexing_feeds_num--; + dvb_dmx_free_rec_info(ts_feed); + feed->rec_info = NULL; + } - spin_unlock_irqrestore(&demux->lock, flags); + mutex_unlock(&demux->mutex); + + return ret; } -EXPORT_SYMBOL(dvb_dmx_swfilter_raw); -static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) +static int dmx_ts_feed_decoder_buff_status(struct dmx_ts_feed *ts_feed, + struct dmx_buffer_status *dmx_buffer_status) { - int i; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; - for (i = 0; i < demux->filternum; i++) - if (demux->filter[i].state == DMX_STATE_FREE) - break; + mutex_lock(&demux->mutex); - if (i == demux->filternum) - return NULL; + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } - demux->filter[i].state = DMX_STATE_ALLOCATED; + if (!demux->decoder_buffer_status) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } - return &demux->filter[i]; + ret = demux->decoder_buffer_status(feed, dmx_buffer_status); + + mutex_unlock(&demux->mutex); + + return ret; } -static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) +static int dmx_ts_feed_reuse_decoder_buffer(struct dmx_ts_feed *ts_feed, + int cookie) { - int i; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; - for (i = 0; i < demux->feednum; i++) - if (demux->feed[i].state == DMX_STATE_FREE) - break; + mutex_lock(&demux->mutex); - if (i == demux->feednum) - return NULL; + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } - demux->feed[i].state = DMX_STATE_ALLOCATED; + if (!demux->reuse_decoder_buffer) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } - return &demux->feed[i]; + ret = demux->reuse_decoder_buffer(feed, cookie); + + mutex_unlock(&demux->mutex); + + return ret; } -static int dvb_demux_feed_find(struct dvb_demux_feed *feed) +static int dmx_ts_feed_data_ready_cb(struct dmx_ts_feed *feed, + dmx_ts_data_ready_cb callback) { - struct dvb_demux_feed *entry; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - list_for_each_entry(entry, &feed->demux->feed_list, list_head) - if (entry == feed) - return 1; + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + dvbdmxfeed->data_ready_cb.ts = callback; + + mutex_unlock(&dvbdmx->mutex); return 0; } -static void dvb_demux_feed_add(struct dvb_demux_feed *feed) +static int dmx_ts_set_secure_mode(struct dmx_ts_feed *feed, + struct dmx_secure_mode *secure_mode) { - spin_lock_irq(&feed->demux->lock); - if (dvb_demux_feed_find(feed)) { - pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n", - __func__, feed->type, feed->state, feed->pid); - goto out; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EBUSY; } - list_add(&feed->list_head, &feed->demux->feed_list); -out: - spin_unlock_irq(&feed->demux->lock); + dvbdmxfeed->secure_mode = *secure_mode; + mutex_unlock(&dvbdmx->mutex); + return 0; } -static void dvb_demux_feed_del(struct dvb_demux_feed *feed) +static int dmx_ts_set_cipher_ops(struct dmx_ts_feed *feed, + struct dmx_cipher_operations *cipher_ops) { - spin_lock_irq(&feed->demux->lock); - if (!(dvb_demux_feed_find(feed))) { - pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n", - __func__, feed->type, feed->state, feed->pid); - goto out; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + int ret = 0; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if ((dvbdmxfeed->state == DMX_STATE_GO) && + dvbdmx->set_cipher_op) + ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops); + + if (!ret) + dvbdmxfeed->cipher_ops = *cipher_ops; + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + +static int dmx_ts_set_video_codec( + struct dmx_ts_feed *ts_feed, + enum dmx_video_codec video_codec) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + + feed->video_codec = video_codec; + + return 0; +} + +static int dmx_ts_set_idx_params(struct dmx_ts_feed *ts_feed, + struct dmx_indexing_params *idx_params) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *dvbdmx = feed->demux; + int idx_enabled; + int ret = 0; + + mutex_lock(&dvbdmx->mutex); + + if ((feed->state == DMX_STATE_GO) && + !feed->rec_info) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + idx_enabled = feed->idx_params.enable; + feed->idx_params = *idx_params; + + if (feed->state == DMX_STATE_GO) { + spin_lock_irq(&dvbdmx->lock); + if (feed->pattern_num) + feed->rec_info->idx_info.pattern_search_feeds_num--; + if (idx_enabled && !idx_params->enable) + feed->rec_info->idx_info.indexing_feeds_num--; + if (!idx_enabled && idx_params->enable) + feed->rec_info->idx_info.indexing_feeds_num++; + dvb_dmx_init_idx_state(feed); + spin_unlock_irq(&dvbdmx->lock); + + if (dvbdmx->set_indexing) + ret = dvbdmx->set_indexing(feed); + } + + mutex_unlock(&dvbdmx->mutex); + + return ret; +} + +static int dvbdmx_ts_feed_oob_cmd(struct dmx_ts_feed *ts_feed, + struct dmx_oob_command *cmd) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dmx_data_ready data; + struct dvb_demux *dvbdmx = feed->demux; + int ret = 0; + int secure_non_rec = feed->secure_mode.is_secured && + !dvb_dmx_is_rec_feed(feed); + + mutex_lock(&dvbdmx->mutex); + + if (feed->state != DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + /* Decoder & non-recording secure feeds are handled by plug-in */ + if ((feed->ts_type & TS_DECODER) || secure_non_rec) { + if (feed->demux->oob_command) + ret = feed->demux->oob_command(feed, cmd); + } + + if (!(feed->ts_type & (TS_PAYLOAD_ONLY | TS_PACKET)) || + secure_non_rec) { + mutex_unlock(&dvbdmx->mutex); + return ret; + } + + data.data_length = 0; + + switch (cmd->type) { + case DMX_OOB_CMD_EOS: + if (feed->ts_type & TS_PAYLOAD_ONLY) + dvb_dmx_check_pes_end(feed); + + data.status = DMX_OK_EOS; + ret = feed->data_ready_cb.ts(&feed->feed.ts, &data); + break; + + case DMX_OOB_CMD_MARKER: + data.status = DMX_OK_MARKER; + data.marker.id = cmd->params.marker.id; + ret = feed->data_ready_cb.ts(&feed->feed.ts, &data); + break; + + default: + ret = -EINVAL; + break; } - list_del(&feed->list_head); -out: - spin_unlock_irq(&feed->demux->lock); + mutex_unlock(&dvbdmx->mutex); + return ret; } -static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, ktime_t timeout) +static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed, + u8 *value) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; - if (pid > DMX_MAX_PID) + spin_lock(&demux->lock); + + if (!ts_feed->is_filtering) { + spin_unlock(&demux->lock); return -EINVAL; + } - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; + *value = feed->scrambling_bits; + spin_unlock(&demux->lock); - if (ts_type & TS_DECODER) { - if (pes_type >= DMX_PES_OTHER) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } + return 0; +} - if (demux->pesfilter[pes_type] && - demux->pesfilter[pes_type] != feed) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } +static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed, + char *data, size_t size) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; - demux->pesfilter[pes_type] = feed; - demux->pids[pes_type] = pid; + spin_lock(&demux->lock); + if (!ts_feed->is_filtering) { + spin_unlock(&demux->lock); + return 0; } - dvb_demux_feed_add(feed); - - feed->pid = pid; - feed->timeout = timeout; - feed->ts_type = ts_type; - feed->pes_type = pes_type; + feed->cb.ts(data, size, NULL, 0, ts_feed); - feed->state = DMX_STATE_READY; - mutex_unlock(&demux->mutex); + spin_unlock(&demux->lock); return 0; } -static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) +static int dmx_ts_set_tsp_out_format( + struct dmx_ts_feed *ts_feed, + enum dmx_tsp_format_t tsp_format) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - struct dvb_demux *demux = feed->demux; - int ret; + struct dvb_demux *dvbdmx = feed->demux; - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; + mutex_lock(&dvbdmx->mutex); - if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { - mutex_unlock(&demux->mutex); + if (feed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); return -EINVAL; } - if (!demux->start_feed) { - mutex_unlock(&demux->mutex); - return -ENODEV; - } + feed->tsp_out_format = tsp_format; + mutex_unlock(&dvbdmx->mutex); + return 0; +} - if ((ret = demux->start_feed(feed)) < 0) { - mutex_unlock(&demux->mutex); - return ret; - } +/** + * dvbdmx_ts_reset_pes_state() - Reset the current PES length and PES counters + * + * @feed: dvb demux feed object + */ +void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed) +{ + unsigned long flags; - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 1; - feed->state = DMX_STATE_GO; - spin_unlock_irq(&demux->lock); - mutex_unlock(&demux->mutex); + /* + * Reset PES state. + * PUSI seen indication is kept so we can get partial PES. + */ + spin_lock_irqsave(&feed->demux->lock, flags); - return 0; + feed->peslen = 0; + feed->pes_tei_counter = 0; + feed->pes_cont_err_counter = 0; + feed->pes_ts_packets_num = 0; + + spin_unlock_irqrestore(&feed->demux->lock, flags); } +EXPORT_SYMBOL(dvbdmx_ts_reset_pes_state); -static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) +static int dvbdmx_ts_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; - int ret; + int ret = 0; - mutex_lock(&demux->mutex); - - if (feed->state < DMX_STATE_GO) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; - if (!demux->stop_feed) { - mutex_unlock(&demux->mutex); - return -ENODEV; - } + dvbdmx_ts_reset_pes_state(feed); - ret = demux->stop_feed(feed); + if ((feed->ts_type & TS_DECODER) && demux->flush_decoder_buffer) + /* Call decoder specific flushing if one exists */ + ret = demux->flush_decoder_buffer(feed, length); - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 0; - feed->state = DMX_STATE_ALLOCATED; - spin_unlock_irq(&demux->lock); mutex_unlock(&demux->mutex); - return ret; } @@ -778,7 +2597,21 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, feed->cb.ts = callback; feed->demux = demux; feed->pid = 0xffff; - feed->peslen = 0xfffa; + feed->peslen = 0; + feed->pes_tei_counter = 0; + feed->pes_ts_packets_num = 0; + feed->pes_cont_err_counter = 0; + feed->secure_mode.is_secured = 0; + feed->buffer = NULL; + feed->tsp_out_format = DMX_TSP_FORMAT_188; + feed->idx_params.enable = 0; + + /* default behaviour - pass first PES data even if it is + * partial PES data from previous PES that we didn't receive its header. + * Override this to 0 in your start_feed function in order to handle + * first PES differently. + */ + feed->pusi_seen = 1; (*ts_feed) = &feed->feed.ts; (*ts_feed)->parent = dmx; @@ -787,6 +2620,22 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; (*ts_feed)->set = dmx_ts_feed_set; + (*ts_feed)->set_video_codec = dmx_ts_set_video_codec; + (*ts_feed)->set_idx_params = dmx_ts_set_idx_params; + (*ts_feed)->set_tsp_out_format = dmx_ts_set_tsp_out_format; + (*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status; + (*ts_feed)->reuse_decoder_buffer = dmx_ts_feed_reuse_decoder_buffer; + (*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb; + (*ts_feed)->notify_data_read = NULL; + (*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode; + (*ts_feed)->set_cipher_ops = dmx_ts_set_cipher_ops; + (*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd; + (*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits; + (*ts_feed)->ts_insertion_init = NULL; + (*ts_feed)->ts_insertion_terminate = NULL; + (*ts_feed)->ts_insertion_insert_buffer = + dvbdmx_ts_insertion_insert_buffer; + (*ts_feed)->flush_buffer = dvbdmx_ts_flush_buffer; if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { feed->state = DMX_STATE_FREE; @@ -815,10 +2664,14 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, mutex_unlock(&demux->mutex); return -EINVAL; } +#ifndef NOBUFS + vfree(feed->buffer); + feed->buffer = NULL; +#endif feed->state = DMX_STATE_FREE; feed->filter->state = DMX_STATE_FREE; - + ts_feed->priv = NULL; dvb_demux_feed_del(feed); feed->pid = 0xffff; @@ -866,7 +2719,8 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, } static int dmx_section_feed_set(struct dmx_section_feed *feed, - u16 pid, int check_crc) + u16 pid, size_t circular_buffer_size, + int check_crc) { struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; @@ -880,8 +2734,19 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed, dvb_demux_feed_add(dvbdmxfeed); dvbdmxfeed->pid = pid; + dvbdmxfeed->buffer_size = circular_buffer_size; dvbdmxfeed->feed.sec.check_crc = check_crc; +#ifdef NOBUFS + dvbdmxfeed->buffer = NULL; +#else + dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); + if (!dvbdmxfeed->buffer) { + mutex_unlock(&dvbdmx->mutex); + return -ENOMEM; + } +#endif + dvbdmxfeed->state = DMX_STATE_READY; mutex_unlock(&dvbdmx->mutex); return 0; @@ -932,6 +2797,8 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = 0; dvbdmxfeed->feed.sec.seclen = 0; + dvbdmxfeed->first_cc = 1; + dvbdmxfeed->scrambling_bits = 0; if (!dvbdmx->start_feed) { mutex_unlock(&dvbdmx->mutex); @@ -962,6 +2829,11 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) mutex_lock(&dvbdmx->mutex); + if (dvbdmxfeed->state < DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + if (!dvbdmx->stop_feed) { mutex_unlock(&dvbdmx->mutex); return -ENODEV; @@ -978,6 +2850,66 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) return ret; } + +static int dmx_section_feed_data_ready_cb(struct dmx_section_feed *feed, + dmx_section_data_ready_cb callback) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + dvbdmxfeed->data_ready_cb.sec = callback; + + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dmx_section_set_secure_mode(struct dmx_section_feed *feed, + struct dmx_secure_mode *secure_mode) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EBUSY; + } + + dvbdmxfeed->secure_mode = *secure_mode; + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dmx_section_set_cipher_ops(struct dmx_section_feed *feed, + struct dmx_cipher_operations *cipher_ops) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + int ret = 0; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if ((dvbdmxfeed->state == DMX_STATE_GO) && + dvbdmx->set_cipher_op) { + ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops); + } + + if (!ret) + dvbdmxfeed->cipher_ops = *cipher_ops; + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, struct dmx_section_filter *filter) { @@ -1011,12 +2943,82 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, f->next = f->next->next; } + filter->priv = NULL; dvbdmxfilter->state = DMX_STATE_FREE; spin_unlock_irq(&dvbdmx->lock); mutex_unlock(&dvbdmx->mutex); return 0; } +static int dvbdmx_section_feed_oob_cmd(struct dmx_section_feed *section_feed, + struct dmx_oob_command *cmd) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed; + struct dvb_demux *dvbdmx = feed->demux; + struct dmx_data_ready data; + int ret = 0; + + data.data_length = 0; + + mutex_lock(&dvbdmx->mutex); + + if (feed->state != DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + /* Secure section feeds are handled by the plug-in */ + if (feed->secure_mode.is_secured) { + if (feed->demux->oob_command) + ret = feed->demux->oob_command(feed, cmd); + else + ret = 0; + + mutex_unlock(&dvbdmx->mutex); + return ret; + } + + switch (cmd->type) { + case DMX_OOB_CMD_EOS: + data.status = DMX_OK_EOS; + break; + + case DMX_OOB_CMD_MARKER: + data.status = DMX_OK_MARKER; + data.marker.id = cmd->params.marker.id; + break; + + default: + ret = -EINVAL; + break; + } + + if (!ret) + ret = dvb_dmx_notify_section_event(feed, &data, 1); + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + +static int dvbdmx_section_get_scrambling_bits( + struct dmx_section_feed *section_feed, u8 *value) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed; + struct dvb_demux *demux = feed->demux; + + spin_lock(&demux->lock); + + if (!section_feed->is_filtering) { + spin_unlock(&demux->lock); + return -EINVAL; + } + + *value = feed->scrambling_bits; + spin_unlock(&demux->lock); + + return 0; +} + static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, struct dmx_section_feed **feed, dmx_section_cb callback) @@ -1036,10 +3038,14 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->cb.sec = callback; dvbdmxfeed->demux = dvbdmx; dvbdmxfeed->pid = 0xffff; + dvbdmxfeed->secure_mode.is_secured = 0; + dvbdmxfeed->tsp_out_format = DMX_TSP_FORMAT_188; dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.tsfeedp = 0; dvbdmxfeed->filter = NULL; + dvbdmxfeed->buffer = NULL; + dvbdmxfeed->idx_params.enable = 0; (*feed) = &dvbdmxfeed->feed.sec; (*feed)->is_filtering = 0; @@ -1051,6 +3057,13 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, (*feed)->start_filtering = dmx_section_feed_start_filtering; (*feed)->stop_filtering = dmx_section_feed_stop_filtering; (*feed)->release_filter = dmx_section_feed_release_filter; + (*feed)->data_ready_cb = dmx_section_feed_data_ready_cb; + (*feed)->notify_data_read = NULL; + (*feed)->set_secure_mode = dmx_section_set_secure_mode; + (*feed)->set_cipher_ops = dmx_section_set_cipher_ops; + (*feed)->oob_command = dvbdmx_section_feed_oob_cmd; + (*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits; + (*feed)->flush_buffer = NULL; mutex_unlock(&dvbdmx->mutex); return 0; @@ -1068,8 +3081,12 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux, mutex_unlock(&dvbdmx->mutex); return -EINVAL; } +#ifndef NOBUFS + vfree(dvbdmxfeed->buffer); + dvbdmxfeed->buffer = NULL; +#endif dvbdmxfeed->state = DMX_STATE_FREE; - + feed->priv = NULL; dvb_demux_feed_del(dvbdmxfeed); dvbdmxfeed->pid = 0xffff; @@ -1105,23 +3122,18 @@ static int dvbdmx_close(struct dmx_demux *demux) return 0; } -static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) +static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) { struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - void *p; - if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) + if (!demux->frontend || !buf || demux->dvr_input_protected || + (demux->frontend->source != DMX_MEMORY_FE)) return -EINVAL; - - p = memdup_user(buf, count); - if (IS_ERR(p)) - return PTR_ERR(p); - if (mutex_lock_interruptible(&dvbdemux->mutex)) { - kfree(p); + if (mutex_lock_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; - } - dvb_dmx_swfilter(dvbdemux, p, count); - kfree(p); + + dvb_dmx_swfilter_format(dvbdemux, buf, count, dvbdemux->tsp_format); + mutex_unlock(&dvbdemux->mutex); if (signal_pending(current)) @@ -1129,6 +3141,40 @@ static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t return count; } +static int dvbdmx_write_cancel(struct dmx_demux *demux) +{ + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; + + spin_lock_irq(&dvbdmx->lock); + + /* cancel any pending wait for decoder's buffers */ + dvbdmx->sw_filter_abort = 1; + dvbdmx->tsbufp = 0; + dvb_dmx_configure_decoder_fullness(dvbdmx, 0); + + spin_unlock_irq(&dvbdmx->lock); + + return 0; +} + +static int dvbdmx_set_playback_mode(struct dmx_demux *demux, + enum dmx_playback_mode_t mode, + dmx_ts_fullness ts_fullness_callback, + dmx_section_fullness sec_fullness_callback) +{ + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; + + mutex_lock(&dvbdmx->mutex); + + dvbdmx->playback_mode = mode; + dvbdmx->buffer_ctrl.ts = ts_fullness_callback; + dvbdmx->buffer_ctrl.sec = sec_fullness_callback; + + mutex_unlock(&dvbdmx->mutex); + + return 0; +} + static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) { @@ -1186,7 +3232,7 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; mutex_lock(&dvbdemux->mutex); - + dvbdemux->sw_filter_abort = 0; demux->frontend = NULL; mutex_unlock(&dvbdemux->mutex); return 0; @@ -1196,7 +3242,50 @@ static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) { struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); + /* 4 Demux Instances each with group of 5 pids */ + memcpy(pids, dvbdemux->pids, DMX_PES_OTHER*sizeof(u16)); + return 0; +} + +static int dvbdmx_get_tsp_size(struct dmx_demux *demux) +{ + int tsp_size; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + mutex_lock(&dvbdemux->mutex); + tsp_size = dvbdemux->ts_packet_size; + mutex_unlock(&dvbdemux->mutex); + + return tsp_size; +} + +static int dvbdmx_set_tsp_format( + struct dmx_demux *demux, + enum dmx_tsp_format_t tsp_format) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + if ((tsp_format > DMX_TSP_FORMAT_204) || + (tsp_format < DMX_TSP_FORMAT_188)) + return -EINVAL; + + mutex_lock(&dvbdemux->mutex); + + dvbdemux->tsp_format = tsp_format; + switch (tsp_format) { + case DMX_TSP_FORMAT_188: + dvbdemux->ts_packet_size = 188; + break; + case DMX_TSP_FORMAT_192_TAIL: + case DMX_TSP_FORMAT_192_HEAD: + dvbdemux->ts_packet_size = 192; + break; + case DMX_TSP_FORMAT_204: + dvbdemux->ts_packet_size = 204; + break; + } + + mutex_unlock(&dvbdemux->mutex); return 0; } @@ -1218,18 +3307,53 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->filter = NULL; return -ENOMEM; } + + dvbdemux->rec_info_pool = vmalloc(dvbdemux->feednum * + sizeof(struct dvb_demux_rec_info)); + if (!dvbdemux->rec_info_pool) { + vfree(dvbdemux->feed); + vfree(dvbdemux->filter); + dvbdemux->feed = NULL; + dvbdemux->filter = NULL; + return -ENOMEM; + } + + dvbdemux->sw_filter_abort = 0; + dvbdemux->total_process_time = 0; + dvbdemux->total_crc_time = 0; + snprintf(dvbdemux->alias, + MAX_DVB_DEMUX_NAME_LEN, + "demux%d", + dvb_demux_index++); + + dvbdemux->dmx.debugfs_demux_dir = + debugfs_create_dir(dvbdemux->alias, NULL); + + if (dvbdemux->dmx.debugfs_demux_dir != NULL) { + debugfs_create_u32( + "total_processing_time", 0664, + dvbdemux->dmx.debugfs_demux_dir, + &dvbdemux->total_process_time); + + debugfs_create_u32( + "total_crc_time", 0664, + dvbdemux->dmx.debugfs_demux_dir, + &dvbdemux->total_crc_time); + } + for (i = 0; i < dvbdemux->filternum; i++) { dvbdemux->filter[i].state = DMX_STATE_FREE; dvbdemux->filter[i].index = i; } + for (i = 0; i < dvbdemux->feednum; i++) { dvbdemux->feed[i].state = DMX_STATE_FREE; dvbdemux->feed[i].index = i; + + dvbdemux->rec_info_pool[i].ref_count = 0; } dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); - if (!dvbdemux->cnt_storage) - pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n"); INIT_LIST_HEAD(&dvbdemux->frontend_list); @@ -1244,6 +3368,9 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->recording = 0; dvbdemux->tsbufp = 0; + dvbdemux->tsp_format = DMX_TSP_FORMAT_188; + dvbdemux->ts_packet_size = 188; + if (!dvbdemux->check_crc32) dvbdemux->check_crc32 = dvb_dmx_crc32; @@ -1255,10 +3382,14 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->open = dvbdmx_open; dmx->close = dvbdmx_close; dmx->write = dvbdmx_write; + dmx->write_cancel = dvbdmx_write_cancel; + dmx->set_playback_mode = dvbdmx_set_playback_mode; dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed; dmx->release_ts_feed = dvbdmx_release_ts_feed; dmx->allocate_section_feed = dvbdmx_allocate_section_feed; dmx->release_section_feed = dvbdmx_release_section_feed; + dmx->map_buffer = NULL; + dmx->unmap_buffer = NULL; dmx->add_frontend = dvbdmx_add_frontend; dmx->remove_frontend = dvbdmx_remove_frontend; @@ -1267,6 +3398,9 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->disconnect_frontend = dvbdmx_disconnect_frontend; dmx->get_pes_pids = dvbdmx_get_pes_pids; + dmx->set_tsp_format = dvbdmx_set_tsp_format; + dmx->get_tsp_size = dvbdmx_get_tsp_size; + mutex_init(&dvbdemux->mutex); spin_lock_init(&dvbdemux->lock); @@ -1277,9 +3411,14 @@ EXPORT_SYMBOL(dvb_dmx_init); void dvb_dmx_release(struct dvb_demux *dvbdemux) { + if (dvbdemux->dmx.debugfs_demux_dir != NULL) + debugfs_remove_recursive(dvbdemux->dmx.debugfs_demux_dir); + + dvb_demux_index--; vfree(dvbdemux->cnt_storage); vfree(dvbdemux->filter); vfree(dvbdemux->feed); + vfree(dvbdemux->rec_info_pool); } EXPORT_SYMBOL(dvb_dmx_release); diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 6f572ca8d3393fd4731a10c5d69ffe66026a2e6e..4faa4cd7773888b6e11aa9a625a427a2d9954bb7 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "demux.h" @@ -40,6 +41,8 @@ #define MAX_PID 0x1fff +#define TIMESTAMP_LEN 4 + #define SPEED_PKTS_INTERVAL 50000 struct dvb_demux_filter { @@ -60,6 +63,92 @@ struct dvb_demux_filter { #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) + +struct dmx_index_entry { + struct dmx_index_event_info event; + struct list_head next; +}; + +#define DMX_IDX_EVENT_QUEUE_SIZE DMX_EVENT_QUEUE_SIZE + +struct dvb_demux_rec_info { + /* Reference counter for number of feeds using this information */ + int ref_count; + + /* Counter for number of TS packets output to recording buffer */ + u64 ts_output_count; + + /* Indexing information */ + struct { + /* + * Minimum TS packet number encountered in recording filter + * among all feeds that search for video patterns + */ + u64 min_pattern_tsp_num; + + /* Number of indexing-enabled feeds */ + u8 indexing_feeds_num; + + /* Number of feeds with video pattern search request */ + u8 pattern_search_feeds_num; + + /* Index entries pool */ + struct dmx_index_entry events[DMX_IDX_EVENT_QUEUE_SIZE]; + + /* List of free entries that can be used for new index events */ + struct list_head free_list; + + /* List holding ready index entries not notified to user yet */ + struct list_head ready_list; + } idx_info; +}; + +#define DVB_DMX_MAX_PATTERN_LEN 6 +struct dvb_dmx_video_patterns { + /* the byte pattern to look for */ + u8 pattern[DVB_DMX_MAX_PATTERN_LEN]; + + /* the byte mask to use (same length as pattern) */ + u8 mask[DVB_DMX_MAX_PATTERN_LEN]; + + /* the length of the pattern, in bytes */ + size_t size; + + /* the type of the pattern. One of DMX_IDX_* definitions */ + u64 type; +}; + +#define DVB_DMX_MAX_FOUND_PATTERNS 20 +#define DVB_DMX_MAX_SEARCH_PATTERN_NUM 20 +struct dvb_dmx_video_prefix_size_masks { + /* + * a bit mask (per pattern) of possible prefix sizes to use + * when searching for a pattern that started in the previous TS packet. + * Updated by dvb_dmx_video_pattern_search for use in the next lookup. + */ + u32 size_mask[DVB_DMX_MAX_FOUND_PATTERNS]; +}; + +struct dvb_dmx_video_patterns_results { + struct { + /* + * The offset in the buffer where the pattern was found. + * If a pattern is found using a prefix (i.e. started on the + * previous buffer), offset is zero. + */ + u32 offset; + + /* + * The type of the pattern found. + * One of DMX_IDX_* definitions. + */ + u64 type; + + /* The prefix size that was used to find this pattern */ + u32 used_prefix_size; + } info[DVB_DMX_MAX_FOUND_PATTERNS]; +}; + struct dvb_demux_feed { union { struct dmx_ts_feed ts; @@ -71,11 +160,21 @@ struct dvb_demux_feed { dmx_section_cb sec; } cb; + union { + dmx_ts_data_ready_cb ts; + dmx_section_data_ready_cb sec; + } data_ready_cb; + struct dvb_demux *demux; void *priv; int type; int state; u16 pid; + u8 *buffer; + int buffer_size; + enum dmx_tsp_format_t tsp_out_format; + struct dmx_secure_mode secure_mode; + struct dmx_cipher_operations cipher_ops; ktime_t timeout; struct dvb_demux_filter *filter; @@ -84,12 +183,34 @@ struct dvb_demux_feed { enum dmx_ts_pes pes_type; int cc; + int first_cc; int pusi_seen; /* prevents feeding of garbage from previous section */ + u8 scrambling_bits; + + struct dvb_demux_rec_info *rec_info; + u64 prev_tsp_num; + u64 prev_stc; + u64 curr_pusi_tsp_num; + u64 prev_pusi_tsp_num; + int prev_frame_valid; + u64 prev_frame_type; + int first_frame_in_seq; + int first_frame_in_seq_notified; + u64 last_pattern_tsp_num; + int pattern_num; +const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM]; + struct dvb_dmx_video_prefix_size_masks prefix_size; u16 peslen; + u32 pes_tei_counter; + u32 pes_cont_err_counter; + u32 pes_ts_packets_num; struct list_head list_head; unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + + enum dmx_video_codec video_codec; + struct dmx_indexing_params idx_params; }; struct dvb_demux { @@ -101,10 +222,27 @@ struct dvb_demux { int (*stop_feed)(struct dvb_demux_feed *feed); int (*write_to_decoder)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); + int (*decoder_fullness_init)(struct dvb_demux_feed *feed); + int (*decoder_fullness_wait)(struct dvb_demux_feed *feed, + size_t required_space); + int (*decoder_fullness_abort)(struct dvb_demux_feed *feed); + int (*decoder_buffer_status)(struct dvb_demux_feed *feed, + struct dmx_buffer_status *dmx_buffer_status); + int (*reuse_decoder_buffer)(struct dvb_demux_feed *feed, + int cookie); + int (*set_cipher_op)(struct dvb_demux_feed *feed, + struct dmx_cipher_operations *cipher_ops); u32 (*check_crc32)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, const u8 *src, size_t len); + int (*oob_command)(struct dvb_demux_feed *feed, + struct dmx_oob_command *cmd); + void (*convert_ts)(struct dvb_demux_feed *feed, + const u8 timestamp[TIMESTAMP_LEN], + u64 *timestampIn27Mhz); + int (*set_indexing)(struct dvb_demux_feed *feed); + int (*flush_decoder_buffer)(struct dvb_demux_feed *feed, size_t length); int users; #define MAX_DVB_DEMUX_USERS 10 @@ -130,10 +268,35 @@ struct dvb_demux { ktime_t speed_last_time; /* for TS speed check */ uint32_t speed_pkts_cnt; /* for TS speed check */ + + enum dmx_tsp_format_t tsp_format; + size_t ts_packet_size; + + enum dmx_playback_mode_t playback_mode; + int sw_filter_abort; + + struct { + dmx_ts_fullness ts; + dmx_section_fullness sec; + } buffer_ctrl; + + struct dvb_demux_rec_info *rec_info_pool; + + /* + * the following is used for debugfs exposing info + * about dvb demux performance. + */ +#define MAX_DVB_DEMUX_NAME_LEN 10 + char alias[MAX_DVB_DEMUX_NAME_LEN]; + + u32 total_process_time; + u32 total_crc_time; }; int dvb_dmx_init(struct dvb_demux *dvbdemux); void dvb_dmx_release(struct dvb_demux *dvbdemux); +int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf, + int should_lock); void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); @@ -141,5 +304,116 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_format( + struct dvb_demux *demux, const u8 *buf, + size_t count, + enum dmx_tsp_format_t tsp_format); +void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]); +const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern); +int dvb_dmx_video_pattern_search( + const struct dvb_dmx_video_patterns + *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM], + int patterns_num, + const u8 *buf, size_t buf_size, + struct dvb_dmx_video_prefix_size_masks *prefix_size_masks, + struct dvb_dmx_video_patterns_results *results); +int dvb_demux_push_idx_event(struct dvb_demux_feed *feed, + struct dmx_index_event_info *idx_event, int should_lock); +void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed, + struct dvb_dmx_video_patterns_results *patterns, int pattern, + u64 curr_stc, u64 prev_stc, + u64 curr_match_tsp, u64 prev_match_tsp, + u64 curr_pusi_tsp, u64 prev_pusi_tsp); +void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock); +int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed, + struct dmx_data_ready *event, int should_lock); +void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed); + +/** + * dvb_dmx_is_video_feed - Returns whether the PES feed + * is video one. + * + * @feed: The feed to be checked. + * + * Return 1 if feed is video feed, 0 otherwise. + */ +static inline int dvb_dmx_is_video_feed(struct dvb_demux_feed *feed) +{ + if (feed->type != DMX_TYPE_TS) + return 0; + + if (feed->ts_type & (~TS_DECODER)) + return 0; + + if ((feed->pes_type == DMX_PES_VIDEO0) || + (feed->pes_type == DMX_PES_VIDEO1) || + (feed->pes_type == DMX_PES_VIDEO2) || + (feed->pes_type == DMX_PES_VIDEO3)) + return 1; + + return 0; +} + +/** + * dvb_dmx_is_pcr_feed - Returns whether the PES feed + * is PCR one. + * + * @feed: The feed to be checked. + * + * Return 1 if feed is PCR feed, 0 otherwise. + */ +static inline int dvb_dmx_is_pcr_feed(struct dvb_demux_feed *feed) +{ + if (feed->type != DMX_TYPE_TS) + return 0; + + if (feed->ts_type & (~TS_DECODER)) + return 0; + + if ((feed->pes_type == DMX_PES_PCR0) || + (feed->pes_type == DMX_PES_PCR1) || + (feed->pes_type == DMX_PES_PCR2) || + (feed->pes_type == DMX_PES_PCR3)) + return 1; + + return 0; +} + +/** + * dvb_dmx_is_sec_feed - Returns whether this is a section feed + * + * @feed: The feed to be checked. + * + * Return 1 if feed is a section feed, 0 otherwise. + */ +static inline int dvb_dmx_is_sec_feed(struct dvb_demux_feed *feed) +{ + return (feed->type == DMX_TYPE_SEC); +} + +/** + * dvb_dmx_is_rec_feed - Returns whether this is a recording feed + * + * @feed: The feed to be checked. + * + * Return 1 if feed is recording feed, 0 otherwise. + */ +static inline int dvb_dmx_is_rec_feed(struct dvb_demux_feed *feed) +{ + if (feed->type != DMX_TYPE_TS) + return 0; + + if (feed->ts_type & (TS_DECODER | TS_PAYLOAD_ONLY)) + return 0; + + return 1; +} + +static inline u16 ts_pid(const u8 *buf) +{ + return ((buf[1] & 0x1f) << 8) + buf[2]; +} + #endif /* _DVB_DEMUX_H_ */ diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 06b0dcc13695af9ff25292de21ef1c3859b732d5..28dea04025304616fa1bd28593cf917fafd5f792 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1091,7 +1091,7 @@ static int dvb_net_feed_start(struct net_device *dev) goto error; } - ret = priv->secfeed->set(priv->secfeed, priv->pid, 1); + ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); if (ret<0) { pr_err("%s: could not set section feed\n", dev->name); @@ -1129,7 +1129,7 @@ static int dvb_net_feed_start(struct net_device *dev) netdev_dbg(dev, "start filtering\n"); priv->secfeed->start_filtering(priv->secfeed); } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { - ktime_t timeout = ns_to_ktime(10 * NSEC_PER_MSEC); + ktime_t timeout = ktime_set(0, 10*NSEC_PER_MSEC); // 10 msec /* we have payloads encapsulated in TS */ netdev_dbg(dev, "alloc tsfeed\n"); @@ -1145,6 +1145,7 @@ static int dvb_net_feed_start(struct net_device *dev) priv->pid, /* pid */ TS_PACKET, /* type */ DMX_PES_OTHER, /* pes type */ + 32768, /* circular buffer size */ timeout /* timeout */ ); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index 2322af1b87429aab67454c4ca7f7f486ab9bf211..ea4fed0dfece5f03b740ff3cb97321dac72c85b7 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -33,6 +33,8 @@ #define PKT_READY 0 #define PKT_DISPOSED 1 +#define PKT_PENDING 2 + void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) @@ -205,18 +207,19 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t } ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, - const u8 __user *buf, size_t len) + const u8 __user *buf, size_t len) { - int status; size_t todo = len; size_t split; + ssize_t oldpwrite = rbuf->pwrite; - split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + split = (rbuf->pwrite + len > rbuf->size) ? + rbuf->size - rbuf->pwrite : + 0; if (split > 0) { - status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split); - if (status) - return len - todo; + if (copy_from_user(rbuf->data + rbuf->pwrite, buf, split)) + return -EFAULT; buf += split; todo -= split; /* smp_store_release() for write pointer update to ensure that @@ -226,9 +229,12 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, */ smp_store_release(&rbuf->pwrite, 0); } - status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); - if (status) - return len - todo; + + if (copy_from_user(rbuf->data + rbuf->pwrite, buf, todo)) { + /* smp_store_release() for write pointer update */ + smp_store_release(&rbuf->pwrite, oldpwrite); + return -EFAULT; + } /* smp_store_release() for write pointer update, see above */ smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); @@ -249,6 +255,31 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le return status; } +ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, size_t len) +{ + ssize_t oldpwrite = rbuf->pwrite; + + DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); + DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); + DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_PENDING); + + return oldpwrite; +} +EXPORT_SYMBOL(dvb_ringbuffer_pkt_start); + +int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx) +{ + idx = (idx + 2) % rbuf->size; + + if (rbuf->data[idx] != PKT_PENDING) + return -EINVAL; + + rbuf->data[idx] = PKT_READY; + + return 0; +} +EXPORT_SYMBOL(dvb_ringbuffer_pkt_close); + ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, int offset, u8 __user *buf, size_t len) { @@ -256,6 +287,9 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, size_t split; size_t pktlen; + if (DVB_RINGBUFFER_PEEK(rbuf, (idx+2)) != PKT_READY) + return -EINVAL; + pktlen = rbuf->data[idx] << 8; pktlen |= rbuf->data[(idx + 1) % rbuf->size]; if (offset > pktlen) return -EINVAL; @@ -276,6 +310,7 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, return len; } +EXPORT_SYMBOL(dvb_ringbuffer_pkt_read_user); ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, int offset, u8* buf, size_t len) @@ -284,6 +319,9 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, size_t split; size_t pktlen; + if (rbuf->data[(idx + 2) % rbuf->size] != PKT_READY) + return -EINVAL; + pktlen = rbuf->data[idx] << 8; pktlen |= rbuf->data[(idx + 1) % rbuf->size]; if (offset > pktlen) return -EINVAL; @@ -301,6 +339,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, memcpy(buf, rbuf->data+idx, todo); return len; } +EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) { @@ -320,6 +359,7 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) } } } +EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen) { @@ -335,7 +375,10 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; } - consumed = (idx - rbuf->pread) % rbuf->size; + if (idx >= rbuf->pread) + consumed = idx - rbuf->pread; + else + consumed = rbuf->size - (rbuf->pread - idx); while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { @@ -348,6 +391,9 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* return idx; } + if (curpktstatus == PKT_PENDING) + return -EFAULT; + consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; } @@ -355,8 +401,7 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* // no packets available return -1; } - - +EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_empty); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h index 8ed6bcc3a56e5ffd1299f19bba1db6cda5627fa5..e2196f4ab6e4da92c43177e925afa029cfe49e4f 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb-core/dvb_ringbuffer.h @@ -124,6 +124,9 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); */ #define DVB_RINGBUFFER_PEEK(rbuf, offs) \ ((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size]) +#define DVB_RINGBUFFER_PUSH(rbuf, num) \ + ((rbuf)->pwrite = (((rbuf)->pwrite+(num))%(rbuf)->size)) + /** * DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes @@ -274,7 +277,35 @@ extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); * in bytes. * returns Packet index (if >=0), or -1 if no packets available. */ -extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, - size_t idx, size_t *pktlen); +extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, + size_t *pktlen); + + +/** + * Start a new packet that will be written directly by the user to the packet + * buffer. + * The function only writes the header of the packet into the packet buffer, + * and the packet is in pending state (can't be read by the reader) until it is + * closed using dvb_ringbuffer_pkt_close. You must write the data into the + * packet buffer using dvb_ringbuffer_write followed by + * dvb_ringbuffer_pkt_close. + * + * @rbuf: Ringbuffer concerned. + * @len: Size of the packet's data + * returns Index of the packet's header that was started. + */ +extern ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, + size_t len); + +/** + * Close a packet that was started using dvb_ringbuffer_pkt_start. + * The packet will be marked as ready to be ready. + * + * @rbuf: Ringbuffer concerned. + * @idx: Packet index that was returned by dvb_ringbuffer_pkt_start + * returns error status, -EINVAL if the provided index is invalid + */ +extern int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx); + #endif /* _DVB_RINGBUFFER_H_ */ diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d01b7700756cde33c2ca8b05af3e59..e4d7f2febf00ce0f5fb24227bc0228d325d49955 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1001,7 +1001,7 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (rval) goto out; - for (i = 0; i < 1000; i++) { + for (i = 1000; i > 0; i--) { rval = smiapp_read( sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); @@ -1012,11 +1012,10 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) break; - if (--i == 0) { - rval = -ETIMEDOUT; - goto out; - } - + } + if (!i) { + rval = -ETIMEDOUT; + goto out; } for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 98de74862d472531ecea493e47a6241947f31418..62b2c5d9bdfb704a6cb40d61268d9b35a170536a 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -56,7 +56,7 @@ static int media_device_close(struct file *filp) static long media_device_get_info(struct media_device *dev, void *arg) { - struct media_device_info *info = (struct media_device_info *)arg; + struct media_device_info *info = arg; memset(info, 0, sizeof(*info)); @@ -96,7 +96,7 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) static long media_device_enum_entities(struct media_device *mdev, void *arg) { - struct media_entity_desc *entd = (struct media_entity_desc *)arg; + struct media_entity_desc *entd = arg; struct media_entity *ent; ent = find_entity(mdev, entd->id); @@ -149,7 +149,7 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, static long media_device_enum_links(struct media_device *mdev, void *arg) { - struct media_links_enum *links = (struct media_links_enum *)arg; + struct media_links_enum *links = arg; struct media_entity *entity; entity = find_entity(mdev, links->entity); @@ -197,7 +197,7 @@ static long media_device_enum_links(struct media_device *mdev, void *arg) static long media_device_setup_link(struct media_device *mdev, void *arg) { - struct media_link_desc *linkd = (struct media_link_desc *)arg; + struct media_link_desc *linkd = arg; struct media_link *link = NULL; struct media_entity *source; struct media_entity *sink; @@ -225,7 +225,7 @@ static long media_device_setup_link(struct media_device *mdev, void *arg) static long media_device_get_topology(struct media_device *mdev, void *arg) { - struct media_v2_topology *topo = (struct media_v2_topology *)arg; + struct media_v2_topology *topo = arg; struct media_entity *entity; struct media_interface *intf; struct media_pad *pad; diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index ef4906406ebf9aa67f527c9ac81707a1a786c373..a50461861133f7aebfe73c6b18a7f0dc3a1b201a 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -426,7 +426,8 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) __func__, fw->size); if (fw->size != fwlength) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); + printk(KERN_ERR "saa7164: firmware incorrect size %zu != %u\n", + fw->size, fwlength); ret = -ENOMEM; goto out; } diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index c3fafa97b2d0c1dd30037ff77d72f0baeb1dc221..0ea8dd44026c34e6772b35c391aa03d15aefeffd 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -1228,7 +1228,8 @@ int tw686x_video_init(struct tw686x_dev *dev) vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; vc->vidq.min_buffers_needed = 2; vc->vidq.lock = &vc->vb_mutex; - vc->vidq.gfp_flags = GFP_DMA32; + vc->vidq.gfp_flags = dev->dma_mode != TW686X_DMA_MODE_MEMCPY ? + GFP_DMA32 : 0; vc->vidq.dev = &dev->pci_dev->dev; err = vb2_queue_init(&vc->vidq); diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index 0d776945531161815bc47286f8ea92600b17d172..9c43ecb5ac31bcec8b44386bc8393ac4a43cbc8f 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -16,3 +16,5 @@ menuconfig SPECTRA_CAMERA source "drivers/media/platform/msm/vidc/Kconfig" source "drivers/media/platform/msm/sde/Kconfig" source "drivers/media/platform/msm/npu/Kconfig" +source "drivers/media/platform/msm/dvb/Kconfig" +source "drivers/media/platform/msm/broadcast/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index 1a3763dc0ec6d5e92d2d4fb3d9d7523f6ef3679b..18ea8e6d97c98dba3d5d02805116e975f4678b3d 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -5,4 +5,6 @@ obj-y += sde/ obj-$(CONFIG_MSM_NPU) += npu/ obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/ -obj-$(CONFIG_SPECTRA_CAMERA) += camera/ \ No newline at end of file +obj-$(CONFIG_SPECTRA_CAMERA) += camera/ +obj-$(CONFIG_TSPP) += broadcast/ +obj-$(CONFIG_DVB_MPQ) += dvb/ diff --git a/drivers/media/platform/msm/broadcast/Kconfig b/drivers/media/platform/msm/broadcast/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..cdd1b20911791f9ea0a50981a532db643aa9f4a8 --- /dev/null +++ b/drivers/media/platform/msm/broadcast/Kconfig @@ -0,0 +1,14 @@ +# +# MSM Broadcast subsystem drivers +# + +config TSPP + depends on ARCH_QCOM + tristate "TSPP (Transport Stream Packet Processor) Support" + ---help--- + Transport Stream Packet Processor v1 is used to offload the + processing of MPEG transport streams from the main processor. + It is used to process incoming transport streams from TSIF + to supports use-cases such as transport stream live play + and recording. + This can also be compiled as a loadable module. diff --git a/drivers/media/platform/msm/broadcast/Makefile b/drivers/media/platform/msm/broadcast/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3735bdc212ad4da9d502dc6997bbfeba369002c4 --- /dev/null +++ b/drivers/media/platform/msm/broadcast/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for MSM Broadcast subsystem drivers. +# +obj-$(CONFIG_TSPP) += tspp.o diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c new file mode 100644 index 0000000000000000000000000000000000000000..9a701ccf191230a3de0e0fee909ec4787d8ae644 --- /dev/null +++ b/drivers/media/platform/msm/broadcast/tspp.c @@ -0,0 +1,3330 @@ +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 /* Just for modules */ +#include /* Only for KERN_INFO */ +#include /* Error macros */ +#include /* Linked list */ +#include +#include /* Needed for the macros */ +#include /* IO macros */ +#include /* Device drivers need this */ +#include /* Externally defined globals */ +#include /* Runtime power management */ +#include +#include /* copy_to_user */ +#include /* kfree, kzalloc */ +#include /* XXX_ mem_region */ +#include +#include /* dma_XXX */ +#include /* DMA pools */ +#include /* msleep */ +#include +#include +#include /* poll() file op */ +#include /* wait() macros, sleeping */ +#include /* BIT() macro */ +#include +#include +#include /* BAM stuff */ +#include /* Timer services */ +#include /* Jiffies counter */ +#include +#include +#include +#include +#include +#include +#include /* tasklet */ +#include /* Timer */ +#include + +/* + * General defines + */ +#define TSPP_TSIF_INSTANCES 2 +#define TSPP_GPIOS_PER_TSIF 4 +#define TSPP_FILTER_TABLES 3 +#define TSPP_MAX_DEVICES 1 +#define TSPP_NUM_CHANNELS 16 +#define TSPP_NUM_PRIORITIES 16 +#define TSPP_NUM_KEYS 8 +#define INVALID_CHANNEL 0xFFFFFFFF +#define TSPP_BAM_DEFAULT_IPC_LOGLVL 2 + +#define TSPP_SMMU_IOVA_START (0x10000000) +#define TSPP_SMMU_IOVA_SIZE (0x40000000) + +/* + * BAM descriptor FIFO size (in number of descriptors). + * Max number of descriptors allowed by SPS which is 8K-1. + */ +#define TSPP_SPS_DESCRIPTOR_COUNT (8 * 1024 - 1) +#define TSPP_PACKET_LENGTH 188 +#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH) + +/* Max descriptor buffer size allowed by SPS */ +#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1) + +/* + * Returns whether to use DMA pool for TSPP output buffers. + * For buffers smaller than page size, using DMA pool + * provides better memory utilization as dma_alloc_coherent + * allocates minimum of page size. + */ +#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE) + +/* + * Max allowed TSPP buffers/descriptors. + * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors. + */ +#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1) +#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60 +#define SPS_DESCRIPTOR_SIZE 8 +#define MIN_ACCEPTABLE_BUFFER_COUNT 2 +#define TSPP_DEBUG(msg...) + +/* + * TSIF register offsets + */ +#define TSIF_STS_CTL_OFF (0x0) +#define TSIF_TIME_LIMIT_OFF (0x4) +#define TSIF_CLK_REF_OFF (0x8) +#define TSIF_LPBK_FLAGS_OFF (0xc) +#define TSIF_LPBK_DATA_OFF (0x10) +#define TSIF_TEST_CTL_OFF (0x14) +#define TSIF_TEST_MODE_OFF (0x18) +#define TSIF_TEST_RESET_OFF (0x1c) +#define TSIF_TEST_EXPORT_OFF (0x20) +#define TSIF_TEST_CURRENT_OFF (0x24) +#define TSIF_TTS_CTL_OFF (0x38) + +#define TSIF_DATA_PORT_OFF (0x100) + +/* bits for TSIF_STS_CTL register */ +#define TSIF_STS_CTL_EN_IRQ BIT(28) +#define TSIF_STS_CTL_PACK_AVAIL BIT(27) +#define TSIF_STS_CTL_1ST_PACKET BIT(26) +#define TSIF_STS_CTL_OVERFLOW BIT(25) +#define TSIF_STS_CTL_LOST_SYNC BIT(24) +#define TSIF_STS_CTL_TIMEOUT BIT(23) +#define TSIF_STS_CTL_INV_SYNC BIT(21) +#define TSIF_STS_CTL_INV_NULL BIT(20) +#define TSIF_STS_CTL_INV_ERROR BIT(19) +#define TSIF_STS_CTL_INV_ENABLE BIT(18) +#define TSIF_STS_CTL_INV_DATA BIT(17) +#define TSIF_STS_CTL_INV_CLOCK BIT(16) +#define TSIF_STS_CTL_SPARE BIT(15) +#define TSIF_STS_CTL_EN_NULL BIT(11) +#define TSIF_STS_CTL_EN_ERROR BIT(10) +#define TSIF_STS_CTL_LAST_BIT BIT(9) +#define TSIF_STS_CTL_EN_TIME_LIM BIT(8) +#define TSIF_STS_CTL_EN_TCR BIT(7) +#define TSIF_STS_CTL_TEST_MODE BIT(6) +#define TSIF_STS_CTL_MODE_2 BIT(5) +#define TSIF_STS_CTL_EN_DM BIT(4) +#define TSIF_STS_CTL_STOP BIT(3) +#define TSIF_STS_CTL_START BIT(0) + +/* bits for TSIF_TTS_CTRL register */ +#define TSIF_TTS_CTL_TTS_ENDIANNESS BIT(4) +#define TSIF_TTS_CTL_TTS_SOURCE BIT(3) +#define TSIF_TTS_CTL_TTS_LENGTH_1 BIT(1) +#define TSIF_TTS_CTL_TTS_LENGTH_0 BIT(0) + +/* + * TSPP register offsets + */ +#define TSPP_RST 0x00 +#define TSPP_CLK_CONTROL 0x04 +#define TSPP_CONFIG 0x08 +#define TSPP_CONTROL 0x0C +#define TSPP_PS_DISABLE 0x10 +#define TSPP_MSG_IRQ_STATUS 0x14 +#define TSPP_MSG_IRQ_MASK 0x18 +#define TSPP_IRQ_STATUS 0x1C +#define TSPP_IRQ_MASK 0x20 +#define TSPP_IRQ_CLEAR 0x24 +#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2)) +#define TSPP_STATUS 0x68 +#define TSPP_CURR_TSP_HEADER 0x6C +#define TSPP_CURR_PID_FILTER 0x70 +#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2)) +#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2)) +#define TSPP_DATA_KEY_RESET 0x9C +#define TSPP_KEY_VALID 0xA0 +#define TSPP_KEY_ERROR 0xA4 +#define TSPP_TEST_CTRL 0xA8 +#define TSPP_VERSION 0xAC +#define TSPP_GENERICS 0xB0 +#define TSPP_NOP 0xB4 + +/* + * Register bit definitions + */ +/* TSPP_RST */ +#define TSPP_RST_RESET BIT(0) + +/* TSPP_CLK_CONTROL */ +#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9) +#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8) +#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7) +#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6) +#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5) +#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4) +#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3) +#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2) +#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1) +#define TSPP_CLK_CONTROL_SET_CLKON BIT(0) + +/* TSPP_CONFIG */ +#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \ +((_b & 0xF) << 8)) +#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF) +#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7) +#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6) +#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5) +#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4) +#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3) +#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2) +#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1) +#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0) + +/* TSPP_CONTROL */ +#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5) +#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4) +#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3) +#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2) +#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1) +#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0) + +/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */ +#define TSPP_MSG_TSPP_IRQ BIT(2) +#define TSPP_MSG_TSIF_1_IRQ BIT(1) +#define TSPP_MSG_TSIF_0_IRQ BIT(0) + +/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */ +#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19) +#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18) +#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17) +#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16) +#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n)) + +/* TSPP_PIPE_ERROR_STATUS */ +#define TSPP_PIPE_PES_SYNC_ERROR BIT(3) +#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2) +#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1) +#define TSPP_PIP_PS_LOST_START BIT(0) + +/* TSPP_STATUS */ +#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10) +#define TSPP_STATUS_TSIF1_DM_REQ BIT(6) +#define TSPP_STATUS_TSIF0_DM_REQ BIT(2) +#define TSPP_CURR_FILTER_TABLE BIT(0) + +/* TSPP_GENERICS */ +#define TSPP_GENERICS_CRYPTO_GEN BIT(12) +#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7) +#define TSPP_GENERICS_MAX_PIPES BIT(2) +#define TSPP_GENERICS_TSIF_1_GEN BIT(1) +#define TSPP_GENERICS_TSIF_0_GEN BIT(0) + +/* + * TSPP memory regions + */ +#define TSPP_PID_FILTER_TABLE0 0x800 +#define TSPP_PID_FILTER_TABLE1 0x880 +#define TSPP_PID_FILTER_TABLE2 0x900 +#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */ +#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */ +#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */ +#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2)) +#define TSPP_DATA_KEY 0xCD0 + +struct debugfs_entry { + const char *name; + mode_t mode; + int offset; +}; + +static const struct debugfs_entry debugfs_tsif_regs[] = { + {"sts_ctl", 0644, TSIF_STS_CTL_OFF}, + {"time_limit", 0644, TSIF_TIME_LIMIT_OFF}, + {"clk_ref", 0644, TSIF_CLK_REF_OFF}, + {"lpbk_flags", 0644, TSIF_LPBK_FLAGS_OFF}, + {"lpbk_data", 0644, TSIF_LPBK_DATA_OFF}, + {"test_ctl", 0644, TSIF_TEST_CTL_OFF}, + {"test_mode", 0644, TSIF_TEST_MODE_OFF}, + {"test_reset", 0200, TSIF_TEST_RESET_OFF}, + {"test_export", 0644, TSIF_TEST_EXPORT_OFF}, + {"test_current", 0444, TSIF_TEST_CURRENT_OFF}, + {"data_port", 0400, TSIF_DATA_PORT_OFF}, + {"tts_source", 0600, TSIF_TTS_CTL_OFF}, +}; + +static const struct debugfs_entry debugfs_tspp_regs[] = { + {"rst", 0644, TSPP_RST}, + {"clk_control", 0644, TSPP_CLK_CONTROL}, + {"config", 0644, TSPP_CONFIG}, + {"control", 0644, TSPP_CONTROL}, + {"ps_disable", 0644, TSPP_PS_DISABLE}, + {"msg_irq_status", 0644, TSPP_MSG_IRQ_STATUS}, + {"msg_irq_mask", 0644, TSPP_MSG_IRQ_MASK}, + {"irq_status", 0644, TSPP_IRQ_STATUS}, + {"irq_mask", 0644, TSPP_IRQ_MASK}, + {"irq_clear", 0644, TSPP_IRQ_CLEAR}, + {"status", 0644, TSPP_STATUS}, + {"curr_tsp_header", 0644, TSPP_CURR_TSP_HEADER}, + {"curr_pid_filter", 0644, TSPP_CURR_PID_FILTER}, + {"data_key_reset", 0644, TSPP_DATA_KEY_RESET}, + {"key_valid", 0644, TSPP_KEY_VALID}, + {"key_error", 0644, TSPP_KEY_ERROR}, + {"test_ctrl", 0644, TSPP_TEST_CTRL}, + {"version", 0644, TSPP_VERSION}, + {"generics", 0644, TSPP_GENERICS}, + {"pid_filter_table0", 0644, TSPP_PID_FILTER_TABLE0}, + {"pid_filter_table1", 0644, TSPP_PID_FILTER_TABLE1}, + {"pid_filter_table2", 0644, TSPP_PID_FILTER_TABLE2}, + {"tsp_total_num", 0644, TSPP_GLOBAL_PERFORMANCE}, + {"tsp_ignored_num", 0644, TSPP_GLOBAL_PERFORMANCE + 4}, + {"tsp_err_ind_num", 0644, TSPP_GLOBAL_PERFORMANCE + 8}, + {"tsp_sync_err_num", 0644, TSPP_GLOBAL_PERFORMANCE + 16}, + {"pipe_context", 0644, TSPP_PIPE_CONTEXT}, + {"pipe_performance", 0644, TSPP_PIPE_PERFORMANCE}, + {"data_key", 0644, TSPP_DATA_KEY} +}; + +struct tspp_pid_filter { + u32 filter; /* see FILTER_ macros */ + u32 config; /* see FILTER_ macros */ +}; + +/* tsp_info */ +#define FILTER_HEADER_ERROR_MASK BIT(7) +#define FILTER_TRANS_END_DISABLE BIT(6) +#define FILTER_DEC_ON_ERROR_EN BIT(5) +#define FILTER_DECRYPT BIT(4) +#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT) +#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF) +#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \ + (_p->config & ~0xF) | (_b & 0xF)) +#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3) +#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \ + (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30)) +#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF) +#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \ + (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13)) +#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF) +#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \ + (_p->filter & ~0x1FFF) | (_b & 0x1FFF)) +#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3) +#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \ + (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30)) +#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7) +#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \ + (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8)) + +struct tspp_global_performance_regs { + u32 tsp_total; + u32 tsp_ignored; + u32 tsp_error; + u32 tsp_sync; +}; + +struct tspp_pipe_context_regs { + u16 pes_bytes_left; + u16 count; + u32 tsif_suffix; +} __packed; +#define CONTEXT_GET_STATE(_a) (_a & 0x3) +#define CONTEXT_UNSPEC_LENGTH BIT(11) +#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF) + +struct tspp_pipe_performance_regs { + u32 tsp_total; + u32 ps_duplicate_tsp; + u32 tsp_no_payload; + u32 tsp_broken_ps; + u32 ps_total_num; + u32 ps_continuity_error; + u32 ps_length_error; + u32 pes_sync_error; +}; + +struct tspp_tsif_device { + void __iomem *base; + u32 time_limit; + u32 ref_count; + enum tspp_tsif_mode mode; + int clock_inverse; + int data_inverse; + int sync_inverse; + int enable_inverse; + u32 tsif_irq; + + /* debugfs */ + struct dentry *dent_tsif; + struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)]; + u32 stat_rx; + u32 stat_overflow; + u32 stat_lost_sync; + u32 stat_timeout; + enum tsif_tts_source tts_source; + u32 lpass_timer_enable; +}; + +enum tspp_buf_state { + TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */ + TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */ + TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */ + TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */ +}; + +struct tspp_mem_buffer { + struct tspp_mem_buffer *next; + struct sps_mem_buffer sps; + struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */ + enum tspp_buf_state state; + size_t filled; /* how much data this buffer is holding */ + int read_index; /* where to start reading data from */ +}; + +/* this represents each char device 'channel' */ +struct tspp_channel { + struct tspp_device *pdev; /* can use container_of instead? */ + struct sps_pipe *pipe; + struct sps_connect config; + struct sps_register_event event; + struct tspp_mem_buffer *data; /* list of buffers */ + struct tspp_mem_buffer *read; /* first buffer ready to be read */ + struct tspp_mem_buffer *waiting; /* first outstanding transfer */ + struct tspp_mem_buffer *locked; /* buffer currently being read */ + wait_queue_head_t in_queue; /* set when data is received */ + u32 id; /* channel id (0-15) */ + int used; /* is this channel in use? */ + int key; /* which encryption key index is used */ + u32 buffer_size; /* size of the sps transfer buffers */ + u32 max_buffers; /* how many buffers should be allocated */ + u32 buffer_count; /* how many buffers are actually allocated */ + u32 filter_count; /* how many filters have been added to this channel */ + u32 int_freq; /* generate interrupts every x descriptors */ + enum tspp_source src; + enum tspp_mode mode; + tspp_notifier *notifier; /* used only with kernel api */ + void *notify_data; /* data to be passed with the notifier */ + u32 expiration_period_ms; /* notification on partially filled buffers */ + struct timer_list expiration_timer; + struct dma_pool *dma_pool; + tspp_memfree *memfree; /* user defined memory free function */ + void *user_info; /* user cookie passed to memory alloc/free function */ +}; + +struct tspp_pid_filter_table { + struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES]; +}; + +struct tspp_key_entry { + u32 even_lsb; + u32 even_msb; + u32 odd_lsb; + u32 odd_msb; +}; + +struct tspp_key_table { + struct tspp_key_entry entry[TSPP_NUM_KEYS]; +}; + +struct tspp_pinctrl { + struct pinctrl *pinctrl; + + struct pinctrl_state *disabled; + struct pinctrl_state *tsif0_mode1; + struct pinctrl_state *tsif0_mode2; + struct pinctrl_state *tsif1_mode1; + struct pinctrl_state *tsif1_mode2; + struct pinctrl_state *dual_mode1; + struct pinctrl_state *dual_mode2; + + bool tsif0_active; + bool tsif1_active; +}; + +/* this represents the actual hardware device */ +struct tspp_device { + struct list_head devlist; /* list of all devices */ + struct platform_device *pdev; + void __iomem *base; + uint32_t tsif_bus_client; + unsigned int tspp_irq; + unsigned int bam_irq; + unsigned long bam_handle; + struct sps_bam_props bam_props; + struct wakeup_source ws; + spinlock_t spinlock; + struct tasklet_struct tlet; + struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES]; + /* clocks */ + struct clk *tsif_pclk; + struct clk *tsif_ref_clk; + /* regulators */ + struct regulator *tsif_vreg; + /* data */ + struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES]; + struct tspp_channel channels[TSPP_NUM_CHANNELS]; + struct tspp_key_table *tspp_key_table; + struct tspp_global_performance_regs *tspp_global_performance; + struct tspp_pipe_context_regs *tspp_pipe_context; + struct tspp_pipe_performance_regs *tspp_pipe_performance; + bool req_irqs; + /* pinctrl */ + struct mutex mutex; + struct tspp_pinctrl pinctrl; + unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */ + struct dma_iommu_mapping *iommu_mapping; + + struct dentry *dent; + struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)]; +}; + +static int tspp_key_entry; +static u32 channel_id; /* next channel id number to assign */ + +static LIST_HEAD(tspp_devices); + +/*** IRQ ***/ +static irqreturn_t tspp_isr(int irq, void *dev) +{ + struct tspp_device *device = dev; + u32 status, mask; + u32 data; + + status = readl_relaxed(device->base + TSPP_IRQ_STATUS); + mask = readl_relaxed(device->base + TSPP_IRQ_MASK); + status &= mask; + + if (!status) { + pr_warn("%s: spurious interrupt\n", __func__); + return IRQ_NONE; + } + + if (status & TSPP_IRQ_STATUS_KEY_ERROR) { + /* read the key error info */ + data = readl_relaxed(device->base + TSPP_KEY_ERROR); + pr_err("%s: key error 0x%x\n", __func__, data); + } + if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) { + data = readl_relaxed(device->base + TSPP_KEY_VALID); + pr_err("%s: key invalidated: 0x%x\n", __func__, data); + } + if (status & TSPP_IRQ_STATUS_KEY_SWITCHED) + pr_debug("%s: key switched\n", __func__); + + if (status & 0xffff) + pr_debug("%s: broken pipe %d\n", __func__, status & 0xffff); + + writel_relaxed(status, device->base + TSPP_IRQ_CLEAR); + + /* + * Before returning IRQ_HANDLED to the generic interrupt handling + * framework need to make sure all operations including clearing of + * interrupt status registers in the hardware is performed. + * Thus a barrier after clearing the interrupt status register + * is required to guarantee that the interrupt status register has + * really been cleared by the time we return from this handler. + */ + wmb(); + return IRQ_HANDLED; +} + +static irqreturn_t tsif_isr(int irq, void *dev) +{ + struct tspp_tsif_device *tsif_device = dev; + u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF); + + if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL | + TSIF_STS_CTL_OVERFLOW | + TSIF_STS_CTL_LOST_SYNC | + TSIF_STS_CTL_TIMEOUT))) + return IRQ_NONE; + + if (sts_ctl & TSIF_STS_CTL_OVERFLOW) + tsif_device->stat_overflow++; + + if (sts_ctl & TSIF_STS_CTL_LOST_SYNC) + tsif_device->stat_lost_sync++; + + if (sts_ctl & TSIF_STS_CTL_TIMEOUT) + tsif_device->stat_timeout++; + + iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF); + + /* + * Before returning IRQ_HANDLED to the generic interrupt handling + * framework need to make sure all operations including clearing of + * interrupt status registers in the hardware is performed. + * Thus a barrier after clearing the interrupt status register + * is required to guarantee that the interrupt status register has + * really been cleared by the time we return from this handler. + */ + wmb(); + return IRQ_HANDLED; +} + +/*** callbacks ***/ +static void tspp_sps_complete_cb(struct sps_event_notify *notify) +{ + struct tspp_device *pdev; + + if (!notify || !notify->user) + return; + + pdev = notify->user; + tasklet_schedule(&pdev->tlet); +} + +static void tspp_expiration_timer(unsigned long data) +{ + struct tspp_device *pdev = (struct tspp_device *)data; + + if (pdev) + tasklet_schedule(&pdev->tlet); +} + +/*** tasklet ***/ +static void tspp_sps_complete_tlet(unsigned long data) +{ + int i; + int complete; + unsigned long flags; + struct sps_iovec iovec; + struct tspp_channel *channel; + struct tspp_device *device = (struct tspp_device *)data; + + spin_lock_irqsave(&device->spinlock, flags); + + for (i = 0; i < TSPP_NUM_CHANNELS; i++) { + complete = 0; + channel = &device->channels[i]; + + if (!channel->used || !channel->waiting) + continue; + + /* stop the expiration timer */ + if (channel->expiration_period_ms) + del_timer(&channel->expiration_timer); + + /* get completions */ + while (channel->waiting->state == TSPP_BUF_STATE_WAITING) { + if (sps_get_iovec(channel->pipe, &iovec) != 0) { + pr_err("%s: error in iovec on channel %d\n", + __func__, channel->id); + break; + } + if (iovec.size == 0) + break; + + if (DESC_FULL_ADDR(iovec.flags, iovec.addr) + != channel->waiting->sps.phys_base) + pr_err("%s: buffer mismatch\n", __func__); + + complete = 1; + channel->waiting->state = TSPP_BUF_STATE_DATA; + channel->waiting->filled = iovec.size; + channel->waiting->read_index = 0; + + if (channel->src == TSPP_SOURCE_TSIF0) + device->tsif[0].stat_rx++; + else if (channel->src == TSPP_SOURCE_TSIF1) + device->tsif[1].stat_rx++; + + /* update the pointers */ + channel->waiting = channel->waiting->next; + } + + /* wake any waiting processes */ + if (complete) { + wake_up_interruptible(&channel->in_queue); + + /* call notifiers */ + if (channel->notifier) + channel->notifier(channel->id, + channel->notify_data); + } + + /* restart expiration timer */ + if (channel->expiration_period_ms) + mod_timer(&channel->expiration_timer, + jiffies + + msecs_to_jiffies( + channel->expiration_period_ms)); + } + + spin_unlock_irqrestore(&device->spinlock, flags); +} + +static int tspp_config_gpios(struct tspp_device *device, + enum tspp_source source, + int enable) +{ + int ret; + struct pinctrl_state *s; + struct tspp_pinctrl *p = &device->pinctrl; + bool mode2; + + /* + * TSIF devices are handled separately, however changing of the pinctrl + * state must be protected from race condition. + */ + if (mutex_lock_interruptible(&device->mutex)) + return -ERESTARTSYS; + + switch (source) { + case TSPP_SOURCE_TSIF0: + mode2 = device->tsif[0].mode == TSPP_TSIF_MODE_2; + if (enable == p->tsif1_active) { + if (enable) + /* Both tsif enabled */ + s = mode2 ? p->dual_mode2 : p->dual_mode1; + else + /* Both tsif disabled */ + s = p->disabled; + } else if (enable) { + /* Only tsif0 is enabled */ + s = mode2 ? p->tsif0_mode2 : p->tsif0_mode1; + } else { + /* Only tsif1 is enabled */ + s = mode2 ? p->tsif1_mode2 : p->tsif1_mode1; + } + + ret = pinctrl_select_state(p->pinctrl, s); + if (!ret) + p->tsif0_active = enable; + break; + case TSPP_SOURCE_TSIF1: + mode2 = device->tsif[1].mode == TSPP_TSIF_MODE_2; + if (enable == p->tsif0_active) { + if (enable) + /* Both tsif enabled */ + s = mode2 ? p->dual_mode2 : p->dual_mode1; + else + /* Both tsif disabled */ + s = p->disabled; + } else if (enable) { + /* Only tsif1 is enabled */ + s = mode2 ? p->tsif1_mode2 : p->tsif1_mode1; + } else { + /* Only tsif0 is enabled */ + s = mode2 ? p->tsif0_mode2 : p->tsif0_mode1; + } + + ret = pinctrl_select_state(p->pinctrl, s); + if (!ret) + p->tsif1_active = enable; + break; + default: + pr_err("%s: invalid source %d\n", __func__, source); + mutex_unlock(&device->mutex); + return -EINVAL; + } + + if (ret) + pr_err("%s: failed to change pinctrl state, ret=%d\n", + __func__, ret); + + mutex_unlock(&device->mutex); + return ret; +} + +static int tspp_get_pinctrl(struct tspp_device *device) +{ + struct pinctrl *pinctrl; + struct pinctrl_state *state; + + pinctrl = devm_pinctrl_get(&device->pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("%s: unable to get pinctrl handle\n", __func__); + return -EINVAL; + } + device->pinctrl.pinctrl = pinctrl; + + state = pinctrl_lookup_state(pinctrl, "disabled"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", __func__, "disabled"); + return -EINVAL; + } + device->pinctrl.disabled = state; + + state = pinctrl_lookup_state(pinctrl, "tsif0-mode1"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif0-mode1"); + return -EINVAL; + } + device->pinctrl.tsif0_mode1 = state; + + state = pinctrl_lookup_state(pinctrl, "tsif0-mode2"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif0-mode2"); + return -EINVAL; + } + device->pinctrl.tsif0_mode2 = state; + + state = pinctrl_lookup_state(pinctrl, "tsif1-mode1"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif1-mode1"); + return -EINVAL; + } + device->pinctrl.tsif1_mode1 = state; + + state = pinctrl_lookup_state(pinctrl, "tsif1-mode2"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif1-mode2"); + return -EINVAL; + } + device->pinctrl.tsif1_mode2 = state; + + state = pinctrl_lookup_state(pinctrl, "dual-tsif-mode1"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "dual-tsif-mode1"); + return -EINVAL; + } + device->pinctrl.dual_mode1 = state; + + state = pinctrl_lookup_state(pinctrl, "dual-tsif-mode2"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "dual-tsif-mode2"); + return -EINVAL; + } + device->pinctrl.dual_mode2 = state; + + device->pinctrl.tsif0_active = false; + device->pinctrl.tsif1_active = false; + + return 0; +} + + +/*** Clock functions ***/ +static int tspp_clock_start(struct tspp_device *device) +{ + int rc; + + if (device->tsif_bus_client) { + rc = msm_bus_scale_client_update_request( + device->tsif_bus_client, 1); + if (rc) { + pr_err("%s: can't enable bus\n", __func__); + return -EBUSY; + } + } + + if (device->tsif_vreg) { + rc = regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + if (rc) { + pr_err("%s: unable to set CX voltage\n", __func__); + if (device->tsif_bus_client) + msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + return rc; + } + } + + if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) { + pr_err("%s: can't start %s\n", __func__, "pclk"); + + if (device->tsif_vreg) { + regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + } + + if (device->tsif_bus_client) + msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + return -EBUSY; + } + + if (device->tsif_ref_clk && + clk_prepare_enable(device->tsif_ref_clk) != 0) { + pr_err("%s: can't start %s\n", __func__, "ref clk"); + clk_disable_unprepare(device->tsif_pclk); + if (device->tsif_vreg) { + regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + } + + if (device->tsif_bus_client) + msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + return -EBUSY; + } + + return 0; +} + +static void tspp_clock_stop(struct tspp_device *device) +{ + int rc; + + if (device->tsif_pclk) + clk_disable_unprepare(device->tsif_pclk); + + if (device->tsif_ref_clk) + clk_disable_unprepare(device->tsif_ref_clk); + + if (device->tsif_vreg) { + rc = regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + if (rc) + pr_err("%s: unable to set CX voltage\n", __func__); + } + + if (device->tsif_bus_client) { + rc = msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + if (rc) + pr_err("%s: can't disable bus\n", __func__); + } +} + +/*** TSIF functions ***/ +static int tspp_start_tsif(struct tspp_tsif_device *tsif_device) +{ + int start_hardware = 0; + u32 ctl; + + if (tsif_device->ref_count == 0) { + start_hardware = 1; + } else if (tsif_device->ref_count > 0) { + ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF); + if ((ctl & TSIF_STS_CTL_START) != 1) { + /* this hardware should already be running */ + pr_err("%s: tsif hw not started but ref count > 0\n", + __func__); + start_hardware = 1; + } + } + + if (start_hardware) { + ctl = TSIF_STS_CTL_EN_IRQ | + TSIF_STS_CTL_EN_DM | + TSIF_STS_CTL_PACK_AVAIL | + TSIF_STS_CTL_OVERFLOW | + TSIF_STS_CTL_LOST_SYNC; + + if (tsif_device->clock_inverse) + ctl |= TSIF_STS_CTL_INV_CLOCK; + + if (tsif_device->data_inverse) + ctl |= TSIF_STS_CTL_INV_DATA; + + if (tsif_device->sync_inverse) + ctl |= TSIF_STS_CTL_INV_SYNC; + + if (tsif_device->enable_inverse) + ctl |= TSIF_STS_CTL_INV_ENABLE; + + switch (tsif_device->mode) { + case TSPP_TSIF_MODE_LOOPBACK: + ctl |= TSIF_STS_CTL_EN_NULL | + TSIF_STS_CTL_EN_ERROR | + TSIF_STS_CTL_TEST_MODE; + break; + case TSPP_TSIF_MODE_1: + ctl |= TSIF_STS_CTL_EN_TIME_LIM; + if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER) + ctl |= TSIF_STS_CTL_EN_TCR; + break; + case TSPP_TSIF_MODE_2: + ctl |= TSIF_STS_CTL_EN_TIME_LIM | + TSIF_STS_CTL_MODE_2; + if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER) + ctl |= TSIF_STS_CTL_EN_TCR; + break; + default: + pr_warn("%s: unknown tsif mode 0x%x\n", __func__, + tsif_device->mode); + } + + writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF); + /* write Status control register */ + wmb(); + writel_relaxed(tsif_device->time_limit, + tsif_device->base + TSIF_TIME_LIMIT_OFF); + /* assure register configuration is done before starting TSIF */ + wmb(); + writel_relaxed(ctl | TSIF_STS_CTL_START, + tsif_device->base + TSIF_STS_CTL_OFF); + /* assure TSIF start configuration */ + wmb(); + } + + ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF); + if (!(ctl & TSIF_STS_CTL_START)) + return -EBUSY; + + tsif_device->ref_count++; + return 0; +} + +static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device) +{ + if (tsif_device->ref_count == 0) + return; + + tsif_device->ref_count--; + + if (tsif_device->ref_count == 0) { + writel_relaxed(TSIF_STS_CTL_STOP, + tsif_device->base + TSIF_STS_CTL_OFF); + /* assure TSIF stop configuration */ + wmb(); + } +} + +/*** local TSPP functions ***/ +static int tspp_channels_in_use(struct tspp_device *pdev) +{ + int i; + int count = 0; + + for (i = 0; i < TSPP_NUM_CHANNELS; i++) + count += (pdev->channels[i].used ? 1 : 0); + + return count; +} + +static struct tspp_device *tspp_find_by_id(int id) +{ + struct tspp_device *dev; + + list_for_each_entry(dev, &tspp_devices, devlist) { + if (dev->pdev->id == id) + return dev; + } + return NULL; +} + +static int tspp_get_key_entry(void) +{ + int i; + + for (i = 0; i < TSPP_NUM_KEYS; i++) { + if (!(tspp_key_entry & (1 << i))) { + tspp_key_entry |= (1 << i); + return i; + } + } + return 1 < TSPP_NUM_KEYS; +} + +static void tspp_free_key_entry(int entry) +{ + if (entry > TSPP_NUM_KEYS) { + pr_err("%s: index out of bounds\n", __func__); + return; + } + + tspp_key_entry &= ~(1 << entry); +} + +static int tspp_iommu_init(struct tspp_device *device) +{ + struct dma_iommu_mapping *iommu_map; + struct device_node *node; + int s1_bypass; + int ret; + + node = device->pdev->dev.of_node; + + iommu_map = arm_iommu_create_mapping(&platform_bus_type, + TSPP_SMMU_IOVA_START, + TSPP_SMMU_IOVA_SIZE); + if (IS_ERR(iommu_map)) { + pr_err("%s: iommu_create_mapping failure\n", __func__); + return PTR_ERR(iommu_map); + } + + s1_bypass = of_property_read_bool(node, "qcom,smmu-s1-bypass"); + ret = iommu_domain_set_attr(iommu_map->domain, + DOMAIN_ATTR_S1_BYPASS, &s1_bypass); + if (ret) { + pr_err("%s: IOMMU set s1 bypass (%d) failed (%d)\n", __func__, + s1_bypass, ret); + } + + if (arm_iommu_attach_device(&device->pdev->dev, iommu_map)) { + pr_err("%s: can't arm_iommu_attach_device\n", __func__); + arm_iommu_release_mapping(iommu_map); + return -EIO; + } + + device->iommu_mapping = iommu_map; + return 0; +} + +static void tspp_iommu_release_iomapping(struct tspp_device *device) +{ + if (device->iommu_mapping) + arm_iommu_release_mapping(device->iommu_mapping); + + device->iommu_mapping = NULL; +} + +static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc, + u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user) +{ + if (size < TSPP_MIN_BUFFER_SIZE || + size > TSPP_MAX_BUFFER_SIZE) { + pr_err("%s: bad buffer size %d\n", __func__, size); + return -ENOMEM; + } + + if (alloc) { + TSPP_DEBUG("%s: using alloc function\n"); + desc->virt_base = alloc(channel_id, size, + &desc->phys_base, &desc->dma_base, user); + } else { + if (!dma_pool) + desc->virt_base = dma_alloc_coherent(NULL, size, + &desc->phys_base, GFP_KERNEL); + else + desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL, + &desc->phys_base); + + if (desc->virt_base == 0) { + pr_err("%s: dma buffer allocation failed %d\n", + __func__, size); + return -ENOMEM; + } + } + + desc->size = size; + return 0; +} + +static int tspp_queue_buffer(struct tspp_channel *channel, + struct tspp_mem_buffer *buffer) +{ + int rc; + u32 flags = 0; + + /* make sure the interrupt frequency is valid */ + if (channel->int_freq < 1) + channel->int_freq = 1; + + /* generate interrupt according to requested frequency */ + if (buffer->desc.id % channel->int_freq == channel->int_freq-1) + flags = SPS_IOVEC_FLAG_INT; + + /* start the transfer */ + rc = sps_transfer_one(channel->pipe, + buffer->sps.phys_base, + buffer->sps.size, + flags ? channel->pdev : NULL, + flags); + if (rc < 0) + return rc; + + buffer->state = TSPP_BUF_STATE_WAITING; + + return 0; +} + +static int tspp_global_reset(struct tspp_device *pdev) +{ + u32 i, val; + + /* stop all TSIFs */ + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { + pdev->tsif[i].ref_count = 1; /* allows stopping hw */ + tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */ + pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT; + pdev->tsif[i].clock_inverse = 0; + pdev->tsif[i].data_inverse = 0; + pdev->tsif[i].sync_inverse = 0; + pdev->tsif[i].enable_inverse = 0; + pdev->tsif[i].lpass_timer_enable = 0; + } + writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST); + /* assure state is reset before continuing with configuration */ + wmb(); + + /* TSPP tables */ + for (i = 0; i < TSPP_FILTER_TABLES; i++) + memset_io(pdev->filters[i], + 0, sizeof(*pdev->filters[i])); + + /* disable all filters */ + val = (2 << TSPP_NUM_CHANNELS) - 1; + writel_relaxed(val, pdev->base + TSPP_PS_DISABLE); + + /* TSPP registers */ + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT, + pdev->base + TSPP_CONTROL); + /* assure tspp performance count clock is set to 0 */ + wmb(); + memset_io(pdev->tspp_global_performance, 0, + sizeof(*pdev->tspp_global_performance)); + memset_io(pdev->tspp_pipe_context, 0, + sizeof(*pdev->tspp_pipe_context)); + memset_io(pdev->tspp_pipe_performance, 0, + sizeof(*pdev->tspp_pipe_performance)); + /* assure tspp pipe context registers are set to 0 */ + wmb(); + writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT, + pdev->base + TSPP_CONTROL); + /* assure tspp performance count clock is reset */ + wmb(); + + val = readl_relaxed(pdev->base + TSPP_CONFIG); + val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK | + TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK | + TSPP_CONFIG_PS_CONT_ERR_MASK); + TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH); + writel_relaxed(val, pdev->base + TSPP_CONFIG); + writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK); + writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR); + writel_relaxed(0, pdev->base + TSPP_RST); + /* assure tspp reset clear */ + wmb(); + + tspp_key_entry = 0; + + return 0; +} + +static void tspp_channel_init(struct tspp_channel *channel, + struct tspp_device *pdev) +{ + channel->pdev = pdev; + channel->data = NULL; + channel->read = NULL; + channel->waiting = NULL; + channel->locked = NULL; + channel->id = channel_id++; + channel->used = 0; + channel->buffer_size = TSPP_MIN_BUFFER_SIZE; + channel->max_buffers = TSPP_NUM_BUFFERS; + channel->buffer_count = 0; + channel->filter_count = 0; + channel->int_freq = 1; + channel->src = TSPP_SOURCE_NONE; + channel->mode = TSPP_MODE_DISABLED; + channel->notifier = NULL; + channel->notify_data = NULL; + channel->expiration_period_ms = 0; + channel->memfree = NULL; + channel->user_info = NULL; + init_waitqueue_head(&channel->in_queue); +} + +static void tspp_set_tsif_mode(struct tspp_channel *channel, + enum tspp_tsif_mode mode) +{ + int index; + + switch (channel->src) { + case TSPP_SOURCE_TSIF0: + index = 0; + break; + case TSPP_SOURCE_TSIF1: + index = 1; + break; + default: + pr_warn("%s: can't set mode for non-tsif source %d\n", __func__, + channel->src); + return; + } + channel->pdev->tsif[index].mode = mode; +} + +static void tspp_set_signal_inversion(struct tspp_channel *channel, + int clock_inverse, int data_inverse, + int sync_inverse, int enable_inverse) +{ + int index; + + switch (channel->src) { + case TSPP_SOURCE_TSIF0: + index = 0; + break; + case TSPP_SOURCE_TSIF1: + index = 1; + break; + default: + return; + } + channel->pdev->tsif[index].clock_inverse = clock_inverse; + channel->pdev->tsif[index].data_inverse = data_inverse; + channel->pdev->tsif[index].sync_inverse = sync_inverse; + channel->pdev->tsif[index].enable_inverse = enable_inverse; +} + +static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode) +{ + u32 alignment; + + switch (mode) { + case TSPP_MODE_RAW: + /* must be a multiple of 192 */ + alignment = (TSPP_PACKET_LENGTH + 4); + if (size % alignment) + return 0; + return 1; + + case TSPP_MODE_RAW_NO_SUFFIX: + /* must be a multiple of 188 */ + alignment = TSPP_PACKET_LENGTH; + if (size % alignment) + return 0; + return 1; + + case TSPP_MODE_DISABLED: + case TSPP_MODE_PES: + default: + /* no alignment requirement */ + return 1; + } + +} + +static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode) +{ + u32 new_size; + u32 alignment; + + switch (mode) { + case TSPP_MODE_RAW: + /* must be a multiple of 192 */ + alignment = (TSPP_PACKET_LENGTH + 4); + break; + + case TSPP_MODE_RAW_NO_SUFFIX: + /* must be a multiple of 188 */ + alignment = TSPP_PACKET_LENGTH; + break; + + case TSPP_MODE_DISABLED: + case TSPP_MODE_PES: + default: + /* no alignment requirement - give the user what he asks for */ + alignment = 1; + break; + } + /* align up */ + new_size = (((size + alignment - 1) / alignment) * alignment); + return new_size; +} + +static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel) +{ + int i; + struct tspp_mem_buffer *pbuf, *temp; + + pbuf = channel->data; + for (i = 0; i < channel->buffer_count; i++) { + if (pbuf->desc.phys_base) { + if (channel->memfree) { + channel->memfree(channel_id, + pbuf->desc.size, + pbuf->desc.virt_base, + pbuf->desc.phys_base, + channel->user_info); + } else { + if (!channel->dma_pool) + dma_free_coherent( + &channel->pdev->pdev->dev, + pbuf->desc.size, + pbuf->desc.virt_base, + pbuf->desc.phys_base); + else + dma_pool_free(channel->dma_pool, + pbuf->desc.virt_base, + pbuf->desc.phys_base); + } + pbuf->desc.phys_base = 0; + } + pbuf->desc.virt_base = 0; + pbuf->state = TSPP_BUF_STATE_EMPTY; + temp = pbuf; + pbuf = pbuf->next; + kfree(temp); + } +} + +static int msm_tspp_req_irqs(struct tspp_device *device) +{ + int rc; + int i; + int j; + + rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED, + dev_name(&device->pdev->dev), device); + if (rc) { + pr_err("%s: failed to request TSPP IRQ %d : %d\n", __func__, + device->tspp_irq, rc); + return rc; + } + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { + rc = request_irq(device->tsif[i].tsif_irq, + tsif_isr, IRQF_SHARED, dev_name(&device->pdev->dev), + &device->tsif[i]); + if (rc) { + pr_err("%s: failed to request TSIF%d IRQ: %d\n", + __func__, i, rc); + goto failed; + } + } + device->req_irqs = true; + return 0; + +failed: + free_irq(device->tspp_irq, device); + for (j = 0; j < i; j++) + free_irq(device->tsif[j].tsif_irq, device); + + return rc; +} + +static inline void msm_tspp_free_irqs(struct tspp_device *device) +{ + int i; + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + free_irq(device->tsif[i].tsif_irq, &device->tsif[i]); + + free_irq(device->tspp_irq, device); + device->req_irqs = false; +} + +/*** TSPP API functions ***/ + +/** + * tspp_open_stream - open a TSPP stream for use. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @source: stream source parameters. + * + * Return error status + * + */ +int tspp_open_stream(u32 dev, u32 channel_id, + struct tspp_select_source *source) +{ + u32 val; + int rc; + struct tspp_device *pdev; + struct tspp_channel *channel; + bool req_irqs = false; + + TSPP_DEBUG("%s: %d %d %d %d\n", __func__, dev, channel_id, + source->source, source->mode); + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return -ENODEV; + } + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + channel->src = source->source; + tspp_set_tsif_mode(channel, source->mode); + tspp_set_signal_inversion(channel, source->clk_inverse, + source->data_inverse, source->sync_inverse, + source->enable_inverse); + + /* Request IRQ resources on first open */ + if (!pdev->req_irqs && (source->source == TSPP_SOURCE_TSIF0 || + source->source == TSPP_SOURCE_TSIF1)) { + rc = msm_tspp_req_irqs(pdev); + if (rc) + return rc; + req_irqs = true; + } + + switch (source->source) { + case TSPP_SOURCE_TSIF0: + if (tspp_config_gpios(pdev, channel->src, 1) != 0) { + rc = -EBUSY; + pr_err("%s: error enabling %s\n", + __func__, "tsif0 GPIOs"); + goto free_irq; + } + /* make sure TSIF0 is running & enabled */ + if (tspp_start_tsif(&pdev->tsif[0]) != 0) { + rc = -EBUSY; + pr_err("%s: error starting %s\n", __func__, "tsif0"); + goto free_irq; + } + if (pdev->tsif[0].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is enabled */ + wmb(); + } + break; + case TSPP_SOURCE_TSIF1: + if (tspp_config_gpios(pdev, channel->src, 1) != 0) { + rc = -EBUSY; + pr_err("%s: error enabling %s\n", + __func__, "tsif1 GPIOs"); + goto free_irq; + } + /* make sure TSIF1 is running & enabled */ + if (tspp_start_tsif(&pdev->tsif[1]) != 0) { + rc = -EBUSY; + pr_err("%s: error starting %s\n", __func__, "tsif1"); + goto free_irq; + } + if (pdev->tsif[1].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is enabled */ + wmb(); + } + break; + case TSPP_SOURCE_MEM: + break; + default: + pr_err("%s: channel %d invalid source %d\n", __func__, + channel->id, source->source); + return -EBUSY; + } + + return 0; + +free_irq: + /* Free irqs only if were requested during opening of this stream */ + if (req_irqs) + msm_tspp_free_irqs(pdev); + return rc; +} +EXPORT_SYMBOL(tspp_open_stream); + +/** + * tspp_close_stream - close a TSPP stream. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_close_stream(u32 dev, u32 channel_id) +{ + u32 val; + u32 prev_ref_count = 0; + struct tspp_device *pdev; + struct tspp_channel *channel; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", __func__, + TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -EBUSY; + } + channel = &pdev->channels[channel_id]; + + switch (channel->src) { + case TSPP_SOURCE_TSIF0: + prev_ref_count = pdev->tsif[0].ref_count; + tspp_stop_tsif(&pdev->tsif[0]); + if (tspp_config_gpios(pdev, channel->src, 0) != 0) + pr_err("%s: error disabling %s\n", + __func__, "tsif0 GPIOs"); + + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is disabled */ + wmb(); + } + break; + case TSPP_SOURCE_TSIF1: + prev_ref_count = pdev->tsif[1].ref_count; + tspp_stop_tsif(&pdev->tsif[1]); + if (tspp_config_gpios(pdev, channel->src, 0) != 0) + pr_err("%s: error disabling %s\n", + __func__, "tsif1 GPIOs"); + + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is disabled */ + wmb(); + } + break; + case TSPP_SOURCE_MEM: + break; + case TSPP_SOURCE_NONE: + break; + } + + channel->src = TSPP_SOURCE_NONE; + + /* Free requested interrupts to save power */ + if ((pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0 && + prev_ref_count) + msm_tspp_free_irqs(pdev); + + return 0; +} +EXPORT_SYMBOL(tspp_close_stream); + +static int tspp_init_sps_device(struct tspp_device *dev) +{ + int ret; + + ret = sps_register_bam_device(&dev->bam_props, &dev->bam_handle); + if (ret) { + pr_err("%s: failed to register bam device, err-%d\n", + __func__, ret); + return ret; + } + + ret = sps_device_reset(dev->bam_handle); + if (ret) { + sps_deregister_bam_device(dev->bam_handle); + pr_err("%s: error resetting bam device, err=%d\n", + __func__, ret); + return ret; + } + + return 0; +} + +/** + * tspp_open_channel - open a TSPP channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_open_channel(u32 dev, u32 channel_id) +{ + int rc = 0; + struct sps_connect *config; + struct sps_register_event *event; + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + + if (channel->used) { + pr_err("%s: channel already in use\n", __func__); + return -EBUSY; + } + + config = &channel->config; + event = &channel->event; + + /* start the clocks if needed */ + if (tspp_channels_in_use(pdev) == 0) { + rc = tspp_clock_start(pdev); + if (rc) + return rc; + + if (pdev->bam_handle == SPS_DEV_HANDLE_INVALID) { + rc = tspp_init_sps_device(pdev); + if (rc) { + tspp_clock_stop(pdev); + return rc; + } + } + + __pm_stay_awake(&pdev->ws); + } + + /* mark it as used */ + channel->used = 1; + + /* start the bam */ + channel->pipe = sps_alloc_endpoint(); + if (channel->pipe == NULL) { + pr_err("%s: error allocating endpoint\n", __func__); + rc = -ENOMEM; + goto err_sps_alloc; + } + + /* get default configuration */ + sps_get_config(channel->pipe, config); + + config->source = pdev->bam_handle; + config->destination = SPS_DEV_HANDLE_MEM; + config->mode = SPS_MODE_SRC; + config->options = + SPS_O_AUTO_ENABLE | /* connection is auto-enabled */ + SPS_O_STREAMING | /* streaming mode */ + SPS_O_DESC_DONE | /* interrupt on end of descriptor */ + SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */ + SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */ + config->src_pipe_index = channel->id; + config->desc.size = + TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE; + config->desc.base = dma_alloc_coherent(&pdev->pdev->dev, + config->desc.size, + &config->desc.phys_base, + GFP_KERNEL); + if (config->desc.base == 0) { + pr_err("%s: error allocating sps descriptors\n", __func__); + rc = -ENOMEM; + goto err_desc_alloc; + } + + memset(config->desc.base, 0, config->desc.size); + + rc = sps_connect(channel->pipe, config); + if (rc) { + pr_err("%s: error connecting bam\n", __func__); + goto err_connect; + } + + event->mode = SPS_TRIGGER_CALLBACK; + event->options = SPS_O_DESC_DONE; + event->callback = tspp_sps_complete_cb; + event->xfer_done = NULL; + event->user = pdev; + + rc = sps_register_event(channel->pipe, event); + if (rc) { + pr_err("%s: error registering event\n", __func__); + goto err_event; + } + + init_timer(&channel->expiration_timer); + channel->expiration_timer.function = tspp_expiration_timer; + channel->expiration_timer.data = (unsigned long)pdev; + channel->expiration_timer.expires = 0xffffffffL; + + rc = pm_runtime_get(&pdev->pdev->dev); + if (rc < 0) { + pr_err( + "%s: Runtime PM : Unable to wake up tspp device, rc = %d\n", + __func__, rc); + } + return 0; + +err_event: + sps_disconnect(channel->pipe); +err_connect: + dma_free_coherent(&pdev->pdev->dev, config->desc.size, + config->desc.base, config->desc.phys_base); +err_desc_alloc: + sps_free_endpoint(channel->pipe); +err_sps_alloc: + channel->used = 0; + return rc; +} +EXPORT_SYMBOL(tspp_open_channel); + +/** + * tspp_close_channel - close a TSPP channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_close_channel(u32 dev, u32 channel_id) +{ + int i; + int id; + int table_idx; + u32 val; + unsigned long flags; + + struct sps_connect *config; + struct tspp_device *pdev; + struct tspp_channel *channel; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + + /* if the channel is not used, we are done */ + if (!channel->used) + return 0; + + /* + * Need to protect access to used and waiting fields, as they are + * used by the tasklet which is invoked from interrupt context + */ + spin_lock_irqsave(&pdev->spinlock, flags); + channel->used = 0; + channel->waiting = NULL; + spin_unlock_irqrestore(&pdev->spinlock, flags); + + if (channel->expiration_period_ms) + del_timer(&channel->expiration_timer); + + channel->notifier = NULL; + channel->notify_data = NULL; + channel->expiration_period_ms = 0; + + config = &channel->config; + pdev = channel->pdev; + + /* disable pipe (channel) */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is set */ + wmb(); + + /* unregister all filters for this channel */ + for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) { + for (i = 0; i < TSPP_NUM_PRIORITIES; i++) { + struct tspp_pid_filter *filter = + &pdev->filters[table_idx]->filter[i]; + id = FILTER_GET_PIPE_NUMBER0(filter); + if (id == channel->id) { + if (FILTER_HAS_ENCRYPTION(filter)) + tspp_free_key_entry( + FILTER_GET_KEY_NUMBER(filter)); + filter->config = 0; + filter->filter = 0; + } + } + } + channel->filter_count = 0; + + /* disconnect the bam */ + if (sps_disconnect(channel->pipe) != 0) + pr_warn("%s: Error freeing sps endpoint (%d)\n", + __func__, channel->id); + + /* destroy the buffers */ + dma_free_coherent(&pdev->pdev->dev, config->desc.size, + config->desc.base, config->desc.phys_base); + + sps_free_endpoint(channel->pipe); + + tspp_destroy_buffers(channel_id, channel); + + dma_pool_destroy(channel->dma_pool); + channel->dma_pool = NULL; + + channel->src = TSPP_SOURCE_NONE; + channel->mode = TSPP_MODE_DISABLED; + channel->memfree = NULL; + channel->user_info = NULL; + channel->buffer_count = 0; + channel->data = NULL; + channel->read = NULL; + channel->locked = NULL; + + if (tspp_channels_in_use(pdev) == 0) { + sps_deregister_bam_device(pdev->bam_handle); + pdev->bam_handle = SPS_DEV_HANDLE_INVALID; + + __pm_relax(&pdev->ws); + tspp_clock_stop(pdev); + } + + pm_runtime_put(&pdev->pdev->dev); + + return 0; +} +EXPORT_SYMBOL(tspp_close_channel); + +/** + * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @source: The TSIF source from which the counter should be read + * @tcr_counter: the value of TCR counter + * + * Return error status + * + * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz. + * If source is neither TSIF 0 or TSIF1 0 is returned. + */ +int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter) +{ + struct tspp_device *pdev; + struct tspp_tsif_device *tsif_device; + + if (!tcr_counter) + return -EINVAL; + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + switch (source) { + case TSPP_SOURCE_TSIF0: + tsif_device = &pdev->tsif[0]; + break; + + case TSPP_SOURCE_TSIF1: + tsif_device = &pdev->tsif[1]; + break; + + default: + tsif_device = NULL; + break; + } + + if (tsif_device && tsif_device->ref_count) + *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF); + else + *tcr_counter = 0; + + return 0; +} +EXPORT_SYMBOL(tspp_get_ref_clk_counter); + +/** + * tspp_get_lpass_time_counter - return the LPASS Timer counter value. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @source: The TSIF source from which the counter should be read + * @tcr_counter: the value of TCR counter + * + * Return error status + * + * If source is neither TSIF 0 or TSIF1 0 is returned. + */ +int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source, + u64 *lpass_time_counter) +{ + return -EPERM; +} +EXPORT_SYMBOL(tspp_get_lpass_time_counter); + +/** + * tspp_get_tts_source - Return the TTS source value. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @tts_source:Updated TTS source type + * + * Return error status + * + */ +int tspp_get_tts_source(u32 dev, int *tts_source) +{ + struct tspp_device *pdev; + + if (tts_source == NULL) + return -EINVAL; + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + *tts_source = pdev->tts_source; + + return 0; +} +EXPORT_SYMBOL(tspp_get_tts_source); + +/** + * tspp_add_filter - add a TSPP filter to a channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @filter: TSPP filter parameters + * + * Return error status + * + */ +int tspp_add_filter(u32 dev, u32 channel_id, + struct tspp_filter *filter) +{ + int i, rc; + int other_channel; + int entry; + u32 val, pid, enabled; + struct tspp_device *pdev; + struct tspp_pid_filter p; + struct tspp_channel *channel; + + TSPP_DEBUG("%s: add filter\n"); + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + channel = &pdev->channels[channel_id]; + + if (filter->source > TSPP_SOURCE_MEM) { + pr_err("%s: invalid source\n", __func__); + return -ENOSR; + } + + if (filter->priority >= TSPP_NUM_PRIORITIES) { + pr_err("%s: invalid filter priority\n", __func__); + return -ENOSR; + } + + channel->mode = filter->mode; + /* + * if buffers are already allocated, verify they fulfil + * the alignment requirements. + */ + if ((channel->buffer_count > 0) && + (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode))) + pr_warn("%s: buffers allocated with incorrect alignment\n", + __func__); + + if (filter->mode == TSPP_MODE_PES) { + for (i = 0; i < TSPP_NUM_PRIORITIES; i++) { + struct tspp_pid_filter *tspp_filter = + &pdev->filters[channel->src]->filter[i]; + pid = FILTER_GET_PIPE_PID((tspp_filter)); + enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter); + if (enabled && (pid == filter->pid)) { + other_channel = + FILTER_GET_PIPE_NUMBER0(tspp_filter); + pr_err( + "%s: pid 0x%x already in use by channel %d\n", + __func__, filter->pid, other_channel); + return -EBADSLT; + } + } + } + + /* make sure this priority is not already in use */ + enabled = FILTER_GET_PIPE_PROCESS0( + (&(pdev->filters[channel->src]->filter[filter->priority]))); + if (enabled) { + pr_err("%s: filter priority %d source %d is already enabled\n", + __func__, filter->priority, channel->src); + return -ENOSR; + } + + if (channel->mode == TSPP_MODE_PES) { + /* + * if we are already processing in PES mode, disable pipe + * (channel) and filter to be updated + */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val | (1 << channel->id), + pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is set */ + wmb(); + } + + /* update entry */ + p.filter = 0; + p.config = FILTER_TRANS_END_DISABLE; + FILTER_SET_PIPE_PROCESS0((&p), filter->mode); + FILTER_SET_PIPE_PID((&p), filter->pid); + FILTER_SET_PID_MASK((&p), filter->mask); + FILTER_SET_PIPE_NUMBER0((&p), channel->id); + FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED); + if (filter->decrypt) { + entry = tspp_get_key_entry(); + if (entry == -1) { + pr_err("%s: no more keys available\n", __func__); + } else { + p.config |= FILTER_DECRYPT; + FILTER_SET_KEY_NUMBER((&p), entry); + } + } + + pdev->filters[channel->src]->filter[filter->priority].config = p.config; + pdev->filters[channel->src]->filter[filter->priority].filter = p.filter; + + /* + * allocate buffers if needed (i.e. if user did has not already called + * tspp_allocate_buffers() explicitly). + */ + if (channel->buffer_count == 0) { + channel->buffer_size = + tspp_align_buffer_size_by_mode(channel->buffer_size, + channel->mode); + rc = tspp_allocate_buffers(dev, channel->id, + channel->max_buffers, + channel->buffer_size, + channel->int_freq, NULL, NULL, NULL); + if (rc != 0) { + pr_err("%s: tspp_allocate_buffers failed\n", __func__); + return rc; + } + } + + /* reenable pipe */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is reset */ + wmb(); + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + + channel->filter_count++; + + return 0; +} +EXPORT_SYMBOL(tspp_add_filter); + +/** + * tspp_remove_filter - remove a TSPP filter from a channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @filter: TSPP filter parameters + * + * Return error status + * + */ +int tspp_remove_filter(u32 dev, u32 channel_id, + struct tspp_filter *filter) +{ + int entry; + u32 val; + struct tspp_device *pdev; + int src; + struct tspp_pid_filter *tspp_filter; + struct tspp_channel *channel; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + if (!filter) { + pr_err("%s: NULL filter pointer\n", __func__); + return -EINVAL; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + if (filter->priority >= TSPP_NUM_PRIORITIES) { + pr_err("%s: invalid filter priority\n", __func__); + return -ENOSR; + } + channel = &pdev->channels[channel_id]; + + src = channel->src; + if ((src == TSPP_SOURCE_TSIF0) || (src == TSPP_SOURCE_TSIF1)) + tspp_filter = &(pdev->filters[src]->filter[filter->priority]); + else { + pr_err("%s: wrong source type %d\n", __func__, src); + return -EINVAL; + } + + + /* disable pipe (channel) */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is set */ + wmb(); + + /* update data keys */ + if (tspp_filter->config & FILTER_DECRYPT) { + entry = FILTER_GET_KEY_NUMBER(tspp_filter); + tspp_free_key_entry(entry); + } + + /* update pid table */ + tspp_filter->config = 0; + tspp_filter->filter = 0; + + channel->filter_count--; + + /* reenable pipe */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val & ~(1 << channel->id), + pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is reset */ + wmb(); + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + + return 0; +} +EXPORT_SYMBOL(tspp_remove_filter); + +/** + * tspp_set_key - set TSPP key in key table. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @key: TSPP key parameters + * + * Return error status + * + */ +int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key) +{ + int i; + int id; + int key_index; + int data; + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + + /* read the key index used by this channel */ + for (i = 0; i < TSPP_NUM_PRIORITIES; i++) { + struct tspp_pid_filter *tspp_filter = + &(pdev->filters[channel->src]->filter[i]); + id = FILTER_GET_PIPE_NUMBER0(tspp_filter); + if (id == channel->id) { + if (FILTER_HAS_ENCRYPTION(tspp_filter)) { + key_index = FILTER_GET_KEY_NUMBER(tspp_filter); + break; + } + } + } + if (i == TSPP_NUM_PRIORITIES) { + pr_err("%s: no encryption on this channel\n"); + return -ENOKEY; + } + + if (key->parity == TSPP_KEY_PARITY_EVEN) { + pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb; + pdev->tspp_key_table->entry[key_index].even_msb = key->msb; + } else { + pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb; + pdev->tspp_key_table->entry[key_index].odd_msb = key->msb; + } + data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID); + + return 0; +} +EXPORT_SYMBOL(tspp_set_key); + +/** + * tspp_register_notification - register TSPP channel notification function. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @notify: notification function + * @userdata: user data to pass to notification function + * @timer_ms: notification for partially filled buffers + * + * Return error status + * + */ +int tspp_register_notification(u32 dev, u32 channel_id, + tspp_notifier *notify, void *userdata, u32 timer_ms) +{ + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + channel->notifier = notify; + channel->notify_data = userdata; + channel->expiration_period_ms = timer_ms; + + return 0; +} +EXPORT_SYMBOL(tspp_register_notification); + +/** + * tspp_unregister_notification - unregister TSPP channel notification function. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_unregister_notification(u32 dev, u32 channel_id) +{ + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + channel->notifier = NULL; + channel->notify_data = 0; + return 0; +} +EXPORT_SYMBOL(tspp_unregister_notification); + +/** + * tspp_get_buffer - get TSPP data buffer. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id) +{ + struct tspp_mem_buffer *buffer; + struct tspp_channel *channel; + struct tspp_device *pdev; + unsigned long flags; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return NULL; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return NULL; + } + + spin_lock_irqsave(&pdev->spinlock, flags); + + channel = &pdev->channels[channel_id]; + + if (!channel->read) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + pr_warn("%s: no buffer to get on channel %d\n", __func__, + channel->id); + return NULL; + } + + buffer = channel->read; + /* see if we have any buffers ready to read */ + if (buffer->state != TSPP_BUF_STATE_DATA) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + return NULL; + } + + if (buffer->state == TSPP_BUF_STATE_DATA) { + /* mark the buffer as busy */ + buffer->state = TSPP_BUF_STATE_LOCKED; + + /* increment the pointer along the list */ + channel->read = channel->read->next; + } + + spin_unlock_irqrestore(&pdev->spinlock, flags); + + return &buffer->desc; +} +EXPORT_SYMBOL(tspp_get_buffer); + +/** + * tspp_release_buffer - release TSPP data buffer back to TSPP. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @descriptor_id: buffer descriptor ID + * + * Return error status + * + */ +int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id) +{ + int i, found = 0; + struct tspp_mem_buffer *buffer; + struct tspp_channel *channel; + struct tspp_device *pdev; + unsigned long flags; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + spin_lock_irqsave(&pdev->spinlock, flags); + + channel = &pdev->channels[channel_id]; + + if (descriptor_id > channel->buffer_count) + pr_warn("%s: invalid desc id: 0x%08x\n", + __func__, descriptor_id); + + /* find the correct descriptor */ + buffer = channel->locked; + for (i = 0; i < channel->buffer_count; i++) { + if (buffer->desc.id == descriptor_id) { + found = 1; + break; + } + buffer = buffer->next; + } + channel->locked = channel->locked->next; + + if (!found) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + pr_err("%s: cant find desc %d\n", __func__, descriptor_id); + return -EINVAL; + } + + /* make sure the buffer is in the expected state */ + if (buffer->state != TSPP_BUF_STATE_LOCKED) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + pr_err("%s: buffer %d not locked\n", __func__, descriptor_id); + return -EINVAL; + } + /* unlock the buffer and requeue it */ + buffer->state = TSPP_BUF_STATE_WAITING; + + if (tspp_queue_buffer(channel, buffer)) + pr_warn("%s: can't requeue buffer\n", __func__); + + spin_unlock_irqrestore(&pdev->spinlock, flags); + + return 0; +} +EXPORT_SYMBOL(tspp_release_buffer); + +/** + * tspp_allocate_buffers - allocate TSPP data buffers. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @count: number of buffers to allocate + * @size: size of each buffer to allocate + * @int_freq: interrupt frequency + * @alloc: user defined memory allocator function. Pass NULL for default. + * @memfree: user defined memory free function. Pass NULL for default. + * @user: user data to pass to the memory allocator/free function + * + * Return error status + * + * The user can optionally call this function explicitly to allocate the TSPP + * data buffers. Alternatively, if the user did not call this function, it + * is called implicitly by tspp_add_filter(). + */ +int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size, + u32 int_freq, tspp_allocator *alloc, + tspp_memfree *memfree, void *user) +{ + struct tspp_channel *channel; + struct tspp_device *pdev; + struct tspp_mem_buffer *last = NULL; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + if (count < MIN_ACCEPTABLE_BUFFER_COUNT) { + pr_err("%s: tspp requires a minimum of %d buffers\n", __func__, + MIN_ACCEPTABLE_BUFFER_COUNT); + return -EINVAL; + } + + if (count > TSPP_NUM_BUFFERS) { + pr_err("%s: tspp requires a maximum of %d buffers\n", __func__, + TSPP_NUM_BUFFERS); + return -EINVAL; + } + + channel = &pdev->channels[channel_id]; + + /* allow buffer allocation only if there was no previous buffer + * allocation for this channel. + */ + if (channel->buffer_count > 0) { + pr_err("%s: buffers already allocated for channel %u\n", + __func__, channel_id); + return -EINVAL; + } + + channel->max_buffers = count; + + /* set up interrupt frequency */ + if (int_freq > channel->max_buffers) { + int_freq = channel->max_buffers; + pr_debug("%s: setting interrupt frequency to %u\n", __func__, + int_freq); + } + channel->int_freq = int_freq; + /* + * it is the responsibility of the caller to tspp_allocate_buffers(), + * whether it's the user or the driver, to make sure the size parameter + * is compatible to the channel mode. + */ + channel->buffer_size = size; + + /* save user defined memory free function for later use */ + channel->memfree = memfree; + channel->user_info = user; + + /* + * For small buffers, create a DMA pool so that memory + * is not wasted through dma_alloc_coherent. + */ + if (TSPP_USE_DMA_POOL(channel->buffer_size)) { + channel->dma_pool = dma_pool_create("tspp", + &pdev->pdev->dev, channel->buffer_size, 0, 0); + if (!channel->dma_pool) { + pr_err("%s: Can't allocate memory pool\n", __func__); + return -ENOMEM; + } + } else { + channel->dma_pool = NULL; + } + + + for (channel->buffer_count = 0; + channel->buffer_count < channel->max_buffers; + channel->buffer_count++) { + + /* allocate the descriptor */ + struct tspp_mem_buffer *desc = + kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL); + if (!desc) { + pr_warn("%s: Can't allocate desc %d\n", + __func__, channel->buffer_count); + break; + } + + desc->desc.id = channel->buffer_count; + /* allocate the buffer */ + if (tspp_alloc_buffer(channel_id, &desc->desc, + channel->buffer_size, channel->dma_pool, + alloc, user) != 0) { + kfree(desc); + pr_warn("%s: Can't allocate buffer %d\n", + __func__, channel->buffer_count); + break; + } + + /* add the descriptor to the list */ + desc->filled = 0; + desc->read_index = 0; + if (!channel->data) { + channel->data = desc; + desc->next = channel->data; + } else { + if (last != NULL) + last->next = desc; + } + last = desc; + desc->next = channel->data; + + /* prepare the sps descriptor */ + desc->sps.phys_base = desc->desc.phys_base; + desc->sps.base = desc->desc.virt_base; + desc->sps.size = desc->desc.size; + + /* start the transfer */ + if (tspp_queue_buffer(channel, desc)) + pr_err("%s: can't queue buffer %d\n", __func__, + desc->desc.id); + } + + if (channel->buffer_count < channel->max_buffers) { + /* + * we failed to allocate the requested number of buffers. + * we don't allow a partial success, so need to clean up here. + */ + tspp_destroy_buffers(channel_id, channel); + channel->buffer_count = 0; + + dma_pool_destroy(channel->dma_pool); + channel->dma_pool = NULL; + return -ENOMEM; + } + + channel->waiting = channel->data; + channel->read = channel->data; + channel->locked = channel->data; + + /* Now that buffers are scheduled to HW, kick data expiration timer */ + if (channel->expiration_period_ms) + mod_timer(&channel->expiration_timer, + jiffies + + msecs_to_jiffies( + channel->expiration_period_ms)); + + return 0; +} +EXPORT_SYMBOL(tspp_allocate_buffers); + +/** + * tspp_detach_ion_dma_buff - detach the mapped ion dma buffer from TSPP device + * It will detach previously mapped DMA buffer from TSPP device. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @ion_dma_buf: It contains required members for ION buffer dma mapping. + * + * Return error status + * + */ +int tspp_detach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf) +{ + struct tspp_device *pdev; + int dir = DMA_FROM_DEVICE; + + if (ion_dma_buf == NULL || ion_dma_buf->dbuf == NULL || + ion_dma_buf->table == NULL || ion_dma_buf->table->sgl == NULL || + ion_dma_buf->smmu_map == false) { + pr_err("%s: invalid input argument\n", __func__); + return -EINVAL; + } + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return -ENODEV; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + + dma_unmap_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl, + ion_dma_buf->table->nents, dir); + dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir); + dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach); + dma_buf_put(ion_dma_buf->dbuf); + + ion_dma_buf->smmu_map = false; + return 0; +} +EXPORT_SYMBOL(tspp_detach_ion_dma_buff); + +/** + * tspp_allocate_dma_buffer - Allocates DMA buffer using dma_alloc_coherent + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @size: Size of memory to be allocated + * @paddr: Returns the physical address of the allocated memory + * + * Return error status + * + */ +void *tspp_allocate_dma_buffer(u32 dev, int size, phys_addr_t *paddr) +{ + + struct tspp_device *pdev; + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return NULL; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return NULL; + } + + return dma_alloc_coherent(&pdev->pdev->dev, + size, paddr, GFP_KERNEL); +} +EXPORT_SYMBOL(tspp_allocate_dma_buffer); + +/** + * tspp_free_dma_buffer - Free the allocated memmory + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @size: Size of allocated memory + * @vaddr: Virtual address of the allocated memory + * @paddr: Physical address of the allocated memory + * + * Return error status + * + */ +int tspp_free_dma_buffer(u32 dev, int size, void *vaddr, dma_addr_t paddr) +{ + + struct tspp_device *pdev; + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return -ENODEV; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + dma_free_coherent(&pdev->pdev->dev, + size, vaddr, paddr); + + return 0; +} +EXPORT_SYMBOL(tspp_free_dma_buffer); + + +/*** debugfs ***/ +static int debugfs_iomem_x32_set(void *data, u64 val) +{ + int rc; + int clock_started = 0; + struct tspp_device *pdev; + + pdev = tspp_find_by_id(0); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, 0); + return 0; + } + + if (tspp_channels_in_use(pdev) == 0) { + rc = tspp_clock_start(pdev); + if (rc) { + pr_err("%s: tspp_clock_start failed %d\n", + __func__, rc); + return 0; + } + clock_started = 1; + } + + writel_relaxed(val, data); + /* Assure register write */ + wmb(); + + if (clock_started) + tspp_clock_stop(pdev); + return 0; +} + +static int debugfs_iomem_x32_get(void *data, u64 *val) +{ + int rc; + int clock_started = 0; + struct tspp_device *pdev; + + pdev = tspp_find_by_id(0); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, 0); + *val = 0; + return 0; + } + + if (tspp_channels_in_use(pdev) == 0) { + rc = tspp_clock_start(pdev); + if (rc) { + pr_err("%s: tspp_clock_start failed %d\n", + __func__, rc); + *val = 0; + return 0; + } + clock_started = 1; + } + + *val = readl_relaxed(data); + + if (clock_started) + tspp_clock_stop(pdev); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get, + debugfs_iomem_x32_set, "0x%08llx"); + +static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device, + int instance) +{ + char name[10]; + + snprintf(name, sizeof(name), "tsif%d", instance); + tsif_device->dent_tsif = debugfs_create_dir( + name, NULL); + if (tsif_device->dent_tsif) { + int i; + void __iomem *base = tsif_device->base; + + for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) { + tsif_device->debugfs_tsif_regs[i] = + debugfs_create_file( + debugfs_tsif_regs[i].name, + debugfs_tsif_regs[i].mode, + tsif_device->dent_tsif, + base + debugfs_tsif_regs[i].offset, + &fops_iomem_x32); + } + + debugfs_create_u32( + "stat_rx_chunks", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_rx); + + debugfs_create_u32( + "stat_overflow", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_overflow); + + debugfs_create_u32( + "stat_lost_sync", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_lost_sync); + + debugfs_create_u32( + "stat_timeout", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_timeout); + } +} + +static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device) +{ + int i; + + debugfs_remove_recursive(tsif_device->dent_tsif); + tsif_device->dent_tsif = NULL; + for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) + tsif_device->debugfs_tsif_regs[i] = NULL; +} + +static void tspp_debugfs_init(struct tspp_device *device, int instance) +{ + char name[10]; + + snprintf(name, sizeof(name), "tspp%d", instance); + device->dent = debugfs_create_dir( + name, NULL); + if (device->dent) { + int i; + void __iomem *base = device->base; + + for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) + device->debugfs_regs[i] = + debugfs_create_file( + debugfs_tspp_regs[i].name, + debugfs_tspp_regs[i].mode, + device->dent, + base + debugfs_tspp_regs[i].offset, + &fops_iomem_x32); + } +} + +static void tspp_debugfs_exit(struct tspp_device *device) +{ + int i; + + debugfs_remove_recursive(device->dent); + for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) + device->debugfs_regs[i] = NULL; +} + +static int msm_tspp_map_irqs(struct platform_device *pdev, + struct tspp_device *device) +{ + int rc; + + /* get IRQ numbers from platform information */ + + /* map TSPP IRQ */ + rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ"); + if (rc > 0) { + device->tspp_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSPP IRQ"); + return -EINVAL; + } + + /* map TSIF IRQs */ + rc = platform_get_irq_byname(pdev, "TSIF0_IRQ"); + if (rc > 0) { + device->tsif[0].tsif_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSIF0 IRQ"); + return -EINVAL; + } + + rc = platform_get_irq_byname(pdev, "TSIF1_IRQ"); + if (rc > 0) { + device->tsif[1].tsif_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSIF1 IRQ"); + return -EINVAL; + } + + /* map BAM IRQ */ + rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ"); + if (rc > 0) { + device->bam_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSPP BAM IRQ"); + return -EINVAL; + } + + return 0; +} + +static int msm_tspp_probe(struct platform_device *pdev) +{ + int rc = -ENODEV; + u32 version; + u32 i; + struct tspp_device *device; + struct resource *mem_tsif0; + struct resource *mem_tsif1; + struct resource *mem_tspp; + struct resource *mem_bam; + struct msm_bus_scale_pdata *tspp_bus_pdata = NULL; + unsigned long rate; + + if (pdev->dev.of_node) { + /* ID is always 0 since there is only 1 instance of TSPP */ + pdev->id = 0; + tspp_bus_pdata = msm_bus_cl_get_pdata(pdev); + } else { + /* must have device tree data */ + pr_err("%s: Device tree data not available\n", __func__); + rc = -EINVAL; + goto out; + } + + /* OK, we will use this device */ + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) { + rc = -ENOMEM; + goto out; + } + + /* set up references */ + device->pdev = pdev; + platform_set_drvdata(pdev, device); + + /* setup pin control */ + rc = tspp_get_pinctrl(device); + if (rc) { + pr_err("%s: failed to get pin control data, rc=%d\n", + __func__, rc); + goto err_pinctrl; + } + + /* register bus client */ + if (tspp_bus_pdata) { + device->tsif_bus_client = + msm_bus_scale_register_client(tspp_bus_pdata); + if (!device->tsif_bus_client) + pr_err("%s: Unable to register bus client\n", __func__); + } else { + device->tsif_bus_client = 0; + } + + /* map regulators */ + device->tsif_vreg = devm_regulator_get_optional(&pdev->dev, "vdd_cx"); + if (IS_ERR_OR_NULL(device->tsif_vreg)) { + rc = PTR_ERR(device->tsif_vreg); + device->tsif_vreg = NULL; + if (rc == -ENODEV) { + pr_notice("%s: vdd_cx regulator will not be used\n", + __func__); + } else { + pr_err("%s: failed to get CX regulator, err=%d\n", + __func__, rc); + goto err_regulator; + } + } else { + /* Set an initial voltage and enable the regulator */ + rc = regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + if (rc) { + pr_err("%s: Unable to set CX voltage\n", __func__); + goto err_regulator; + } + + rc = regulator_enable(device->tsif_vreg); + if (rc) { + pr_err("%s: Unable to enable CX regulator\n", __func__); + goto err_regulator; + } + } + + /* map clocks */ + device->tsif_pclk = clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR_OR_NULL(device->tsif_pclk)) { + rc = PTR_ERR(device->tsif_pclk); + device->tsif_pclk = NULL; + goto err_pclock; + } + + device->tsif_ref_clk = clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR_OR_NULL(device->tsif_ref_clk)) { + rc = PTR_ERR(device->tsif_ref_clk); + device->tsif_ref_clk = NULL; + goto err_refclock; + } + rate = clk_round_rate(device->tsif_ref_clk, 1); + rc = clk_set_rate(device->tsif_ref_clk, rate); + if (rc) + goto err_res_tsif0; + + /* map I/O memory */ + mem_tsif0 = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSIF0_PHYS"); + if (!mem_tsif0) { + pr_err("%s: Missing tsif0 MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_tsif0; + } + device->tsif[0].base = ioremap(mem_tsif0->start, + resource_size(mem_tsif0)); + if (!device->tsif[0].base) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_tsif0; + } + + mem_tsif1 = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSIF1_PHYS"); + if (!mem_tsif1) { + pr_err("%s: missing tsif1 MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_tsif1; + } + device->tsif[1].base = ioremap(mem_tsif1->start, + resource_size(mem_tsif1)); + if (!device->tsif[1].base) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_tsif1; + } + + mem_tspp = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSPP_PHYS"); + if (!mem_tspp) { + pr_err("%s: missing MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_dev; + } + device->base = ioremap(mem_tspp->start, resource_size(mem_tspp)); + if (!device->base) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_dev; + } + + mem_bam = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS"); + if (!mem_bam) { + pr_err("%s: Missing bam MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_bam; + } + memset(&device->bam_props, 0, sizeof(device->bam_props)); + device->bam_props.phys_addr = mem_bam->start; + device->bam_props.virt_addr = ioremap(mem_bam->start, + resource_size(mem_bam)); + if (!device->bam_props.virt_addr) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_bam; + } + + if (msm_tspp_map_irqs(pdev, device)) + goto err_irq; + device->req_irqs = false; + + if (tspp_iommu_init(device)) + goto err_iommu; + + device->tts_source = TSIF_TTS_TCR; + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + device->tsif[i].tts_source = device->tts_source; + + /* power management */ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + tspp_debugfs_init(device, 0); + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + tsif_debugfs_init(&device->tsif[i], i); + + wakeup_source_init(&device->ws, dev_name(&pdev->dev)); + + /* set up pointers to ram-based 'registers' */ + device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0; + device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1; + device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2; + device->tspp_key_table = device->base + TSPP_DATA_KEY; + device->tspp_global_performance = + device->base + TSPP_GLOBAL_PERFORMANCE; + device->tspp_pipe_context = + device->base + TSPP_PIPE_CONTEXT; + device->tspp_pipe_performance = + device->base + TSPP_PIPE_PERFORMANCE; + + device->bam_props.summing_threshold = 0x10; + device->bam_props.irq = device->bam_irq; + device->bam_props.manage = SPS_BAM_MGR_LOCAL; + /*add SPS BAM log level*/ + device->bam_props.ipc_loglevel = TSPP_BAM_DEFAULT_IPC_LOGLVL; + + if (tspp_clock_start(device) != 0) { + pr_err("%s: Can't start clocks\n", __func__); + goto err_clock; + } + + device->bam_handle = SPS_DEV_HANDLE_INVALID; + + spin_lock_init(&device->spinlock); + mutex_init(&device->mutex); + tasklet_init(&device->tlet, tspp_sps_complete_tlet, + (unsigned long)device); + + /* initialize everything to a known state */ + tspp_global_reset(device); + + version = readl_relaxed(device->base + TSPP_VERSION); + /* + * TSPP version can be bits [7:0] or alternatively, + * TSPP major version is bits [31:28]. + */ + if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1)) + pr_err("%s: unrecognized hw version=%d\n", __func__, version); + + /* initialize the channels */ + for (i = 0; i < TSPP_NUM_CHANNELS; i++) + tspp_channel_init(&(device->channels[i]), device); + + /* stop the clocks for power savings */ + tspp_clock_stop(device); + + /* everything is ok, so add the device to the list */ + list_add_tail(&(device->devlist), &tspp_devices); + return 0; + +err_clock: + tspp_debugfs_exit(device); + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + tsif_debugfs_exit(&device->tsif[i]); +err_iommu: + tspp_iommu_release_iomapping(device); +err_irq: + iounmap(device->bam_props.virt_addr); +err_map_bam: +err_res_bam: + iounmap(device->base); +err_map_dev: +err_res_dev: + iounmap(device->tsif[1].base); +err_map_tsif1: +err_res_tsif1: + iounmap(device->tsif[0].base); +err_map_tsif0: +err_res_tsif0: + if (device->tsif_ref_clk) + clk_put(device->tsif_ref_clk); +err_refclock: + if (device->tsif_pclk) + clk_put(device->tsif_pclk); +err_pclock: + if (device->tsif_vreg) + regulator_disable(device->tsif_vreg); +err_regulator: + if (device->tsif_bus_client) + msm_bus_scale_unregister_client(device->tsif_bus_client); +err_pinctrl: + kfree(device); + +out: + return rc; +} + +static int msm_tspp_remove(struct platform_device *pdev) +{ + struct tspp_channel *channel; + u32 i; + + struct tspp_device *device = platform_get_drvdata(pdev); + + /* free the buffers, and delete the channels */ + for (i = 0; i < TSPP_NUM_CHANNELS; i++) { + channel = &device->channels[i]; + tspp_close_channel(device->pdev->id, i); + } + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + tsif_debugfs_exit(&device->tsif[i]); + + mutex_destroy(&device->mutex); + + if (device->tsif_bus_client) + msm_bus_scale_unregister_client(device->tsif_bus_client); + + wakeup_source_trash(&device->ws); + if (device->req_irqs) + msm_tspp_free_irqs(device); + + iounmap(device->bam_props.virt_addr); + iounmap(device->base); + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + iounmap(device->tsif[i].base); + + if (device->tsif_ref_clk) + clk_put(device->tsif_ref_clk); + + if (device->tsif_pclk) + clk_put(device->tsif_pclk); + + if (device->tsif_vreg) + regulator_disable(device->tsif_vreg); + + tspp_iommu_release_iomapping(device); + arm_iommu_detach_device(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + kfree(device); + + return 0; +} + +/*** power management ***/ + +static int tspp_runtime_suspend(struct device *dev) +{ + pr_debug("%s: pm_runtime: suspending\n", __func__); + return 0; +} + +static int tspp_runtime_resume(struct device *dev) +{ + pr_debug("%s: pm_runtime: resuming\n", __func__); + return 0; +} + +static const struct dev_pm_ops tspp_dev_pm_ops = { + .runtime_suspend = tspp_runtime_suspend, + .runtime_resume = tspp_runtime_resume, +}; + +static const struct of_device_id msm_match_table[] = { + {.compatible = "qcom,msm_tspp"}, + {}, +}; + +static struct platform_driver msm_tspp_driver = { + .probe = msm_tspp_probe, + .remove = msm_tspp_remove, + .driver = { + .name = "msm_tspp", + .pm = &tspp_dev_pm_ops, + .of_match_table = msm_match_table, + }, +}; + + +static int __init mod_init(void) +{ + int rc; + + /* register the driver, and check hardware */ + rc = platform_driver_register(&msm_tspp_driver); + if (rc) + pr_err("%s: platform_driver_register failed: %d\n", + __func__, rc); + + return rc; +} + +static void __exit mod_exit(void) +{ + /* delete low level driver */ + platform_driver_unregister(&msm_tspp_driver); +} + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_DESCRIPTION("TSPP platform device"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c index 9e602544523ee3d7b9c0b3edf915b6ae418523c4..cddbd8309ece7bd5b1736b4532cac5ccae87b92c 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c @@ -1125,6 +1125,7 @@ static struct platform_driver cam_hw_cdm_driver = { .name = "msm_cam_cdm", .owner = THIS_MODULE, .of_match_table = msm_cam_hw_cdm_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c index db377e02a87a63e598ba7d96657e4b9b486847aa..871276170ac4ff9c3e3a5c5fd804252732a1b2aa 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c @@ -562,6 +562,7 @@ static struct platform_driver cam_cdm_intf_driver = { .name = "msm_cam_cdm_intf", .owner = THIS_MODULE, .of_match_table = msm_cam_cdm_intf_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c index 24685b985bcdae9266e3ff862013f147d553ff20..06151bbd3440f3f15a302083d610c6096f0295f6 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c @@ -58,7 +58,7 @@ int cam_context_shutdown(struct cam_context *ctx) } if (!rc) - cam_destroy_device_hdl(ctx_hdl); + rc = cam_destroy_device_hdl(ctx_hdl); return rc; } diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index fce7fc6cc6b86178747c76ce3db1db975bc939d3..89aad8cb58c3f80b76f9d74cf0b365d0cc856e1c 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c @@ -490,6 +490,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, release.ctxt_to_hw_map = ctx->ctxt_to_hw_map; ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); ctx->ctxt_to_hw_map = NULL; + ctx->dev_hdl = -1; end: return rc; } @@ -504,6 +505,7 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) bool free_req; CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name); + memset(&flush_args, 0, sizeof(flush_args)); /* * flush pending requests, take the sync lock to synchronize with the @@ -670,6 +672,7 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, CAM_DBG(CAM_CTXT, "[%s] E: NRT flush req", ctx->dev_name); + memset(&flush_args, 0, sizeof(flush_args)); flush_args.num_req_pending = 0; flush_args.num_req_active = 0; mutex_lock(&ctx->sync_mutex); diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c index 6e46c4ca950ff775ca85dd76893275603f9937c1..235c754c30f425beca90009e08a9d8d4fc06adb9 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c @@ -413,13 +413,16 @@ int cam_node_deinit(struct cam_node *node) int cam_node_shutdown(struct cam_node *node) { int i = 0; + int rc = 0; if (!node) return -EINVAL; for (i = 0; i < node->ctx_size; i++) { - if (node->ctx_list[i].dev_hdl >= 0) { - cam_context_shutdown(&(node->ctx_list[i])); + if (node->ctx_list[i].dev_hdl > 0) { + rc = cam_context_shutdown(&(node->ctx_list[i])); + if (rc) + continue; cam_context_putref(&(node->ctx_list[i])); } } diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index e68e1614afa1289d003e0fd98d387926a42817b4..13417bd74a4eef8990eb1b045c0ecdf79b6aff68 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -597,7 +597,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( required_camnoc_bw, clk_rate); rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); - if (!rc) + if (rc) CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %d %d", required_camnoc_bw, clk_rate, rc); diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c index 13d59d6755bbfb9ded1726a21708c696e7d3f86a..cdc8a3baef28cd4d32e1c356c282a5287f6e0795 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c @@ -642,6 +642,7 @@ static struct platform_driver cam_cpas_driver = { .name = CAM_CPAS_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_cpas_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c index 1166f208019139f29891793cbf0568a36e1a96f6..7f531fdddd9e959e6ce29a12f663ba240f1f8550 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -20,6 +20,7 @@ #include "cam_io_util.h" #include "cam_cpas_soc.h" #include "cpastop100.h" +#include "cpastop_v150_100.h" #include "cpastop_v170_110.h" #include "cpastop_v175_100.h" #include "cpastop_v175_101.h" @@ -104,6 +105,13 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->cpas_version.minor == 0) && (hw_caps->cpas_version.incr == 1)) soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 5) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_150_V100; } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -578,6 +586,9 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_175_V101: camnoc_info = &cam175_cpas101_camnoc_info; break; + case CAM_CPAS_TITAN_150_V100: + camnoc_info = &cam150_cpas100_camnoc_info; + break; default: CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", hw_caps->camera_version.major, diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h new file mode 100644 index 0000000000000000000000000000000000000000..ceb3c02f1d15980e68d1d16dac63bb19d8e5f2a6 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h @@ -0,0 +1,537 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CPASTOP_V150_100_H_ +#define _CPASTOP_V150_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v150_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v150_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v150_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam150_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam150_cpas100_camnoc_info = { + .specific = &cam_cpas_v150_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / + sizeof(cam_cpas_v150_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v150_100_irq_sbm, + .irq_err = &cam_cpas_v150_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v150_100_irq_err) / + sizeof(cam_cpas_v150_100_irq_err[0]), + .err_logger = &cam150_cpas100_err_logger_offsets, + .errata_wa_list = &cam150_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V150_100_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h index 8760ad17c2c9a136f09a315b510d48a3c4614205..02c4d01ae7d6486274db671c7dd59f0ba0cf12ff 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h +++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h @@ -41,6 +41,7 @@ enum cam_cpas_reg_base { */ enum cam_cpas_hw_version { CAM_CPAS_TITAN_NONE = 0, + CAM_CPAS_TITAN_150_V100 = 0x150100, CAM_CPAS_TITAN_170_V100 = 0x170100, CAM_CPAS_TITAN_170_V110 = 0x170110, CAM_CPAS_TITAN_170_V120 = 0x170120, diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c index 3f0124436b9e1baed2b1c575ad745db56dff7466..d5068ca26971bb7b57af98358530fc6d2e3b16ba 100644 --- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c @@ -194,6 +194,7 @@ static struct platform_driver cam_fd_driver = { .name = "cam_fd", .owner = THIS_MODULE, .of_match_table = cam_fd_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index 5d6c9fa8076930a6d9e206ae6a17610c287f3dfa..8a84c0ee7e99bf08a200b30b482d38f91614a1be 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -221,6 +221,7 @@ static struct platform_driver cam_fd_hw_driver = { .name = "cam_fd_hw", .owner = THIS_MODULE, .of_match_table = cam_fd_hw_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c index a9804caed5642dbb13bd2048dea41529200c15fa..fa714c8c7fea02f5cdd2158f5fdeaffb5ca07ea5 100644 --- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c +++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c @@ -238,6 +238,7 @@ static struct platform_driver cam_icp_driver = { .name = "cam_icp", .owner = THIS_MODULE, .of_match_table = cam_icp_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index 14a3e656e76dfc89ea7a5b7103d2581512ccb522..f91e29a8f2d97c68ee67dae04b1bd0106db9a3a6 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -64,30 +64,30 @@ void cam_hfi_queue_dump(void) qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; qtbl_hdr = &qtbl->q_tbl_hdr; - CAM_INFO(CAM_HFI, + CAM_DBG(CAM_HFI, "qtbl: version = %x size = %u num q = %u qhdr_size = %u", qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size, qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size); cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; - CAM_INFO(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", + CAM_DBG(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx, cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova); read_q = (uint32_t *)g_hfi->map.cmd_q.kva; read_ptr = (uint32_t *)(read_q + 0); - CAM_INFO(CAM_HFI, "CMD Q START"); + CAM_DBG(CAM_HFI, "CMD Q START"); for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) - CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); msg_q_hdr = &qtbl->q_hdr[Q_MSG]; - CAM_INFO(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", + CAM_DBG(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx, msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova); read_q = (uint32_t *)g_hfi->map.msg_q.kva; read_ptr = (uint32_t *)(read_q + 0); - CAM_INFO(CAM_HFI, "MSG Q START"); + CAM_DBG(CAM_HFI, "MSG Q START"); for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) - CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); } int hfi_write_cmd(void *cmd_ptr) diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c index 6518c67f98af19f39157cef4f057da6991d50a4b..3b652e72466e870502af8c5bcf03afbb68218010 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c @@ -215,6 +215,7 @@ static struct platform_driver cam_a5_driver = { .name = "cam-a5", .owner = THIS_MODULE, .of_match_table = cam_a5_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c index 6e51b1e91b14c5dac0b57ed1f0688888c0499aa1..56abb4b8e6e902a51060991dd1be73c95d87fc4b 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c @@ -194,6 +194,7 @@ static struct platform_driver cam_bps_driver = { .name = "cam-bps", .owner = THIS_MODULE, .of_match_table = cam_bps_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 1e84175f1c4a4d1669ffb717e8c5bc45f24f3d29..6639d33f31d14f42f950b449a5f0c0cdc4b951a8 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3176,8 +3176,8 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) frame_info = (struct icp_frame_info *)config_args->priv; req_id = frame_info->request_id; idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); - ctx_data->hfi_frame_process.fw_process_flag[idx] = true; cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); + ctx_data->hfi_frame_process.fw_process_flag[idx] = true; CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, frame_info->io_config); @@ -3842,19 +3842,15 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) return -EINVAL; } - CAM_DBG(CAM_REQ, "ctx_id %d req %lld Flush type %d", - ctx_data->ctx_id, - *(int64_t *)flush_args->flush_req_pending[0], - flush_args->flush_type); + CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d", + ctx_data->ctx_id, flush_args->flush_type); switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: mutex_lock(&hw_mgr->hw_mgr_mutex); - if (!hw_mgr->recovery) { - if (flush_args->num_req_active) { - mutex_unlock(&hw_mgr->hw_mgr_mutex); - cam_icp_mgr_abort_handle(ctx_data); - } + if (!hw_mgr->recovery && flush_args->num_req_active) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_abort_handle(ctx_data); } else { mutex_unlock(&hw_mgr->hw_mgr_mutex); } diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c index 456d45e08b74c752d7ed257139fb27e1257f5814..a01d114bae7b27214ca8f7f1b64889d59824bbba 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c @@ -186,6 +186,7 @@ static struct platform_driver cam_ipe_driver = { .name = "cam-ipe", .owner = THIS_MODULE, .of_match_table = cam_ipe_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index d14718c27c405294a4b0c056a9f901d9a0505a74..334928fd8bb1a60c6af06fdf73253ebbb5454e62 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -723,9 +723,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; - if (list_empty(&ctx->pending_req_list)) { + if (list_empty(&ctx->wait_req_list)) { /* - * If no pending req in epoch, this is an error case. + * If no wait req in epoch, this is an error case. * The recovery is to go back to sof state */ CAM_ERR(CAM_ISP, "No pending request"); @@ -738,7 +738,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, goto end; } - req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; @@ -747,6 +747,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + notify.link_hdl = ctx->link_hdl; notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; @@ -1365,12 +1368,56 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_isp_stop_args stop_isp; + struct cam_hw_stop_args stop_args; + struct cam_isp_start_args start_isp; int rc = 0; CAM_DBG(CAM_ISP, "try to flush pending list"); spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + /* if active and wait list are empty, return */ + spin_lock_bh(&ctx->lock); + if ((list_empty(&ctx->wait_req_list)) && + (list_empty(&ctx->active_req_list))) { + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "active and wait list are empty"); + goto end; + } + spin_unlock_bh(&ctx->lock); + + /* Stop hw first before active list flush */ + stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; + stop_isp.stop_only = true; + stop_args.args = (void *)&stop_isp; + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop_args); + + spin_lock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "try to flush wait list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, + flush_req); + CAM_DBG(CAM_ISP, "try to flush active list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, + flush_req); + spin_unlock_bh(&ctx->lock); + + /* Start hw */ + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; + start_isp.start_only = true; + start_isp.hw_config.priv = NULL; + + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &start_isp); + } + +end: CAM_DBG(CAM_ISP, "Flush request in top state %d", ctx->state); return rc; @@ -1386,7 +1433,7 @@ static int __cam_isp_ctx_flush_req_in_ready( spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - /* if nothing is in pending req list, change state to acquire*/ + /* if nothing is in pending req list, change state to acquire */ if (list_empty(&ctx->pending_req_list)) ctx->state = CAM_CTX_ACQUIRED; spin_unlock_bh(&ctx->lock); @@ -2291,7 +2338,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; - struct cam_hw_config_args arg; + struct cam_isp_start_args start_isp; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; struct cam_isp_context *ctx_isp = @@ -2320,12 +2367,13 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } - arg.ctxt_to_hw_map = ctx_isp->hw_ctx; - arg.request_id = req->request_id; - arg.hw_update_entries = req_isp->cfg; - arg.num_hw_update_entries = req_isp->num_cfg; - arg.priv = &req_isp->hw_update_data; - arg.init_packet = 1; + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; + start_isp.hw_config.request_id = req->request_id; + start_isp.hw_config.hw_update_entries = req_isp->cfg; + start_isp.hw_config.num_hw_update_entries = req_isp->num_cfg; + start_isp.hw_config.priv = &req_isp->hw_update_data; + start_isp.hw_config.init_packet = 1; + start_isp.start_only = false; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; @@ -2342,7 +2390,8 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, */ ctx->state = CAM_CTX_ACTIVATED; trace_cam_context_state("ISP", ctx); - rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, &arg); + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &start_isp); if (rc) { /* HW failure. user need to clean up the resource */ CAM_ERR(CAM_ISP, "Start HW failed"); @@ -2383,6 +2432,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( struct cam_isp_ctx_req *req_isp; struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + struct cam_isp_stop_args stop_isp; /* Mask off all the incoming hardware events */ spin_lock_bh(&ctx->lock); @@ -2393,7 +2443,15 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( /* stop hw first */ if (ctx_isp->hw_ctx) { stop.ctxt_to_hw_map = ctx_isp->hw_ctx; - stop.args = stop_cmd; + + if (stop_cmd) + stop_isp.hw_stop_cmd = + CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; + else + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + + stop_isp.stop_only = false; + stop.args = (void *) &stop_isp; ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, &stop); } @@ -2414,6 +2472,22 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( list_add_tail(&req->list, &ctx->free_req_list); } + while (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in wait list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + while (!list_empty(&ctx->active_req_list)) { req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c index c4020a04ad92815138abd4e9272ccde97fd7ef35..5eefcae859e008e230e33ee7083edb6052dc6ab9 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c @@ -135,6 +135,7 @@ static struct platform_driver isp_driver = { .name = "cam_isp", .owner = THIS_MODULE, .of_match_table = cam_isp_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index a4b1d457e6f7c1a84a2cd529c385b17424f54a86..c4c16f07b33750f1210c15af8086ef5936aebdb4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -284,6 +284,100 @@ static void cam_ife_hw_mgr_deinit_hw_res( } } +static int cam_ife_hw_mgr_init_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int rc = 0, i; + + CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", + ctx->ctx_index); + /* INIT IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)", + hw_mgr_res->res_id); + return rc; + } + } + + CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d", + ctx->ctx_index); + + /* INIT IFE csid */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)", + hw_mgr_res->res_id); + return rc; + } + } + + /* INIT IFE SRC */ + CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)", + hw_mgr_res->res_id); + return rc; + } + } + + /* INIT IFE OUT */ + CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", + ctx->ctx_index); + + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)", + ctx->res_list_ife_out[i].res_id); + return rc; + } + } + + return rc; +} + +static void cam_ife_hw_mgr_deinit_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int i = 0; + + if (!ctx->init_done) { + CAM_WARN(CAM_ISP, "ctx is not in init state"); + return; + } + + /* Deinit IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE CSID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint IFE MUX(SRC) */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE OUT */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); + + ctx->init_done = false; +} + static int cam_ife_hw_mgr_put_res( struct list_head *src_list, struct cam_ife_hw_mgr_res **res) @@ -1917,6 +2011,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) { int rc = 0; struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_isp_stop_args *stop_isp; struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_ife_hw_mgr_ctx *ctx; enum cam_ife_csid_halt_cmd csid_halt_type; @@ -1926,6 +2021,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) CAM_ERR(CAM_ISP, "Invalid arguments"); return -EINVAL; } + ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; if (!ctx || !ctx->ctx_in_use) { CAM_ERR(CAM_ISP, "Invalid context is used"); @@ -1933,12 +2029,20 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) } CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index); + stop_isp = (struct cam_isp_stop_args *)stop_args->args; + + if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_IMMEDIATELY) && + (stop_isp->stop_only)) { + CAM_ERR(CAM_ISP, "Invalid params hw_stop_cmd:%d stop_only:%d", + stop_isp->hw_stop_cmd, stop_isp->stop_only); + return -EPERM; + } /* Set the csid halt command */ - if (!stop_args->args) - csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; - else + if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + else + csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; /* Note:stop resource will remove the irq mask from the hardware */ @@ -2014,30 +2118,15 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, csid_halt_type); } - /* Deinit IFE CID */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { - CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); - cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); - } - - /* Deinit IFE CSID */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { - CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__); - cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); - } - - /* Deint IFE MUX(SRC) */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); - } - - /* Deinit IFE OUT */ - for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) - cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); + if (stop_isp->stop_only) + goto end; + cam_ife_hw_mgr_deinit_hw(ctx); CAM_DBG(CAM_ISP, "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); +end: + mutex_lock(&g_ife_hw_mgr.ctx_mutex); if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) { rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE); @@ -2149,19 +2238,20 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args) static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) { int rc = -1; - struct cam_hw_config_args *start_args = start_hw_args; + struct cam_isp_start_args *start_isp = start_hw_args; struct cam_hw_stop_args stop_args; - struct cam_isp_stop_hw_method stop_hw_method; + struct cam_isp_stop_args stop_isp; struct cam_ife_hw_mgr_ctx *ctx; struct cam_ife_hw_mgr_res *hw_mgr_res; uint32_t i; - if (!hw_mgr_priv || !start_hw_args) { + if (!hw_mgr_priv || !start_isp) { CAM_ERR(CAM_ISP, "Invalid arguments"); return -EINVAL; } - ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map; + ctx = (struct cam_ife_hw_mgr_ctx *) + start_isp->hw_config.ctxt_to_hw_map; if (!ctx || !ctx->ctx_in_use) { CAM_ERR(CAM_ISP, "Invalid context is used"); return -EPERM; @@ -2174,6 +2264,9 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) cam_tasklet_start(ctx->common.tasklet_info); + if (ctx->init_done && start_isp->start_only) + goto start_only; + /* set current csid debug information to CSID HW */ for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { if (g_ife_hw_mgr.csid_devices[i]) @@ -2184,58 +2277,13 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) sizeof(g_ife_hw_mgr.debug_cfg.csid_debug)); } - /* INIT IFE Root: do nothing */ - - CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", - ctx->ctx_index); - /* INIT IFE CID */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { - rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)", - hw_mgr_res->res_id); - goto err; - } - } - - - CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d", - ctx->ctx_index); - - /* INIT IFE csid */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { - rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)", - hw_mgr_res->res_id); - goto err; - } - } - - /* INIT IFE SRC */ - CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d", - ctx->ctx_index); - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)", - hw_mgr_res->res_id); - goto err; - } + rc = cam_ife_hw_mgr_init_hw(ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Init failed"); + goto err; } - /* INIT IFE OUT */ - CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", - ctx->ctx_index); - - for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { - rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)", - ctx->res_list_ife_out[i].res_id); - goto err; - } - } +start_only: mutex_lock(&g_ife_hw_mgr.ctx_mutex); if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) { @@ -2256,12 +2304,15 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) goto err; } - /* Apply initial configuration */ - CAM_DBG(CAM_ISP, "Config HW"); - rc = cam_ife_mgr_config_hw(hw_mgr_priv, start_hw_args); - if (rc) { - CAM_ERR(CAM_ISP, "Config HW failed"); - goto err; + if (!start_isp->start_only) { + /* Apply initial configuration */ + CAM_DBG(CAM_ISP, "Config HW"); + rc = cam_ife_mgr_config_hw(hw_mgr_priv, + &start_isp->hw_config); + if (rc) { + CAM_ERR(CAM_ISP, "Config HW failed"); + goto err; + } } CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", @@ -2313,13 +2364,18 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } + ctx->init_done = true; /* Start IFE root node: do nothing */ CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); + return 0; + err: - stop_hw_method.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; - stop_args.ctxt_to_hw_map = start_args->ctxt_to_hw_map; - stop_args.args = (void *)(&stop_hw_method); + stop_isp.stop_only = false; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map; + stop_args.args = (void *)(&stop_isp); + cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args); CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); return rc; @@ -2358,6 +2414,9 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index); + if (ctx->init_done) + cam_ife_hw_mgr_deinit_hw(ctx); + /* we should called the stop hw before this already */ cam_ife_hw_mgr_release_hw_for_ctx(ctx); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 0e678b4584cd72b702057a1694c89eabeecb3675..0198f3d62e9cfea2860b935a109ac98a165ee859 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -123,6 +123,7 @@ struct cam_ife_hw_mgr_debug { * context * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete + * @init_done indicate whether init hw is done */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -156,6 +157,7 @@ struct cam_ife_hw_mgr_ctx { atomic_t overflow_pending; uint32_t is_rdi_only_context; struct completion config_done_complete; + bool init_done; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index b9c51de98dcc1a2fe93b58319eb86087ecea2358..2c08e4d3cf85eaad34140116b7ca302b208968b3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -93,14 +93,14 @@ int cam_tasklet_get_cmd( } if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active!\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active"); rc = -EPIPE; return rc; } spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->free_cmd_list)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd!\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd"); rc = -ENODEV; goto spin_unlock; } else { @@ -163,12 +163,6 @@ static int cam_tasklet_dequeue_cmd( *tasklet_cmd = NULL; - if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR(CAM_ISP, "Tasklet is not active!"); - rc = -EPIPE; - return rc; - } - CAM_DBG(CAM_ISP, "Dequeue before lock."); spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->used_cmd_list)) { @@ -199,27 +193,28 @@ void cam_tasklet_enqueue_cmd( struct cam_tasklet_info *tasklet = bottom_half; if (!bottom_half) { - CAM_ERR(CAM_ISP, "NULL bottom half"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bottom half"); return; } if (!bh_cmd) { - CAM_ERR(CAM_ISP, "NULL bh cmd"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bh cmd"); return; } - if (tasklet_cmd) { - CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); - tasklet_cmd->bottom_half_handler = bottom_half_handler; - tasklet_cmd->payload = evt_payload_priv; - spin_lock_irqsave(&tasklet->tasklet_lock, flags); - list_add_tail(&tasklet_cmd->list, - &tasklet->used_cmd_list); - spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); - tasklet_schedule(&tasklet->tasklet); - } else { - CAM_ERR(CAM_ISP, "tasklet cmd is NULL!"); + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active\n"); + return; } + + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); + tasklet_cmd->bottom_half_handler = bottom_half_handler; + tasklet_cmd->payload = evt_payload_priv; + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_add_tail(&tasklet_cmd->list, + &tasklet->used_cmd_list); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_schedule(&tasklet->tasklet); } int cam_tasklet_init( @@ -251,7 +246,7 @@ int cam_tasklet_init( } tasklet_init(&tasklet->tasklet, cam_tasklet_action, (unsigned long)tasklet); - cam_tasklet_stop(tasklet); + tasklet_disable(&tasklet->tasklet); *tasklet_info = tasklet; @@ -262,19 +257,18 @@ void cam_tasklet_deinit(void **tasklet_info) { struct cam_tasklet_info *tasklet = *tasklet_info; - atomic_set(&tasklet->tasklet_active, 0); - tasklet_kill(&tasklet->tasklet); + if (atomic_read(&tasklet->tasklet_active)) { + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + } kfree(tasklet); *tasklet_info = NULL; } -static void cam_tasklet_flush(void *tasklet_info) +static inline void cam_tasklet_flush(struct cam_tasklet_info *tasklet_info) { - unsigned long data; - struct cam_tasklet_info *tasklet = tasklet_info; - - data = (unsigned long)tasklet; - cam_tasklet_action(data); + cam_tasklet_action((unsigned long) tasklet_info); } int cam_tasklet_start(void *tasklet_info) @@ -287,7 +281,6 @@ int cam_tasklet_start(void *tasklet_info) tasklet->index); return -EBUSY; } - atomic_set(&tasklet->tasklet_active, 1); /* clean up the command queue first */ for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { @@ -296,6 +289,8 @@ int cam_tasklet_start(void *tasklet_info) &tasklet->free_cmd_list); } + atomic_set(&tasklet->tasklet_active, 1); + tasklet_enable(&tasklet->tasklet); return 0; @@ -305,9 +300,10 @@ void cam_tasklet_stop(void *tasklet_info) { struct cam_tasklet_info *tasklet = tasklet_info; - cam_tasklet_flush(tasklet); atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); tasklet_disable(&tasklet->tasklet); + cam_tasklet_flush(tasklet); } /* diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 8f1911edf2c91e70d571b7c8f5c126e0994e3e26..fd71c37c8fa1cc34f13820bbd4ec69c7bc474e03 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -60,13 +60,29 @@ enum cam_isp_hw_stop_cmd { }; /** - * struct cam_isp_stop_hw_method - hardware stop method + * struct cam_isp_stop_args - hardware stop arguments * * @hw_stop_cmd: Hardware stop command type information + * @stop_only Send stop only to hw drivers. No Deinit to be + * done. * */ -struct cam_isp_stop_hw_method { +struct cam_isp_stop_args { enum cam_isp_hw_stop_cmd hw_stop_cmd; + bool stop_only; +}; + +/** + * struct cam_isp_start_args - isp hardware start arguments + * + * @config_args: Hardware configuration commands. + * @start_only Send start only to hw drivers. No init to + * be done. + * + */ +struct cam_isp_start_args { + struct cam_hw_config_args hw_config; + bool start_only; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c index 13eb2887667c9a74e18d153695d95f65090ae0ab..0df2fdddb1be634c679c7c64a507d00d169a9315 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -52,6 +52,7 @@ static struct platform_driver cam_ife_csid17x_driver = { .name = CAM_CSID_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid17x_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 7bd7b9e7206b821858e50531b4dc077062c31e43..548e849dd45c8e7aca5b8def4c1dfe2e6eb222b7 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1064,10 +1064,6 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - /* Enable the top IRQ interrupt */ - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_mask_addr); - val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -2299,25 +2295,38 @@ static int cam_ife_csid_reset_retain_sw_reg( struct cam_ife_csid_hw *csid_hw) { int rc = 0; + uint32_t status; const struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; + struct cam_hw_soc_info *soc_info; + + soc_info = &csid_hw->hw_info->soc_info; + /* clear the top interrupt first */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); - init_completion(&csid_hw->csid_top_complete); cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, - csid_hw->hw_info->soc_info.reg_map[0].mem_base + + soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); - - CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler"); - rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, - msecs_to_jiffies(IFE_CSID_TIMEOUT)); - if (rc <= 0) { - CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - if (rc == 0) - rc = -ETIMEDOUT; + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; } else { + CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", + csid_hw->hw_intf->hw_idx, rc); rc = 0; } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); return rc; } @@ -2735,8 +2744,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); /* clear */ - cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) @@ -2762,13 +2769,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); - if (irq_status_top) { - CAM_DBG(CAM_ISP, "CSID global reset complete......Exit"); - complete(&csid_hw->csid_top_complete); - return IRQ_HANDLED; - } - - if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c index a1c77d15b64be1231d2d5cdbc5a122e648990b37..5fdb52a2d9f06425adb15778882e0600fa3a83fd 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -41,6 +41,7 @@ static struct platform_driver cam_ife_csid_lite_driver = { .name = CAM_CSID_LITE_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid_lite_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 2379bdc8e206dfd8a43dbb14a05a54a2e1d5c004..bab5f204b3ff19482f571f1fdca01e52548a4b59 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -639,10 +639,11 @@ int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { cam_irq_controller_unsubscribe_irq( core_info->vfe_irq_controller, isp_res->irq_handle); + isp_res->irq_handle = 0; + rc = core_info->vfe_top->hw_ops.stop( core_info->vfe_top->top_priv, isp_res, sizeof(struct cam_isp_resource_node)); - } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); } else { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c index 28ca7c25533bdf87c7117127a9ed9f842743c570..c94b64e2b28c07c557df5d03a6d7d123d4e78678 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c @@ -46,6 +46,7 @@ static struct platform_driver cam_vfe_driver = { .name = "cam_vfe17x", .owner = THIS_MODULE, .of_match_table = cam_vfe_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 0377f71125ec2ce5863788f32313180249ef457a..654f274f8079834744443eddb4f3a29784a1bd7d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1250,7 +1250,10 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) struct cam_vfe_bus_ver2_common_data *common_data = rsrc_data->common_data; - /* disable WM */ + /* Disable WM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + /* Disable all register access, reply on global reset */ CAM_DBG(CAM_ISP, "WM res %d irq_enabled %d", rsrc_data->index, rsrc_data->irq_enabled); @@ -2692,8 +2695,9 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_client = NULL; uint32_t *reg_val_pair; - uint32_t i, j, size = 0; + uint32_t i, j, k, size = 0; uint32_t frame_inc = 0, val; + uint32_t loop_size = 0; bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; @@ -2776,20 +2780,6 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, update_buf->wm_update->image_buf[i]); } - /* WM Image address */ - if (wm_data->en_ubwc) - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - (update_buf->wm_update->image_buf[i] + - io_cfg->planes[i].meta_size)); - else - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - update_buf->wm_update->image_buf[i] + - wm_data->offset); - CAM_DBG(CAM_ISP, "WM %d image address 0x%x", - wm_data->index, reg_val_pair[j-1]); - if (wm_data->en_ubwc) { frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride * io_cfg->planes[i].slice_height, 4096); @@ -2805,6 +2795,28 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, io_cfg->planes[i].slice_height; } + if (wm_data->index < 3) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_ubwc) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size + + k * frame_inc); + else + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc); + CAM_DBG(CAM_ISP, "WM %d image address 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->frame_inc, frame_inc); CAM_DBG(CAM_ISP, "WM %d frame_inc %d", @@ -2875,6 +2887,13 @@ static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, wm_data = vfe_out_data->wm_res[i]->res_priv; + if (wm_data->index <= 2 && hfr_cfg->subsample_period > 3) { + CAM_ERR(CAM_ISP, + "RDI doesn't support irq subsample period %d", + hfr_cfg->subsample_period); + return -EINVAL; + } + if ((wm_data->framedrop_pattern != hfr_cfg->framedrop_pattern) || !wm_data->hfr_cfg_done) { diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c index 60feeacde477fd415b531f603b75f4f9e0e2ca30..46cc08f7ea5fea95509ff0a8e1971aea38397dbe 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c @@ -138,6 +138,7 @@ static struct platform_driver jpeg_driver = { .name = "cam_jpeg", .owner = THIS_MODULE, .of_match_table = cam_jpeg_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index b8b3612786c02662611e5d923f4fd8b0b2d01f41..74e0dacb4bf36f357a53855019f9f7d4503fc259 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -729,15 +729,59 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return rc; } +static void cam_jpeg_mgr_stop_deinit_dev(struct cam_jpeg_hw_mgr *hw_mgr, + struct cam_jpeg_hw_cfg_req *p_cfg_req, uint32_t dev_type) +{ + int rc = 0; + struct cam_jpeg_set_irq_cb irq_cb; + + /* stop reset Unregister CB and deinit */ + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_JPEG, "SET_IRQ_CB fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "process_cmd null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "stop fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "op stop null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %d HW %d", + dev_type, rc); + } else { + CAM_ERR(CAM_JPEG, "op deinit null %d", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; +} + static int cam_jpeg_mgr_flush(void *hw_mgr_priv, struct cam_jpeg_hw_ctx_data *ctx_data) { - int rc = 0; struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; uint32_t dev_type; struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL; - struct cam_jpeg_set_irq_cb irq_cb; CAM_DBG(CAM_JPEG, "E: JPEG flush ctx"); @@ -753,51 +797,12 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, p_cfg_req != NULL) { if ((struct cam_jpeg_hw_ctx_data *) p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) { - /* stop reset Unregister CB and deinit */ - irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; - irq_cb.data = NULL; - irq_cb.b_set_cb = false; - if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { - rc = - hw_mgr->devices[dev_type][0]->hw_ops.process_cmd - (hw_mgr->devices[dev_type][0]->hw_priv, - CAM_JPEG_CMD_SET_IRQ_CB, &irq_cb, - sizeof(irq_cb)); - if (rc) - CAM_ERR(CAM_JPEG, - "CMD_SET_IRQ_CB failed %d", rc); - - } else { - CAM_ERR(CAM_JPEG, "process_cmd null "); - } - - if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { - rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_JPEG, "stop fail %d", rc); - } else { - CAM_ERR(CAM_JPEG, "op stop null "); - } - - if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { - rc = hw_mgr->devices[dev_type][0] - ->hw_ops.deinit( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_JPEG, - "Failed to Deinit %d HW", - dev_type); - } else { - CAM_ERR(CAM_JPEG, "op deinit null"); - } + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); } - - hw_mgr->device_in_use[dev_type][0] = false; - p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; - hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; } list_for_each_entry_safe(cfg_req, req_temp, @@ -807,14 +812,14 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, continue; list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); } - CAM_DBG(CAM_JPEG, "X: JPEG flush ctx with rc: %d", rc); + CAM_DBG(CAM_JPEG, "X: JPEG flush ctx"); - return rc; + return 0; } - static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, struct cam_jpeg_hw_ctx_data *ctx_data, struct cam_hw_flush_args *flush_args) @@ -822,7 +827,10 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_jpeg_hw_cfg_req *cfg_req = NULL; struct cam_jpeg_hw_cfg_req *req_temp = NULL; - int64_t request_id; + int64_t request_id = 0; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + bool b_req_found = false; CAM_DBG(CAM_JPEG, "E: JPEG flush req"); @@ -834,7 +842,33 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, if (flush_args->num_req_pending) return 0; - request_id = *(int64_t *)flush_args->flush_req_active[0]; + request_id = (int64_t)flush_args->flush_req_active[0]; + + if (!flush_args->num_req_active) + return 0; + + if (request_id <= 0) { + CAM_ERR(CAM_JPEG, "Invalid red id %lld", request_id); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if (((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) && + (p_cfg_req->req_id == request_id)) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + b_req_found = true; + } + } + list_for_each_entry_safe(cfg_req, req_temp, &hw_mgr->hw_config_req_list, list) { if ((struct cam_jpeg_hw_ctx_data *) @@ -845,10 +879,17 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, continue; list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + b_req_found = true; + break; } - CAM_DBG(CAM_JPEG, "X: JPEG flush req"); + if (!b_req_found) { + CAM_ERR(CAM_JPEG, "req not found %lld", request_id); + return -EINVAL; + } + CAM_DBG(CAM_JPEG, "X: JPEG flush req"); return 0; } @@ -888,7 +929,6 @@ static int cam_jpeg_mgr_hw_flush(void *hw_mgr_priv, void *flush_hw_args) break; case CAM_FLUSH_TYPE_REQ: rc = cam_jpeg_mgr_flush_req(hw_mgr_priv, ctx_data, flush_args); - CAM_ERR(CAM_JPEG, "Flush per request is not supported"); break; default: CAM_ERR(CAM_JPEG, "Invalid flush type: %d", @@ -957,7 +997,6 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) { mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_JPEG, "Error Unbalanced deinit"); - kfree(ctx_data->cdm_cmd); return -EFAULT; } @@ -979,10 +1018,13 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_JPEG, "JPEG release ctx failed"); kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + return -EINVAL; } kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; CAM_DBG(CAM_JPEG, "handle %llu", ctx_data); return rc; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c index ef10406b823a9232e68184a1ae8f30281ab7b63d..fd4fdab19fa73552892e249c89e52c0a37534583 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -220,6 +220,7 @@ static struct platform_driver cam_jpeg_dma_driver = { .name = "cam-jpeg-dma", .owner = THIS_MODULE, .of_match_table = cam_jpeg_dma_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 9fa691b2bff646d040771ac1bca671fa39015bb5..7fcc1ada1a36f897d857047cf1cc533ad7d8b988 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -349,7 +349,7 @@ int cam_jpeg_enc_stop_hw(void *data, hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; - mutex_unlock(&core_info->core_mutex); + mutex_lock(&core_info->core_mutex); spin_lock(&jpeg_enc_dev->hw_lock); if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { CAM_ERR(CAM_JPEG, "alrady stopping"); diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c index d1eb526428e29d7841dcf184702376653422d90d..d4daa6dde308957bfb2561ae340211a9f942bd3c 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -218,6 +218,7 @@ static struct platform_driver cam_jpeg_enc_driver = { .name = "cam-jpeg-enc", .owner = THIS_MODULE, .of_match_table = cam_jpeg_enc_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c index c58e9f38629136b63572115bd5d83872c8cf961d..a4ee1040e4c86388a73cef7050f2c1660778eed4 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c @@ -214,6 +214,7 @@ static struct platform_driver cam_lrme_driver = { .name = "cam_lrme", .owner = THIS_MODULE, .of_match_table = cam_lrme_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index ec392f5d0752c63ce3df12f4b628b5c96188d856..ec4297822fb7c857f0e2cb365648f8abf88eab0e 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -300,6 +300,7 @@ static struct platform_driver cam_lrme_hw_driver = { .name = "cam_lrme_hw", .owner = THIS_MODULE, .of_match_table = cam_lrme_hw_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 3c9d44fccaa8e6406065052972e9164492279a5c..3311f29fba1ee0e27043173b21a26ecce04648e1 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -502,6 +502,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, for (; i >= 0; i--) { dev = &link->l_dev[i]; evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.dev_hdl = dev->dev_hdl; evt_data.link_hdl = link->link_hdl; evt_data.req_id = apply_req.request_id; evt_data.u.error = CRM_KMD_ERR_BUBBLE; @@ -1140,24 +1141,26 @@ static void __cam_req_mgr_notify_sof_freeze( } /** - * __cam_req_mgr_sof_freeze() + * __cam_req_mgr_process_sof_freeze() * * @brief : Apoptosis - Handles case when connected devices are not responding - * @data : timer pointer + * @priv : link information + * @data : task data * */ -static void __cam_req_mgr_sof_freeze(unsigned long data) +static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) { - struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_core_session *session = NULL; struct cam_req_mgr_message msg; + int rc = 0; - if (!timer) { - CAM_ERR(CAM_CRM, "NULL timer"); - return; + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + return -EINVAL; } - link = (struct cam_req_mgr_core_link *)timer->parent; + + link = (struct cam_req_mgr_core_link *)priv; session = (struct cam_req_mgr_core_session *)link->parent; CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", @@ -1171,12 +1174,47 @@ static void __cam_req_mgr_sof_freeze(unsigned long data) msg.u.err_msg.request_id = 0; msg.u.err_msg.link_hdl = link->link_hdl; + rc = cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT); - if (cam_req_mgr_notify_message(&msg, - V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT)) + if (rc) CAM_ERR(CAM_CRM, - "Error notifying SOF freeze for session %d link 0x%x", - session->session_hdl, link->link_hdl); + "Error notifying SOF freeze for session %d link 0x%x rc %d", + session->session_hdl, link->link_hdl, rc); + + return rc; +} + +/** + * __cam_req_mgr_sof_freeze() + * + * @brief : Callback function for timer timeout indicating SOF freeze + * @data : timer pointer + * + */ +static void __cam_req_mgr_sof_freeze(unsigned long data) +{ + struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct crm_task_payload *task_data; + + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + + link = (struct cam_req_mgr_core_link *)timer->parent; + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "No empty task"); + return; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_FREEZE; + task->process_cb = &__cam_req_mgr_process_sof_freeze; + cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); } /** diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h index 025c16aacfdfe57dc25bd421a11f899355601ca2..68ec09b1e89edba79d2cc94e44f0ac2a37d5b5cc 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h @@ -45,6 +45,7 @@ enum crm_workq_task_type { CRM_WORKQ_TASK_APPLY_REQ, CRM_WORKQ_TASK_NOTIFY_SOF, CRM_WORKQ_TASK_NOTIFY_ERR, + CRM_WORKQ_TASK_NOTIFY_FREEZE, CRM_WORKQ_TASK_SCHED_REQ, CRM_WORKQ_TASK_FLUSH_REQ, CRM_WORKQ_TASK_INVALID, diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c index 9a93feba1ac5afbf68a4c981d6b8e9ec00abd21f..543e3329fc523ed68a9a5ec691f1b0ce2de64b30 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c @@ -591,6 +591,7 @@ static int cam_req_mgr_remove(struct platform_device *pdev) cam_v4l2_device_cleanup(); mutex_destroy(&g_dev.dev_lock); g_dev.state = false; + g_dev.subdev_nodes_created = false; return 0; } @@ -680,6 +681,7 @@ static struct platform_driver cam_req_mgr_driver = { .name = "cam_req_mgr", .owner = THIS_MODULE, .of_match_table = cam_req_mgr_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index a48cfa239293ec257c2166f9d96ecc0373f83c83..ed0a26b70effc1c7c37f2402b146531fff45e32e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -878,6 +878,11 @@ int32_t cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + if (a_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_ACTUATOR, "i2c frame data is NULL"); + return -EINVAL; + } + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { i2c_set = &(a_ctrl->i2c_data.per_frame[i]); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 733c9e87063736b7682fc2f60aa255838679e0a8..7d23f900199e0c7620be4e94244f0dab721b05dd 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -397,6 +397,7 @@ static struct platform_driver cam_actuator_platform_driver = { .name = "qcom,actuator", .owner = THIS_MODULE, .of_match_table = cam_actuator_driver_dt_match, + .suppress_bind_attrs = true, }, .remove = cam_actuator_platform_remove, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c index dbda92109f3466c2d574d372f8131150251fac12..b203948ae39efe914223ff05203c3b4792b508ad 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1013,7 +1013,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, read_words = cam_io_r_mb(base + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); total_read_words += read_words; - do { + while (read_words > 0) { val = cam_io_r_mb(base + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); for (i = 0; (i < 4) && @@ -1031,7 +1031,8 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, index++; } } - } while (--read_words > 0); + read_words--; + } } rel_mutex: @@ -1199,7 +1200,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, index = 0; CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); first_byte = 0; - do { + while (read_words > 0) { val = cam_io_r_mb(base + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); CAM_DBG(CAM_CCI, "read val 0x%x", val); @@ -1216,7 +1217,8 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, index++; } } - } while (--read_words > 0); + read_words--; + } rel_mutex: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index 8d44bcf3ce224e2b5b9c5c8787a2ead0e3226c68..a763d3ffb39eee0b1a439bfe435b89a7797e9345 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -382,6 +382,7 @@ static struct platform_driver cci_driver = { .name = CAMX_CCI_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_cci_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 754646ce4c899272009ec47ef3d27f932e10aa06..b0b4db53e4940961570a975f91f3d123d4637969 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -246,10 +246,17 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) mask <<= 1; } } else { - if (csiphy_dev->csiphy_info.combo_mode == 1) - reg_array = + if (csiphy_dev->csiphy_info.combo_mode == 1) { + if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) + reg_array = csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg; - else + else { + reg_array = + csiphy_dev->ctrl_reg->csiphy_3ph_reg; + CAM_ERR(CAM_CSIPHY, + "Unsupported configuration, Falling back to CPHY mode"); + } + } else reg_array = csiphy_dev->ctrl_reg->csiphy_3ph_reg; csiphy_dev->num_irq_registers = 11; @@ -283,6 +290,24 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) usleep_range(csiphy_common_reg->delay * 1000, csiphy_common_reg->delay * 1000 + 10); break; + case CSIPHY_2PH_REGS: + if (!csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; + case CSIPHY_3PH_REGS: + if (csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; default: break; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index a560b00d8add9381bcafd7e12df0afde75526104..32bb34bb257b720fba9f91052249b1af3a535e48 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -233,6 +233,7 @@ static struct platform_driver csiphy_driver = { .name = CAMX_CSIPHY_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_csiphy_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 5e871ad1f813bd844a31d1b4be17efde05f286dd..68f20b4acd597822c4268a7ede323bf8e5302db3 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -57,6 +57,8 @@ #define CSIPHY_SETTLE_CNT_LOWER_BYTE 2 #define CSIPHY_SETTLE_CNT_HIGHER_BYTE 3 #define CSIPHY_DNP_PARAMS 4 +#define CSIPHY_2PH_REGS 5 +#define CSIPHY_3PH_REGS 6 #define ENABLE_IRQ false diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 8199087908b48d6ff2facb15a139fd6115241a21..0b9f52f9d3336dc8e39d1f05bb7a34158f7ed6c9 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -14,6 +14,7 @@ #include "cam_csiphy_core.h" #include "include/cam_csiphy_1_1_hwreg.h" #include "include/cam_csiphy_1_0_hwreg.h" +#include "include/cam_csiphy_2_0_hwreg.h" #define BYTES_PER_REGISTER 4 #define NUM_REGISTER_PER_LINE 4 @@ -192,6 +193,20 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->hw_version = CSIPHY_VERSION_V11; csiphy_dev->clk_lane = 0; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v2.0")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v2_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + csiphy_dev->hw_version = CSIPHY_VERSION_V20; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->clk_lane = 0; } else { CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", csiphy_dev->hw_version); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index c7792d6acebbed0132348d6b4a092cd7ddc0111f..972fff99b8e816b889d8ad7f1ca1808bac24bba3 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -37,6 +37,7 @@ #define CSIPHY_VERSION_V35 0x35 #define CSIPHY_VERSION_V10 0x10 #define CSIPHY_VERSION_V11 0x11 +#define CSIPHY_VERSION_V20 0x20 /** * @csiphy_dev: CSIPhy device structure diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..04b827f9cb7995957bc96224b1f2769a01cca421 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -0,0 +1,294 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CAM_CSIPHY_2_0_HWREG_H_ +#define _CAM_CSIPHY_2_0_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v2_0 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 3, + .csiphy_2ph_config_array_size = 15, + .csiphy_3ph_config_array_size = 17, +}; + +struct csiphy_reg_t csiphy_common_reg_2_0[] = { + {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_2_0[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_2_0[] = { + {0x082c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xff, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xfb, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xef, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_2ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v2_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t csiphy_3ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_2_0_HWREG_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index c7a9a32e4d0dd8ecde06ed1f43f9cc67ea57aebd..dbeb4af4820ed9d59478ec3a91920ed6793d9662 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -506,6 +506,7 @@ static struct platform_driver cam_eeprom_platform_driver = { .name = "qcom,eeprom", .owner = THIS_MODULE, .of_match_table = cam_eeprom_dt_match, + .suppress_bind_attrs = true, }, .probe = cam_eeprom_platform_driver_probe, .remove = cam_eeprom_platform_driver_remove, diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c index b58abdf03bc39f05f2bd68697601445ceb61c8fe..bd087b7ec51f05aa7c5d3b1227d23e7e89f05390 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c @@ -135,7 +135,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; } - map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + map = vzalloc((sizeof(*map) * data->num_map)); if (!map) { rc = -ENOMEM; return rc; @@ -184,7 +184,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, data->num_data += map[i].mem.valid_size; } - data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + data->mapdata = vzalloc(data->num_data); if (!data->mapdata) { rc = -ENOMEM; goto ERROR; @@ -192,7 +192,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; ERROR: - kfree(data->map); + vfree(data->map); memset(data, 0, sizeof(*data)); return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c index 3a5933417683fd49c07aed82da374c2804b1a48d..ee58e7e17a6c995c817fbe6f39ae2da870d29c5f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c @@ -521,8 +521,14 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, "Flash off failed %d", rc); goto apply_setting_err; } + } else if (flash_data->opcode == CAM_PKT_NOP_OPCODE) { + flash_data->opcode = 0; + CAM_DBG(CAM_FLASH, "NOP Packet"); } else { - CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id); + rc = -EINVAL; + CAM_ERR(CAM_FLASH, "Invalid opcode: %d req_id: %llu", + flash_data->opcode, req_id); + goto apply_setting_err; } } @@ -807,17 +813,20 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) break; } case CAM_PKT_NOP_OPCODE: { + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { CAM_WARN(CAM_FLASH, "Rxed NOP packets without linking"); - frm_offset = csl_packet->header.request_id % - MAX_PER_FRAME_ARRAY; fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; return 0; } + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; + fctrl->per_frame[frm_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u", csl_packet->header.request_id); goto update_req_mgr; @@ -967,19 +976,15 @@ int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply) fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(apply->dev_hdl); if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); - rc = -EINVAL; - goto free_resource; + return -EINVAL; } - if (!(apply->report_if_bubble)) { - mutex_lock(&fctrl->flash_wq_mutex); - rc = cam_flash_apply_setting(fctrl, apply->request_id); - if (rc) - CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", - rc); - mutex_unlock(&fctrl->flash_wq_mutex); - } + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, apply->request_id); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); -free_resource: return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c index f9411fcfa4b35e1a17c8fc300231cf0ef83eac7f..d9b5f6406058b0fca7bc54085b05ade6bd5936b8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -394,6 +394,7 @@ static struct platform_driver cam_flash_platform_driver = { .name = "CAM-FLASH-DRIVER", .owner = THIS_MODULE, .of_match_table = cam_flash_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h index 4fcd81d2ece0731787fe3e30811a21224e4d4bcd..0e8d4ee7c611fd6bea87d6bd45ff895c4471baa8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -79,10 +79,10 @@ struct cam_flash_intf_params { * @cmd_type : Command buffer type */ struct cam_flash_common_attr { - bool is_settings_valid; - int32_t request_id; - uint16_t count; - uint8_t cmd_type; + bool is_settings_valid; + uint64_t request_id; + uint16_t count; + uint8_t cmd_type; }; /** diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index 43513e8c14854039efe29d5cdda267c16b68501d..d03faef4d3a6d5c570e3538cd21353642162544c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -718,6 +718,7 @@ static struct platform_driver cam_res_mgr_driver = { .name = "cam_res_mgr", .owner = THIS_MODULE, .of_match_table = cam_res_mgr_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c index e3b2ffc5f45eaec588940ff7bc23c33861a55eff..6cf40f8b0f1086b94de3b299965eb065cb239ae8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -339,6 +339,7 @@ static struct platform_driver cam_sensor_platform_driver = { .name = "qcom,camera", .owner = THIS_MODULE, .of_match_table = cam_sensor_driver_dt_match, + .suppress_bind_attrs = true, }, .remove = cam_sensor_platform_remove, }; diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index 43902c977a4940fba0c594595f8005a80ba9d335..75a841222718c17224872780dd7c68424d63d386 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -3407,6 +3407,7 @@ static struct platform_driver cam_smmu_driver = { .name = "msm_cam_smmu", .owner = THIS_MODULE, .of_match_table = msm_cam_smmu_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c index 55896f497c59ed768df7ff4ee1dd76b4136372cd..c5438c917bc0e5a8e9a14cfa8b1d8176346d3f55 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -21,6 +21,13 @@ struct sync_device *sync_dev; +/* + * Flag to determine whether to enqueue cb of a + * signaled fence onto the workq or invoke it + * directly in the same context + */ +static bool trigger_cb_without_switch; + int cam_sync_create(int32_t *sync_obj, const char *name) { int rc; @@ -36,7 +43,8 @@ int cam_sync_create(int32_t *sync_obj, const char *name) } while (bit); spin_lock_bh(&sync_dev->row_spinlocks[idx]); - rc = cam_sync_init_object(sync_dev->sync_table, idx, name); + rc = cam_sync_init_row(sync_dev->sync_table, idx, name, + CAM_SYNC_TYPE_INDV); if (rc) { CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", idx); @@ -58,6 +66,7 @@ int cam_sync_register_callback(sync_callback cb_func, struct sync_callback_info *sync_cb; struct sync_callback_info *cb_info; struct sync_table_row *row = NULL; + int status = 0; if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func) return -EINVAL; @@ -94,18 +103,27 @@ int cam_sync_register_callback(sync_callback cb_func, if ((row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS || row->state == CAM_SYNC_STATE_SIGNALED_ERROR) && (!row->remaining)) { - sync_cb->callback_func = cb_func; - sync_cb->cb_data = userdata; - sync_cb->sync_obj = sync_obj; - INIT_WORK(&sync_cb->cb_dispatch_work, - cam_sync_util_cb_dispatch); - sync_cb->status = row->state; - CAM_DBG(CAM_SYNC, "Callback trigger for sync object:%d", - sync_cb->sync_obj); - queue_work(sync_dev->work_queue, - &sync_cb->cb_dispatch_work); + if (trigger_cb_without_switch) { + CAM_DBG(CAM_SYNC, "Invoke callback for sync object:%d", + sync_obj); + status = row->state; + kfree(sync_cb); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + cb_func(sync_obj, status, userdata); + } else { + sync_cb->callback_func = cb_func; + sync_cb->cb_data = userdata; + sync_cb->sync_obj = sync_obj; + INIT_WORK(&sync_cb->cb_dispatch_work, + cam_sync_util_cb_dispatch); + sync_cb->status = row->state; + CAM_DBG(CAM_SYNC, "Enqueue callback for sync object:%d", + sync_cb->sync_obj); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); return 0; } @@ -157,18 +175,11 @@ int cam_sync_deregister_callback(sync_callback cb_func, int cam_sync_signal(int32_t sync_obj, uint32_t status) { - int rc; struct sync_table_row *row = NULL; struct sync_table_row *parent_row = NULL; - struct sync_callback_info *sync_cb; - struct sync_user_payload *payload_info; - struct sync_parent_info *parent_info; - struct list_head sync_list; - struct cam_signalable_info *list_info = NULL; - struct cam_signalable_info *temp_list_info = NULL; - - /* Objects to be signaled will be added into this list */ - INIT_LIST_HEAD(&sync_list); + struct sync_parent_info *parent_info, *temp_parent_info; + struct list_head parents_list; + int rc = 0; if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)", @@ -211,119 +222,50 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) } row->state = status; - rc = cam_sync_util_add_to_signalable_list(sync_obj, status, &sync_list); - if (rc < 0) { - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); - CAM_ERR(CAM_SYNC, - "Error: Unable to add sync object :%d to signalable list", - sync_obj); - return rc; - } + cam_sync_util_dispatch_signaled_cb(sync_obj, status); + + /* copy parent list to local and release child lock */ + INIT_LIST_HEAD(&parents_list); + list_splice_init(&row->parents_list, &parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + if (list_empty(&parents_list)) + return 0; /* * Now iterate over all parents of this object and if they too need to - * be signaled add them to the list + * be signaled dispatch cb's */ - list_for_each_entry(parent_info, - &row->parents_list, + list_for_each_entry_safe(parent_info, + temp_parent_info, + &parents_list, list) { parent_row = sync_dev->sync_table + parent_info->sync_id; spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); parent_row->remaining--; - parent_row->state = cam_sync_util_get_state( - parent_row->state, + rc = cam_sync_util_update_parent_state( + parent_row, status); - - if (!parent_row->remaining) { - rc = cam_sync_util_add_to_signalable_list - (parent_info->sync_id, - parent_row->state, - &sync_list); - if (rc < 0) { - spin_unlock_bh( - &sync_dev->row_spinlocks[ - parent_info->sync_id]); - spin_unlock_bh( - &sync_dev->row_spinlocks[sync_obj]); - return rc; - } - } - spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); - } - - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); - - /* - * Now dispatch the various sync objects collected so far, in our - * list - */ - list_for_each_entry_safe(list_info, - temp_list_info, - &sync_list, - list) { - struct sync_table_row *signalable_row = NULL; - struct sync_callback_info *temp_sync_cb; - struct sync_user_payload *temp_payload_info; - - signalable_row = sync_dev->sync_table + list_info->sync_obj; - - spin_lock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]); - if (signalable_row->state == CAM_SYNC_STATE_INVALID) { + if (rc) { + CAM_ERR(CAM_SYNC, "Invalid parent state %d", + parent_row->state); spin_unlock_bh( - &sync_dev->row_spinlocks[list_info->sync_obj]); + &sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); continue; } - /* Dispatch kernel callbacks if any were registered earlier */ - - list_for_each_entry_safe(sync_cb, - temp_sync_cb, &signalable_row->callback_list, list) { - sync_cb->status = list_info->status; - list_del_init(&sync_cb->list); - queue_work(sync_dev->work_queue, - &sync_cb->cb_dispatch_work); - } - - /* Dispatch user payloads if any were registered earlier */ - list_for_each_entry_safe(payload_info, temp_payload_info, - &signalable_row->user_payload_list, list) { - spin_lock_bh(&sync_dev->cam_sync_eventq_lock); - if (!sync_dev->cam_sync_eventq) { - spin_unlock_bh( - &sync_dev->cam_sync_eventq_lock); - break; - } - spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); - cam_sync_util_send_v4l2_event( - CAM_SYNC_V4L_EVENT_ID_CB_TRIG, - list_info->sync_obj, - list_info->status, - payload_info->payload_data, - CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); - - list_del_init(&payload_info->list); - /* - * We can free the list node here because - * sending V4L event will make a deep copy - * anyway - */ - kfree(payload_info); - } - - /* - * This needs to be done because we want to unblock anyone - * who might be blocked and waiting on this sync object - */ - complete_all(&signalable_row->signaled); - - spin_unlock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]); + if (!parent_row->remaining) + cam_sync_util_dispatch_signaled_cb( + parent_info->sync_id, parent_row->state); - list_del_init(&list_info->list); - kfree(list_info); + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + list_del_init(&parent_info->list); + kfree(parent_info); } - return rc; + return 0; } int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) @@ -337,10 +279,8 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) return -EINVAL; } - rc = cam_sync_util_validate_merge(sync_obj, - num_objs); - if (rc < 0) { - CAM_ERR(CAM_SYNC, "Validation failed, Merge not allowed"); + if (num_objs <= 1) { + CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); return -EINVAL; } @@ -352,7 +292,6 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) } while (bit); spin_lock_bh(&sync_dev->row_spinlocks[idx]); - rc = cam_sync_init_group_object(sync_dev->sync_table, idx, sync_obj, num_objs); @@ -952,6 +891,26 @@ static void cam_sync_init_entity(struct sync_device *sync_dev) } #endif +static int cam_sync_create_debugfs(void) +{ + sync_dev->dentry = debugfs_create_dir("camera_sync", NULL); + + if (!sync_dev->dentry) { + CAM_ERR(CAM_SYNC, "Failed to create sync dir"); + return -ENOMEM; + } + + if (!debugfs_create_bool("trigger_cb_without_switch", + 0644, sync_dev->dentry, + &trigger_cb_without_switch)) { + CAM_ERR(CAM_SYNC, + "failed to create trigger_cb_without_switch entry"); + return -ENOMEM; + } + + return 0; +} + static int cam_sync_probe(struct platform_device *pdev) { int rc; @@ -1017,6 +976,9 @@ static int cam_sync_probe(struct platform_device *pdev) goto v4l2_fail; } + trigger_cb_without_switch = false; + cam_sync_create_debugfs(); + return rc; v4l2_fail: @@ -1036,6 +998,8 @@ static int cam_sync_remove(struct platform_device *pdev) v4l2_device_unregister(sync_dev->vdev->v4l2_dev); cam_sync_media_controller_cleanup(sync_dev); video_device_release(sync_dev->vdev); + debugfs_remove_recursive(sync_dev->dentry); + sync_dev->dentry = NULL; kfree(sync_dev); sync_dev = NULL; @@ -1053,6 +1017,7 @@ static struct platform_driver cam_sync_driver = { .driver = { .name = "cam_sync", .owner = THIS_MODULE, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h index ce7d9491630384fc01f505568e1558944f25315e..38dab42a56cc65a132bcca314f8cce850800491d 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -177,6 +178,7 @@ struct cam_signalable_info { * @row_spinlocks : Spinlock array, one for each row in the table * @table_lock : Mutex used to lock the table * @open_cnt : Count of file open calls made on the sync driver + * @dentry : Debugfs entry * @work_queue : Work queue used for dispatching kernel callbacks * @cam_sync_eventq : Event queue used to dispatch user payloads to user space * @bitmap : Bitmap representation of all sync objects @@ -188,6 +190,7 @@ struct sync_device { spinlock_t row_spinlocks[CAM_SYNC_MAX_OBJS]; struct mutex table_lock; int open_cnt; + struct dentry *dentry; struct workqueue_struct *work_queue; struct v4l2_fh *cam_sync_eventq; spinlock_t cam_sync_eventq_lock; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c index 43bce513bff2be6b5efff1137c71678911aedc68..49a9d2f39974d1b52a82a30db0559853a5aeac8b 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c @@ -31,20 +31,21 @@ int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, return rc; } -int cam_sync_init_object(struct sync_table_row *table, - uint32_t idx, - const char *name) +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type) { struct sync_table_row *row = table + idx; if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) return -EINVAL; + memset(row, 0, sizeof(*row)); + if (name) strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN); INIT_LIST_HEAD(&row->parents_list); INIT_LIST_HEAD(&row->children_list); - row->type = CAM_SYNC_TYPE_INDV; + row->type = type; row->sync_id = idx; row->state = CAM_SYNC_STATE_ACTIVE; row->remaining = 0; @@ -58,147 +59,95 @@ int cam_sync_init_object(struct sync_table_row *table, return 0; } -uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table, +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, uint32_t *sync_objs, uint32_t num_objs) { - int i; + int i, rc = 0; + struct sync_child_info *child_info; + struct sync_parent_info *parent_info; + struct sync_table_row *row = table + idx; struct sync_table_row *child_row = NULL; - int success_count = 0; - int active_count = 0; - if (!table || !sync_objs) - return CAM_SYNC_STATE_SIGNALED_ERROR; + cam_sync_init_row(table, idx, "merged_fence", CAM_SYNC_TYPE_GROUP); /* - * We need to arrive at the state of the merged object based on - * counts of error, active and success states of all children objects + * While traversing for children, parent's row list is updated with + * child info and each child's row is updated with parent info. + * If any child state is ERROR or SUCCESS, it will not be added to list. */ for (i = 0; i < num_objs; i++) { - spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); child_row = table + sync_objs[i]; - switch (child_row->state) { - case CAM_SYNC_STATE_SIGNALED_ERROR: + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + + /* validate child */ + if ((child_row->type == CAM_SYNC_TYPE_GROUP) || + (child_row->state == CAM_SYNC_STATE_INVALID)) { spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return CAM_SYNC_STATE_SIGNALED_ERROR; - case CAM_SYNC_STATE_SIGNALED_SUCCESS: - success_count++; - break; - case CAM_SYNC_STATE_ACTIVE: - active_count++; - break; - default: CAM_ERR(CAM_SYNC, - "Invalid state of child object during merge"); - spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return CAM_SYNC_STATE_SIGNALED_ERROR; + "Invalid child fence:%i state:%u type:%u", + child_row->sync_id, child_row->state, + child_row->type); + rc = -EINVAL; + goto clean_children_info; } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - } - - if (active_count) - return CAM_SYNC_STATE_ACTIVE; - - if (success_count == num_objs) - return CAM_SYNC_STATE_SIGNALED_SUCCESS; - - return CAM_SYNC_STATE_SIGNALED_ERROR; -} - -static int cam_sync_util_get_group_object_remaining_count( - struct sync_table_row *table, - uint32_t *sync_objs, - uint32_t num_objs) -{ - int i; - struct sync_table_row *child_row = NULL; - int remaining_count = 0; - - if (!table || !sync_objs) - return -EINVAL; - - for (i = 0; i < num_objs; i++) { - child_row = table + sync_objs[i]; - if (child_row->state == CAM_SYNC_STATE_ACTIVE) - remaining_count++; - } - return remaining_count; -} - -int cam_sync_init_group_object(struct sync_table_row *table, - uint32_t idx, - uint32_t *sync_objs, - uint32_t num_objs) -{ - int i; - int remaining; - struct sync_child_info *child_info; - struct sync_parent_info *parent_info; - struct sync_table_row *row = table + idx; - struct sync_table_row *child_row = NULL; - - INIT_LIST_HEAD(&row->parents_list); + /* check for child's state */ + if (child_row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + row->state = CAM_SYNC_STATE_SIGNALED_ERROR; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + if (child_row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } - INIT_LIST_HEAD(&row->children_list); + row->remaining++; - /* - * While traversing parents and children, we allocate in a loop and in - * case allocation fails, we call the clean up function which frees up - * all memory allocation thus far - */ - for (i = 0; i < num_objs; i++) { + /* Add child info */ child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC); - if (!child_info) { - cam_sync_util_cleanup_children_list(row, - SYNC_LIST_CLEAN_ALL, 0); - return -ENOMEM; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; } - child_info->sync_id = sync_objs[i]; list_add_tail(&child_info->list, &row->children_list); - } - for (i = 0; i < num_objs; i++) { - /* This gets us the row corresponding to the sync object */ - child_row = table + sync_objs[i]; - spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + /* Add parent info */ parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC); if (!parent_info) { - cam_sync_util_cleanup_parents_list(child_row, - SYNC_LIST_CLEAN_ALL, 0); - cam_sync_util_cleanup_children_list(row, - SYNC_LIST_CLEAN_ALL, 0); spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return -ENOMEM; + rc = -ENOMEM; + goto clean_children_info; } parent_info->sync_id = idx; list_add_tail(&parent_info->list, &child_row->parents_list); spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); } - row->type = CAM_SYNC_TYPE_GROUP; - row->sync_id = idx; - row->state = cam_sync_util_get_group_object_state(table, - sync_objs, num_objs); - remaining = cam_sync_util_get_group_object_remaining_count(table, - sync_objs, num_objs); - if (remaining < 0) { - CAM_ERR(CAM_SYNC, "Failed getting remaining count"); - return -ENODEV; + if (!row->remaining) { + if (row->state != CAM_SYNC_STATE_SIGNALED_ERROR) + row->state = CAM_SYNC_STATE_SIGNALED_SUCCESS; + complete_all(&row->signaled); } - row->remaining = remaining; - - init_completion(&row->signaled); - INIT_LIST_HEAD(&row->callback_list); - INIT_LIST_HEAD(&row->user_payload_list); + return 0; - if (row->state != CAM_SYNC_STATE_ACTIVE) - complete_all(&row->signaled); +clean_children_info: + row->state = CAM_SYNC_STATE_INVALID; + for (i = i-1; i >= 0; i--) { + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + child_row = table + sync_objs[i]; + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } - return 0; + cam_sync_util_cleanup_children_list(row, SYNC_LIST_CLEAN_ALL, 0); + return rc; } int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) @@ -338,6 +287,64 @@ void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work) kfree(cb_info); } +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status) +{ + struct sync_callback_info *sync_cb; + struct sync_user_payload *payload_info; + struct sync_callback_info *temp_sync_cb; + struct sync_table_row *signalable_row; + struct sync_user_payload *temp_payload_info; + + signalable_row = sync_dev->sync_table + sync_obj; + if (signalable_row->state == CAM_SYNC_STATE_INVALID) { + CAM_DBG(CAM_SYNC, + "Accessing invalid sync object:%i", sync_obj); + return; + } + + /* Dispatch kernel callbacks if any were registered earlier */ + list_for_each_entry_safe(sync_cb, + temp_sync_cb, &signalable_row->callback_list, list) { + sync_cb->status = status; + list_del_init(&sync_cb->list); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + } + + /* Dispatch user payloads if any were registered earlier */ + list_for_each_entry_safe(payload_info, temp_payload_info, + &signalable_row->user_payload_list, list) { + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + if (!sync_dev->cam_sync_eventq) { + spin_unlock_bh( + &sync_dev->cam_sync_eventq_lock); + break; + } + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + cam_sync_util_send_v4l2_event( + CAM_SYNC_V4L_EVENT_ID_CB_TRIG, + sync_obj, + status, + payload_info->payload_data, + CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); + + list_del_init(&payload_info->list); + /* + * We can free the list node here because + * sending V4L event will make a deep copy + * anyway + */ + kfree(payload_info); + } + + /* + * This needs to be done because we want to unblock anyone + * who might be blocked and waiting on this sync object + */ + complete_all(&signalable_row->signaled); +} + void cam_sync_util_send_v4l2_event(uint32_t id, uint32_t sync_obj, int status, @@ -363,80 +370,27 @@ void cam_sync_util_send_v4l2_event(uint32_t id, sync_obj); } -int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs) -{ - int i; - struct sync_table_row *row = NULL; - - if (num_objs <= 1) { - CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); - return -EINVAL; - } - - for (i = 0; i < num_objs; i++) { - row = sync_dev->sync_table + sync_obj[i]; - spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - if (row->type == CAM_SYNC_TYPE_GROUP || - row->state == CAM_SYNC_STATE_INVALID) { - CAM_ERR(CAM_SYNC, - "Group obj %d can't be merged or obj UNINIT", - sync_obj[i]); - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - return -EINVAL; - } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - } - return 0; -} - -int cam_sync_util_add_to_signalable_list(int32_t sync_obj, - uint32_t status, - struct list_head *sync_list) -{ - struct cam_signalable_info *signalable_info = NULL; - - signalable_info = kzalloc(sizeof(*signalable_info), GFP_ATOMIC); - if (!signalable_info) - return -ENOMEM; - - signalable_info->sync_obj = sync_obj; - signalable_info->status = status; - - list_add_tail(&signalable_info->list, sync_list); - CAM_DBG(CAM_SYNC, "Add sync_obj :%d with status :%d to signalable list", - sync_obj, status); - - return 0; -} - -int cam_sync_util_get_state(int current_state, +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state) { - int result = CAM_SYNC_STATE_SIGNALED_ERROR; - - if (new_state != CAM_SYNC_STATE_SIGNALED_SUCCESS && - new_state != CAM_SYNC_STATE_SIGNALED_ERROR) - return CAM_SYNC_STATE_SIGNALED_ERROR; - - switch (current_state) { - case CAM_SYNC_STATE_INVALID: - result = CAM_SYNC_STATE_SIGNALED_ERROR; - break; + int rc = 0; + switch (parent_row->state) { case CAM_SYNC_STATE_ACTIVE: case CAM_SYNC_STATE_SIGNALED_SUCCESS: - if (new_state == CAM_SYNC_STATE_SIGNALED_ERROR) - result = CAM_SYNC_STATE_SIGNALED_ERROR; - else if (new_state == CAM_SYNC_STATE_SIGNALED_SUCCESS) - result = CAM_SYNC_STATE_SIGNALED_SUCCESS; + parent_row->state = new_state; break; case CAM_SYNC_STATE_SIGNALED_ERROR: - result = CAM_SYNC_STATE_SIGNALED_ERROR; + break; + + case CAM_SYNC_STATE_INVALID: + default: + rc = -EINVAL; break; } - return result; + return rc; } void cam_sync_util_cleanup_children_list(struct sync_table_row *row, diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h index adb47dec07b4564db813231da4e72922739fe6fe..cfa450c0e744a4a6e931b5079225263cbb3ea5f8 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h @@ -41,12 +41,11 @@ int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, * @param idx : Index of row to initialize * @param name : Optional string representation of the sync object. Should be * 63 characters or less - * + * @param type : type of row to be initialized * @return Status of operation. Negative in case of error. Zero otherwise. */ -int cam_sync_init_object(struct sync_table_row *table, - uint32_t idx, - const char *name); +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type); /** * @brief: Function to uninitialize a row in the sync table @@ -87,6 +86,17 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx); */ void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work); +/** + * @brief: Function to dispatch callbacks for a signaled sync object + * + * @sync_obj : Sync object that is signaled + * @status : Status of the signaled object + * + * @return None + */ +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status); + /** * @brief: Function to send V4L event to user space * @param id : V4L event id to send @@ -103,29 +113,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, void *payload, int len); -/** - * @brief: Function to validate sync merge arguments - * - * @param sync_obj : Array of sync objects to merge - * @param num_objs : Number of sync objects in the array - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs); - -/** - * @brief: Function which adds sync object information to the signalable list - * - * @param sync_obj : Sync object to add - * @param status : Status of above sync object - * @param list : Linked list where the information should be added to - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_sync_util_add_to_signalable_list(int32_t sync_obj, - uint32_t status, - struct list_head *sync_list); - /** * @brief: Function which gets the next state of the sync object based on the * current state and the new state @@ -135,7 +122,7 @@ int cam_sync_util_add_to_signalable_list(int32_t sync_obj, * * @return Next state of the sync object */ -int cam_sync_util_get_state(int current_state, +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state); /** diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c index c38e2889b7010194b6fe6969d8e008e6e17eb0cf..9056b2b87e03f783c4762279238772a1266faf21 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c @@ -46,8 +46,10 @@ static const char *cam_soc_util_get_string_from_level( return "SVSL1[4]"; case CAM_NOMINAL_VOTE: return "NOM[5]"; + case CAM_NOMINALL1_VOTE: + return "NOML1[6]"; case CAM_TURBO_VOTE: - return "TURBO[6]"; + return "TURBO[7]"; default: return ""; } @@ -227,6 +229,8 @@ int cam_soc_util_get_level_from_string(const char *string, *level = CAM_SVSL1_VOTE; } else if (!strcmp(string, "nominal")) { *level = CAM_NOMINAL_VOTE; + } else if (!strcmp(string, "nominal_l1")) { + *level = CAM_NOMINALL1_VOTE; } else if (!strcmp(string, "turbo")) { *level = CAM_TURBO_VOTE; } else { diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h index 94a5898dd3997aca9e96ec766ea403d78298eed3..f6dac3528ec98bdbe64fa5f43cb14caed4256641 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h @@ -44,14 +44,15 @@ /** * enum cam_vote_level - Enum for voting level * - * @CAM_SUSPEND_VOTE : Suspend vote - * @CAM_MINSVS_VOTE : Min SVS vote - * @CAM_LOWSVS_VOTE : Low SVS vote - * @CAM_SVS_VOTE : SVS vote - * @CAM_SVSL1_VOTE : SVS Plus vote - * @CAM_NOMINAL_VOTE : Nominal vote - * @CAM_TURBO_VOTE : Turbo vote - * @CAM_MAX_VOTE : Max voting level, This is invalid level. + * @CAM_SUSPEND_VOTE : Suspend vote + * @CAM_MINSVS_VOTE : Min SVS vote + * @CAM_LOWSVS_VOTE : Low SVS vote + * @CAM_SVS_VOTE : SVS vote + * @CAM_SVSL1_VOTE : SVS Plus vote + * @CAM_NOMINAL_VOTE : Nominal vote + * @CAM_NOMINALL1_VOTE: Nominal plus vote + * @CAM_TURBO_VOTE : Turbo vote + * @CAM_MAX_VOTE : Max voting level, This is invalid level. */ enum cam_vote_level { CAM_SUSPEND_VOTE, @@ -60,6 +61,7 @@ enum cam_vote_level { CAM_SVS_VOTE, CAM_SVSL1_VOTE, CAM_NOMINAL_VOTE, + CAM_NOMINALL1_VOTE, CAM_TURBO_VOTE, CAM_MAX_VOTE, }; diff --git a/drivers/media/platform/msm/dvb/Kconfig b/drivers/media/platform/msm/dvb/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..e205c8172075ec3903aaeefeed92419f0ade296f --- /dev/null +++ b/drivers/media/platform/msm/dvb/Kconfig @@ -0,0 +1,10 @@ +config DVB_MPQ + tristate "Qualcomm Technologies Inc Multimedia Processor DVB Adapter" + depends on ARCH_QCOM && DVB_CORE + default n + + help + Support for Qualcomm Technologies Inc MPQ based DVB adapter. + Say Y or M if you own such a device and want to use it. + +source "drivers/media/platform/msm/dvb/demux/Kconfig" diff --git a/drivers/media/platform/msm/dvb/Makefile b/drivers/media/platform/msm/dvb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..81c4d78ae0901f1c1fe4b235dcd11e098b12c0f3 --- /dev/null +++ b/drivers/media/platform/msm/dvb/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_DVB_MPQ) += adapter/ +obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/ diff --git a/drivers/media/platform/msm/dvb/adapter/Makefile b/drivers/media/platform/msm/dvb/adapter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..662bf99c4d7e2a0ca76a0ec9679bda0a5d6893ec --- /dev/null +++ b/drivers/media/platform/msm/dvb/adapter/Makefile @@ -0,0 +1,7 @@ +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/platform/msm/dvb/include/ +ccflags-y += -Idrivers/media/platform/msm/dvb/demux/ + +obj-$(CONFIG_DVB_MPQ) += mpq-adapter.o + +mpq-adapter-y := mpq_adapter.o mpq_stream_buffer.o diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c b/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c new file mode 100644 index 0000000000000000000000000000000000000000..17f5eda8e514329e0fa64803c8448e4061ba4ced --- /dev/null +++ b/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 +#include + +#include "mpq_adapter.h" +#include "mpq_dvb_debug.h" + + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* data-structure holding MPQ adapter information */ +static struct +{ + /* MPQ adapter registered to dvb-core */ + struct dvb_adapter adapter; + + /* mutex protect against the data-structure */ + struct mutex mutex; + + /* List of stream interfaces registered to the MPQ adapter */ + struct { + /* pointer to the stream buffer using for data tunneling */ + struct mpq_streambuffer *stream_buffer; + + /* callback triggered when the stream interface is registered */ + mpq_adapter_stream_if_callback callback; + + /* parameter passed to the callback function */ + void *user_param; + } interfaces[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES]; +} mpq_info; + + +/** + * Initialize MPQ DVB adapter module. + * + * Return error status + */ +static int __init mpq_adapter_init(void) +{ + int i; + int result; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + mutex_init(&mpq_info.mutex); + + /* reset stream interfaces list */ + for (i = 0; i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; i++) { + mpq_info.interfaces[i].stream_buffer = NULL; + mpq_info.interfaces[i].callback = NULL; + } + + /* register a new dvb-adapter to dvb-core */ + result = dvb_register_adapter(&mpq_info.adapter, + "Qualcomm Technologies, Inc. DVB adapter", + THIS_MODULE, NULL, adapter_nr); + if (result < 0) { + MPQ_DVB_ERR_PRINT( + "%s: dvb_register_adapter failed, errno %d\n", + __func__, + result); + } + + return result; +} + + +/** + * Cleanup MPQ DVB adapter module. + */ +static void __exit mpq_adapter_exit(void) +{ + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + /* un-register adapter from dvb-core */ + dvb_unregister_adapter(&mpq_info.adapter); + mutex_destroy(&mpq_info.mutex); +} + +struct dvb_adapter *mpq_adapter_get(void) +{ + return &mpq_info.adapter; +} +EXPORT_SYMBOL(mpq_adapter_get); + + +int mpq_adapter_register_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer *stream_buffer) +{ + int ret; + + if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) { + ret = -EINVAL; + goto register_failed; + } + + if (mutex_lock_interruptible(&mpq_info.mutex)) { + ret = -ERESTARTSYS; + goto register_failed; + } + + if (mpq_info.interfaces[interface_id].stream_buffer != NULL) { + /* already registered interface */ + ret = -EINVAL; + goto register_failed_unlock_mutex; + } + + mpq_info.interfaces[interface_id].stream_buffer = stream_buffer; + mutex_unlock(&mpq_info.mutex); + + /* + * If callback is installed, trigger it to notify that + * stream interface was registered. + */ + if (mpq_info.interfaces[interface_id].callback != NULL) { + mpq_info.interfaces[interface_id].callback( + interface_id, + mpq_info.interfaces[interface_id].user_param); + } + + return 0; + +register_failed_unlock_mutex: + mutex_unlock(&mpq_info.mutex); +register_failed: + return ret; +} +EXPORT_SYMBOL(mpq_adapter_register_stream_if); + + +int mpq_adapter_unregister_stream_if( + enum mpq_adapter_stream_if interface_id) +{ + if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) + return -EINVAL; + + if (mutex_lock_interruptible(&mpq_info.mutex)) + return -ERESTARTSYS; + + /* clear the registered interface */ + mpq_info.interfaces[interface_id].stream_buffer = NULL; + + mutex_unlock(&mpq_info.mutex); + + return 0; +} +EXPORT_SYMBOL(mpq_adapter_unregister_stream_if); + + +int mpq_adapter_get_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer **stream_buffer) +{ + if ((interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) || + (stream_buffer == NULL)) + return -EINVAL; + + if (mutex_lock_interruptible(&mpq_info.mutex)) + return -ERESTARTSYS; + + *stream_buffer = mpq_info.interfaces[interface_id].stream_buffer; + + mutex_unlock(&mpq_info.mutex); + + return 0; +} +EXPORT_SYMBOL(mpq_adapter_get_stream_if); + + +int mpq_adapter_notify_stream_if( + enum mpq_adapter_stream_if interface_id, + mpq_adapter_stream_if_callback callback, + void *user_param) +{ + if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) + return -EINVAL; + + if (mutex_lock_interruptible(&mpq_info.mutex)) + return -ERESTARTSYS; + + mpq_info.interfaces[interface_id].callback = callback; + mpq_info.interfaces[interface_id].user_param = user_param; + + mutex_unlock(&mpq_info.mutex); + + return 0; +} +EXPORT_SYMBOL(mpq_adapter_notify_stream_if); + + +module_init(mpq_adapter_init); +module_exit(mpq_adapter_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. MPQ adapter"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c new file mode 100644 index 0000000000000000000000000000000000000000..2fb0fb67bd7a42860a5d923a855ff8561a64d7e7 --- /dev/null +++ b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c @@ -0,0 +1,825 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 +#include +#include +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_stream_buffer.h" + + +int mpq_streambuffer_init( + struct mpq_streambuffer *sbuff, + enum mpq_streambuffer_mode mode, + struct mpq_streambuffer_buffer_desc *data_buffers, + u32 data_buff_num, + void *packet_buff, + size_t packet_buff_size) +{ + if ((sbuff == NULL) || (data_buffers == NULL) || + (packet_buff == NULL) || (data_buff_num == 0)) + return -EINVAL; + + if (data_buff_num > 1) { + if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + return -EINVAL; + /* Linear buffer group */ + dvb_ringbuffer_init( + &sbuff->raw_data, + data_buffers, + data_buff_num * + sizeof(struct mpq_streambuffer_buffer_desc)); + } else { + if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING) + return -EINVAL; + /* Single ring-buffer */ + dvb_ringbuffer_init(&sbuff->raw_data, + data_buffers[0].base, data_buffers[0].size); + } + sbuff->mode = mode; + sbuff->buffers = data_buffers; + sbuff->pending_buffers_count = 0; + sbuff->buffers_num = data_buff_num; + sbuff->cb = NULL; + dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_init); + +void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff) +{ + spin_lock(&sbuff->packet_data.lock); + spin_lock(&sbuff->raw_data.lock); + sbuff->packet_data.error = -ENODEV; + sbuff->raw_data.error = -ENODEV; + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + + wake_up_all(&sbuff->raw_data.queue); + wake_up_all(&sbuff->packet_data.queue); +} +EXPORT_SYMBOL(mpq_streambuffer_terminate); + +ssize_t mpq_streambuffer_pkt_next( + struct mpq_streambuffer *sbuff, + ssize_t idx, size_t *pktlen) +{ + ssize_t packet_idx; + + spin_lock(&sbuff->packet_data.lock); + + /* buffer was released, return no packet available */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + packet_idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen); + spin_unlock(&sbuff->packet_data.lock); + + return packet_idx; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_next); + + +ssize_t mpq_streambuffer_pkt_read( + struct mpq_streambuffer *sbuff, + size_t idx, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data) +{ + int ret; + size_t read_len; + + spin_lock(&sbuff->packet_data.lock); + + /* buffer was released, return no packet available */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* read-out the packet header first */ + ret = dvb_ringbuffer_pkt_read( + &sbuff->packet_data, idx, 0, + (u8 *)packet, + sizeof(struct mpq_streambuffer_packet_header)); + + /* verify length, at least packet header should exist */ + if (ret != sizeof(struct mpq_streambuffer_packet_header)) { + spin_unlock(&sbuff->packet_data.lock); + return -EINVAL; + } + + read_len = ret; + + /* read-out private user-data if there are such */ + if ((packet->user_data_len) && (user_data != NULL)) { + ret = dvb_ringbuffer_pkt_read( + &sbuff->packet_data, + idx, + sizeof(struct mpq_streambuffer_packet_header), + user_data, + packet->user_data_len); + + if (ret < 0) { + spin_unlock(&sbuff->packet_data.lock); + return ret; + } + + read_len += ret; + } + + spin_unlock(&sbuff->packet_data.lock); + + return read_len; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_read); + + +int mpq_streambuffer_pkt_dispose( + struct mpq_streambuffer *sbuff, + size_t idx, + int dispose_data) +{ + int ret; + struct mpq_streambuffer_packet_header packet; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + + /* check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* read-out the packet header first */ + ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx, + 0, + (u8 *)&packet, + sizeof(struct mpq_streambuffer_packet_header)); + + spin_unlock(&sbuff->packet_data.lock); + + if (ret != sizeof(struct mpq_streambuffer_packet_header)) + return -EINVAL; + + if ((sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) || + (dispose_data)) { + /* Advance the read pointer in the raw-data buffer first */ + ret = mpq_streambuffer_data_read_dispose(sbuff, + packet.raw_data_len); + if (ret != 0) + return ret; + } + + spin_lock(&sbuff->packet_data.lock); + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if ((sbuff->packet_data.error == -ENODEV) || + (sbuff->raw_data.error == -ENODEV)) { + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* Move read pointer to the next linear buffer for subsequent reads */ + if ((sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) && + (packet.raw_data_len > 0)) { + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + desc->write_ptr = 0; + desc->read_ptr = 0; + + DVB_RINGBUFFER_SKIP(&sbuff->raw_data, + sizeof(struct mpq_streambuffer_buffer_desc)); + sbuff->pending_buffers_count--; + + wake_up_all(&sbuff->raw_data.queue); + } + + /* Now clear the packet from the packet header */ + dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx); + + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose); + +int mpq_streambuffer_pkt_write( + struct mpq_streambuffer *sbuff, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data) +{ + ssize_t idx; + size_t len; + + if ((sbuff == NULL) || (packet == NULL)) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + + /* check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* Make sure we can go to the next linear buffer */ + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR && + sbuff->pending_buffers_count == sbuff->buffers_num && + packet->raw_data_len) { + spin_unlock(&sbuff->packet_data.lock); + return -ENOSPC; + } + + len = sizeof(struct mpq_streambuffer_packet_header) + + packet->user_data_len; + + /* Make sure enough space available for packet header */ + if (dvb_ringbuffer_free(&sbuff->packet_data) < + (len + DVB_RINGBUFFER_PKTHDRSIZE)) { + spin_unlock(&sbuff->packet_data.lock); + return -ENOSPC; + } + + /* Starting writing packet header */ + idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len); + + /* Write non-user private data header */ + dvb_ringbuffer_write(&sbuff->packet_data, + (u8 *)packet, + sizeof(struct mpq_streambuffer_packet_header)); + + /* Write user's own private data header */ + dvb_ringbuffer_write(&sbuff->packet_data, + user_data, + packet->user_data_len); + + dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx); + + /* Move write pointer to next linear buffer for subsequent writes */ + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR && + packet->raw_data_len) { + DVB_RINGBUFFER_PUSH(&sbuff->raw_data, + sizeof(struct mpq_streambuffer_buffer_desc)); + sbuff->pending_buffers_count++; + } + + spin_unlock(&sbuff->packet_data.lock); + wake_up_all(&sbuff->packet_data.queue); + + return idx; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_write); + +ssize_t mpq_streambuffer_data_write( + struct mpq_streambuffer *sbuff, + const u8 *buf, size_t len) +{ + int res; + + if ((sbuff == NULL) || (buf == NULL)) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) { + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (sbuff->raw_data.data == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (desc->base == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + + if ((sbuff->pending_buffers_count == sbuff->buffers_num) || + ((desc->size - desc->write_ptr) < len)) { + MPQ_DVB_DBG_PRINT( + "%s: No space available %d pending buffers out of %d", + __func__, + sbuff->pending_buffers_count, + sbuff->buffers_num); + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + memcpy(desc->base + desc->write_ptr, buf, len); + desc->write_ptr += len; + res = len; + } + + spin_unlock(&sbuff->raw_data.lock); + return res; +} +EXPORT_SYMBOL(mpq_streambuffer_data_write); + + +int mpq_streambuffer_data_write_deposit( + struct mpq_streambuffer *sbuff, + size_t len) +{ + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) { + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + + DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc = + (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + + if ((sbuff->pending_buffers_count == sbuff->buffers_num) || + ((desc->size - desc->write_ptr) < len)) { + MPQ_DVB_ERR_PRINT( + "%s: No space available\n", + __func__); + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + desc->write_ptr += len; + } + + spin_unlock(&sbuff->raw_data.lock); + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit); + + +ssize_t mpq_streambuffer_data_read( + struct mpq_streambuffer *sbuff, + u8 *buf, size_t len) +{ + ssize_t actual_len = 0; + u32 offset; + + if ((sbuff == NULL) || (buf == NULL)) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (sbuff->raw_data.data == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + + offset = sbuff->raw_data.pread; + actual_len = dvb_ringbuffer_avail(&sbuff->raw_data); + if (actual_len < len) + len = actual_len; + if (len) + dvb_ringbuffer_read(&sbuff->raw_data, buf, len); + + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (desc->base == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + + actual_len = (desc->write_ptr - desc->read_ptr); + if (actual_len < len) + len = actual_len; + memcpy(buf, desc->base + desc->read_ptr, len); + offset = desc->read_ptr; + desc->read_ptr += len; + } + + spin_unlock(&sbuff->raw_data.lock); + + if (sbuff->cb) + sbuff->cb(sbuff, offset, len, sbuff->cb_user_data); + + return len; +} +EXPORT_SYMBOL(mpq_streambuffer_data_read); + + +ssize_t mpq_streambuffer_data_read_user( + struct mpq_streambuffer *sbuff, + u8 __user *buf, size_t len) +{ + ssize_t actual_len = 0; + u32 offset; + + if ((sbuff == NULL) || (buf == NULL)) + return -EINVAL; + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) + return -ENODEV; + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (sbuff->raw_data.data == NULL) + return -EPERM; + + offset = sbuff->raw_data.pread; + actual_len = dvb_ringbuffer_avail(&sbuff->raw_data); + if (actual_len < len) + len = actual_len; + if (len) + dvb_ringbuffer_read_user(&sbuff->raw_data, buf, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (desc->base == NULL) + return -EPERM; + + actual_len = (desc->write_ptr - desc->read_ptr); + if (actual_len < len) + len = actual_len; + if (copy_to_user(buf, desc->base + desc->read_ptr, len)) + return -EFAULT; + + offset = desc->read_ptr; + desc->read_ptr += len; + } + + if (sbuff->cb) + sbuff->cb(sbuff, offset, len, sbuff->cb_user_data); + + return len; +} +EXPORT_SYMBOL(mpq_streambuffer_data_read_user); + +int mpq_streambuffer_data_read_dispose( + struct mpq_streambuffer *sbuff, + size_t len) +{ + u32 offset; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len)) { + spin_unlock(&sbuff->raw_data.lock); + return -EINVAL; + } + + offset = sbuff->raw_data.pread; + DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + offset = desc->read_ptr; + + if ((desc->read_ptr + len) > desc->size) + desc->read_ptr = desc->size; + else + desc->read_ptr += len; + } + + spin_unlock(&sbuff->raw_data.lock); + + if (sbuff->cb) + sbuff->cb(sbuff, offset, len, sbuff->cb_user_data); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose); + + +int mpq_streambuffer_get_buffer_handle( + struct mpq_streambuffer *sbuff, + int read_buffer, + int *handle) +{ + struct mpq_streambuffer_buffer_desc *desc = NULL; + + if ((sbuff == NULL) || (handle == NULL)) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + *handle = sbuff->buffers[0].handle; + } else { + if (read_buffer) + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + else + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + *handle = desc->handle; + } + + spin_unlock(&sbuff->raw_data.lock); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle); + + +int mpq_streambuffer_register_data_dispose( + struct mpq_streambuffer *sbuff, + mpq_streambuffer_dispose_cb cb_func, + void *user_data) +{ + if ((sbuff == NULL) || (cb_func == NULL)) + return -EINVAL; + + sbuff->cb = cb_func; + sbuff->cb_user_data = user_data; + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_register_data_dispose); + + +ssize_t mpq_streambuffer_data_free( + struct mpq_streambuffer *sbuff) +{ + struct mpq_streambuffer_buffer_desc *desc; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + spin_unlock(&sbuff->raw_data.lock); + return dvb_ringbuffer_free(&sbuff->raw_data); + } + + if (sbuff->pending_buffers_count == sbuff->buffers_num) { + spin_unlock(&sbuff->raw_data.lock); + return 0; + } + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + + spin_unlock(&sbuff->raw_data.lock); + + return desc->size - desc->write_ptr; +} +EXPORT_SYMBOL(mpq_streambuffer_data_free); + + +ssize_t mpq_streambuffer_data_avail( + struct mpq_streambuffer *sbuff) +{ + struct mpq_streambuffer_buffer_desc *desc; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + ssize_t avail = dvb_ringbuffer_avail(&sbuff->raw_data); + + spin_unlock(&sbuff->raw_data.lock); + return avail; + } + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + spin_unlock(&sbuff->raw_data.lock); + + return desc->write_ptr - desc->read_ptr; +} +EXPORT_SYMBOL(mpq_streambuffer_data_avail); + +int mpq_streambuffer_get_data_rw_offset( + struct mpq_streambuffer *sbuff, + u32 *read_offset, + u32 *write_offset) +{ + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (read_offset) + *read_offset = sbuff->raw_data.pread; + if (write_offset) + *write_offset = sbuff->raw_data.pwrite; + } else { + struct mpq_streambuffer_buffer_desc *desc; + + if (read_offset) { + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + *read_offset = desc->read_ptr; + } + if (write_offset) { + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + *write_offset = desc->write_ptr; + } + } + + spin_unlock(&sbuff->raw_data.lock); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_get_data_rw_offset); + +ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff) +{ + ssize_t free; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + + /* check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + free = dvb_ringbuffer_free(&sbuff->packet_data); + + spin_unlock(&sbuff->packet_data.lock); + + return free; +} +EXPORT_SYMBOL(mpq_streambuffer_metadata_free); + +int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff) +{ + struct mpq_streambuffer_buffer_desc *desc; + size_t len; + int idx; + int ret = 0; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + spin_lock(&sbuff->raw_data.lock); + + /* Check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV || + sbuff->raw_data.error == -ENODEV) { + ret = -ENODEV; + goto end; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + while (sbuff->pending_buffers_count) { + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + desc->write_ptr = 0; + desc->read_ptr = 0; + DVB_RINGBUFFER_SKIP(&sbuff->raw_data, + sizeof(struct mpq_streambuffer_buffer_desc)); + sbuff->pending_buffers_count--; + } + else + dvb_ringbuffer_flush(&sbuff->raw_data); + + /* + * Dispose all packets (simply flushing is not enough since we want + * the packets' status to move to disposed). + */ + do { + idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, -1, &len); + if (idx >= 0) + dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx); + } while (idx >= 0); + +end: + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + return ret; +} +EXPORT_SYMBOL(mpq_streambuffer_flush); diff --git a/drivers/media/platform/msm/dvb/demux/Kconfig b/drivers/media/platform/msm/dvb/demux/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..5b10e2ff36b00e519a023b8dda2fb1bec28e3f58 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/Kconfig @@ -0,0 +1,38 @@ +comment "Qualcomm Technologies, Inc. Demux device config" +menuconfig DVB_MPQ_DEMUX + tristate "DVB Demux Device" + depends on DVB_MPQ && ION + default n + + help + Support for Qualcomm Technologies Inc based dvb demux device. + Say Y if you own such a device and want to use it. + The Demux device is used to stream playback either + from TSIF interface or from DVR interface. + +config DVB_MPQ_NUM_DMX_DEVICES + int "Number of demux devices" + depends on DVB_MPQ_DEMUX + default 4 + range 1 255 + + help + Configure number of demux devices. + Depends on your use-cases for maximum concurrent stream playback. + +config DVB_MPQ_TSPP1 + bool "TSPPv1 plugin" + depends on DVB_MPQ_DEMUX && TSPP + help + Use this option if your HW has + Transport Stream Packet Processor(TSPP) version1 support. + Demux may take adavantage of HW capabilities to perform + some tasks in HW instead of SW. + +config DVB_MPQ_SW + bool "Software plugin" + depends on DVB_MPQ_DEMUX && !DVB_MPQ_TSPP1 + help + Use this option if your HW does not have any + TSPP hardware support. All demux tasks will be + performed in SW. diff --git a/drivers/media/platform/msm/dvb/demux/Makefile b/drivers/media/platform/msm/dvb/demux/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c08fa85a8d5d644e257122a13e683c060be83b66 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/Makefile @@ -0,0 +1,14 @@ + +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/platform/msm/dvb/include/ +ccflags-y += -Idrivers/misc/ + +obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o + +mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o + +mpq-dmx-hw-plugin-$(CONFIG_QSEECOM) += mpq_sdmx.o + +mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o + +mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_SW) += mpq_dmx_plugin_sw.o diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c new file mode 100644 index 0000000000000000000000000000000000000000..06d05f9512aff0a928d7ab34b41074b26e67277a --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c @@ -0,0 +1,5204 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 +#include +#include +#include +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_dmx_plugin_common.h" +#include "mpq_sdmx.h" +#include +#include +#include +#include +#include + +#define SDMX_MAJOR_VERSION_MATCH (8) + +/* Length of mandatory fields that must exist in header of video PES */ +#define PES_MANDATORY_FIELDS_LEN 9 + +/* Index of first byte in TS packet holding STC */ +#define STC_LOCATION_IDX 188 + +#define MAX_PES_LENGTH (SZ_64K) + +#define MAX_TS_PACKETS_FOR_SDMX_PROCESS (500) + +/* + * PES header length field is 8 bits so PES header length after this field + * can be up to 256 bytes. + * Preceding fields of the PES header total to 9 bytes + * (including the PES header length field). + */ +#define MAX_PES_HEADER_LENGTH (256 + PES_MANDATORY_FIELDS_LEN) + +/* TS packet with adaptation field only can take up the entire TSP */ +#define MAX_TSP_ADAPTATION_LENGTH (184) + +#define MAX_SDMX_METADATA_LENGTH \ + (TS_PACKET_HEADER_LENGTH + \ + MAX_TSP_ADAPTATION_LENGTH + \ + MAX_PES_HEADER_LENGTH) + +#define SDMX_METADATA_BUFFER_SIZE (64*1024) +#define SDMX_SECTION_BUFFER_SIZE (64*1024) +#define SDMX_PCR_BUFFER_SIZE (64*1024) + +/* Number of demux devices, has default of linux configuration */ +static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; +module_param(mpq_demux_device_num, int, 0444); + +/* ION heap IDs used for allocating video output buffer */ +static int video_secure_ion_heap = ION_CP_MM_HEAP_ID; +module_param(video_secure_ion_heap, int, 0644); +MODULE_PARM_DESC(video_secure_ion_heap, + "ION heap for secure video buffer allocation"); + +static int video_nonsecure_ion_heap = ION_SYSTEM_HEAP_ID; +module_param(video_nonsecure_ion_heap, int, 0644); +MODULE_PARM_DESC(video_nonsecure_ion_heap, + "ION heap for non-secure video buffer allocation"); + +/* Value of TS packet scramble bits field for even key */ +static int mpq_sdmx_scramble_even = 0x2; +module_param(mpq_sdmx_scramble_even, int, 0644); + +/* Value of TS packet scramble bits field for odd key */ +static int mpq_sdmx_scramble_odd = 0x3; +module_param(mpq_sdmx_scramble_odd, int, 0644); + +/* + * Default action (discard or pass) taken when scramble bit is not one of the + * pass-through / odd / even values. + * When set packets will be discarded, otherwise passed through. + */ +static int mpq_sdmx_scramble_default_discard = 1; +module_param(mpq_sdmx_scramble_default_discard, int, 0644); + +/* Max number of TS packets allowed as input for a single sdmx process */ +static int mpq_sdmx_proc_limit = MAX_TS_PACKETS_FOR_SDMX_PROCESS; +module_param(mpq_sdmx_proc_limit, int, 0644); + +/* Debug flag for secure demux process */ +static int mpq_sdmx_debug; +module_param(mpq_sdmx_debug, int, 0644); + +/* + * Indicates whether the demux should search for frame boundaries + * and notify on video packets on frame-basis or whether to provide + * only video PES packet payloads as-is. + */ +static int video_framing = 1; +module_param(video_framing, int, 0644); + +/* TSIF operation mode: 1 = TSIF_MODE_1, 2 = TSIF_MODE_2, 3 = TSIF_LOOPBACK */ +static int tsif_mode = 2; +module_param(tsif_mode, int, 0644); + +/* Inverse TSIF clock signal */ +static int clock_inv; +module_param(clock_inv, int, 0644); + +/* Global data-structure for managing demux devices */ +static struct +{ + /* ION demux client used for memory allocation */ + struct ion_client *ion_client; + + /* demux devices array */ + struct mpq_demux *devices; + + /* Stream buffers objects used for tunneling to decoders */ + struct mpq_streambuffer + decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES]; + + /* Indicates whether secure demux TZ application is available */ + int secure_demux_app_loaded; +} mpq_dmx_info; + + +int mpq_dmx_get_param_scramble_odd(void) +{ + return mpq_sdmx_scramble_odd; +} + +int mpq_dmx_get_param_scramble_even(void) +{ + return mpq_sdmx_scramble_even; +} + +int mpq_dmx_get_param_scramble_default_discard(void) +{ + return mpq_sdmx_scramble_default_discard; +} + +int mpq_dmx_get_param_tsif_mode(void) +{ + return tsif_mode; +} + +int mpq_dmx_get_param_clock_inv(void) +{ + return clock_inv; +} + +/* Check that PES header is valid and that it is a video PES */ +static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header) +{ + /* start-code valid? */ + if ((pes_header->packet_start_code_prefix_1 != 0) || + (pes_header->packet_start_code_prefix_2 != 0) || + (pes_header->packet_start_code_prefix_3 != 1)) + return -EINVAL; + + /* stream_id is video? */ + if ((pes_header->stream_id & 0xF0) != 0xE0) + return -EINVAL; + + return 0; +} + +/* Check if a framing pattern is a video frame pattern or a header pattern */ +static inline int mpq_dmx_is_video_frame( + enum dmx_video_codec codec, + u64 pattern_type) +{ + switch (codec) { + case DMX_VIDEO_CODEC_MPEG2: + if ((pattern_type == DMX_IDX_MPEG_I_FRAME_START) || + (pattern_type == DMX_IDX_MPEG_P_FRAME_START) || + (pattern_type == DMX_IDX_MPEG_B_FRAME_START)) + return 1; + return 0; + + case DMX_VIDEO_CODEC_H264: + if ((pattern_type == DMX_IDX_H264_IDR_START) || + (pattern_type == DMX_IDX_H264_NON_IDR_START)) + return 1; + return 0; + + case DMX_VIDEO_CODEC_VC1: + if (pattern_type == DMX_IDX_VC1_FRAME_START) + return 1; + return 0; + + default: + return -EINVAL; + } +} + +/* + * mpq_dmx_get_pattern_params - Returns the required video + * patterns for framing operation based on video codec. + * + * @video_codec: the video codec. + * @patterns: a pointer to the pattern parameters, updated by this function. + * @patterns_num: number of patterns, updated by this function. + */ +static inline int mpq_dmx_get_pattern_params( + enum dmx_video_codec video_codec, + const struct dvb_dmx_video_patterns + *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM], + int *patterns_num) +{ + switch (video_codec) { + case DMX_VIDEO_CODEC_MPEG2: + patterns[0] = dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER); + patterns[1] = dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP); + patterns[2] = dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START); + patterns[3] = dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START); + patterns[4] = dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START); + *patterns_num = 5; + break; + + case DMX_VIDEO_CODEC_H264: + patterns[0] = dvb_dmx_get_pattern(DMX_IDX_H264_SPS); + patterns[1] = dvb_dmx_get_pattern(DMX_IDX_H264_PPS); + patterns[2] = dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START); + patterns[3] = dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START); + patterns[4] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI); + *patterns_num = 5; + break; + + case DMX_VIDEO_CODEC_VC1: + patterns[0] = dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER); + patterns[1] = dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT); + patterns[2] = dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START); + *patterns_num = 3; + break; + + default: + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + *patterns_num = 0; + return -EINVAL; + } + + return 0; +} + +static int mpq_dmx_dmabuf_map(int ion_fd, struct sg_table **sgt, + struct dma_buf_attachment **attach, + struct dma_buf **dmabuf) +{ + struct dma_buf *new_dma_buf = NULL; + struct dma_buf_attachment *new_attach = NULL; + struct sg_table *new_sgt = NULL; + int ret = 0; + + new_dma_buf = dma_buf_get(ion_fd); + if (new_dma_buf == NULL) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_get() for ion_fd %d failed\n", + __func__, ion_fd); + ret = -ENOMEM; + goto err; + } + + new_attach = dma_buf_attach(new_dma_buf, + &mpq_dmx_info.devices[0].pdev->dev); + + if (IS_ERR(new_attach)) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_attach() for ion_fd %d failed\n", + __func__, ion_fd); + ret = -ENOMEM; + goto err_put; + } + + new_sgt = dma_buf_map_attachment(new_attach, DMA_BIDIRECTIONAL); + if (IS_ERR(new_sgt)) { + ret = PTR_ERR(new_sgt); + MPQ_DVB_ERR_PRINT( + "%s: dma_buf_map_attachment for ion_fd %d failed ret = %d\n", + __func__, ion_fd, ret); + goto err_detach; + } + *sgt = new_sgt; + *attach = new_attach; + *dmabuf = new_dma_buf; + + return ret; + +err_detach: + dma_buf_detach(new_dma_buf, new_attach); +err_put: + dma_buf_put(new_dma_buf); +err: + return ret; +} + +static void mpq_dmx_dmabuf_unmap(struct sg_table *sgt, + struct dma_buf_attachment *attach, + struct dma_buf *dmabuf) +{ + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); + dma_buf_detach(dmabuf, attach); + dma_buf_put(dmabuf); +} + +/* convert ion_fd to phys_adds and virt_addr*/ +static int mpq_dmx_vaddr_map(int ion_fd, + phys_addr_t *paddr, void **vaddr, + struct sg_table **sgt, + struct dma_buf_attachment **attach, + size_t *sb_length, struct dma_buf **dmabuf) +{ + struct dma_buf *new_dma_buf = NULL; + struct dma_buf_attachment *new_attach = NULL; + struct sg_table *new_sgt = NULL; + void *new_va = NULL; + int ret = 0; + + ret = mpq_dmx_dmabuf_map(ion_fd, &new_sgt, &new_attach, &new_dma_buf); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: qseecom_dmabuf_map for ion_fd %d failed ret = %d\n", + __func__, ion_fd, ret); + goto err; + } + + *paddr = sg_dma_address(new_sgt->sgl); + *sb_length = new_sgt->sgl->length; + + dma_buf_begin_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); + /* TODO: changing kmap to vmap otherwise you need to map + * each 4K chunk need to be mapped and stored its address; + */ + new_va = dma_buf_vmap(new_dma_buf); + if (!new_va) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_kmap failed\n", __func__); + ret = -ENOMEM; + goto err_unmap; + } + *dmabuf = new_dma_buf; + *attach = new_attach; + *sgt = new_sgt; + *vaddr = new_va; + return ret; + +err_unmap: + MPQ_DVB_ERR_PRINT("%s Map fail\n", __func__); + dma_buf_end_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(new_sgt, new_attach, new_dma_buf); +err: + MPQ_DVB_ERR_PRINT("%s Init fail\n", __func__); + return ret; +} + +static void mpq_dmx_vaddr_unmap(void *vaddr, struct sg_table *sgt, + struct dma_buf_attachment *attach, + struct dma_buf *dmabuf) +{ + dma_buf_vunmap(dmabuf, vaddr); + dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(sgt, attach, dmabuf); +} + +static int mpq_dmx_paddr_map(int ion_fd, + phys_addr_t *paddr, + struct sg_table **sgt, + struct dma_buf_attachment **attach, + size_t *sb_length, struct dma_buf **dmabuf) +{ + struct dma_buf *new_dma_buf = NULL; + struct dma_buf_attachment *new_attach = NULL; + struct sg_table *new_sgt = NULL; + int ret = 0; + + ret = mpq_dmx_dmabuf_map(ion_fd, &new_sgt, &new_attach, &new_dma_buf); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: qseecom_dmabuf_map for ion_fd %d failed ret = %d\n", + __func__, ion_fd, ret); + goto err; + } + + *paddr = sg_dma_address(new_sgt->sgl); + *sb_length = new_sgt->sgl->length; + + dma_buf_begin_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); + *dmabuf = new_dma_buf; + *attach = new_attach; + *sgt = new_sgt; + return ret; + +err: + return ret; +} + +static void mpq_dmx_paddr_unmap(struct sg_table *sgt, + struct dma_buf_attachment *attach, + struct dma_buf *dmabuf) +{ + dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(sgt, attach, dmabuf); +} + +/* + * mpq_dmx_update_decoder_stat - + * Update decoder output statistics in debug-fs. + * + * @mpq_feed: decoder feed object + */ +void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed) +{ + ktime_t curr_time; + u32 delta_time_ms; + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + enum mpq_adapter_stream_if idx; + + if (!dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed)) + return; + + if (mpq_feed->video_info.stream_interface <= + MPQ_ADAPTER_VIDEO3_STREAM_IF) + idx = mpq_feed->video_info.stream_interface; + else + return; + + curr_time = ktime_get(); + if (unlikely(!mpq_demux->decoder_stat[idx].out_count)) { + mpq_demux->decoder_stat[idx].out_last_time = curr_time; + mpq_demux->decoder_stat[idx].out_count++; + return; + } + + /* calculate time-delta between frame */ + delta_time_ms = mpq_dmx_calc_time_delta(curr_time, + mpq_demux->decoder_stat[idx].out_last_time); + + mpq_demux->decoder_stat[idx].out_interval_sum += delta_time_ms; + + mpq_demux->decoder_stat[idx].out_interval_average = + mpq_demux->decoder_stat[idx].out_interval_sum / + mpq_demux->decoder_stat[idx].out_count; + + if (delta_time_ms > mpq_demux->decoder_stat[idx].out_interval_max) + mpq_demux->decoder_stat[idx].out_interval_max = delta_time_ms; + + mpq_demux->decoder_stat[idx].out_last_time = curr_time; + mpq_demux->decoder_stat[idx].out_count++; +} + +/* + * mpq_dmx_update_sdmx_stat - + * Update SDMX statistics in debug-fs. + * + * @mpq_demux: mpq_demux object + * @bytes_processed: number of bytes processed by sdmx + * @process_start_time: time before sdmx process was triggered + * @process_end_time: time after sdmx process finished + */ +static inline void mpq_dmx_update_sdmx_stat(struct mpq_demux *mpq_demux, + u32 bytes_processed, ktime_t process_start_time, + ktime_t process_end_time) +{ + u32 packets_num; + u32 process_time; + + mpq_demux->sdmx_process_count++; + packets_num = bytes_processed / mpq_demux->demux.ts_packet_size; + mpq_demux->sdmx_process_packets_sum += packets_num; + mpq_demux->sdmx_process_packets_average = + mpq_demux->sdmx_process_packets_sum / + mpq_demux->sdmx_process_count; + + process_time = + mpq_dmx_calc_time_delta(process_end_time, process_start_time); + + mpq_demux->sdmx_process_time_sum += process_time; + mpq_demux->sdmx_process_time_average = + mpq_demux->sdmx_process_time_sum / + mpq_demux->sdmx_process_count; + + if ((mpq_demux->sdmx_process_count == 1) || + (packets_num < mpq_demux->sdmx_process_packets_min)) + mpq_demux->sdmx_process_packets_min = packets_num; + + if ((mpq_demux->sdmx_process_count == 1) || + (process_time > mpq_demux->sdmx_process_time_max)) + mpq_demux->sdmx_process_time_max = process_time; +} + +static int mpq_sdmx_log_level_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t mpq_sdmx_log_level_read(struct file *fp, + char __user *user_buffer, size_t count, loff_t *position) +{ + char user_str[16]; + struct mpq_demux *mpq_demux = fp->private_data; + int ret; + + ret = scnprintf(user_str, 16, "%d", mpq_demux->sdmx_log_level); + ret = simple_read_from_buffer(user_buffer, count, position, + user_str, ret+1); + + return ret; +} + +static ssize_t mpq_sdmx_log_level_write(struct file *fp, + const char __user *user_buffer, size_t count, loff_t *position) +{ + char user_str[16]; + int ret; + int ret_count; + int level; + struct mpq_demux *mpq_demux = fp->private_data; + + if (count == 0 || count >= 16) + return -EINVAL; + + memset(user_str, '\0', sizeof(user_str)); + + ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer, + count); + if (ret_count < 0) + return ret_count; + else if (ret_count == 0) + return -EINVAL; + + ret = kstrtoint(user_str, 0, &level); + if (ret) + return ret; + + if (level < SDMX_LOG_NO_PRINT || level > SDMX_LOG_VERBOSE) + return -EINVAL; + + mutex_lock(&mpq_demux->mutex); + mpq_demux->sdmx_log_level = level; + if (mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) { + ret = sdmx_set_log_level(mpq_demux->sdmx_session_handle, + mpq_demux->sdmx_log_level); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Could not set sdmx log level. ret = %d\n", + __func__, ret); + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + } + + mutex_unlock(&mpq_demux->mutex); + return ret_count; +} + +static const struct file_operations sdmx_debug_fops = { + .open = mpq_sdmx_log_level_open, + .read = mpq_sdmx_log_level_read, + .write = mpq_sdmx_log_level_write, + .owner = THIS_MODULE, +}; + +/* Extend dvb-demux debugfs with common plug-in entries */ +void mpq_dmx_init_debugfs_entries(struct mpq_demux *mpq_demux) +{ + int i; + char file_name[50]; + struct dentry *debugfs_decoder_dir; + + /* + * Extend dvb-demux debugfs with HW statistics. + * Note that destruction of debugfs directory is done + * when dvb-demux is terminated. + */ + mpq_demux->hw_notification_count = 0; + mpq_demux->hw_notification_interval = 0; + mpq_demux->hw_notification_size = 0; + mpq_demux->hw_notification_min_size = 0xFFFFFFFF; + + if (mpq_demux->demux.dmx.debugfs_demux_dir == NULL) + return; + + debugfs_create_u32( + "hw_notification_interval", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_interval); + + debugfs_create_u32( + "hw_notification_min_interval", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_min_interval); + + debugfs_create_u32( + "hw_notification_count", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_count); + + debugfs_create_u32( + "hw_notification_size", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_size); + + debugfs_create_u32( + "hw_notification_min_size", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_min_size); + + debugfs_decoder_dir = debugfs_create_dir("decoder", + mpq_demux->demux.dmx.debugfs_demux_dir); + + for (i = 0; + debugfs_decoder_dir && + (i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES); + i++) { + snprintf(file_name, 50, "decoder%d_drop_count", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].drop_count); + + snprintf(file_name, 50, "decoder%d_out_count", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_count); + + snprintf(file_name, 50, "decoder%d_out_interval_sum", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_interval_sum); + + snprintf(file_name, 50, "decoder%d_out_interval_average", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_interval_average); + + snprintf(file_name, 50, "decoder%d_out_interval_max", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_interval_max); + + snprintf(file_name, 50, "decoder%d_ts_errors", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].ts_errors); + + snprintf(file_name, 50, "decoder%d_cc_errors", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].cc_errors); + } + + debugfs_create_u32( + "sdmx_process_count", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_count); + + debugfs_create_u32( + "sdmx_process_time_sum", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_time_sum); + + debugfs_create_u32( + "sdmx_process_time_average", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_time_average); + + debugfs_create_u32( + "sdmx_process_time_max", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_time_max); + + debugfs_create_u32( + "sdmx_process_packets_sum", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_packets_sum); + + debugfs_create_u32( + "sdmx_process_packets_average", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_packets_average); + + debugfs_create_u32( + "sdmx_process_packets_min", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_packets_min); + + debugfs_create_file("sdmx_log_level", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + mpq_demux, + &sdmx_debug_fops); +} + +/* Update dvb-demux debugfs with HW notification statistics */ +void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux) +{ + ktime_t curr_time; + u32 delta_time_ms; + + curr_time = ktime_get(); + if (likely(mpq_demux->hw_notification_count)) { + /* calculate time-delta between notifications */ + delta_time_ms = mpq_dmx_calc_time_delta(curr_time, + mpq_demux->last_notification_time); + + mpq_demux->hw_notification_interval = delta_time_ms; + + if ((mpq_demux->hw_notification_count == 1) || + (mpq_demux->hw_notification_interval && + mpq_demux->hw_notification_interval < + mpq_demux->hw_notification_min_interval)) + mpq_demux->hw_notification_min_interval = + mpq_demux->hw_notification_interval; + } + + mpq_demux->hw_notification_count++; + mpq_demux->last_notification_time = curr_time; +} + +static void mpq_sdmx_check_app_loaded(void) +{ + int session; + u32 version; + int ret; + + ret = sdmx_open_session(&session); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT( + "%s: Could not initialize session with SDMX. ret = %d\n", + __func__, ret); + mpq_dmx_info.secure_demux_app_loaded = 0; + return; + } + + /* Check proper sdmx major version */ + ret = sdmx_get_version(session, &version); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT( + "%s: Could not get sdmx version. ret = %d\n", + __func__, ret); + } else { + if ((version >> 8) != SDMX_MAJOR_VERSION_MATCH) { + MPQ_DVB_ERR_PRINT( + "%s: sdmx major version does not match", + __func__); + MPQ_DVB_ERR_PRINT( + "%s: version : expected=%d, actual=%d\n", + __func__, SDMX_MAJOR_VERSION_MATCH, + (version >> 8)); + } else { + MPQ_DVB_DBG_PRINT( + "%s: sdmx major version is ok = %d\n", + __func__, SDMX_MAJOR_VERSION_MATCH); + } + } + + mpq_dmx_info.secure_demux_app_loaded = 1; + sdmx_close_session(session); +} + +int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func, + struct platform_device *pdev) +{ + int i; + int j; + int result; + struct mpq_demux *mpq_demux; + struct dvb_adapter *mpq_adapter; + struct mpq_feed *feed; + + if (pdev == NULL) { + MPQ_DVB_ERR_PRINT("%s: NULL platform device\n", __func__); + return -EINVAL; + } + MPQ_DVB_DBG_PRINT("%s executed, device num %d\n", + __func__, + mpq_demux_device_num); + + mpq_adapter = mpq_adapter_get(); + + if (mpq_adapter == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_adapter is not valid\n", + __func__); + result = -EPERM; + goto init_failed; + } + + if (mpq_demux_device_num == 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_demux_device_num set to 0\n", + __func__); + + result = -EPERM; + goto init_failed; + } + + mpq_dmx_info.devices = NULL; + mpq_dmx_info.ion_client = NULL; + + mpq_dmx_info.secure_demux_app_loaded = 0; + + /* Allocate memory for all MPQ devices */ + mpq_dmx_info.devices = + vzalloc(mpq_demux_device_num*sizeof(struct mpq_demux)); + + if (!mpq_dmx_info.devices) { + result = -ENOMEM; + goto init_failed; + goto init_failed; + } + + /* Initialize and register all demux devices to the system */ + for (i = 0; i < mpq_demux_device_num; i++) { + mpq_demux = mpq_dmx_info.devices+i; + mpq_demux->idx = i; + + /* Set platform device */ + mpq_demux->pdev = pdev; + /* initialize demux source to memory by default */ + mpq_demux->source = DMX_SOURCE_DVR0 + i; + + mutex_init(&mpq_demux->mutex); + + mpq_demux->num_secure_feeds = 0; + mpq_demux->num_active_feeds = 0; + mpq_demux->sdmx_filter_count = 0; + mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE; + mpq_demux->sdmx_eos = 0; + mpq_demux->sdmx_log_level = SDMX_LOG_NO_PRINT; + mpq_demux->ts_packet_timestamp_source = 0; + mpq_demux->disable_cache_ops = 1; + + if (mpq_demux->demux.feednum > MPQ_MAX_DMX_FILES) { + MPQ_DVB_ERR_PRINT( + "%s: actual feednum (%d) larger than MPQ_MAX_DMX_FILES\n", + __func__, + mpq_demux->demux.feednum); + result = -EINVAL; + goto init_failed_free_demux_devices; + } + + /* Initialize private feed info */ + for (j = 0; j < MPQ_MAX_DMX_FILES; j++) { + feed = &mpq_demux->feeds[j]; + memset(feed, 0, sizeof(*feed)); + feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE; + feed->mpq_demux = mpq_demux; + feed->session_id = 0; + } + + /* + * mpq_demux_plugin_hw_init should be implemented + * by the specific plugin + */ + result = dmx_init_func(mpq_adapter, mpq_demux); + if (result < 0) { + MPQ_DVB_ERR_PRINT( + "%s: dmx_init_func (errno=%d)\n", + __func__, + result); + + goto init_failed_free_demux_devices; + } + + mpq_demux->is_initialized = 1; + + /* + * dvb-demux is now initialized, + * update back-pointers of private feeds + */ + for (j = 0; j < MPQ_MAX_DMX_FILES; j++) { + feed = &mpq_demux->feeds[j]; + feed->dvb_demux_feed = &mpq_demux->demux.feed[j]; + mpq_demux->demux.feed[j].priv = feed; + } + + /* + * Add capability of receiving input from memory. + * Every demux in our system may be connected to memory input, + * or any live input. + */ + mpq_demux->fe_memory.source = DMX_MEMORY_FE; + result = + mpq_demux->demux.dmx.add_frontend( + &mpq_demux->demux.dmx, + &mpq_demux->fe_memory); + + if (result < 0) { + MPQ_DVB_ERR_PRINT( + "%s: add_frontend (mem) failed (errno=%d)\n", + __func__, + result); + + goto init_failed_free_demux_devices; + } + } + + return 0; + +init_failed_free_demux_devices: + mpq_dmx_plugin_exit(); +init_failed: + return result; +} + +void mpq_dmx_plugin_exit(void) +{ + int i; + struct mpq_demux *mpq_demux; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + if (mpq_dmx_info.devices != NULL) { + for (i = 0; i < mpq_demux_device_num; i++) { + mpq_demux = mpq_dmx_info.devices + i; + + if (!mpq_demux->is_initialized) + continue; + + if (mpq_demux->mpq_dmx_plugin_release) + mpq_demux->mpq_dmx_plugin_release(mpq_demux); + + mpq_demux->demux.dmx.remove_frontend( + &mpq_demux->demux.dmx, + &mpq_demux->fe_memory); + + if (mpq_dmx_info.secure_demux_app_loaded) + mpq_sdmx_close_session(mpq_demux); + mutex_destroy(&mpq_demux->mutex); + dvb_dmxdev_release(&mpq_demux->dmxdev); + dvb_dmx_release(&mpq_demux->demux); + } + + vfree(mpq_dmx_info.devices); + mpq_dmx_info.devices = NULL; + } +} + +int mpq_dmx_set_source( + struct dmx_demux *demux, + const dmx_source_t *src) +{ + int i; + int dvr_index; + int dmx_index; + struct dvb_demux *dvb_demux = demux->priv; + struct mpq_demux *mpq_demux; + + if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL)) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_demux = dvb_demux->priv; + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + /* + * For dvr sources, + * verify that this source is connected to the respective demux + */ + dmx_index = mpq_demux - mpq_dmx_info.devices; + + if (*src >= DMX_SOURCE_DVR0) { + dvr_index = *src - DMX_SOURCE_DVR0; + + if (dvr_index != dmx_index) { + MPQ_DVB_ERR_PRINT( + "%s: can't connect demux%d to dvr%d\n", + __func__, + dmx_index, + dvr_index); + return -EINVAL; + } + } + + /* + * For front-end sources, + * verify that this source is not already set to different demux + */ + for (i = 0; i < mpq_demux_device_num; i++) { + if ((&mpq_dmx_info.devices[i] != mpq_demux) && + (mpq_dmx_info.devices[i].source == *src)) { + MPQ_DVB_ERR_PRINT( + "%s: demux%d source can't be set\n", + __func__, dmx_index); + MPQ_DVB_ERR_PRINT( + "%s: demux%d occupies this source already\n", + __func__, i); + return -EBUSY; + } + } + + mpq_demux->source = *src; + return 0; +} + +int mpq_dmx_map_buffer(struct dmx_demux *demux, + struct dmx_buffer *dmx_buffer, + struct ion_dma_buff_info *dma_buffer, + void **kernel_mem) +{ + struct dvb_demux *dvb_demux = demux->priv; + struct mpq_demux *mpq_demux; + int ret; + + if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) || + (dmx_buffer == NULL) || (kernel_mem == NULL) || + (dmx_buffer->handle <= 0)) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_demux = dvb_demux->priv; + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + ret = mpq_dmx_vaddr_map(dmx_buffer->handle, &dma_buffer->pa, + &dma_buffer->va, &dma_buffer->sgt, + &dma_buffer->attach, &dma_buffer->len, + &dma_buffer->dmabuf); + if (ret) { + MPQ_DVB_ERR_PRINT("%s: Failed to map vaddr for ion_fd %d\n", + __func__, dmx_buffer->handle); + return -ENOMEM; + } + + if (dma_buffer->va != NULL) { + *kernel_mem = dma_buffer->va; + } else { + MPQ_DVB_ERR_PRINT("%s: Fail to map buffer\n", __func__); + return -ENOMEM; + } + + return 0; +} + +int mpq_dmx_unmap_buffer(struct dmx_demux *demux, + struct ion_dma_buff_info *dma_buffer) +{ + struct dvb_demux *dvb_demux = demux->priv; + struct mpq_demux *mpq_demux; + + if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) || + (dma_buffer == NULL)) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_demux = dvb_demux->priv; + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_dmx_vaddr_unmap(dma_buffer->va, dma_buffer->sgt, + dma_buffer->attach, dma_buffer->dmabuf); + memset(dma_buffer, 0, sizeof(struct ion_dma_buff_info)); + + return 0; +} + +int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie) +{ + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, cookie); + + if (cookie < 0) { + MPQ_DVB_ERR_PRINT("%s: invalid cookie parameter\n", __func__); + return -EINVAL; + } + + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_video_feed_info *feed_data; + struct mpq_feed *mpq_feed; + struct mpq_streambuffer *stream_buffer; + int ret; + + mutex_lock(&mpq_demux->mutex); + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + if (stream_buffer == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: invalid feed, feed_data->video_buffer is NULL\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + + ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1); + spin_unlock(&feed_data->video_buffer_lock); + mutex_unlock(&mpq_demux->mutex); + + return ret; + } + MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n", + __func__, feed->pes_type); + + return -EINVAL; +} + +/** + * Handles the details of internal decoder buffer allocation via ION. + * Internal helper function. + * @feed_data: decoder feed object + * @dec_buffs: buffer information + * @client: ION client + * + * Return error status + */ +static int mpq_dmx_init_internal_buffers( + struct mpq_demux *mpq_demux, + struct mpq_video_feed_info *feed_data, + struct dmx_decoder_buffers *dec_buffs) +{ + struct ion_dma_buff_info *dbuf = NULL; + int size = 0; + int ret = 0; + + MPQ_DVB_DBG_PRINT("%s: Internal decoder buffer allocation\n", __func__); + + size = dec_buffs->buffers_size; + size = ALIGN(size, SZ_4K); + + dbuf = &feed_data->buffer_desc.buff_dma_info[0]; + memset(dbuf, 0, sizeof(struct ion_dma_buff_info)); + + dbuf->dmabuf = ion_alloc(size, + ION_HEAP(video_secure_ion_heap) | + ION_HEAP(video_nonsecure_ion_heap), + mpq_demux->decoder_alloc_flags); + + if (IS_ERR_OR_NULL(dbuf->dmabuf)) { + ret = PTR_ERR(dbuf->dmabuf); + MPQ_DVB_ERR_PRINT( + "%s: FAILED to allocate sdmx buffer %d\n", + __func__, ret); + ret = -ENOMEM; + goto err; + } + + dbuf->attach = dma_buf_attach(dbuf->dmabuf, + &mpq_demux->pdev->dev); + if (IS_ERR_OR_NULL(dbuf->attach)) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_attach fail\n", __func__); + dma_buf_put(dbuf->dmabuf); + ret = -ENOMEM; + goto err_put; + } + + dbuf->sgt = dma_buf_map_attachment(dbuf->attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(dbuf->sgt)) { + ret = PTR_ERR(dbuf->sgt); + MPQ_DVB_ERR_PRINT( + "%s: dma_buf_map_attachment failed ret = %d\n", + __func__, ret); + goto err_detach; + } + + dbuf->pa = sg_dma_address(dbuf->sgt->sgl); + dbuf->len = dbuf->sgt->sgl->length; + + dma_buf_begin_cpu_access(dbuf->dmabuf, DMA_BIDIRECTIONAL); + dbuf->va = dma_buf_vmap(dbuf->dmabuf); + if (!dbuf->va) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_vmap failed\n", __func__); + dma_buf_end_cpu_access(dbuf->dmabuf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(dbuf->sgt, dbuf->attach, dbuf->dmabuf); + ret = -ENOMEM; + goto err; + } + + feed_data->buffer_desc.decoder_buffers_num = 1; + feed_data->buffer_desc.desc[0].base = dbuf->va; + feed_data->buffer_desc.desc[0].size = size; + feed_data->buffer_desc.desc[0].read_ptr = 0; + feed_data->buffer_desc.desc[0].write_ptr = 0; + return 0; + +err_detach: + dma_buf_detach(dbuf->dmabuf, dbuf->attach); +err_put: + dma_buf_put(dbuf->dmabuf); +err: + return ret; + +} + +/** + * Handles the details of external decoder buffers allocated by user. + * Each buffer is mapped into kernel memory and an ION handle is obtained, and + * decoder feed object is updated with related information. + * Internal helper function. + * @feed_data: decoder feed object + * @dec_buffs: buffer information + * @client: ION client + * + * Return error status + */ +static int mpq_dmx_init_external_buffers( + struct mpq_video_feed_info *feed_data, + struct dmx_decoder_buffers *dec_buffs, + bool is_secure_feed) +{ + struct ion_dma_buff_info buff; + int actual_buffer_size = 0; + int ret = 0; + int i; + + /* + * Payload buffer was allocated externally (through ION). + * Map the ion handles to kernel memory + */ + MPQ_DVB_DBG_PRINT("%s: External decoder buffer allocation\n", __func__); + memset(&buff, 0, sizeof(struct ion_dma_buff_info)); + + actual_buffer_size = dec_buffs->buffers_size; + if (!dec_buffs->is_linear) { + MPQ_DVB_DBG_PRINT("%s: Ex. Ring-buffer\n", __func__); + feed_data->buffer_desc.decoder_buffers_num = 1; + } else { + MPQ_DVB_DBG_PRINT("%s: Ex. Linear\n", __func__); + feed_data->buffer_desc.decoder_buffers_num = + dec_buffs->buffers_num; + } + + for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) { + if (is_secure_feed == false) { + mpq_dmx_vaddr_map(dec_buffs->handles[i], &buff.pa, + &buff.va, &buff.sgt, &buff.attach, + &buff.len, &buff.dmabuf); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: Failed mapping buffer %d\n", + __func__, i); + goto init_failed; + } + memcpy(&feed_data->buffer_desc.buff_dma_info[i], &buff, + sizeof(struct ion_dma_buff_info)); + + } else { + mpq_dmx_paddr_map(dec_buffs->handles[i], &buff.pa, + &buff.sgt, &buff.attach, + &buff.len, &buff.dmabuf); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: Failed mapping buffer %d\n", + __func__, i); + goto init_failed; + } + memcpy(&feed_data->buffer_desc.buff_dma_info[i], &buff, + sizeof(struct ion_dma_buff_info)); + + } + if (buff.va) + feed_data->buffer_desc.desc[i].base = buff.va; + else + feed_data->buffer_desc.desc[i].base = NULL; + + feed_data->buffer_desc.desc[i].handle = + dec_buffs->handles[i]; + feed_data->buffer_desc.desc[i].size = + dec_buffs->buffers_size; + feed_data->buffer_desc.desc[i].read_ptr = 0; + feed_data->buffer_desc.desc[i].write_ptr = 0; + + memset(&buff, 0, sizeof(struct ion_dma_buff_info)); + + MPQ_DVB_DBG_PRINT( + "%s: Buffer #%d: handle=%d, size=%d\n", + __func__, i, + feed_data->buffer_desc.desc[i].handle, + feed_data->buffer_desc.desc[i].size); + } + + return 0; + +init_failed: + MPQ_DVB_DBG_PRINT("%s: Init failed\n", __func__); + + for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) { + struct ion_dma_buff_info *buff = + &feed_data->buffer_desc.buff_dma_info[i]; + if (feed_data->buffer_desc.desc[i].base) { + mpq_dmx_vaddr_unmap(buff->va, buff->sgt, + buff->attach, + buff->dmabuf); + feed_data->buffer_desc.desc[i].base = NULL; + } + feed_data->buffer_desc.desc[i].size = 0; + memset(buff, 0, sizeof(struct ion_dma_buff_info)); + } + return ret; +} + +/** + * Handles the details of initializing the mpq_streambuffer object according + * to the user decoder buffer configuration: External/Internal buffers and + * ring/linear buffering mode. + * Internal helper function. + * @feed: dvb demux feed object, contains the buffers configuration + * @feed_data: decoder feed object + * @stream_buffer: stream buffer object to initialize + * + * Return error status + */ +static int mpq_dmx_init_streambuffer( + struct mpq_feed *feed, + struct mpq_video_feed_info *feed_data, + struct mpq_streambuffer *stream_buffer) +{ + int ret; + void *packet_buffer = NULL; + struct mpq_demux *mpq_demux = feed->mpq_demux; + struct dmx_decoder_buffers *dec_buffs = NULL; + enum mpq_streambuffer_mode mode; + bool is_secure_feed = false; + + dec_buffs = feed->dvb_demux_feed->feed.ts.decoder_buffers; + is_secure_feed = feed->dvb_demux_feed->secure_mode.is_secured; + + /* Allocate packet buffer holding the meta-data */ + packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE); + + if (packet_buffer == NULL) { + ret = -ENOMEM; + goto end; + } + + MPQ_DVB_DBG_PRINT("%s: dec_buffs: num=%d, size=%d, linear=%d\n", + __func__, + dec_buffs->buffers_num, + dec_buffs->buffers_size, + dec_buffs->is_linear); + + if (dec_buffs->buffers_num == 0) + ret = mpq_dmx_init_internal_buffers( + mpq_demux, feed_data, dec_buffs); + else + ret = mpq_dmx_init_external_buffers( + feed_data, dec_buffs, is_secure_feed); + + if (ret != 0) + goto init_failed_free_packet_buffer; + + mode = dec_buffs->is_linear ? MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR : + MPQ_STREAMBUFFER_BUFFER_MODE_RING; + ret = mpq_streambuffer_init( + feed_data->video_buffer, + mode, + feed_data->buffer_desc.desc, + feed_data->buffer_desc.decoder_buffers_num, + packet_buffer, + VIDEO_META_DATA_BUFFER_SIZE); + + if (ret != 0) + goto init_failed_free_packet_buffer; + + goto end; + + +init_failed_free_packet_buffer: + vfree(packet_buffer); +end: + return ret; +} + +static void mpq_dmx_release_streambuffer( + struct mpq_feed *feed, + struct mpq_video_feed_info *feed_data, + struct mpq_streambuffer *video_buffer, + struct ion_client *client) +{ + int buf_num = 0; + int i; + struct dmx_decoder_buffers *dec_buffs = + feed->dvb_demux_feed->feed.ts.decoder_buffers; + struct ion_dma_buff_info *buff = NULL; + + mpq_adapter_unregister_stream_if(feed_data->stream_interface); + + mpq_streambuffer_terminate(video_buffer); + + vfree(video_buffer->packet_data.data); + + buf_num = feed_data->buffer_desc.decoder_buffers_num; + + for (i = 0; i < buf_num; i++) { + buff = &feed_data->buffer_desc.buff_dma_info[i]; + if (buff->va) { + if (feed_data->buffer_desc.desc[i].base) { + mpq_dmx_vaddr_unmap(buff->va, buff->sgt, + buff->attach, buff->dmabuf); + feed_data->buffer_desc.desc[i].base = NULL; + } + + /* + * Un-share the buffer if kernel it the one that + * shared it. + */ + if (!dec_buffs->buffers_num && + feed_data->buffer_desc.shared_file) { + fput(feed_data->buffer_desc.shared_file); + feed_data->buffer_desc.shared_file = NULL; + } + + feed_data->buffer_desc.desc[i].size = 0; + } else if (buff->pa) { + mpq_dmx_paddr_unmap(buff->sgt, buff->attach, + buff->dmabuf); + buff->pa = 0; + } + memset(buff, 0, sizeof(struct ion_dma_buff_info)); + } +} + +int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed) +{ + struct mpq_feed *mpq_feed = feed->priv; + struct mpq_video_feed_info *feed_data = &mpq_feed->video_info; + struct mpq_streambuffer *sbuff; + int ret = 0; + + if (!dvb_dmx_is_video_feed(feed)) { + MPQ_DVB_DBG_PRINT("%s: not a video feed, feed type=%d\n", + __func__, feed->pes_type); + return 0; + } + + spin_lock(&feed_data->video_buffer_lock); + + sbuff = feed_data->video_buffer; + if (sbuff == NULL) { + MPQ_DVB_DBG_PRINT("%s: feed_data->video_buffer is NULL\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return -ENODEV; + } + + feed_data->pending_pattern_len = 0; + + ret = mpq_streambuffer_flush(sbuff); + if (ret) + MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer_flush failed, ret=%d\n", + __func__, ret); + + spin_unlock(&feed_data->video_buffer_lock); + + return ret; +} + +static int mpq_dmx_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret = 0; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + dvbdmx_ts_reset_pes_state(feed); + + if (dvb_dmx_is_video_feed(feed)) { + MPQ_DVB_DBG_PRINT("%s: flushing video buffer\n", __func__); + + ret = mpq_dmx_flush_stream_buffer(feed); + } + mutex_unlock(&demux->mutex); + return ret; +} + +/** + * mpq_dmx_init_video_feed - Initializes of video feed information + * used to pass data directly to decoder. + * + * @mpq_feed: The mpq feed object + * + * Return error code. + */ +int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed) +{ + int ret; + struct mpq_video_feed_info *feed_data = &mpq_feed->video_info; + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + struct mpq_streambuffer *stream_buffer; + + /* get and store framing information if required */ + if (video_framing) { + mpq_dmx_get_pattern_params( + mpq_feed->dvb_demux_feed->video_codec, + feed_data->patterns, &feed_data->patterns_num); + if (!feed_data->patterns_num) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to get framing pattern parameters\n", + __func__); + + ret = -EINVAL; + goto init_failed_free_priv_data; + } + } + + /* Register the new stream-buffer interface to MPQ adapter */ + switch (mpq_feed->dvb_demux_feed->pes_type) { + case DMX_PES_VIDEO0: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO0_STREAM_IF; + break; + + case DMX_PES_VIDEO1: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO1_STREAM_IF; + break; + + case DMX_PES_VIDEO2: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO2_STREAM_IF; + break; + + case DMX_PES_VIDEO3: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO3_STREAM_IF; + break; + + default: + MPQ_DVB_ERR_PRINT( + "%s: Invalid pes type %d\n", + __func__, + mpq_feed->dvb_demux_feed->pes_type); + ret = -EINVAL; + goto init_failed_free_priv_data; + } + + /* make sure not occupied already */ + stream_buffer = NULL; + mpq_adapter_get_stream_if( + feed_data->stream_interface, + &stream_buffer); + if (stream_buffer != NULL) { + MPQ_DVB_ERR_PRINT( + "%s: Video interface %d already occupied!\n", + __func__, + feed_data->stream_interface); + ret = -EBUSY; + goto init_failed_free_priv_data; + } + + feed_data->video_buffer = + &mpq_dmx_info.decoder_buffers[feed_data->stream_interface]; + + ret = mpq_dmx_init_streambuffer( + mpq_feed, feed_data, feed_data->video_buffer); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_init_streambuffer failed, err = %d\n", + __func__, ret); + goto init_failed_free_priv_data; + } + + ret = mpq_adapter_register_stream_if( + feed_data->stream_interface, + feed_data->video_buffer); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_adapter_register_stream_if failed, err = %d\n", + __func__, ret); + goto init_failed_free_stream_buffer; + } + + spin_lock_init(&feed_data->video_buffer_lock); + + feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN; + feed_data->pes_header_offset = 0; + mpq_feed->dvb_demux_feed->pusi_seen = 0; + mpq_feed->dvb_demux_feed->peslen = 0; + feed_data->fullness_wait_cancel = 0; + mpq_streambuffer_get_data_rw_offset(feed_data->video_buffer, NULL, + &feed_data->frame_offset); + feed_data->last_pattern_offset = 0; + feed_data->pending_pattern_len = 0; + feed_data->last_framing_match_type = 0; + feed_data->found_sequence_header_pattern = 0; + memset(&feed_data->prefix_size, 0, + sizeof(struct dvb_dmx_video_prefix_size_masks)); + feed_data->first_prefix_size = 0; + feed_data->saved_pts_dts_info.pts_exist = 0; + feed_data->saved_pts_dts_info.dts_exist = 0; + feed_data->new_pts_dts_info.pts_exist = 0; + feed_data->new_pts_dts_info.dts_exist = 0; + feed_data->saved_info_used = 1; + feed_data->new_info_exists = 0; + feed_data->first_pts_dts_copy = 1; + feed_data->tei_errs = 0; + feed_data->last_continuity = -1; + feed_data->continuity_errs = 0; + feed_data->ts_packets_num = 0; + feed_data->ts_dropped_bytes = 0; + + mpq_demux->decoder_stat[feed_data->stream_interface].drop_count = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].out_count = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].out_interval_sum + = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].out_interval_max + = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors = 0; + + return 0; + +init_failed_free_stream_buffer: + mpq_dmx_release_streambuffer(mpq_feed, feed_data, + feed_data->video_buffer, mpq_demux->ion_client); + mpq_adapter_unregister_stream_if(feed_data->stream_interface); +init_failed_free_priv_data: + feed_data->video_buffer = NULL; + return ret; +} + +/** + * mpq_dmx_terminate_video_feed - terminate video feed information + * that was previously initialized in mpq_dmx_init_video_feed + * + * @mpq_feed: The mpq feed used for the video TS packets + * + * Return error code. + */ +int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed) +{ + struct mpq_streambuffer *video_buffer; + struct mpq_video_feed_info *feed_data; + struct mpq_demux *mpq_demux; + + if (mpq_feed == NULL) + return -EINVAL; + + mpq_demux = mpq_feed->mpq_demux; + feed_data = &mpq_feed->video_info; + + spin_lock(&feed_data->video_buffer_lock); + video_buffer = feed_data->video_buffer; + feed_data->video_buffer = NULL; + wake_up_all(&video_buffer->raw_data.queue); + spin_unlock(&feed_data->video_buffer_lock); + + mpq_dmx_release_streambuffer(mpq_feed, feed_data, + video_buffer, mpq_demux->ion_client); + + return 0; +} + +struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux_feed *tmp; + struct dvb_demux *dvb_demux = feed->demux; + + list_for_each_entry(tmp, &dvb_demux->feed_list, list_head) { + if (tmp != feed && tmp->state == DMX_STATE_GO && + tmp->feed.ts.buffer.ringbuff == + feed->feed.ts.buffer.ringbuff) { + MPQ_DVB_DBG_PRINT( + "%s: main feed pid=%d, secondary feed pid=%d\n", + __func__, tmp->pid, feed->pid); + return tmp; + } + } + + return NULL; +} + +static int mpq_sdmx_alloc_data_buf(struct mpq_feed *mpq_feed, size_t size) +{ + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + int ret = 0; + struct sdmx_buff_descriptor *desc = &mpq_feed->data_desc; + + desc->virt_base = dma_alloc_coherent(&mpq_demux->pdev->dev, + size, &desc->phys_base, + GFP_KERNEL); + if (IS_ERR_OR_NULL(desc->virt_base)) { + ret = PTR_ERR(desc->virt_base); + MPQ_DVB_ERR_PRINT("%s: dma_alloc_coherent failed ret = %d\n", + __func__, ret); + return ret; + } + desc->size = size; + dvb_ringbuffer_init(&mpq_feed->sdmx_buf, desc->virt_base, size); + + return 0; +} + +static int mpq_sdmx_free_data_buf(struct mpq_feed *mpq_feed) +{ + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + struct sdmx_buff_descriptor *desc = &mpq_feed->data_desc; + + dma_free_coherent(&mpq_demux->pdev->dev, + desc->size, desc->virt_base, + desc->phys_base); + + memset(desc, 0, sizeof(struct sdmx_buff_descriptor)); + return 0; +} +static int mpq_sdmx_init_metadata_buffer(struct mpq_demux *mpq_demux, + struct mpq_feed *feed, struct sdmx_buff_descr *metadata_buff_desc) +{ + + int ret = 0; + struct sdmx_buff_descriptor *desc = &feed->metadata_desc; + + desc->virt_base = dma_alloc_coherent(&mpq_demux->pdev->dev, + SDMX_METADATA_BUFFER_SIZE, + &desc->phys_base, + GFP_KERNEL); + if (IS_ERR_OR_NULL(desc->virt_base)) { + ret = PTR_ERR(desc->virt_base); + MPQ_DVB_ERR_PRINT( + "%s: dma_buf_map_attachment failed ret = %d\n", + __func__, ret); + return ret; + } + desc->size = SDMX_METADATA_BUFFER_SIZE; + + metadata_buff_desc->size = SDMX_METADATA_BUFFER_SIZE; + metadata_buff_desc->base_addr = desc->phys_base; + dvb_ringbuffer_init(&feed->metadata_buf, desc->virt_base, + SDMX_METADATA_BUFFER_SIZE); + + return 0; +} + +static int mpq_sdmx_terminate_metadata_buffer(struct mpq_feed *mpq_feed) +{ + + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + + struct sdmx_buff_descriptor *desc = &mpq_feed->data_desc; + + dma_free_coherent(&mpq_demux->pdev->dev, + desc->size, desc->virt_base, + desc->phys_base); + + memset(desc, 0, sizeof(struct sdmx_buff_descriptor)); + return 0; +} +int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed) +{ + int ret = 0; + struct mpq_demux *mpq_demux; + struct mpq_feed *mpq_feed; + struct mpq_feed *main_rec_feed = NULL; + struct dvb_demux_feed *tmp; + + if (feed == NULL) + return -EINVAL; + + mpq_demux = feed->demux->priv; + + mutex_lock(&mpq_demux->mutex); + mpq_feed = feed->priv; + + if (mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE) { + if (mpq_feed->filter_type == SDMX_RAW_FILTER) { + tmp = mpq_dmx_peer_rec_feed(feed); + if (tmp) + main_rec_feed = tmp->priv; + } + + if (main_rec_feed) { + /* This feed is part of a recording filter */ + MPQ_DVB_DBG_PRINT( + "%s: Removing raw pid %d from filter %d\n", + __func__, feed->pid, + mpq_feed->sdmx_filter_handle); + ret = sdmx_remove_raw_pid( + mpq_demux->sdmx_session_handle, + mpq_feed->sdmx_filter_handle, feed->pid); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: SDMX_remove_raw_pid failed. ret = %d\n", + __func__, ret); + + /* If this feed that we are removing was set as primary, + * now other feeds should be set as primary + */ + if (!mpq_feed->secondary_feed) + main_rec_feed->secondary_feed = 0; + } else { + MPQ_DVB_DBG_PRINT("%s: Removing filter %d, pid %d\n", + __func__, mpq_feed->sdmx_filter_handle, + feed->pid); + ret = sdmx_remove_filter(mpq_demux->sdmx_session_handle, + mpq_feed->sdmx_filter_handle); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: SDMX_remove_filter failed. ret = %d\n", + __func__, ret); + } + + mpq_demux->sdmx_filter_count--; + mpq_feed->sdmx_filter_handle = + SDMX_INVALID_FILTER_HANDLE; + } + + mpq_sdmx_close_session(mpq_demux); + if (mpq_demux->num_secure_feeds > 0) + mpq_demux->num_secure_feeds--; + else + MPQ_DVB_DBG_PRINT("%s: Invalid secure feed count= %u\n", + __func__, mpq_demux->num_secure_feeds); + } + + if (dvb_dmx_is_video_feed(feed)) { + + ret = mpq_dmx_terminate_video_feed(mpq_feed); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_terminate_video_feed failed. ret = %d\n", + __func__, ret); + } + + if (mpq_feed->sdmx_dma_buff.va) { + wake_up_all(&mpq_feed->sdmx_buf.queue); + mpq_sdmx_free_data_buf(mpq_feed); + } + + mpq_sdmx_terminate_metadata_buffer(mpq_feed); + if (mpq_demux->num_active_feeds > 0) + mpq_demux->num_active_feeds--; + else + MPQ_DVB_DBG_PRINT("%s: Invalid num_active_feeds count = %u\n", + __func__, mpq_demux->num_active_feeds); + + mutex_unlock(&mpq_demux->mutex); + + return ret; +} + +int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed) +{ + struct mpq_feed *mpq_feed; + + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_video_feed_info *feed_data; + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + feed_data->fullness_wait_cancel = 0; + + return 0; + } + + MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n", __func__, + feed->pes_type); + + return -EINVAL; +} + +/** + * Returns whether the free space of decoder's output + * buffer is larger than specific number of bytes. + * + * @sbuff: MPQ stream buffer used for decoder data. + * @required_space: number of required free bytes in the buffer + * + * Return 1 if required free bytes are available, 0 otherwise. + */ +static inline int mpq_dmx_check_video_decoder_fullness( + struct mpq_streambuffer *sbuff, + size_t required_space) +{ + ssize_t free = mpq_streambuffer_data_free(sbuff); + ssize_t free_meta = mpq_streambuffer_metadata_free(sbuff); + + /* Verify meta-data buffer can contain at least 1 packet */ + if (free_meta < VIDEO_META_DATA_PACKET_SIZE) + return 0; + + /* + * For linear buffers, verify there's enough space for this TSP + * and an additional buffer is free, as framing might required one + * more buffer to be available. + */ + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + return (free >= required_space && + sbuff->pending_buffers_count < sbuff->buffers_num-1); + else + /* Ring buffer mode */ + return (free >= required_space); +} + +/** + * Checks whether decoder's output buffer has free space + * for specific number of bytes, if not, the function waits + * until the amount of free-space is available. + * + * @feed: decoder's feed object + * @required_space: number of required free bytes in the buffer + * @lock_feed: indicates whether mutex should be held before + * accessing the feed information. If the caller of this function + * already holds a mutex then this should be set to 0 and 1 otherwise. + * + * Return 0 if required space is available and error code + * in case waiting on buffer fullness was aborted. + */ +static int mpq_dmx_decoder_fullness_check( + struct dvb_demux_feed *feed, + size_t required_space, + int lock_feed) +{ + struct mpq_demux *mpq_demux = feed->demux->priv; + struct mpq_streambuffer *sbuff = NULL; + struct mpq_video_feed_info *feed_data; + struct mpq_feed *mpq_feed; + int ret = 0; + + if (!dvb_dmx_is_video_feed(feed)) { + MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n", + __func__, + feed->pes_type); + return -EINVAL; + } + + if (lock_feed) { + mutex_lock(&mpq_demux->mutex); + } else if (!mutex_is_locked(&mpq_demux->mutex)) { + MPQ_DVB_ERR_PRINT( + "%s: Mutex should have been locked\n", + __func__); + return -EINVAL; + } + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + sbuff = feed_data->video_buffer; + if (sbuff == NULL) { + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n", + __func__); + return -EINVAL; + } + + if ((feed_data->video_buffer != NULL) && + (!feed_data->fullness_wait_cancel) && + (!mpq_dmx_check_video_decoder_fullness(sbuff, + required_space))) { + DEFINE_WAIT(__wait); + + for (;;) { + prepare_to_wait(&sbuff->raw_data.queue, + &__wait, + TASK_INTERRUPTIBLE); + if (!feed_data->video_buffer || + feed_data->fullness_wait_cancel || + mpq_dmx_check_video_decoder_fullness(sbuff, + required_space)) + break; + + if (!signal_pending(current)) { + mutex_unlock(&mpq_demux->mutex); + schedule(); + mutex_lock(&mpq_demux->mutex); + continue; + } + + ret = -ERESTARTSYS; + break; + } + finish_wait(&sbuff->raw_data.queue, &__wait); + } + + if (ret < 0) { + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + return ret; + } + + if ((feed_data->fullness_wait_cancel) || + (feed_data->video_buffer == NULL)) { + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + return 0; +} + +int mpq_dmx_decoder_fullness_wait( + struct dvb_demux_feed *feed, + size_t required_space) +{ + return mpq_dmx_decoder_fullness_check(feed, required_space, 1); +} + +int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed) +{ + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_feed *mpq_feed; + struct mpq_video_feed_info *feed_data; + struct dvb_ringbuffer *video_buff; + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + feed_data->fullness_wait_cancel = 1; + + spin_lock(&feed_data->video_buffer_lock); + if (feed_data->video_buffer == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + video_buff = &feed_data->video_buffer->raw_data; + wake_up_all(&video_buff->queue); + spin_unlock(&feed_data->video_buffer_lock); + + return 0; + } + MPQ_DVB_ERR_PRINT( + "%s: Invalid feed type %d\n", __func__, feed->pes_type); + + return -EINVAL; +} + +int mpq_dmx_parse_mandatory_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail) +{ + int left_size, copy_len; + + if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) { + left_size = + PES_MANDATORY_FIELDS_LEN - + feed_data->pes_header_offset; + + copy_len = (left_size > *bytes_avail) ? + *bytes_avail : + left_size; + + memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset), + (buf + *ts_payload_offset), + copy_len); + + feed_data->pes_header_offset += copy_len; + + if (left_size > *bytes_avail) + return -EINVAL; + + /* else - we have beginning of PES header */ + *bytes_avail -= left_size; + *ts_payload_offset += left_size; + + /* Make sure the PES packet is valid */ + if (mpq_dmx_is_valid_video_pes(pes_header) < 0) { + /* + * Since the new PES header parsing + * failed, reset pusi_seen to drop all + * data until next PUSI + */ + feed->pusi_seen = 0; + feed_data->pes_header_offset = 0; + + MPQ_DVB_ERR_PRINT( + "%s: invalid packet\n", + __func__); + + return -EINVAL; + } + + feed_data->pes_header_left_bytes = + pes_header->pes_header_data_length; + } + + return 0; +} + +static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header) +{ + struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info); + + /* Get PTS/DTS information from PES header */ + + if ((pes_header->pts_dts_flag == 2) || + (pes_header->pts_dts_flag == 3)) { + info->pts_exist = 1; + + info->pts = + ((u64)pes_header->pts_1 << 30) | + ((u64)pes_header->pts_2 << 22) | + ((u64)pes_header->pts_3 << 15) | + ((u64)pes_header->pts_4 << 7) | + (u64)pes_header->pts_5; + } else { + info->pts_exist = 0; + info->pts = 0; + } + + if (pes_header->pts_dts_flag == 3) { + info->dts_exist = 1; + + info->dts = + ((u64)pes_header->dts_1 << 30) | + ((u64)pes_header->dts_2 << 22) | + ((u64)pes_header->dts_3 << 15) | + ((u64)pes_header->dts_4 << 7) | + (u64)pes_header->dts_5; + } else { + info->dts_exist = 0; + info->dts = 0; + } + + feed_data->new_info_exists = 1; +} + +int mpq_dmx_parse_remaining_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail) +{ + int left_size, copy_len; + + /* Remaining header bytes that need to be processed? */ + if (!feed_data->pes_header_left_bytes) + return 0; + + /* Did we capture the PTS value (if exists)? */ + if ((*bytes_avail != 0) && + (feed_data->pes_header_offset < + (PES_MANDATORY_FIELDS_LEN+5)) && + ((pes_header->pts_dts_flag == 2) || + (pes_header->pts_dts_flag == 3))) { + + /* 5 more bytes should be there */ + left_size = + PES_MANDATORY_FIELDS_LEN + 5 - + feed_data->pes_header_offset; + + copy_len = (left_size > *bytes_avail) ? + *bytes_avail : + left_size; + + memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset), + (buf + *ts_payload_offset), + copy_len); + + feed_data->pes_header_offset += copy_len; + feed_data->pes_header_left_bytes -= copy_len; + + if (left_size > *bytes_avail) + return -EINVAL; + + /* else - we have the PTS */ + *bytes_avail -= copy_len; + *ts_payload_offset += copy_len; + } + + /* Did we capture the DTS value (if exist)? */ + if ((*bytes_avail != 0) && + (feed_data->pes_header_offset < + (PES_MANDATORY_FIELDS_LEN+10)) && + (pes_header->pts_dts_flag == 3)) { + + /* 5 more bytes should be there */ + left_size = + PES_MANDATORY_FIELDS_LEN + 10 - + feed_data->pes_header_offset; + + copy_len = (left_size > *bytes_avail) ? + *bytes_avail : + left_size; + + memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset), + (buf + *ts_payload_offset), + copy_len); + + feed_data->pes_header_offset += copy_len; + feed_data->pes_header_left_bytes -= copy_len; + + if (left_size > *bytes_avail) + return -EINVAL; + + /* else - we have the DTS */ + *bytes_avail -= copy_len; + *ts_payload_offset += copy_len; + } + + /* Any more header bytes?! */ + if (feed_data->pes_header_left_bytes >= *bytes_avail) { + feed_data->pes_header_left_bytes -= *bytes_avail; + return -EINVAL; + } + + /* get PTS/DTS information from PES header to be written later */ + mpq_dmx_get_pts_dts(feed_data, pes_header); + + /* Got PES header, process payload */ + *bytes_avail -= feed_data->pes_header_left_bytes; + *ts_payload_offset += feed_data->pes_header_left_bytes; + feed_data->pes_header_left_bytes = 0; + + return 0; +} + +static void mpq_dmx_check_continuity(struct mpq_video_feed_info *feed_data, + int current_continuity, + int discontinuity_indicator) +{ + const int max_continuity = 0x0F; /* 4 bits in the TS packet header */ + + /* sanity check */ + if (unlikely((current_continuity < 0) || + (current_continuity > max_continuity))) { + MPQ_DVB_DBG_PRINT( + "%s: received invalid continuity counter value %d\n", + __func__, current_continuity); + return; + } + + /* reset last continuity */ + if ((feed_data->last_continuity == -1) || + (discontinuity_indicator)) { + feed_data->last_continuity = current_continuity; + return; + } + + /* check for continuity errors */ + if (current_continuity != + ((feed_data->last_continuity + 1) & max_continuity)) + feed_data->continuity_errs++; + + /* save for next time */ + feed_data->last_continuity = current_continuity; +} + +static inline void mpq_dmx_prepare_es_event_data( + struct mpq_streambuffer_packet_header *packet, + struct mpq_adapter_video_meta_data *meta_data, + struct mpq_video_feed_info *feed_data, + struct mpq_streambuffer *stream_buffer, + struct dmx_data_ready *data, + int cookie) +{ + struct dmx_pts_dts_info *pts_dts; + + if (meta_data->packet_type == DMX_PES_PACKET) { + pts_dts = &meta_data->info.pes.pts_dts_info; + data->buf.stc = meta_data->info.pes.stc; + } else { + pts_dts = &meta_data->info.framing.pts_dts_info; + data->buf.stc = meta_data->info.framing.stc; + } + + pts_dts = meta_data->packet_type == DMX_PES_PACKET ? + &meta_data->info.pes.pts_dts_info : + &meta_data->info.framing.pts_dts_info; + + data->data_length = 0; + data->buf.handle = packet->raw_data_handle; + data->buf.cookie = cookie; + data->buf.offset = packet->raw_data_offset; + data->buf.len = packet->raw_data_len; + data->buf.pts_exists = pts_dts->pts_exist; + data->buf.pts = pts_dts->pts; + data->buf.dts_exists = pts_dts->dts_exist; + data->buf.dts = pts_dts->dts; + data->buf.tei_counter = feed_data->tei_errs; + data->buf.cont_err_counter = feed_data->continuity_errs; + data->buf.ts_packets_num = feed_data->ts_packets_num; + data->buf.ts_dropped_bytes = feed_data->ts_dropped_bytes; + data->status = DMX_OK_DECODER_BUF; + + MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, data->buf.cookie); + + /* reset counters */ + feed_data->ts_packets_num = 0; + feed_data->ts_dropped_bytes = 0; + feed_data->tei_errs = 0; + feed_data->continuity_errs = 0; +} + +static int mpq_sdmx_dvr_buffer_desc(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *buf_desc) +{ + struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *) + mpq_demux->demux.dmx.dvr_input.ringbuff; + struct ion_dma_buff_info *dma_buff = + &mpq_demux->demux.dmx.dvr_input.buff_dma_info; + if (dma_buff->pa) { + buf_desc->base_addr = (u64)dma_buff->pa; + buf_desc->size = rbuf->size; + } + + return 0; +} + +static inline int mpq_dmx_notify_overflow(struct dvb_demux_feed *feed) +{ + struct dmx_data_ready data; + + data.data_length = 0; + data.status = DMX_OVERRUN_ERROR; + return feed->data_ready_cb.ts(&feed->feed.ts, &data); +} + +/** + * mpq_dmx_decoder_frame_closure - Helper function to handle closing current + * pending frame upon reaching EOS. + * + * @mpq_demux - mpq demux instance + * @mpq_feed - mpq feed object + */ +static void mpq_dmx_decoder_frame_closure(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed) +{ + struct mpq_streambuffer_packet_header packet; + struct mpq_streambuffer *stream_buffer; + struct mpq_adapter_video_meta_data meta_data; + struct mpq_video_feed_info *feed_data; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dmx_data_ready data; + int cookie; + + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return; + } + + /* Report last pattern found */ + if ((feed_data->pending_pattern_len) && + mpq_dmx_is_video_frame(feed->video_codec, + feed_data->last_framing_match_type)) { + meta_data.packet_type = DMX_FRAMING_INFO_PACKET; + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.framing.pts_dts_info)); + mpq_dmx_save_pts_dts(feed_data); + packet.user_data_len = + sizeof(struct mpq_adapter_video_meta_data); + packet.raw_data_len = feed_data->pending_pattern_len; + packet.raw_data_offset = feed_data->frame_offset; + meta_data.info.framing.pattern_type = + feed_data->last_framing_match_type; + meta_data.info.framing.stc = feed_data->last_framing_match_stc; + meta_data.info.framing.continuity_error_counter = + feed_data->continuity_errs; + meta_data.info.framing.transport_error_indicator_counter = + feed_data->tei_errs; + meta_data.info.framing.ts_dropped_bytes = + feed_data->ts_dropped_bytes; + meta_data.info.framing.ts_packets_num = + feed_data->ts_packets_num; + + mpq_streambuffer_get_buffer_handle(stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + + mpq_dmx_update_decoder_stat(mpq_feed); + + /* Writing meta-data that includes the framing information */ + cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet, + (u8 *)&meta_data); + if (cookie >= 0) { + mpq_dmx_prepare_es_event_data(&packet, &meta_data, + feed_data, stream_buffer, &data, cookie); + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } else { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_pkt_write failed, ret=%d\n", + __func__, cookie); + } + } + + spin_unlock(&feed_data->video_buffer_lock); +} + +/** + * mpq_dmx_decoder_pes_closure - Helper function to handle closing current PES + * upon reaching EOS. + * + * @mpq_demux - mpq demux instance + * @mpq_feed - mpq feed object + */ +static void mpq_dmx_decoder_pes_closure(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed) +{ + struct mpq_streambuffer_packet_header packet; + struct mpq_streambuffer *stream_buffer; + struct mpq_adapter_video_meta_data meta_data; + struct mpq_video_feed_info *feed_data; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dmx_data_ready data; + int cookie; + + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return; + } + + /* + * Close previous PES. + * Push new packet to the meta-data buffer. + */ + if ((feed->pusi_seen) && (feed_data->pes_header_left_bytes == 0)) { + packet.raw_data_len = feed->peslen; + mpq_streambuffer_get_buffer_handle(stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + packet.raw_data_offset = feed_data->frame_offset; + packet.user_data_len = + sizeof(struct mpq_adapter_video_meta_data); + + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.pes.pts_dts_info)); + + meta_data.packet_type = DMX_PES_PACKET; + meta_data.info.pes.stc = feed_data->prev_stc; + + mpq_dmx_update_decoder_stat(mpq_feed); + + cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet, + (u8 *)&meta_data); + if (cookie >= 0) { + /* Save write offset where new PES will begin */ + mpq_streambuffer_get_data_rw_offset(stream_buffer, NULL, + &feed_data->frame_offset); + mpq_dmx_prepare_es_event_data(&packet, &meta_data, + feed_data, stream_buffer, &data, cookie); + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } else { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_pkt_write failed, ret=%d\n", + __func__, cookie); + } + } + /* Reset PES info */ + feed->peslen = 0; + feed_data->pes_header_offset = 0; + feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN; + + spin_unlock(&feed_data->video_buffer_lock); +} + +static int mpq_dmx_process_video_packet_framing( + struct dvb_demux_feed *feed, + const u8 *buf, + u64 curr_stc) +{ + int bytes_avail; + u32 ts_payload_offset; + struct mpq_video_feed_info *feed_data; + const struct ts_packet_header *ts_header; + struct mpq_streambuffer *stream_buffer; + struct pes_packet_header *pes_header; + struct mpq_demux *mpq_demux; + struct mpq_feed *mpq_feed; + + struct dvb_dmx_video_patterns_results framing_res; + struct mpq_streambuffer_packet_header packet; + struct mpq_adapter_video_meta_data meta_data; + int bytes_written = 0; + int bytes_to_write = 0; + int found_patterns = 0; + int first_pattern = 0; + int i; + int is_video_frame = 0; + int pending_data_len = 0; + int ret = 0; + int discontinuity_indicator = 0; + struct dmx_data_ready data; + struct dmx_framing_packet_info *framing; + + mpq_demux = feed->demux->priv; + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). Mutex on the video-feed cannot be held here + * since SW demux holds a spin-lock while calling write_to_decoder + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + ts_header = (const struct ts_packet_header *)buf; + + pes_header = &feed_data->pes_header; + + /* Make sure this TS packet has a payload and not scrambled */ + if ((ts_header->sync_byte != 0x47) || + (ts_header->adaptation_field_control == 0) || + (ts_header->adaptation_field_control == 2) || + (ts_header->transport_scrambling_control)) { + /* continue to next packet */ + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (ts_header->payload_unit_start_indicator) { /* PUSI? */ + if (feed->pusi_seen) { /* Did we see PUSI before? */ + /* + * Double check that we are not in middle of + * previous PES header parsing. + */ + if (feed_data->pes_header_left_bytes != 0) + MPQ_DVB_ERR_PRINT( + "%s: received PUSI while handling PES header of previous PES\n", + __func__); + + feed->peslen = 0; + feed_data->pes_header_offset = 0; + feed_data->pes_header_left_bytes = + PES_MANDATORY_FIELDS_LEN; + } else { + feed->pusi_seen = 1; + } + } + + /* + * Parse PES data only if PUSI was encountered, + * otherwise the data is dropped + */ + if (!feed->pusi_seen) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; /* drop and wait for next packets */ + } + + ts_payload_offset = sizeof(struct ts_packet_header); + + /* + * Skip adaptation field if exists. + * Save discontinuity indicator if exists. + */ + if (ts_header->adaptation_field_control == 3) { + const struct ts_adaptation_field *adaptation_field = + (const struct ts_adaptation_field *)(buf + + ts_payload_offset); + + discontinuity_indicator = + adaptation_field->discontinuity_indicator; + ts_payload_offset += buf[ts_payload_offset] + 1; + } + + bytes_avail = TS_PACKET_SIZE - ts_payload_offset; + + /* Get the mandatory fields of the video PES header */ + if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (mpq_dmx_parse_remaining_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * If we reached here, + * then we are now at the PES payload data + */ + if (bytes_avail == 0) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * the decoder requires demux to do framing, + * so search for the patterns now. + */ + found_patterns = dvb_dmx_video_pattern_search( + feed_data->patterns, + feed_data->patterns_num, + (buf + ts_payload_offset), + bytes_avail, + &feed_data->prefix_size, + &framing_res); + + if (!feed_data->found_sequence_header_pattern) { + for (i = 0; i < found_patterns; i++) { + if ((framing_res.info[i].type == + DMX_IDX_MPEG_SEQ_HEADER) || + (framing_res.info[i].type == + DMX_IDX_H264_SPS) || + (framing_res.info[i].type == + DMX_IDX_VC1_SEQ_HEADER)) { + + MPQ_DVB_DBG_PRINT( + "%s: Found Sequence Pattern", __func__); + MPQ_DVB_DBG_PRINT( + "i = %d, offset = %d, type = %lld\n", i, + framing_res.info[i].offset, + framing_res.info[i].type); + + first_pattern = i; + feed_data->found_sequence_header_pattern = 1; + ts_payload_offset += + framing_res.info[i].offset; + bytes_avail -= framing_res.info[i].offset; + + if (framing_res.info[i].used_prefix_size) { + feed_data->first_prefix_size = + framing_res.info[i].used_prefix_size; + } + break; + } + } + } + + /* + * If decoder requires demux to do framing, + * pass data to decoder only after sequence header + * or equivalent is found. Otherwise the data is dropped. + */ + if (!feed_data->found_sequence_header_pattern) { + feed_data->prev_stc = curr_stc; + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* Update error counters based on TS header */ + feed_data->ts_packets_num++; + feed_data->tei_errs += ts_header->transport_error_indicator; + mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors += + ts_header->transport_error_indicator; + mpq_dmx_check_continuity(feed_data, + ts_header->continuity_counter, + discontinuity_indicator); + mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors += + feed_data->continuity_errs; + + /* Need to back-up the PTS information of the very first frame */ + if (feed_data->first_pts_dts_copy) { + for (i = first_pattern; i < found_patterns; i++) { + is_video_frame = mpq_dmx_is_video_frame( + feed->video_codec, + framing_res.info[i].type); + + if (is_video_frame == 1) { + mpq_dmx_save_pts_dts(feed_data); + feed_data->first_pts_dts_copy = 0; + break; + } + } + } + + /* + * write prefix used to find first Sequence pattern, if needed. + * feed_data->patterns[0]->pattern always contains the sequence + * header pattern. + */ + if (feed_data->first_prefix_size) { + ret = mpq_streambuffer_data_write(stream_buffer, + feed_data->patterns[0]->pattern, + feed_data->first_prefix_size); + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += + feed_data->first_prefix_size; + feed_data->ts_dropped_bytes += + feed_data->first_prefix_size; + MPQ_DVB_DBG_PRINT("%s: could not write prefix\n", + __func__); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + MPQ_DVB_DBG_PRINT( + "%s: Writing pattern prefix of size %d\n", + __func__, feed_data->first_prefix_size); + /* + * update the length of the data we report + * to include the size of the prefix that was used. + */ + feed_data->pending_pattern_len += + feed_data->first_prefix_size; + } + } + + feed->peslen += bytes_avail; + pending_data_len += bytes_avail; + + meta_data.packet_type = DMX_FRAMING_INFO_PACKET; + packet.user_data_len = sizeof(struct mpq_adapter_video_meta_data); + + /* + * Go over all the patterns that were found in this packet. + * For each pattern found, write the relevant data to the data + * buffer, then write the respective meta-data. + * Each pattern can only be reported when the next pattern is found + * (in order to know the data length). + * There are three possible cases for each pattern: + * 1. This is the very first pattern we found in any TS packet in this + * feed. + * 2. This is the first pattern found in this TS packet, but we've + * already found patterns in previous packets. + * 3. This is not the first pattern in this packet, i.e., we've + * already found patterns in this TS packet. + */ + for (i = first_pattern; i < found_patterns; i++) { + if (i == first_pattern) { + /* + * The way to identify the very first pattern: + * 1. It's the first pattern found in this packet. + * 2. The pending_pattern_len, which indicates the + * data length of the previous pattern that has + * not yet been reported, is usually 0. However, + * it may be larger than 0 if a prefix was used + * to find this pattern (i.e., the pattern was + * split over two TS packets). In that case, + * pending_pattern_len equals first_prefix_size. + * first_prefix_size is set to 0 later in this + * function. + */ + if (feed_data->first_prefix_size == + feed_data->pending_pattern_len) { + /* + * This is the very first pattern, so no + * previous pending frame data exists. + * Update frame info and skip to the + * next frame. + */ + feed_data->last_framing_match_type = + framing_res.info[i].type; + feed_data->last_pattern_offset = + framing_res.info[i].offset; + if (framing_res.info[i].used_prefix_size) + feed_data->last_framing_match_stc = + feed_data->prev_stc; + else + feed_data->last_framing_match_stc = + curr_stc; + continue; + } + /* + * This is the first pattern in this + * packet and previous frame from + * previous packet is pending for report + */ + bytes_to_write = framing_res.info[i].offset; + } else { + /* Previous pending frame is in the same packet */ + bytes_to_write = + framing_res.info[i].offset - + feed_data->last_pattern_offset; + } + + ret = mpq_streambuffer_data_write( + stream_buffer, + (buf + ts_payload_offset + bytes_written), + bytes_to_write); + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += + bytes_to_write; + feed_data->ts_dropped_bytes += bytes_to_write; + MPQ_DVB_DBG_PRINT( + "%s: Couldn't write %d bytes to data buffer, ret=%d\n", + __func__, bytes_to_write, ret); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + bytes_written += bytes_to_write; + pending_data_len -= bytes_to_write; + feed_data->pending_pattern_len += bytes_to_write; + } + + is_video_frame = mpq_dmx_is_video_frame( + feed->video_codec, + feed_data->last_framing_match_type); + if (is_video_frame == 1) { + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.framing.pts_dts_info)); + mpq_dmx_save_pts_dts(feed_data); + + packet.raw_data_len = feed_data->pending_pattern_len - + framing_res.info[i].used_prefix_size; + packet.raw_data_offset = feed_data->frame_offset; + + framing = &meta_data.info.framing; + framing->pattern_type = + feed_data->last_framing_match_type; + framing->stc = feed_data->last_framing_match_stc; + framing->continuity_error_counter = + feed_data->continuity_errs; + framing->transport_error_indicator_counter = + feed_data->tei_errs; + framing->ts_dropped_bytes = + feed_data->ts_dropped_bytes; + framing->ts_packets_num = + feed_data->ts_packets_num; + + mpq_streambuffer_get_buffer_handle( + stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + + mpq_dmx_update_decoder_stat(mpq_feed); + + /* + * Write meta-data that includes the framing information + */ + ret = mpq_streambuffer_pkt_write(stream_buffer, &packet, + (u8 *)&meta_data); + if (ret < 0) { + MPQ_DVB_ERR_PRINT + ("%s: mpq_sb_pkt_write failed ret=%d\n", + __func__, ret); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + mpq_dmx_prepare_es_event_data( + &packet, &meta_data, feed_data, + stream_buffer, &data, ret); + + /* Trigger ES Data Event for VPTS */ + feed->data_ready_cb.ts(&feed->feed.ts, &data); + + if (feed_data->video_buffer->mode == + MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + feed_data->frame_offset = 0; + else + mpq_streambuffer_get_data_rw_offset( + feed_data->video_buffer, + NULL, + &feed_data->frame_offset); + } + + /* + * In linear buffers, after writing the packet + * we switched over to a new linear buffer for the new + * frame. In that case, we should re-write the prefix + * of the existing frame if any exists. + */ + if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == + feed_data->video_buffer->mode) && + framing_res.info[i].used_prefix_size) { + ret = mpq_streambuffer_data_write(stream_buffer, + feed_data->prev_pattern + + DVB_DMX_MAX_PATTERN_LEN - + framing_res.info[i].used_prefix_size, + framing_res.info[i].used_prefix_size); + + if (ret < 0) { + feed_data->pending_pattern_len = 0; + mpq_demux->decoder_stat + [feed_data->stream_interface]. + drop_count += bytes_avail; + feed_data->ts_dropped_bytes += + framing_res.info[i].used_prefix_size; + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + feed_data->pending_pattern_len = + framing_res.info[i].used_prefix_size; + } + } else { + s32 offset = (s32)feed_data->frame_offset; + u32 buff_size = + feed_data->video_buffer->buffers[0].size; + + offset -= framing_res.info[i].used_prefix_size; + offset += (offset < 0) ? buff_size : 0; + feed_data->pending_pattern_len = + framing_res.info[i].used_prefix_size; + + if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == + feed_data->video_buffer->mode) { + feed_data->frame_offset = (u32)offset; + } + } + } + + /* save the last match for next time */ + feed_data->last_framing_match_type = + framing_res.info[i].type; + feed_data->last_pattern_offset = + framing_res.info[i].offset; + if (framing_res.info[i].used_prefix_size) + feed_data->last_framing_match_stc = feed_data->prev_stc; + else + feed_data->last_framing_match_stc = curr_stc; + } + + feed_data->prev_stc = curr_stc; + feed_data->first_prefix_size = 0; + + /* + * Save the trailing of the TS packet as we might have a pattern + * split that we need to re-use when closing the next + * video linear buffer. + */ + if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == + feed_data->video_buffer->mode) + memcpy(feed_data->prev_pattern, + buf + TS_PACKET_SIZE - DVB_DMX_MAX_PATTERN_LEN, + DVB_DMX_MAX_PATTERN_LEN); + + if (pending_data_len) { + ret = mpq_streambuffer_data_write( + stream_buffer, + (buf + ts_payload_offset + bytes_written), + pending_data_len); + + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += + pending_data_len; + feed_data->ts_dropped_bytes += pending_data_len; + MPQ_DVB_DBG_PRINT( + "%s: Couldn't write %d pending bytes to data buffer, ret=%d\n", + __func__, pending_data_len, ret); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + feed_data->pending_pattern_len += pending_data_len; + } + } + + spin_unlock(&feed_data->video_buffer_lock); + return 0; +} + +static int mpq_dmx_process_video_packet_no_framing( + struct dvb_demux_feed *feed, + const u8 *buf, + u64 curr_stc) +{ + int bytes_avail; + u32 ts_payload_offset; + struct mpq_video_feed_info *feed_data; + const struct ts_packet_header *ts_header; + struct mpq_streambuffer *stream_buffer; + struct pes_packet_header *pes_header; + struct mpq_demux *mpq_demux; + struct mpq_feed *mpq_feed; + int discontinuity_indicator = 0; + struct dmx_data_ready data; + int cookie; + int ret; + + mpq_demux = feed->demux->priv; + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). Mutex on the video-feed cannot be held here + * since SW demux holds a spin-lock while calling write_to_decoder + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + ts_header = (const struct ts_packet_header *)buf; + + pes_header = &feed_data->pes_header; + + /* Make sure this TS packet has a payload and not scrambled */ + if ((ts_header->sync_byte != 0x47) || + (ts_header->adaptation_field_control == 0) || + (ts_header->adaptation_field_control == 2) || + (ts_header->transport_scrambling_control)) { + /* continue to next packet */ + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (ts_header->payload_unit_start_indicator) { /* PUSI? */ + if (feed->pusi_seen) { /* Did we see PUSI before? */ + struct mpq_streambuffer_packet_header packet; + struct mpq_adapter_video_meta_data meta_data; + + /* + * Close previous PES. + * Push new packet to the meta-data buffer. + * Double check that we are not in middle of + * previous PES header parsing. + */ + + if (feed_data->pes_header_left_bytes == 0) { + packet.raw_data_len = feed->peslen; + mpq_streambuffer_get_buffer_handle( + stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + packet.raw_data_offset = + feed_data->frame_offset; + packet.user_data_len = + sizeof(struct + mpq_adapter_video_meta_data); + + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.pes.pts_dts_info)); + + /* Mark that we detected start of new PES */ + feed_data->first_pts_dts_copy = 1; + + meta_data.packet_type = DMX_PES_PACKET; + meta_data.info.pes.stc = feed_data->prev_stc; + + mpq_dmx_update_decoder_stat(mpq_feed); + + cookie = mpq_streambuffer_pkt_write( + stream_buffer, &packet, + (u8 *)&meta_data); + if (cookie < 0) { + MPQ_DVB_ERR_PRINT + ("%s: write failed, ret=%d\n", + __func__, cookie); + } else { + /* + * Save write offset where new PES + * will begin + */ + mpq_streambuffer_get_data_rw_offset( + stream_buffer, + NULL, + &feed_data->frame_offset); + + mpq_dmx_prepare_es_event_data( + &packet, &meta_data, + feed_data, + stream_buffer, &data, cookie); + + feed->data_ready_cb.ts(&feed->feed.ts, + &data); + } + } else { + MPQ_DVB_ERR_PRINT( + "%s: received PUSI while handling PES header of previous PES\n", + __func__); + } + + /* Reset PES info */ + feed->peslen = 0; + feed_data->pes_header_offset = 0; + feed_data->pes_header_left_bytes = + PES_MANDATORY_FIELDS_LEN; + } else { + feed->pusi_seen = 1; + } + + feed_data->prev_stc = curr_stc; + } + + /* + * Parse PES data only if PUSI was encountered, + * otherwise the data is dropped + */ + if (!feed->pusi_seen) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; /* drop and wait for next packets */ + } + + ts_payload_offset = sizeof(struct ts_packet_header); + + /* + * Skip adaptation field if exists. + * Save discontinuity indicator if exists. + */ + if (ts_header->adaptation_field_control == 3) { + const struct ts_adaptation_field *adaptation_field = + (const struct ts_adaptation_field *)(buf + + ts_payload_offset); + + discontinuity_indicator = + adaptation_field->discontinuity_indicator; + ts_payload_offset += buf[ts_payload_offset] + 1; + } + + bytes_avail = TS_PACKET_SIZE - ts_payload_offset; + + /* Get the mandatory fields of the video PES header */ + if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (mpq_dmx_parse_remaining_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * If we reached here, + * then we are now at the PES payload data + */ + if (bytes_avail == 0) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * Need to back-up the PTS information + * of the start of new PES + */ + if (feed_data->first_pts_dts_copy) { + mpq_dmx_save_pts_dts(feed_data); + feed_data->first_pts_dts_copy = 0; + } + + /* Update error counters based on TS header */ + feed_data->ts_packets_num++; + feed_data->tei_errs += ts_header->transport_error_indicator; + mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors += + ts_header->transport_error_indicator; + mpq_dmx_check_continuity(feed_data, + ts_header->continuity_counter, + discontinuity_indicator); + mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors += + feed_data->continuity_errs; + + ret = mpq_streambuffer_data_write(stream_buffer, buf+ts_payload_offset, + bytes_avail); + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += bytes_avail; + feed_data->ts_dropped_bytes += bytes_avail; + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + feed->peslen += bytes_avail; + } + + spin_unlock(&feed_data->video_buffer_lock); + + return 0; +} + +/* function ptr used in several places, handle differently */ +int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed, + struct dmx_buffer_status *dmx_buffer_status) +{ + + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_demux *mpq_demux = feed->demux->priv; + struct mpq_video_feed_info *feed_data; + struct mpq_streambuffer *video_buff; + struct mpq_feed *mpq_feed; + + mutex_lock(&mpq_demux->mutex); + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + video_buff = feed_data->video_buffer; + if (!video_buff) { + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + + dmx_buffer_status->error = video_buff->raw_data.error; + + if (video_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) { + dmx_buffer_status->fullness = + video_buff->buffers[0].size * + video_buff->pending_buffers_count; + dmx_buffer_status->free_bytes = + video_buff->buffers[0].size * + (video_buff->buffers_num - + video_buff->pending_buffers_count); + dmx_buffer_status->size = + video_buff->buffers[0].size * + video_buff->buffers_num; + } else { + dmx_buffer_status->fullness = + mpq_streambuffer_data_avail(video_buff); + dmx_buffer_status->free_bytes = + mpq_streambuffer_data_free(video_buff); + dmx_buffer_status->size = video_buff->buffers[0].size; + } + + mpq_streambuffer_get_data_rw_offset( + video_buff, + &dmx_buffer_status->read_offset, + &dmx_buffer_status->write_offset); + + mutex_unlock(&mpq_demux->mutex); + + } else { + MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n", + __func__, feed->pes_type); + return -EINVAL; + } + return 0; +} + +int mpq_dmx_process_video_packet( + struct dvb_demux_feed *feed, + const u8 *buf) +{ + u64 curr_stc; + struct mpq_demux *mpq_demux = feed->demux->priv; + + if ((mpq_demux->source >= DMX_SOURCE_DVR0) && + (mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) { + curr_stc = 0; + } else { + curr_stc = buf[STC_LOCATION_IDX + 2] << 16; + curr_stc += buf[STC_LOCATION_IDX + 1] << 8; + curr_stc += buf[STC_LOCATION_IDX]; + curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */ + } + + if (!video_framing) + return mpq_dmx_process_video_packet_no_framing(feed, buf, + curr_stc); + else + return mpq_dmx_process_video_packet_framing(feed, buf, + curr_stc); +} + +int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci) +{ + const struct ts_packet_header *ts_header; + const struct ts_adaptation_field *adaptation_field; + + if (buf == NULL || pcr == NULL || dci == NULL) + return 0; + + ts_header = (const struct ts_packet_header *)buf; + + /* Make sure this TS packet has a adaptation field */ + if ((ts_header->sync_byte != 0x47) || + (ts_header->adaptation_field_control == 0) || + (ts_header->adaptation_field_control == 1) || + ts_header->transport_error_indicator) + return 0; + + adaptation_field = (const struct ts_adaptation_field *) + (buf + sizeof(struct ts_packet_header)); + + if ((!adaptation_field->adaptation_field_length) || + (!adaptation_field->PCR_flag)) + return 0; /* 0 adaptation field or no PCR */ + + *pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25; + *pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17; + *pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9; + *pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1; + *pcr += adaptation_field->program_clock_reference_base_5; + *pcr *= 300; + *pcr += (((u64)adaptation_field->program_clock_reference_ext_1) << 8) + + adaptation_field->program_clock_reference_ext_2; + + *dci = adaptation_field->discontinuity_indicator; + + return 1; +} + +int mpq_dmx_process_pcr_packet( + struct dvb_demux_feed *feed, + const u8 *buf) +{ + u64 stc; + struct dmx_data_ready data; + struct mpq_demux *mpq_demux = feed->demux->priv; + + if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr, + &data.pcr.disc_indicator_set) == 0) + return 0; + + /* + * When we play from front-end, we configure HW + * to output the extra timestamp, if we are playing + * from DVR, we don't have a timestamp if the packet + * format is not 192-tail. + */ + if ((mpq_demux->source >= DMX_SOURCE_DVR0) && + (mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) { + stc = 0; + } else { + stc = buf[STC_LOCATION_IDX + 2] << 16; + stc += buf[STC_LOCATION_IDX + 1] << 8; + stc += buf[STC_LOCATION_IDX]; + stc *= 256; /* convert from 105.47 KHZ to 27MHz */ + } + + data.data_length = 0; + data.pcr.stc = stc; + data.status = DMX_OK_PCR; + feed->data_ready_cb.ts(&feed->feed.ts, &data); + + return 0; +} + +int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed) +{ + struct mpq_video_feed_info *feed_data = &mpq_feed->video_info; + struct mpq_streambuffer *stream_buffer; + struct mpq_streambuffer_packet_header oob_packet; + struct mpq_adapter_video_meta_data oob_meta_data; + int ret; + + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + memset(&oob_packet, 0, sizeof(oob_packet)); + oob_packet.user_data_len = sizeof(oob_meta_data); + oob_meta_data.packet_type = DMX_EOS_PACKET; + + ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet, + (u8 *)&oob_meta_data); + + spin_unlock(&feed_data->video_buffer_lock); + return (ret < 0) ? ret : 0; +} + +void mpq_dmx_convert_tts(struct dvb_demux_feed *feed, + const u8 timestamp[TIMESTAMP_LEN], + u64 *timestampIn27Mhz) +{ + if (unlikely(!timestampIn27Mhz)) + return; + + *timestampIn27Mhz = timestamp[2] << 16; + *timestampIn27Mhz += timestamp[1] << 8; + *timestampIn27Mhz += timestamp[0]; + *timestampIn27Mhz *= 256; /* convert from 105.47 KHZ to 27MHz */ +} + +int mpq_sdmx_open_session(struct mpq_demux *mpq_demux) +{ + enum sdmx_status ret = SDMX_SUCCESS; + enum sdmx_proc_mode proc_mode; + enum sdmx_pkt_format pkt_format; + + MPQ_DVB_DBG_PRINT("%s: ref_count %d\n", + __func__, mpq_demux->sdmx_session_ref_count); + + if (mpq_demux->sdmx_session_ref_count) { + /* session is already open */ + mpq_demux->sdmx_session_ref_count++; + return ret; + } + + proc_mode = (mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) ? + SDMX_PUSH_MODE : SDMX_PULL_MODE; + MPQ_DVB_DBG_PRINT( + "%s: Proc mode = %s\n", + __func__, SDMX_PUSH_MODE == proc_mode ? "Push" : "Pull"); + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + pkt_format = SDMX_192_BYTE_PKT; + } else if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_188) { + pkt_format = SDMX_188_BYTE_PKT; + } else if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_192_TAIL) { + pkt_format = SDMX_192_BYTE_PKT; + } else { + MPQ_DVB_ERR_PRINT("%s: invalid tsp format\n", __func__); + return -EINVAL; + } + + MPQ_DVB_DBG_PRINT("%s: (%s) source, packet format: %d\n", + __func__, + (mpq_demux->source < DMX_SOURCE_DVR0) ? + "frontend" : "DVR", pkt_format); + + /* open session and set configuration */ + ret = sdmx_open_session(&mpq_demux->sdmx_session_handle); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: Could not open session. ret=%d\n", + __func__, ret); + return ret; + } + + MPQ_DVB_DBG_PRINT("%s: new session_handle = %d\n", + __func__, mpq_demux->sdmx_session_handle); + + ret = sdmx_set_session_cfg(mpq_demux->sdmx_session_handle, + proc_mode, + SDMX_PKT_ENC_MODE, + pkt_format, + mpq_sdmx_scramble_odd, + mpq_sdmx_scramble_even); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: Could not set session config. ret=%d\n", + __func__, ret); + sdmx_close_session(mpq_demux->sdmx_session_handle); + mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE; + return -EINVAL; + } + + ret = sdmx_set_log_level(mpq_demux->sdmx_session_handle, + mpq_demux->sdmx_log_level); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: Could not set log level. ret=%d\n", + __func__, ret); + /* Don't fail open session if just log level setting failed */ + ret = 0; + } + + mpq_demux->sdmx_process_count = 0; + mpq_demux->sdmx_process_time_sum = 0; + mpq_demux->sdmx_process_time_average = 0; + mpq_demux->sdmx_process_time_max = 0; + mpq_demux->sdmx_process_packets_sum = 0; + mpq_demux->sdmx_process_packets_average = 0; + mpq_demux->sdmx_process_packets_min = 0; + + mpq_demux->sdmx_session_ref_count++; + return ret; +} + +int mpq_sdmx_close_session(struct mpq_demux *mpq_demux) +{ + int ret = 0; + enum sdmx_status status; + + MPQ_DVB_DBG_PRINT("%s: session_handle = %d, ref_count %d\n", + __func__, + mpq_demux->sdmx_session_handle, + mpq_demux->sdmx_session_ref_count); + + if (!mpq_demux->sdmx_session_ref_count) + return -EINVAL; + + if (mpq_demux->sdmx_session_ref_count == 1) { + status = sdmx_close_session(mpq_demux->sdmx_session_handle); + if (status != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: sdmx_close_session failed %d\n", + __func__, status); + } + mpq_demux->sdmx_eos = 0; + mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE; + } + + mpq_demux->sdmx_session_ref_count--; + + return ret; +} + +static int mpq_sdmx_get_buffer_chunks(struct mpq_demux *mpq_demux, + struct ion_dma_buff_info *buff_info, + u32 actual_buff_size, + struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS]) +{ + int i; + struct sg_table *sg_ptr; + struct scatterlist *sg; + u32 chunk_size; + int ret; + + memset(buff_chunks, 0, + sizeof(struct sdmx_buff_descr) * SDMX_MAX_PHYSICAL_CHUNKS); + + sg_ptr = buff_info->sgt; + if (IS_ERR_OR_NULL(sg_ptr)) { + ret = PTR_ERR(sg_ptr); + MPQ_DVB_ERR_PRINT("%s: ion_sg_table failed, ret=%d\n", + __func__, ret); + if (!ret) + ret = -EINVAL; + return ret; + } + + if (sg_ptr->nents == 0) { + MPQ_DVB_ERR_PRINT("%s: num of scattered entries is 0\n", + __func__); + return -EINVAL; + } + + if (sg_ptr->nents > SDMX_MAX_PHYSICAL_CHUNKS) { + MPQ_DVB_ERR_PRINT( + "%s: num of scattered entries %d greater than max supported %d\n", + __func__, sg_ptr->nents, SDMX_MAX_PHYSICAL_CHUNKS); + return -EINVAL; + } + + sg = sg_ptr->sgl; + for (i = 0; i < sg_ptr->nents; i++) { + buff_chunks[i].base_addr = (u64)sg_dma_address(sg); + + if (sg->length > actual_buff_size) + chunk_size = actual_buff_size; + else + chunk_size = sg->length; + + buff_chunks[i].size = chunk_size; + sg = sg_next(sg); + actual_buff_size -= chunk_size; + } + + return 0; +} + +static int mpq_sdmx_init_data_buffer(struct mpq_demux *mpq_demux, + struct mpq_feed *feed, u32 *num_buffers, + struct sdmx_data_buff_descr buf_desc[DMX_MAX_DECODER_BUFFER_NUM], + enum sdmx_buf_mode *buf_mode) +{ + struct dvb_demux_feed *dvbdmx_feed = feed->dvb_demux_feed; + struct dvb_ringbuffer *buffer; + struct mpq_video_feed_info *feed_data = &feed->video_info; + struct ion_dma_buff_info *sdmx_buff; + int ret; + int i; + + *buf_mode = SDMX_RING_BUF; + + if (dvb_dmx_is_video_feed(feed->dvb_demux_feed)) { + + if (feed_data->buffer_desc.decoder_buffers_num > 1) + *buf_mode = SDMX_LINEAR_GROUP_BUF; + *num_buffers = feed_data->buffer_desc.decoder_buffers_num; + + MPQ_DVB_ERR_PRINT("%s: video feed case no of buffers=%zu\n", + __func__, *num_buffers); + + for (i = 0; i < *num_buffers; i++) { + buf_desc[i].length = + feed_data->buffer_desc.desc[i].size; + + ret = mpq_sdmx_get_buffer_chunks(mpq_demux, + &feed_data->buffer_desc.buff_dma_info[i], + buf_desc[i].length, + buf_desc[i].buff_chunks); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_get_buffer_chunks failed\n", + __func__); + return ret; + } + } + + return 0; + } + + *num_buffers = 1; + if (dvb_dmx_is_sec_feed(dvbdmx_feed) || + dvb_dmx_is_pcr_feed(dvbdmx_feed)) { + buffer = &feed->sdmx_buf; + sdmx_buff = &feed->sdmx_dma_buff; + + buf_desc[0].length = buffer->size; + buf_desc[0].buff_chunks[0].base_addr = + feed->data_desc.phys_base; + buf_desc[0].buff_chunks[0].size = feed->data_desc.size; + } else { + buffer = (struct dvb_ringbuffer *) + dvbdmx_feed->feed.ts.buffer.ringbuff; + + sdmx_buff = &dvbdmx_feed->feed.ts.buffer.buff_dma_info; + + if (sdmx_buff == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: Invalid buffer allocation\n", + __func__); + return -ENOMEM; + } + + buf_desc[0].length = buffer->size; + ret = mpq_sdmx_get_buffer_chunks(mpq_demux, sdmx_buff, + buf_desc[0].length, + buf_desc[0].buff_chunks); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_get_buffer_chunks failed\n", + __func__); + return ret; + } + + } + return 0; +} + +static int mpq_sdmx_filter_setup(struct mpq_demux *mpq_demux, + struct dvb_demux_feed *dvbdmx_feed) +{ + int ret = 0; + struct mpq_feed *feed; + struct mpq_feed *main_rec_feed = NULL; + struct dvb_demux_feed *tmp; + struct sdmx_buff_descr metadata_buff_desc; + struct sdmx_data_buff_descr *data_buff_desc = NULL; + u32 data_buf_num = DMX_MAX_DECODER_BUFFER_NUM; + enum sdmx_buf_mode buf_mode; + enum sdmx_raw_out_format ts_out_format = SDMX_188_OUTPUT; + u32 filter_flags = 0; + + feed = dvbdmx_feed->priv; + + if (dvb_dmx_is_sec_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_SECTION_FILTER; + if (dvbdmx_feed->feed.sec.check_crc) + filter_flags |= SDMX_FILTER_FLAG_VERIFY_SECTION_CRC; + MPQ_DVB_DBG_PRINT("%s: SDMX_SECTION_FILTER\n", __func__); + } else if (dvb_dmx_is_pcr_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_PCR_FILTER; + MPQ_DVB_DBG_PRINT("%s: SDMX_PCR_FILTER\n", __func__); + } else if (dvb_dmx_is_video_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_SEPARATED_PES_FILTER; + MPQ_DVB_DBG_PRINT("%s: SDMX_SEPARATED_PES_FILTER\n", __func__); + } else if (dvb_dmx_is_rec_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_RAW_FILTER; + switch (dvbdmx_feed->tsp_out_format) { + case (DMX_TSP_FORMAT_188): + ts_out_format = SDMX_188_OUTPUT; + break; + case (DMX_TSP_FORMAT_192_HEAD): + ts_out_format = SDMX_192_HEAD_OUTPUT; + break; + case (DMX_TSP_FORMAT_192_TAIL): + ts_out_format = SDMX_192_TAIL_OUTPUT; + break; + default: + MPQ_DVB_ERR_PRINT( + "%s: Unsupported TS output format %d\n", + __func__, dvbdmx_feed->tsp_out_format); + return -EINVAL; + } + MPQ_DVB_DBG_PRINT("%s: SDMX_RAW_FILTER\n", __func__); + } else { + feed->filter_type = SDMX_PES_FILTER; + MPQ_DVB_DBG_PRINT("%s: SDMX_PES_FILTER\n", __func__); + } + + data_buff_desc = vmalloc( + sizeof(*data_buff_desc)*DMX_MAX_DECODER_BUFFER_NUM); + if (!data_buff_desc) { + MPQ_DVB_ERR_PRINT( + "%s: failed to allocate memory for data buffer\n", + __func__); + return -ENOMEM; + } + + /* + * Recording feed sdmx filter handle lookup: + * In case this is a recording filter with multiple feeds, + * this feed is either the first feed of a new recording filter, + * or it is another feed of an existing filter for which a filter was + * already opened with sdmx. In such case, we need to look up in the + * feed pool for a allocated feed with same output buffer (meaning they + * belong to the same filter) and to use the already allocated sdmx + * filter handle. + */ + if (feed->filter_type == SDMX_RAW_FILTER) { + tmp = mpq_dmx_peer_rec_feed(dvbdmx_feed); + if (tmp) + main_rec_feed = tmp->priv; + } + + /* + * If this PID is not part of existing recording filter, + * configure a new filter to SDMX. + */ + if (!main_rec_feed) { + feed->secondary_feed = 0; + + MPQ_DVB_DBG_PRINT("%s: Adding new sdmx filter", __func__); + MPQ_DVB_DBG_PRINT("%s: pid %d, flags=0x%X, ts_out_format=%d\n", + __func__, dvbdmx_feed->pid, filter_flags, + ts_out_format); + + /* Meta-data initialization, + * Recording filters do no need meta-data buffers. + */ + if (dvb_dmx_is_rec_feed(dvbdmx_feed)) { + metadata_buff_desc.base_addr = 0; + metadata_buff_desc.size = 0; + } else { + ret = mpq_sdmx_init_metadata_buffer(mpq_demux, feed, + &metadata_buff_desc); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to initialize metadata buffer. ret=%d\n", + __func__, ret); + goto sdmx_filter_setup_failed; + } + } + + ret = mpq_sdmx_init_data_buffer(mpq_demux, feed, &data_buf_num, + data_buff_desc, &buf_mode); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to initialize data buffer. ret=%d\n", + __func__, ret); + mpq_sdmx_terminate_metadata_buffer(feed); + goto sdmx_filter_setup_failed; + } + ret = sdmx_add_filter(mpq_demux->sdmx_session_handle, + dvbdmx_feed->pid, + feed->filter_type, + &metadata_buff_desc, + buf_mode, + data_buf_num, + data_buff_desc, + &feed->sdmx_filter_handle, + ts_out_format, + filter_flags); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: SDMX_add_filter failed. ret = %d\n", + __func__, ret); + ret = -ENODEV; + mpq_sdmx_terminate_metadata_buffer(feed); + goto sdmx_filter_setup_failed; + } + + MPQ_DVB_DBG_PRINT( + "%s: filter pid=%d, handle=%d, data buffer(s)=%d, size=%d\n", + __func__, dvbdmx_feed->pid, + feed->sdmx_filter_handle, + data_buf_num, data_buff_desc[0].length); + + mpq_demux->sdmx_filter_count++; + } else { + MPQ_DVB_DBG_PRINT( + "%s: Adding RAW pid to sdmx, pid %d\n", + __func__, dvbdmx_feed->pid); + + feed->secondary_feed = 1; + feed->sdmx_filter_handle = main_rec_feed->sdmx_filter_handle; + ret = sdmx_add_raw_pid(mpq_demux->sdmx_session_handle, + feed->sdmx_filter_handle, dvbdmx_feed->pid); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to add raw pid, ret=%d\n", + __func__, ret); + ret = -ENODEV; + goto sdmx_filter_setup_failed; + } + } + + /* + * If pid has a key ladder id associated, we need to + * set it to SDMX. + */ + if (dvbdmx_feed->secure_mode.is_secured && + dvbdmx_feed->cipher_ops.operations_count) { + MPQ_DVB_DBG_PRINT( + "%s: set key-ladder %d to PID %d\n", + __func__, + dvbdmx_feed->cipher_ops.operations[0].key_ladder_id, + dvbdmx_feed->cipher_ops.pid); + + ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle, + dvbdmx_feed->cipher_ops.pid, + dvbdmx_feed->cipher_ops.operations[0].key_ladder_id); + + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to set key ladder, ret=%d\n", + __func__, ret); + } + } + + vfree(data_buff_desc); + return 0; + +sdmx_filter_setup_failed: + vfree(data_buff_desc); + return ret; +} + +/** + * mpq_sdmx_init_feed - initialize secure demux related elements of mpq feed + * + * @mpq_demux: mpq_demux object + * @mpq_feed: mpq_feed object + * + * Note: the function assumes mpq_demux->mutex locking is done by caller. + */ +static int mpq_sdmx_init_feed(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed) +{ + int ret; + + ret = mpq_sdmx_open_session(mpq_demux); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_open_session failed, ret=%d\n", + __func__, ret); + + ret = -ENODEV; + goto init_sdmx_feed_failed; + } + + /* PCR and sections have internal buffer for SDMX */ + if (dvb_dmx_is_pcr_feed(mpq_feed->dvb_demux_feed)) + ret = mpq_sdmx_alloc_data_buf(mpq_feed, SDMX_PCR_BUFFER_SIZE); + else if (dvb_dmx_is_sec_feed(mpq_feed->dvb_demux_feed)) + ret = mpq_sdmx_alloc_data_buf(mpq_feed, + SDMX_SECTION_BUFFER_SIZE); + else + ret = 0; + + if (ret) { + MPQ_DVB_ERR_PRINT("%s: init buffer failed, ret=%d\n", + __func__, ret); + goto init_sdmx_feed_failed_free_sdmx; + } + + ret = mpq_sdmx_filter_setup(mpq_demux, mpq_feed->dvb_demux_feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_filter_setup failed, ret=%d\n", + __func__, ret); + goto init_sdmx_feed_failed_free_data_buff; + } + + mpq_demux->num_secure_feeds++; + return 0; + +init_sdmx_feed_failed_free_data_buff: + mpq_sdmx_free_data_buf(mpq_feed); +init_sdmx_feed_failed_free_sdmx: + mpq_sdmx_close_session(mpq_demux); +init_sdmx_feed_failed: + return ret; +} + +int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed) +{ + int ret = 0; + struct mpq_demux *mpq_demux = feed->demux->priv; + struct mpq_feed *mpq_feed = feed->priv; + + if (mutex_lock_interruptible(&mpq_demux->mutex)) + return -ERESTARTSYS; + + mpq_feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE; + + if (feed->type != DMX_TYPE_SEC) + feed->feed.ts.flush_buffer = mpq_dmx_flush_buffer; + + if (dvb_dmx_is_video_feed(feed)) { + ret = mpq_dmx_init_video_feed(mpq_feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_init_video_feed failed, ret=%d\n", + __func__, ret); + goto init_mpq_feed_end; + } + } + + /* + * sdmx is not relevant for recording filters, which always use + * regular filters (non-sdmx) + */ + if (!mpq_sdmx_is_loaded() || !feed->secure_mode.is_secured || + dvb_dmx_is_rec_feed(feed)) { + if (!mpq_sdmx_is_loaded()) + mpq_demux->sdmx_session_handle = + SDMX_INVALID_SESSION_HANDLE; + MPQ_DVB_ERR_PRINT( + " %s: init feed exit\n", + __func__); + goto init_mpq_feed_end; + } + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_init_feed enter\n", + __func__); + MPQ_DVB_DBG_PRINT("%s: Init sdmx feed start\n", __func__); + + /* Initialization of secure demux filters (PES/PCR/Video/Section) */ + ret = mpq_sdmx_init_feed(mpq_demux, mpq_feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_init_feed failed, ret=%d\n", + __func__, ret); + if (dvb_dmx_is_video_feed(feed)) + mpq_dmx_terminate_video_feed(mpq_feed); + } + +init_mpq_feed_end: + if (!ret) { + mpq_demux->num_active_feeds++; + mpq_feed->session_id++; + } + mutex_unlock(&mpq_demux->mutex); + return ret; +} + +/** + * Note: Called only when filter is in "GO" state - after feed has been started. + */ +int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed, + struct dmx_cipher_operations *cipher_ops) +{ + struct mpq_feed *mpq_feed; + struct mpq_demux *mpq_demux; + int ret = 0; + + if (!feed || !feed->priv || !cipher_ops) { + MPQ_DVB_ERR_PRINT( + "%s: invalid parameters\n", + __func__); + return -EINVAL; + } + + MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n", + __func__, cipher_ops->pid, + cipher_ops->operations_count, + cipher_ops->operations[0].key_ladder_id); + + if ((cipher_ops->operations_count > 1) || + (cipher_ops->operations_count && + cipher_ops->operations[0].encrypt)) { + MPQ_DVB_ERR_PRINT( + "%s: Invalid cipher operations, count=%d, encrypt=%d\n", + __func__, cipher_ops->operations_count, + cipher_ops->operations[0].encrypt); + return -EINVAL; + } + + if (!feed->secure_mode.is_secured) { + /* + * Filter is not configured as secured, setting cipher + * operations is not allowed. + */ + MPQ_DVB_ERR_PRINT( + "%s: Cannot set cipher operations to non-secure filter\n", + __func__); + return -EPERM; + } + + mpq_feed = feed->priv; + mpq_demux = mpq_feed->mpq_demux; + + mutex_lock(&mpq_demux->mutex); + + /* + * Feed is running in secure mode, this secure mode request is to + * update the key ladder id + */ + if ((mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) && + cipher_ops->operations_count) { + ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle, + cipher_ops->pid, + cipher_ops->operations[0].key_ladder_id); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to set key ladder, ret=%d\n", + __func__, ret); + ret = -ENODEV; + } + } + + mutex_unlock(&mpq_demux->mutex); + + return ret; +} + +static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_ringbuffer *buffer; + int ret = 0; + + if (!dvb_dmx_is_video_feed(feed)) { + if (dvb_dmx_is_sec_feed(feed) || + dvb_dmx_is_pcr_feed(feed)) { + buffer = (struct dvb_ringbuffer *) + &mpq_feed->sdmx_buf; + } else { + buffer = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + } + } + return ret; +} + +static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux, + struct sdmx_filter_status *filter_sts, + struct mpq_feed *mpq_feed) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct mpq_video_feed_info *feed_data; + struct mpq_streambuffer *sbuff; + + filter_sts->filter_handle = mpq_feed->sdmx_filter_handle; + filter_sts->metadata_fill_count = + dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + filter_sts->metadata_write_offset = mpq_feed->metadata_buf.pwrite; + filter_sts->error_indicators = 0; + filter_sts->status_indicators = 0; + + MPQ_DVB_DBG_PRINT( + "%s: Filter meta-data buffer status: fill count = %d, write_offset = %d\n", + __func__, filter_sts->metadata_fill_count, + filter_sts->metadata_write_offset); + + if (!dvb_dmx_is_video_feed(feed)) { + struct dvb_ringbuffer *buffer; + + if (dvb_dmx_is_sec_feed(feed) || + dvb_dmx_is_pcr_feed(feed)) { + buffer = (struct dvb_ringbuffer *) + &mpq_feed->sdmx_buf; + } else { + buffer = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + } + + filter_sts->data_fill_count = dvb_ringbuffer_avail(buffer); + filter_sts->data_write_offset = buffer->pwrite; + + MPQ_DVB_DBG_PRINT( + "%s: Filter buffers status: fill count = %d, write_offset = %d\n", + __func__, filter_sts->data_fill_count, + filter_sts->data_write_offset); + + return; + } + + /* Video feed - decoder buffers */ + feed_data = &mpq_feed->video_info; + + spin_lock(&mpq_feed->video_info.video_buffer_lock); + sbuff = feed_data->video_buffer; + if (sbuff == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return; + } + + if (feed_data->buffer_desc.decoder_buffers_num > 1) { + /* linear mode */ + filter_sts->data_fill_count = sbuff->pending_buffers_count; + filter_sts->data_write_offset = + sbuff->raw_data.pwrite / + sizeof(struct mpq_streambuffer_buffer_desc); + } else { + /* ring buffer mode */ + filter_sts->data_fill_count = + mpq_streambuffer_data_avail(sbuff); + mpq_streambuffer_get_data_rw_offset(sbuff, NULL, + &filter_sts->data_write_offset); + + } + + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + + MPQ_DVB_DBG_PRINT( + "%s: Decoder buffers filter status: fill count = %d, write_offset = %d\n", + __func__, filter_sts->data_fill_count, + filter_sts->data_write_offset); +} + +static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed, + struct dvb_demux_filter *f, + struct sdmx_metadata_header *header) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + int ret; + u8 neq = 0; + u8 xor; + u8 tmp; + int i; + + if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) { + MPQ_DVB_ERR_PRINT( + "%s: Mutex should have been locked\n", + __func__); + return -EINVAL; + } + + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + tmp = DVB_RINGBUFFER_PEEK(&mpq_feed->sdmx_buf, i); + xor = f->filter.filter_value[i] ^ tmp; + + if (f->maskandmode[i] & xor) + return 0; + + neq |= f->maskandnotmode[i] & xor; + } + + if (f->doneq && !neq) + return 0; + + if (feed->demux->playback_mode == DMX_PB_MODE_PULL) { + mutex_unlock(&mpq_feed->mpq_demux->mutex); + + ret = feed->demux->buffer_ctrl.sec(&f->filter, + header->payload_length, 1); + + mutex_lock(&mpq_feed->mpq_demux->mutex); + + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: buffer_ctrl.sec aborted\n", + __func__); + return ret; + } + + if (mpq_feed->sdmx_filter_handle == + SDMX_INVALID_FILTER_HANDLE) { + MPQ_DVB_DBG_PRINT("%s: filter was stopped\n", + __func__); + return -ENODEV; + } + } + + if (mpq_feed->sdmx_buf.pread + header->payload_length < + mpq_feed->sdmx_buf.size) { + feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread], + header->payload_length, + NULL, 0, &f->filter); + } else { + int split = mpq_feed->sdmx_buf.size - mpq_feed->sdmx_buf.pread; + + feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread], + split, + &mpq_feed->sdmx_buf.data[0], + header->payload_length - split, + &f->filter); + } + + return 0; +} + +static int mpq_sdmx_check_ts_stall(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts, + size_t req, + int events_only) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + int ret; + + if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) { + MPQ_DVB_ERR_PRINT( + "%s: Mutex should have been locked\n", + __func__); + return -EINVAL; + } + + /* + * For PULL mode need to verify there is enough space for the dmxdev + * event. Also, if data buffer is full we want to stall until some + * data is removed from it to prevent calling the sdmx when it cannot + * output data to the still full buffer. + */ + if (mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) { + MPQ_DVB_DBG_PRINT("%s: Stalling for events and %zu bytes\n", + __func__, req); + + mutex_unlock(&mpq_demux->mutex); + + ret = mpq_demux->demux.buffer_ctrl.ts(&feed->feed.ts, req, 1); + MPQ_DVB_DBG_PRINT("%s: stall result = %d\n", + __func__, ret); + + mutex_lock(&mpq_demux->mutex); + + if (mpq_feed->sdmx_filter_handle == + SDMX_INVALID_FILTER_HANDLE) { + MPQ_DVB_DBG_PRINT("%s: filter was stopped\n", + __func__); + return -ENODEV; + } + + return ret; + } + + return 0; +} + +/* Handle filter results for filters with no extra meta-data */ +static void mpq_sdmx_pes_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + int ret; + struct sdmx_metadata_header header; + struct sdmx_pes_counters counters; + struct dmx_data_ready data_event; + struct dmx_data_ready pes_event; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + ssize_t bytes_avail; + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto pes_filter_check_overflow; + + MPQ_DVB_DBG_PRINT( + "%s: Meta: fill=%u, write=%u. Data: fill=%u, write=%u\n", + __func__, sts->metadata_fill_count, sts->metadata_write_offset, + sts->data_fill_count, sts->data_write_offset); + + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + + if ((sts->metadata_fill_count == 0) && + (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) { + ssize_t free = dvb_ringbuffer_free(buf); + + ret = 0; + if ((free + SZ_2K) < MAX_PES_LENGTH) + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, + free + SZ_2K, 0); + else + MPQ_DVB_ERR_PRINT( + "%s: Cannot stall when free space bigger than max PES size\n", + __func__); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + } + + while (sts->metadata_fill_count) { + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < (sizeof(header) + sizeof(counters))) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header) + sizeof(counters)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header, + sizeof(header)); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u\n", + __func__, header.payload_start, header.payload_length); + sts->metadata_fill_count -= sizeof(header); + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&counters, + sizeof(counters)); + sts->metadata_fill_count -= sizeof(counters); + + /* Notify new data in buffer */ + data_event.status = DMX_OK; + data_event.data_length = header.payload_length; + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, + data_event.data_length, 0); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + + /* Notify new complete PES */ + pes_event.status = DMX_OK_PES_END; + pes_event.pes_end.actual_length = header.payload_length; + pes_event.pes_end.start_gap = 0; + pes_event.data_length = 0; + + /* Parse error indicators */ + if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN) + pes_event.pes_end.pes_length_mismatch = 1; + else + pes_event.pes_end.pes_length_mismatch = 0; + + pes_event.pes_end.disc_indicator_set = 0; + + pes_event.pes_end.stc = 0; + pes_event.pes_end.tei_counter = counters.transport_err_count; + pes_event.pes_end.cont_err_counter = + counters.continuity_err_count; + pes_event.pes_end.ts_packets_num = + counters.pes_ts_count; + + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, 0, 1); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + feed->data_ready_cb.ts(&feed->feed.ts, &pes_event); + } + +pes_filter_check_overflow: + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) && + (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) { + MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__); + mpq_dmx_notify_overflow(feed); + } + + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + data_event.data_length = 0; + data_event.status = DMX_OK_EOS; + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + } +} + +static void mpq_sdmx_section_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + struct sdmx_metadata_header header; + struct dmx_data_ready event; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_demux_filter *f; + struct dmx_section_feed *sec = &feed->feed.sec; + ssize_t bytes_avail; + + /* Parse error indicators */ + if (sts->error_indicators & SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL) { + MPQ_DVB_DBG_PRINT("%s: Notify CRC err event\n", __func__); + event.status = DMX_CRC_ERROR; + event.data_length = 0; + dvb_dmx_notify_section_event(feed, &event, 1); + } + + if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL) + MPQ_DVB_ERR_PRINT("%s: internal section buffer overflowed!\n", + __func__); + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto section_filter_check_eos; + + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + mpq_feed->sdmx_buf.pwrite = sts->data_write_offset; + + while (sts->metadata_fill_count) { + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < sizeof(header)) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header, + sizeof(header)); + sts->metadata_fill_count -= sizeof(header); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u\n", + __func__, header.payload_start, header.payload_length); + + f = feed->filter; + do { + if (mpq_sdmx_section_filtering(mpq_feed, f, &header)) + return; + } while ((f = f->next) && sec->is_filtering); + + DVB_RINGBUFFER_SKIP(&mpq_feed->sdmx_buf, header.payload_length); + } + +section_filter_check_eos: + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + event.data_length = 0; + event.status = DMX_OK_EOS; + dvb_dmx_notify_section_event(feed, &event, 1); + } +} + +static void mpq_sdmx_decoder_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + struct sdmx_metadata_header header; + struct sdmx_pes_counters counters; + int pes_header_offset; + struct ts_packet_header *ts_header; + struct ts_adaptation_field *ts_adapt; + struct pes_packet_header *pes_header; + u8 metadata_buf[MAX_SDMX_METADATA_LENGTH]; + struct mpq_streambuffer *sbuf; + int ret; + struct dmx_data_ready data_event; + struct dmx_data_ready data; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + ssize_t bytes_avail; + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto decoder_filter_check_flags; + + /* Update meta data buffer write pointer */ + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) && + (sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) { + MPQ_DVB_DBG_PRINT("%s: Decoder stall...\n", __func__); + + ret = mpq_dmx_decoder_fullness_check( + mpq_feed->dvb_demux_feed, 0, 0); + if (ret) { + /* we reach here if demuxing was aborted */ + MPQ_DVB_DBG_PRINT( + "%s: mpq_dmx_decoder_fullness_check aborted\n", + __func__); + return; + } + } + + while (sts->metadata_fill_count) { + struct mpq_streambuffer_packet_header packet; + struct mpq_adapter_video_meta_data meta_data; + + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < (sizeof(header) + sizeof(counters))) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header) + sizeof(counters)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + /* Read metadata header */ + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header, + sizeof(header)); + sts->metadata_fill_count -= sizeof(header); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u, metadata=%u\n", + __func__, header.payload_start, header.payload_length, + header.metadata_length); + + /* Read metadata - PES counters */ + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&counters, + sizeof(counters)); + sts->metadata_fill_count -= sizeof(counters); + + /* Read metadata - TS & PES headers */ + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if ((header.metadata_length < MAX_SDMX_METADATA_LENGTH) && + (header.metadata_length >= sizeof(counters)) && + (bytes_avail >= + (header.metadata_length - sizeof(counters)))) { + dvb_ringbuffer_read(&mpq_feed->metadata_buf, + metadata_buf, + header.metadata_length - sizeof(counters)); + } else { + MPQ_DVB_ERR_PRINT( + "%s: meta-data size %d larger than available meta-data %zd or max allowed %d\n", + __func__, header.metadata_length, + bytes_avail, + MAX_SDMX_METADATA_LENGTH); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + sts->metadata_fill_count -= + (header.metadata_length - sizeof(counters)); + + ts_header = (struct ts_packet_header *)&metadata_buf[0]; + if (ts_header->adaptation_field_control == 1) { + ts_adapt = NULL; + pes_header_offset = sizeof(*ts_header); + } else { + ts_adapt = (struct ts_adaptation_field *) + &metadata_buf[sizeof(*ts_header)]; + pes_header_offset = sizeof(*ts_header) + 1 + + ts_adapt->adaptation_field_length; + } + pes_header = (struct pes_packet_header *) + &metadata_buf[pes_header_offset]; + meta_data.packet_type = DMX_PES_PACKET; + /* TODO - set to real STC when SDMX supports it */ + meta_data.info.pes.stc = 0; + + if (pes_header->pts_dts_flag & 0x2) { + meta_data.info.pes.pts_dts_info.pts_exist = 1; + meta_data.info.pes.pts_dts_info.pts = + ((u64)pes_header->pts_1 << 30) | + ((u64)pes_header->pts_2 << 22) | + ((u64)pes_header->pts_3 << 15) | + ((u64)pes_header->pts_4 << 7) | + (u64)pes_header->pts_5; + } else { + meta_data.info.pes.pts_dts_info.pts_exist = 0; + } + + if (pes_header->pts_dts_flag & 0x1) { + meta_data.info.pes.pts_dts_info.dts_exist = 1; + meta_data.info.pes.pts_dts_info.dts = + ((u64)pes_header->dts_1 << 30) | + ((u64)pes_header->dts_2 << 22) | + ((u64)pes_header->dts_3 << 15) | + ((u64)pes_header->dts_4 << 7) | + (u64)pes_header->dts_5; + } else { + meta_data.info.pes.pts_dts_info.dts_exist = 0; + } + + spin_lock(&mpq_feed->video_info.video_buffer_lock); + + mpq_feed->video_info.tei_errs = + counters.transport_err_count; + mpq_feed->video_info.continuity_errs = + counters.continuity_err_count; + mpq_feed->video_info.ts_packets_num = + counters.pes_ts_count; + mpq_feed->video_info.ts_dropped_bytes = + counters.drop_count * + mpq_demux->demux.ts_packet_size; + + sbuf = mpq_feed->video_info.video_buffer; + if (sbuf == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + return; + } + + if (!header.payload_length) { + MPQ_DVB_DBG_PRINT( + "%s: warnning - video frame with 0 length, dropping\n", + __func__); + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + continue; + } + + packet.raw_data_len = header.payload_length; + packet.user_data_len = sizeof(meta_data); + mpq_streambuffer_get_buffer_handle(sbuf, 0, + &packet.raw_data_handle); + mpq_streambuffer_get_data_rw_offset(sbuf, + NULL, &packet.raw_data_offset); + ret = mpq_streambuffer_data_write_deposit(sbuf, + header.payload_length); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_data_write_deposit failed. ret=%d\n", + __func__, ret); + } + mpq_dmx_update_decoder_stat(mpq_feed); + ret = mpq_streambuffer_pkt_write(sbuf, &packet, + (u8 *)&meta_data); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_pkt_write failed, ret=%d\n", + __func__, ret); + } else { + mpq_dmx_prepare_es_event_data( + &packet, &meta_data, &mpq_feed->video_info, + sbuf, &data, ret); + MPQ_DVB_DBG_PRINT("%s: Notify ES Event\n", __func__); + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } + + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + } + +decoder_filter_check_flags: + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) && + (sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) { + MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__); + mpq_dmx_notify_overflow(mpq_feed->dvb_demux_feed); + } + + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + /* Notify decoder via the stream buffer */ + ret = mpq_dmx_decoder_eos_cmd(mpq_feed); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: Failed to notify decoder on EOS, ret=%d\n", + __func__, ret); + + /* Notify user filter */ + data_event.data_length = 0; + data_event.status = DMX_OK_EOS; + mpq_feed->dvb_demux_feed->data_ready_cb.ts( + &mpq_feed->dvb_demux_feed->feed.ts, &data_event); + } +} + +static void mpq_sdmx_pcr_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + int ret; + struct sdmx_metadata_header header; + struct dmx_data_ready data; + struct dvb_ringbuffer *rbuff = &mpq_feed->sdmx_buf; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + u8 buf[TS_PACKET_HEADER_LENGTH + MAX_TSP_ADAPTATION_LENGTH + + TIMESTAMP_LEN]; + size_t stc_len = 0; + ssize_t bytes_avail; + + if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL) + MPQ_DVB_ERR_PRINT("%s: internal PCR buffer overflowed!\n", + __func__); + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto pcr_filter_check_eos; + + if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_192_TAIL) + stc_len = 4; + + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + rbuff->pwrite = sts->data_write_offset; + + while (sts->metadata_fill_count) { + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < sizeof(header)) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header, + sizeof(header)); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u\n", + __func__, header.payload_start, header.payload_length); + sts->metadata_fill_count -= sizeof(header); + + dvb_ringbuffer_read(rbuff, buf, header.payload_length); + + if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr, + &data.pcr.disc_indicator_set)) { + + if (stc_len) { + data.pcr.stc = + buf[header.payload_length-2] << 16; + data.pcr.stc += + buf[header.payload_length-3] << 8; + data.pcr.stc += buf[header.payload_length-4]; + /* convert from 105.47 KHZ to 27MHz */ + data.pcr.stc *= 256; + } else { + data.pcr.stc = 0; + } + + data.data_length = 0; + data.status = DMX_OK_PCR; + ret = mpq_sdmx_check_ts_stall( + mpq_demux, mpq_feed, sts, 0, 1); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } + } + +pcr_filter_check_eos: + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + data.data_length = 0; + data.status = DMX_OK_EOS; + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } +} + +static void mpq_sdmx_raw_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + int ret; + ssize_t new_data; + struct dmx_data_ready data_event; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto raw_filter_check_flags; + + new_data = sts->data_write_offset - + buf->pwrite; + if (new_data < 0) + new_data += buf->size; + + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, + new_data + feed->demux->ts_packet_size, 0); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + + data_event.status = DMX_OK; + data_event.data_length = new_data; + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + MPQ_DVB_DBG_PRINT("%s: Callback DMX_OK, size=%d\n", + __func__, data_event.data_length); + +raw_filter_check_flags: + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) && + (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) { + MPQ_DVB_DBG_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__); + mpq_dmx_notify_overflow(feed); + } + + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + data_event.data_length = 0; + data_event.status = DMX_OK_EOS; + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + } + +} + +static void mpq_sdmx_process_results(struct mpq_demux *mpq_demux) +{ + int i; + int sdmx_filters; + struct sdmx_filter_status *sts; + struct mpq_feed *mpq_feed; + u8 mpq_feed_idx; + + sdmx_filters = mpq_demux->sdmx_filter_count; + for (i = 0; i < sdmx_filters; i++) { + sts = &mpq_demux->sdmx_filters_state.status[i]; + MPQ_DVB_DBG_PRINT( + "%s: Filter: handle=%d, status=0x%x, errors=0x%x\n", + __func__, sts->filter_handle, sts->status_indicators, + sts->error_indicators); + MPQ_DVB_DBG_PRINT("%s: Metadata fill count=%d (write=%d)\n", + __func__, sts->metadata_fill_count, + sts->metadata_write_offset); + MPQ_DVB_DBG_PRINT("%s: Data fill count=%d (write=%d)\n", + __func__, sts->data_fill_count, sts->data_write_offset); + + mpq_feed_idx = mpq_demux->sdmx_filters_state.mpq_feed_idx[i]; + mpq_feed = &mpq_demux->feeds[mpq_feed_idx]; + if ((mpq_feed->dvb_demux_feed->state != DMX_STATE_GO) || + (sts->filter_handle != mpq_feed->sdmx_filter_handle) || + mpq_feed->secondary_feed || + (mpq_demux->sdmx_filters_state.session_id[i] != + mpq_feed->session_id)) + continue; + + /* Invalidate output buffer before processing the results */ + if (!mpq_demux->disable_cache_ops) + mpq_sdmx_invalidate_buffer(mpq_feed); + + if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL) + MPQ_DVB_ERR_PRINT( + "%s: meta-data buff for pid %d overflowed!\n", + __func__, mpq_feed->dvb_demux_feed->pid); + + switch (mpq_feed->filter_type) { + case SDMX_PCR_FILTER: + mpq_sdmx_pcr_filter_results(mpq_demux, mpq_feed, sts); + break; + case SDMX_PES_FILTER: + mpq_sdmx_pes_filter_results(mpq_demux, mpq_feed, + sts); + break; + case SDMX_SEPARATED_PES_FILTER: + mpq_sdmx_decoder_filter_results(mpq_demux, mpq_feed, + sts); + break; + case SDMX_SECTION_FILTER: + mpq_sdmx_section_filter_results(mpq_demux, mpq_feed, + sts); + break; + case SDMX_RAW_FILTER: + mpq_sdmx_raw_filter_results(mpq_demux, mpq_feed, sts); + break; + default: + break; + } + } +} + +static int mpq_sdmx_process_buffer(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *input, + u32 fill_count, + u32 read_offset) +{ + struct sdmx_filter_status *sts; + struct mpq_feed *mpq_feed; + u8 flags = 0; + u32 errors; + u32 status; + u32 prev_read_offset; + u32 prev_fill_count; + enum sdmx_status sdmx_res; + int i; + int filter_index = 0; + int bytes_read; + ktime_t process_start_time; + ktime_t process_end_time; + + mutex_lock(&mpq_demux->mutex); + + /* + * All active filters may get totally closed and therefore + * sdmx session may get terminated, in such case nothing to process + */ + if (mpq_demux->sdmx_session_handle == SDMX_INVALID_SESSION_HANDLE) { + MPQ_DVB_DBG_PRINT( + "%s: sdmx filters aborted, filter-count %d, session %d\n", + __func__, mpq_demux->sdmx_filter_count, + mpq_demux->sdmx_session_handle); + mutex_unlock(&mpq_demux->mutex); + return 0; + } + + /* Set input flags */ + if (mpq_demux->sdmx_eos) + flags |= SDMX_INPUT_FLAG_EOS; + if (mpq_sdmx_debug) + flags |= SDMX_INPUT_FLAG_DBG_ENABLE; + + /* Build up to date filter status array */ + for (i = 0; i < MPQ_MAX_DMX_FILES; i++) { + mpq_feed = &mpq_demux->feeds[i]; + if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE) + && (!mpq_feed->secondary_feed)) { + sts = mpq_demux->sdmx_filters_state.status + + filter_index; + mpq_sdmx_prepare_filter_status(mpq_demux, sts, + mpq_feed); + mpq_demux->sdmx_filters_state.mpq_feed_idx[filter_index] + = i; + mpq_demux->sdmx_filters_state.session_id[filter_index] = + mpq_feed->session_id; + filter_index++; + } + } + + /* Sanity check */ + if (filter_index != mpq_demux->sdmx_filter_count) { + mutex_unlock(&mpq_demux->mutex); + MPQ_DVB_ERR_PRINT( + "%s: Updated %d SDMX filters status but should be %d\n", + __func__, filter_index, mpq_demux->sdmx_filter_count); + return -ERESTART; + } + + MPQ_DVB_DBG_PRINT( + "%s: Before SDMX_process: input read_offset=%u, fill count=%u\n", + __func__, read_offset, fill_count); + + process_start_time = ktime_get(); + + prev_read_offset = read_offset; + prev_fill_count = fill_count; + sdmx_res = sdmx_process(mpq_demux->sdmx_session_handle, flags, input, + &fill_count, &read_offset, &errors, &status, + mpq_demux->sdmx_filter_count, + mpq_demux->sdmx_filters_state.status); + + process_end_time = ktime_get(); + bytes_read = prev_fill_count - fill_count; + + mpq_dmx_update_sdmx_stat(mpq_demux, bytes_read, + process_start_time, process_end_time); + + MPQ_DVB_DBG_PRINT( + "%s: SDMX result=%d, input_fill_count=%u, read_offset=%u, read %d bytes from input, status=0x%X, errors=0x%X\n", + __func__, sdmx_res, fill_count, read_offset, bytes_read, + status, errors); + + if ((sdmx_res == SDMX_SUCCESS) || + (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE)) { + if (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE) + MPQ_DVB_DBG_PRINT("%s: SDMX stalled for PULL mode\n", + __func__); + + mpq_sdmx_process_results(mpq_demux); + } else { + MPQ_DVB_ERR_PRINT( + "%s: SDMX Process returned %d\n", + __func__, sdmx_res); + } + + mutex_unlock(&mpq_demux->mutex); + + return bytes_read; +} + +int mpq_sdmx_process(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *input, + u32 fill_count, + u32 read_offset, + size_t tsp_size) +{ + int ret; + int todo; + int total_bytes_read = 0; + int limit = mpq_sdmx_proc_limit * tsp_size; + + MPQ_DVB_DBG_PRINT( + "%s: read_offset=%u, fill_count=%u, tsp_size=%zu\n", + __func__, read_offset, fill_count, tsp_size); + + while (fill_count >= tsp_size) { + todo = fill_count > limit ? limit : fill_count; + ret = mpq_sdmx_process_buffer(mpq_demux, input, todo, + read_offset); + + if (mpq_demux->demux.sw_filter_abort) { + MPQ_DVB_ERR_PRINT( + "%s: Demuxing from DVR was aborted\n", + __func__); + return -ENODEV; + } + + if (ret > 0) { + total_bytes_read += ret; + fill_count -= ret; + read_offset += ret; + if (read_offset >= input->size) + read_offset -= input->size; + } else { + /* + * ret < 0: some error occurred + * ret == 0: not enough data (less than 1 TS packet) + */ + if (ret < 0) + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_process_buffer failed, returned %d\n", + __func__, ret); + break; + } + } + + return total_bytes_read; +} + +static int mpq_sdmx_write(struct mpq_demux *mpq_demux, + struct ion_dma_buff_info *dvr_input_buff, + const char *buf, + size_t count) +{ + struct ion_dma_buff_info *buff; + struct dvb_ringbuffer *rbuf; + struct sdmx_buff_descr buf_desc; + u32 read_offset; + int ret; + + if (mpq_demux == NULL || dvr_input_buff == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + buff = &mpq_demux->demux.dmx.dvr_input.buff_dma_info; + rbuf = (struct dvb_ringbuffer *)mpq_demux->demux.dmx.dvr_input.ringbuff; + + ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to init input buffer descriptor. ret = %d\n", + __func__, ret); + return ret; + } + read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread; + + return mpq_sdmx_process(mpq_demux, &buf_desc, count, + read_offset, mpq_demux->demux.ts_packet_size); + return 0; +} + +int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count) +{ + struct dvb_demux *dvb_demux; + struct mpq_demux *mpq_demux; + int ret = count; + + if (demux == NULL) + return -EINVAL; + + dvb_demux = demux->priv; + mpq_demux = dvb_demux->priv; + + /* Route through secure demux - process secure feeds if any exist */ + if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) { + ret = mpq_sdmx_write(mpq_demux, + &demux->dvr_input.buff_dma_info, + buf, + count); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_write failed. ret = %d\n", + __func__, ret); + ret = count; + } + } + + /* + * Route through sw filter - process non-secure feeds if any exist. + * For sw filter, should process the same amount of bytes the sdmx + * process managed to consume, unless some sdmx error occurred, for + * which should process the whole buffer + */ + if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds) + dvb_dmx_swfilter_format(dvb_demux, buf, ret, + dvb_demux->tsp_format); + + if (signal_pending(current)) + return -EINTR; + + return ret; +} + +int mpq_sdmx_is_loaded(void) +{ + static int sdmx_load_checked; + + if (!sdmx_load_checked) { + mpq_sdmx_check_app_loaded(); + sdmx_load_checked = 1; + } + + return mpq_dmx_info.secure_demux_app_loaded; +} + +int mpq_dmx_oob_command(struct dvb_demux_feed *feed, + struct dmx_oob_command *cmd) +{ + struct mpq_feed *mpq_feed = feed->priv; + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + struct dmx_data_ready event; + int ret = 0; + + mutex_lock(&mpq_demux->mutex); + mpq_feed = feed->priv; + + if (!dvb_dmx_is_video_feed(feed) && !dvb_dmx_is_pcr_feed(feed) && + !feed->secure_mode.is_secured) { + mutex_unlock(&mpq_demux->mutex); + return 0; + } + + event.data_length = 0; + + switch (cmd->type) { + case DMX_OOB_CMD_EOS: + event.status = DMX_OK_EOS; + if (!feed->secure_mode.is_secured) { + if (dvb_dmx_is_video_feed(feed)) { + if (!video_framing) + mpq_dmx_decoder_pes_closure(mpq_demux, + mpq_feed); + else + mpq_dmx_decoder_frame_closure(mpq_demux, + mpq_feed); + ret = mpq_dmx_decoder_eos_cmd(mpq_feed); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: Couldn't write oob eos packet\n", + __func__); + } + ret = feed->data_ready_cb.ts(&feed->feed.ts, &event); + } else if (!mpq_demux->sdmx_eos) { + struct sdmx_buff_descr buf_desc; + + mpq_demux->sdmx_eos = 1; + ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc); + if (!ret) { + mutex_unlock(&mpq_demux->mutex); + mpq_sdmx_process_buffer(mpq_demux, &buf_desc, + 0, 0); + return 0; + } + } + break; + case DMX_OOB_CMD_MARKER: + event.status = DMX_OK_MARKER; + event.marker.id = cmd->params.marker.id; + + if (feed->type == DMX_TYPE_SEC) + ret = dvb_dmx_notify_section_event(feed, &event, 1); + else + /* MPQ_TODO: Notify decoder via the stream buffer */ + ret = feed->data_ready_cb.ts(&feed->feed.ts, &event); + break; + + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&mpq_demux->mutex); + return ret; +} diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h new file mode 100644 index 0000000000000000000000000000000000000000..9b00dacbfc38b592ca8435c7621e69eca9a1fc36 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h @@ -0,0 +1,1031 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_DMX_PLUGIN_COMMON_H +#define _MPQ_DMX_PLUGIN_COMMON_H + +#include + +#include "dvbdev.h" +#include "dmxdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "mpq_adapter.h" +#include "mpq_sdmx.h" + +#define TS_PACKET_SYNC_BYTE (0x47) +#define TS_PACKET_SIZE (188) +#define TS_PACKET_HEADER_LENGTH (4) + +/* Length of mandatory fields that must exist in header of video PES */ +#define PES_MANDATORY_FIELDS_LEN 9 + +/* + * 500 PES header packets in the meta-data buffer, + * should be more than enough + */ +#define VIDEO_NUM_OF_PES_PACKETS 500 + +#define VIDEO_META_DATA_PACKET_SIZE \ + (DVB_RINGBUFFER_PKTHDRSIZE + \ + sizeof(struct mpq_streambuffer_packet_header) + \ + sizeof(struct mpq_adapter_video_meta_data)) + +#define VIDEO_META_DATA_BUFFER_SIZE \ + (VIDEO_NUM_OF_PES_PACKETS * VIDEO_META_DATA_PACKET_SIZE) + +/* Max number open() request can be done on demux device */ +#define MPQ_MAX_DMX_FILES 128 + +/* TSIF alias name length */ +#define TSIF_NAME_LENGTH 20 + +enum demux_cache_ops { +DEMUX_CACHE_CLEAN, +DEMUX_CACHE_INVALIDATE, +}; + +/** + * struct ts_packet_header - Transport packet header + * as defined in MPEG2 transport stream standard. + */ +struct ts_packet_header { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned sync_byte:8; + unsigned transport_error_indicator:1; + unsigned payload_unit_start_indicator:1; + unsigned transport_priority:1; + unsigned pid_msb:5; + unsigned pid_lsb:8; + unsigned transport_scrambling_control:2; + unsigned adaptation_field_control:2; + unsigned continuity_counter:4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + unsigned sync_byte:8; + unsigned pid_msb:5; + unsigned transport_priority:1; + unsigned payload_unit_start_indicator:1; + unsigned transport_error_indicator:1; + unsigned pid_lsb:8; + unsigned continuity_counter:4; + unsigned adaptation_field_control:2; + unsigned transport_scrambling_control:2; +#else +#error "Please fix " +#endif +} __packed; + +/** + * struct ts_adaptation_field - Adaptation field prefix + * as defined in MPEG2 transport stream standard. + */ +struct ts_adaptation_field { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned adaptation_field_length:8; + unsigned discontinuity_indicator:1; + unsigned random_access_indicator:1; + unsigned elementary_stream_priority_indicator:1; + unsigned PCR_flag:1; + unsigned OPCR_flag:1; + unsigned splicing_point_flag:1; + unsigned transport_private_data_flag:1; + unsigned adaptation_field_extension_flag:1; + unsigned program_clock_reference_base_1:8; + unsigned program_clock_reference_base_2:8; + unsigned program_clock_reference_base_3:8; + unsigned program_clock_reference_base_4:8; + unsigned program_clock_reference_base_5:1; + unsigned reserved:6; + unsigned program_clock_reference_ext_1:1; + unsigned program_clock_reference_ext_2:8; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + unsigned adaptation_field_length:8; + unsigned adaptation_field_extension_flag:1; + unsigned transport_private_data_flag:1; + unsigned splicing_point_flag:1; + unsigned OPCR_flag:1; + unsigned PCR_flag:1; + unsigned elementary_stream_priority_indicator:1; + unsigned random_access_indicator:1; + unsigned discontinuity_indicator:1; + unsigned program_clock_reference_base_1:8; + unsigned program_clock_reference_base_2:8; + unsigned program_clock_reference_base_3:8; + unsigned program_clock_reference_base_4:8; + unsigned program_clock_reference_ext_1:1; + unsigned reserved:6; + unsigned program_clock_reference_base_5:1; + unsigned program_clock_reference_ext_2:8; +#else +#error "Please fix " +#endif +} __packed; + + +/* + * PES packet header containing dts and/or pts values + * as defined in MPEG2 transport stream standard. + */ +struct pes_packet_header { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned packet_start_code_prefix_1:8; + unsigned packet_start_code_prefix_2:8; + unsigned packet_start_code_prefix_3:8; + unsigned stream_id:8; + unsigned pes_packet_length_msb:8; + unsigned pes_packet_length_lsb:8; + unsigned reserved_bits0:2; + unsigned pes_scrambling_control:2; + unsigned pes_priority:1; + unsigned data_alignment_indicator:1; + unsigned copyright:1; + unsigned original_or_copy:1; + unsigned pts_dts_flag:2; + unsigned escr_flag:1; + unsigned es_rate_flag:1; + unsigned dsm_trick_mode_flag:1; + unsigned additional_copy_info_flag:1; + unsigned pes_crc_flag:1; + unsigned pes_extension_flag:1; + unsigned pes_header_data_length:8; + unsigned reserved_bits1:4; + unsigned pts_1:3; + unsigned marker_bit0:1; + unsigned pts_2:8; + unsigned pts_3:7; + unsigned marker_bit1:1; + unsigned pts_4:8; + unsigned pts_5:7; + unsigned marker_bit2:1; + unsigned reserved_bits2:4; + unsigned dts_1:3; + unsigned marker_bit3:1; + unsigned dts_2:8; + unsigned dts_3:7; + unsigned marker_bit4:1; + unsigned dts_4:8; + unsigned dts_5:7; + unsigned marker_bit5:1; + unsigned reserved_bits3:4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + unsigned packet_start_code_prefix_1:8; + unsigned packet_start_code_prefix_2:8; + unsigned packet_start_code_prefix_3:8; + unsigned stream_id:8; + unsigned pes_packet_length_lsb:8; + unsigned pes_packet_length_msb:8; + unsigned original_or_copy:1; + unsigned copyright:1; + unsigned data_alignment_indicator:1; + unsigned pes_priority:1; + unsigned pes_scrambling_control:2; + unsigned reserved_bits0:2; + unsigned pes_extension_flag:1; + unsigned pes_crc_flag:1; + unsigned additional_copy_info_flag:1; + unsigned dsm_trick_mode_flag:1; + unsigned es_rate_flag:1; + unsigned escr_flag:1; + unsigned pts_dts_flag:2; + unsigned pes_header_data_length:8; + unsigned marker_bit0:1; + unsigned pts_1:3; + unsigned reserved_bits1:4; + unsigned pts_2:8; + unsigned marker_bit1:1; + unsigned pts_3:7; + unsigned pts_4:8; + unsigned marker_bit2:1; + unsigned pts_5:7; + unsigned marker_bit3:1; + unsigned dts_1:3; + unsigned reserved_bits2:4; + unsigned dts_2:8; + unsigned marker_bit4:1; + unsigned dts_3:7; + unsigned dts_4:8; + unsigned marker_bit5:1; + unsigned dts_5:7; + unsigned reserved_bits3:4; +#else +#error "Please fix " +#endif +} __packed; + +/** + * mpq_decoder_buffers_desc - decoder buffer(s) management information. + * + * @desc: Array of buffer descriptors as they are passed to mpq_streambuffer + * upon its initialization. These descriptors must remain valid as long as + * the mpq_streambuffer object is used. + * @ion_handle: Array of ION handles, one for each decoder buffer, used for + * kernel memory mapping or allocation. Handles are saved in order to release + * resources properly later on. + * @decoder_buffers_num: number of buffers that are managed, either externally + * or internally by the mpq_streambuffer object + * @shared_file: File handle of internally allocated video buffer shared + * with video consumer. + */ +struct mpq_decoder_buffers_desc { + struct mpq_streambuffer_buffer_desc desc[DMX_MAX_DECODER_BUFFER_NUM]; + struct ion_dma_buff_info buff_dma_info[DMX_MAX_DECODER_BUFFER_NUM]; + u32 decoder_buffers_num; + struct file *shared_file; +}; + +/* + * mpq_video_feed_info - private data used for video feed. + * + * @video_buffer: Holds the streamer buffer shared with + * the decoder for feeds having the data going to the decoder. + * @video_buffer_lock: Lock protecting against video output buffer. + * The lock protects against API calls to manipulate the output buffer + * (initialize, free, re-use buffers) and dvb-sw demux parsing the video + * data through mpq_dmx_process_video_packet(). + * @buffer_desc: Holds decoder buffer(s) information used for stream buffer. + * @pes_header: Used for feeds that output data to decoder, + * holds PES header of current processed PES. + * @pes_header_left_bytes: Used for feeds that output data to decoder, + * holds remaining PES header bytes of current processed PES. + * @pes_header_offset: Holds the offset within the current processed + * pes header. + * @fullness_wait_cancel: Flag used to signal to abort waiting for + * decoder's fullness. + * @stream_interface: The ID of the video stream interface registered + * with this stream buffer. + * @patterns: pointer to the framing patterns to look for. + * @patterns_num: number of framing patterns. + * @prev_pattern: holds the trailing data of the last processed video packet. + * @frame_offset: Saves data buffer offset to which a new frame will be written + * @last_pattern_offset: Holds the previous pattern offset + * @pending_pattern_len: Accumulated number of data bytes that will be + * reported for this frame. + * @last_framing_match_type: Used for saving the type of + * the previous pattern match found in this video feed. + * @last_framing_match_stc: Used for saving the STC attached to TS packet + * of the previous pattern match found in this video feed. + * @found_sequence_header_pattern: Flag used to note that an MPEG-2 + * Sequence Header, H.264 SPS or VC-1 Sequence Header pattern + * (whichever is relevant according to the video standard) had already + * been found. + * @prefix_size: a bit mask representing the size(s) of possible prefixes + * to the pattern, already found in the previous buffer. If bit 0 is set, + * a prefix of size 1 was found. If bit 1 is set, a prefix of size 2 was + * found, etc. This supports a prefix size of up to 32, which is more + * than we need. The search function updates prefix_size as needed + * for the next buffer search. + * @first_prefix_size: used to save the prefix size used to find the first + * pattern written to the stream buffer. + * @saved_pts_dts_info: used to save PTS/DTS information until it is written. + * @new_pts_dts_info: used to store PTS/DTS information from current PES header. + * @saved_info_used: indicates if saved PTS/DTS information was used. + * @new_info_exists: indicates if new PTS/DTS information exists in + * new_pts_dts_info that should be saved to saved_pts_dts_info. + * @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs + * to be copied from the currently parsed PES header to the saved_pts_dts_info. + * @tei_errs: Transport stream Transport Error Indicator (TEI) counter. + * @last_continuity: last continuity counter value found in TS packet header. + * Initialized to -1. + * @continuity_errs: Transport stream continuity error counter. + * @ts_packets_num: TS packets counter. + * @ts_dropped_bytes: counts the number of bytes dropped due to insufficient + * buffer space. + * @prev_stc: STC attached to the previous video TS packet + */ +struct mpq_video_feed_info { + struct mpq_streambuffer *video_buffer; + spinlock_t video_buffer_lock; + struct mpq_decoder_buffers_desc buffer_desc; + struct pes_packet_header pes_header; + u32 pes_header_left_bytes; + u32 pes_header_offset; + int fullness_wait_cancel; + enum mpq_adapter_stream_if stream_interface; +const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM]; + int patterns_num; + char prev_pattern[DVB_DMX_MAX_PATTERN_LEN]; + u32 frame_offset; + u32 last_pattern_offset; + u32 pending_pattern_len; + u64 last_framing_match_type; + u64 last_framing_match_stc; + int found_sequence_header_pattern; + struct dvb_dmx_video_prefix_size_masks prefix_size; + u32 first_prefix_size; + struct dmx_pts_dts_info saved_pts_dts_info; + struct dmx_pts_dts_info new_pts_dts_info; + int saved_info_used; + int new_info_exists; + int first_pts_dts_copy; + u32 tei_errs; + int last_continuity; + u32 continuity_errs; + u32 ts_packets_num; + u32 ts_dropped_bytes; + u64 prev_stc; +}; + +/** + * mpq feed object - mpq common plugin feed information + * + * @dvb_demux_feed: Back pointer to dvb demux level feed object + * @mpq_demux: Pointer to common mpq demux object + * @plugin_priv: Plugin specific private data + * @sdmx_filter_handle: Secure demux filter handle. Recording feed may share + * same filter handle + * @secondary_feed: Specifies if this feed shares filter handle with + * other feeds + * @metadata_buf: Ring buffer object for managing the metadata buffer + * @metadata_buf_handle: Allocation handle for the metadata buffer + * @session_id: Counter that is incremented every time feed is initialized + * through mpq_dmx_init_mpq_feed + * @sdmx_buf: Ring buffer object for intermediate output data from the sdmx + * @sdmx_buf_handle: Allocation handle for the sdmx intermediate data buffer + * @video_info: Video feed specific information + */ +struct mpq_feed { + struct dvb_demux_feed *dvb_demux_feed; + struct mpq_demux *mpq_demux; + void *plugin_priv; + + /* Secure demux related */ + int sdmx_filter_handle; + int secondary_feed; + enum sdmx_filter filter_type; + struct dvb_ringbuffer metadata_buf; + struct ion_dma_buff_info metadata_dma_buff; + struct sdmx_buff_descriptor metadata_desc; + + u8 session_id; + struct dvb_ringbuffer sdmx_buf; + struct ion_dma_buff_info sdmx_dma_buff; + struct sdmx_buff_descriptor data_desc; + + struct mpq_video_feed_info video_info; +}; + +/** + * struct mpq_demux - mpq demux information + * @idx: Instance index + * @demux: The dvb_demux instance used by mpq_demux + * @dmxdev: The dmxdev instance used by mpq_demux + * @fe_memory: Handle of front-end memory source to mpq_demux + * @source: The current source connected to the demux + * @is_initialized: Indicates whether this demux device was + * initialized or not. + * @ion_client: ION demux client used to allocate memory from ION. + * @mutex: Lock used to protect against private feed data + * @feeds: mpq common feed object pool + * @num_active_feeds: Number of active mpq feeds + * @num_secure_feeds: Number of secure feeds (have a sdmx filter associated) + * currently allocated. + * Used before each call to sdmx_process() to build up to date state. + * @sdmx_session_handle: Secure demux open session handle + * @sdmx_filter_count: Number of active secure demux filters + * @sdmx_eos: End-of-stream indication flag for current sdmx session + * @sdmx_filters_state: Array holding buffers status for each secure + * demux filter. + * @decoder_alloc_flags: ION flags to be used when allocating internally + * @plugin_priv: Underlying plugin's own private data + * @mpq_dmx_plugin_release: Underlying plugin's release function + * @hw_notification_interval: Notification interval in msec, + * exposed in debugfs. + * @hw_notification_min_interval: Minimum notification internal in msec, + * exposed in debugfs. + * @hw_notification_count: Notification count, exposed in debugfs. + * @hw_notification_size: Notification size in bytes, exposed in debugfs. + * @hw_notification_min_size: Minimum notification size in bytes, + * exposed in debugfs. + * @decoder_stat: Decoder output statistics, exposed in debug-fs. + * @sdmx_process_count: Total number of times sdmx_process is called. + * @sdmx_process_time_sum: Total time sdmx_process takes. + * @sdmx_process_time_average: Average time sdmx_process takes. + * @sdmx_process_time_max: Max time sdmx_process takes. + * @sdmx_process_packets_sum: Total packets number sdmx_process handled. + * @sdmx_process_packets_average: Average packets number sdmx_process handled. + * @sdmx_process_packets_min: Minimum packets number sdmx_process handled. + * @last_notification_time: Time of last HW notification. + */ +struct mpq_demux { + int idx; + struct platform_device *pdev; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_memory; + dmx_source_t source; + int is_initialized; + struct ion_client *ion_client; + struct mutex mutex; + struct mpq_feed feeds[MPQ_MAX_DMX_FILES]; + u32 num_active_feeds; + u32 num_secure_feeds; + int sdmx_session_handle; + int sdmx_session_ref_count; + int sdmx_filter_count; + int sdmx_eos; + struct { + /* SDMX filters status */ + struct sdmx_filter_status status[MPQ_MAX_DMX_FILES]; + + /* Index of the feed respective to SDMX filter */ + u8 mpq_feed_idx[MPQ_MAX_DMX_FILES]; + + /* + * Snapshot of session_id of the feed + * when SDMX process was called. This is used + * to identify whether the feed has been + * restarted when processing SDMX results. + * May happen when demux is stalled in playback + * from memory with PULL mode. + */ + u8 session_id[MPQ_MAX_DMX_FILES]; + } sdmx_filters_state; + + unsigned int decoder_alloc_flags; + + /* HW plugin specific */ + void *plugin_priv; + int (*mpq_dmx_plugin_release)(struct mpq_demux *mpq_demux); + + /* debug-fs */ + u32 hw_notification_interval; + u32 hw_notification_min_interval; + u32 hw_notification_count; + u32 hw_notification_size; + u32 hw_notification_min_size; + + struct { + /* + * Accumulated number of bytes + * dropped due to decoder buffer fullness. + */ + u32 drop_count; + + /* Counter incremeneted for each video frame output by demux */ + u32 out_count; + + /* + * Sum of intervals (msec) holding the time + * between two successive video frames output. + */ + u32 out_interval_sum; + + /* + * Average interval (msec) between two + * successive video frames output. + */ + u32 out_interval_average; + + /* + * Max interval (msec) between two + * successive video frames output. + */ + u32 out_interval_max; + + /* Counter for number of decoder packets with TEI bit set */ + u32 ts_errors; + + /* + * Counter for number of decoder packets + * with continuity counter errors. + */ + u32 cc_errors; + + /* Time of last video frame output */ + ktime_t out_last_time; + } decoder_stat[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES]; + + u32 sdmx_process_count; + u32 sdmx_process_time_sum; + u32 sdmx_process_time_average; + u32 sdmx_process_time_max; + u32 sdmx_process_packets_sum; + u32 sdmx_process_packets_average; + u32 sdmx_process_packets_min; + enum sdmx_log_level sdmx_log_level; + + ktime_t last_notification_time; + int ts_packet_timestamp_source; + /* Disable cache operations on qseecom heap since not supported */ + int disable_cache_ops; +}; + +/** + * mpq_dmx_init - initialization and registration function of + * single MPQ demux device + * + * @adapter: The adapter to register mpq_demux to + * @mpq_demux: The mpq demux to initialize + * + * Every HW plug-in needs to provide implementation of such + * function that will be called for each demux device on the + * module initialization. The function mpq_demux_plugin_init + * should be called during the HW plug-in module initialization. + */ +typedef int (*mpq_dmx_init)(struct dvb_adapter *mpq_adapter, + struct mpq_demux *demux); + +/** + * mpq_demux_plugin_init - Initialize demux devices and register + * them to the dvb adapter. + * + * @dmx_init_func: Pointer to the function to be used + * to initialize demux of the underlying HW plugin. + * + * Return error code + * + * Should be called at the HW plugin module initialization. + */ +int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func, + struct platform_device *pdev); + +/** + * mpq_demux_plugin_exit - terminate demux devices. + * + * Should be called at the HW plugin module termination. + */ +void mpq_dmx_plugin_exit(void); + +/** + * mpq_dmx_set_source - implmenetation of set_source routine. + * + * @demux: The demux device to set its source. + * @src: The source to be set. + * + * Return error code + * + * Can be used by the underlying plugins to implement kernel + * demux API set_source routine. + */ +int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src); + +/** + * mpq_dmx_map_buffer - map user-space buffer into kernel space. + * + * @demux: The demux device. + * @dmx_buffer: The demux buffer from user-space, assumes that + * buffer handle is ION file-handle. + * @priv_handle: Saves ION-handle of the buffer imported by this function. + * @kernel_mem: Saves kernel mapped address of the buffer. + * + * Return error code + * + * The function maps the buffer into kernel memory only if the buffer + * was not allocated with secure flag, otherwise the returned kernel + * memory address is set to NULL. + */ +int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer, + struct ion_dma_buff_info *buff_dma_info, void **kernel_mem); + +/** + * mpq_dmx_unmap_buffer - unmap user-space buffer from kernel space memory. + * + * @demux: The demux device. + * @priv_handle: ION-handle of the buffer returned from mpq_dmx_map_buffer. + * + * Return error code + * + * The function unmaps the buffer from kernel memory only if the buffer + * was not allocated with secure flag. + */ +int mpq_dmx_unmap_buffer(struct dmx_demux *demux, + struct ion_dma_buff_info *buff_dma_info); + +/** + * mpq_dmx_decoder_fullness_init - Initialize waiting + * mechanism on decoder's buffer fullness. + * + * @feed: The decoder's feed + * + * Return error code. + */ +int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer + * have free space as required, if not, wait for it. + * + * @feed: The decoder's feed + * @required_space: the required free space to wait for + * + * Return error code. + */ +int mpq_dmx_decoder_fullness_wait(struct dvb_demux_feed *feed, + size_t required_space); + +/** + * mpq_dmx_decoder_fullness_abort - Aborts waiting + * on decoder's buffer fullness if any waiting is done + * now. After calling this, to wait again the user must + * call mpq_dmx_decoder_fullness_init. + * + * @feed: The decoder's feed + * + * Return error code. + */ +int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_decoder_buffer_status - Returns the + * status of the decoder's buffer. + * + * @feed: The decoder's feed + * @dmx_buffer_status: Status of decoder's buffer + * + * Return error code. + */ +int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed, + struct dmx_buffer_status *dmx_buffer_status); + +/** + * mpq_dmx_reuse_decoder_buffer - release buffer passed to decoder for reuse + * by the stream-buffer. + * + * @feed: The decoder's feed. + * @cookie: stream-buffer handle of the buffer. + * + * Return error code + * + * The function releases the buffer provided by the stream-buffer + * connected to the decoder back to the stream-buffer for reuse. + */ +int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie); + +/** + * mpq_dmx_process_video_packet - Assemble PES data and output it + * to the stream-buffer connected to the decoder. + * + * @feed: The feed used for the video TS packets + * @buf: The buffer holding video TS packet. + * + * Return error code. + * + * The function assumes it receives buffer with single TS packet + * of the relevant PID. + * If the output buffer is full while assembly, the function drops + * the packet and does not write them to the output buffer. + * Scrambled packets are bypassed. + */ +int mpq_dmx_process_video_packet(struct dvb_demux_feed *feed, const u8 *buf); + +/** + * mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from + * a 192 bytes packet. + * + * @feed: The feed used for the PCR TS packets + * @buf: The buffer holding pcr/stc packet. + * + * Return error code. + * + * The function assumes it receives buffer with single TS packet + * of the relevant PID, and that it has 4 bytes + * suffix as extra timestamp in the following format: + * + * Byte3: TSIF flags + * Byte0-2: TTS, 0..2^24-1 at 105.47 Khz (27*10^6/256). + * + * The function callbacks dmxdev after extraction of the pcr/stc + * pair. + */ +int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf); + +/** + * mpq_dmx_extract_pcr_and_dci() - Extract the PCR field and discontinuity + * indicator from a TS packet buffer. + * + * @buf: TS packet buffer + * @pcr: returned PCR value + * @dci: returned discontinuity indicator + * + * Returns 1 if PCR was extracted, 0 otherwise. + */ +int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci); + +/** + * mpq_dmx_init_debugfs_entries - + * Extend dvb-demux debugfs with mpq related entries (HW statistics and secure + * demux log level). + * + * @mpq_demux: The mpq_demux device to initialize. + */ +void mpq_dmx_init_debugfs_entries(struct mpq_demux *mpq_demux); + +/** + * mpq_dmx_update_hw_statistics - + * Update dvb-demux debugfs with HW notification statistics. + * + * @mpq_demux: The mpq_demux device to update. + */ +void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux); + +/** + * mpq_dmx_set_cipher_ops - Handles setting of cipher operations + * + * @feed: The feed to set its cipher operations + * @cipher_ops: Cipher operations to be set + * + * This common function handles only the case when working with + * secure-demux. When working with secure demux a single decrypt cipher + * operation is allowed. + * + * Return error code + */ +int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed, + struct dmx_cipher_operations *cipher_ops); + +/** + * mpq_dmx_convert_tts - Convert timestamp attached by HW to each TS + * packet to 27MHz. + * + * @feed: The feed with TTS attached + * @timestamp: Buffer holding the timestamp attached by the HW + * @timestampIn27Mhz: Timestamp result in 27MHz + * + * Return error code + */ +void mpq_dmx_convert_tts(struct dvb_demux_feed *feed, + const u8 timestamp[TIMESTAMP_LEN], + u64 *timestampIn27Mhz); + +/** + * mpq_sdmx_open_session - Handle the details of opening a new secure demux + * session for the specified mpq demux instance. Multiple calls to this + * is allowed, reference counting is managed to open it only when needed. + * + * @mpq_demux: mpq demux instance + * + * Return error code + */ +int mpq_sdmx_open_session(struct mpq_demux *mpq_demux); + +/** + * mpq_sdmx_close_session - Closes secure demux session. The session + * is closed only if reference counter of the session reaches 0. + * + * @mpq_demux: mpq demux instance + * + * Return error code + */ +int mpq_sdmx_close_session(struct mpq_demux *mpq_demux); + +/** + * mpq_dmx_init_mpq_feed - Initialize an mpq feed object + * The function allocates mpq_feed object and saves in the dvb_demux_feed + * priv field. + * + * @feed: A dvb demux level feed parent object + * + * Return error code + */ +int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_terminate_feed - Destroy an mpq feed object + * + * @feed: A dvb demux level feed parent object + * + * Return error code + */ +int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_init_video_feed() - Initializes video related data structures + * + * @mpq_feed: mpq_feed object to initialize + * + * Return error code + */ +int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed); + +/** + * mpq_dmx_terminate_video_feed() - Release video related feed resources + * + * @mpq_feed: mpq_feed object to terminate + * + * Return error code + */ +int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed); + +/** + * mpq_dmx_write - demux write() function implementation. + * + * A wrapper function used for writing new data into the demux via DVR. + * It checks where new data should actually go, the secure demux or the normal + * dvb demux software demux. + * + * @demux: demux interface + * @buf: input buffer + * @count: number of data bytes in input buffer + * + * Return number of bytes processed or error code + */ +int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count); + +/** + * mpq_sdmx_process - Perform demuxing process on the specified input buffer + * in the secure demux instance + * + * @mpq_demux: mpq demux instance + * @input: input buffer descriptor + * @fill_count: number of data bytes in input buffer that can be read + * @read_offset: offset in buffer for reading + * @tsp_size: size of single TS packet + * + * Return number of bytes read or error code + */ +int mpq_sdmx_process(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *input, + u32 fill_count, + u32 read_offset, + size_t tsp_size); + +/** + * mpq_sdmx_loaded - Returns 1 if secure demux application is loaded, + * 0 otherwise. This function should be used to determine whether or not + * processing should take place in the SDMX. + */ +int mpq_sdmx_is_loaded(void); + +/** + * mpq_dmx_oob_command - Handles OOB command from dvb-demux. + * + * OOB marker commands trigger callback to the dmxdev. + * Handling of EOS command may trigger current (last on stream) PES/Frame to + * be reported, in addition to callback to the dmxdev. + * In case secure demux is active for the feed, EOS command is passed to the + * secure demux for handling. + * + * @feed: dvb demux feed object + * @cmd: oob command data + * + * returns 0 on success or error + */ +int mpq_dmx_oob_command(struct dvb_demux_feed *feed, + struct dmx_oob_command *cmd); + +/** + * mpq_dmx_peer_rec_feed() - For a recording filter with multiple feeds objects + * search for a feed object that shares the same filter as the specified feed + * object, and return it. + * This can be used to test whether the specified feed object is the first feed + * allocate for the recording filter - return value is NULL. + * + * @feed: dvb demux feed object + * + * Return the dvb_demux_feed sharing the same filter's buffer or NULL if no + * such is found. + */ +struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_decoder_eos_cmd() - Report EOS event to the mpq_streambuffer + * + * @mpq_feed: Video mpq_feed object for notification + * @feed_type: Feed type( Video ) + * + * Return error code + */ +int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed); + +/** + * mpq_dmx_parse_mandatory_pes_header() - Parse non-optional PES header fields + * from TS packet buffer and save results in the feed object. + * + * @feed: Video dvb demux feed object + * @feed_data: Structure where results will be saved + * @pes_header: Saved PES header + * @buf: Input buffer containing TS packet with the PES header + * @ts_payload_offset: Offset in 'buf' where payload begins + * @bytes_avail: Length of actual payload + * + * Return error code + */ +int mpq_dmx_parse_mandatory_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail); + +/** + * mpq_dmx_parse_remaining_pes_header() - Parse optional PES header fields + * from TS packet buffer and save results in the feed object. + * This function depends on mpq_dmx_parse_mandatory_pes_header being called + * first for state to be valid. + * + * @feed: Video dvb demux feed object + * @feed_data: Structure where results will be saved + * @pes_header: Saved PES header + * @buf: Input buffer containing TS packet with the PES header + * @ts_payload_offset: Offset in 'buf' where payload begins + * @bytes_avail: Length of actual payload + * + * Return error code + */ +int mpq_dmx_parse_remaining_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail); + +/** + * mpq_dmx_flush_stream_buffer() - Flush video stream buffer object of the + * specific video feed, both meta-data packets and data. + * + * @feed: dvb demux video feed object + * + * Return error code + */ +int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_save_pts_dts() - Save the current PTS/DTS data + * + * @feed_data: Video feed structure where PTS/DTS is saved + */ +static inline void mpq_dmx_save_pts_dts(struct mpq_video_feed_info *feed_data) +{ + if (feed_data->new_info_exists) { + feed_data->saved_pts_dts_info.pts_exist = + feed_data->new_pts_dts_info.pts_exist; + feed_data->saved_pts_dts_info.pts = + feed_data->new_pts_dts_info.pts; + feed_data->saved_pts_dts_info.dts_exist = + feed_data->new_pts_dts_info.dts_exist; + feed_data->saved_pts_dts_info.dts = + feed_data->new_pts_dts_info.dts; + + feed_data->new_info_exists = 0; + feed_data->saved_info_used = 0; + } +} + +/** + * mpq_dmx_write_pts_dts() - Write out the saved PTS/DTS data and mark as used + * + * @feed_data: Video feed structure where PTS/DTS was saved + * @info: PTS/DTS structure to write to + */ +static inline void mpq_dmx_write_pts_dts(struct mpq_video_feed_info *feed_data, + struct dmx_pts_dts_info *info) +{ + if (!feed_data->saved_info_used) { + info->pts_exist = feed_data->saved_pts_dts_info.pts_exist; + info->pts = feed_data->saved_pts_dts_info.pts; + info->dts_exist = feed_data->saved_pts_dts_info.dts_exist; + info->dts = feed_data->saved_pts_dts_info.dts; + + feed_data->saved_info_used = 1; + } else { + info->pts_exist = 0; + info->dts_exist = 0; + } +} + +/* + * mpq_dmx_calc_time_delta - + * Calculate delta in msec between two time snapshots. + * + * @curr_time: value of current time + * @prev_time: value of previous time + * + * Return time-delta in msec + */ +static inline u32 mpq_dmx_calc_time_delta(ktime_t curr_time, ktime_t prev_time) +{ + s64 delta_time_ms = ktime_ms_delta(curr_time, prev_time); + + return (u32)delta_time_ms; +} + +void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed); + +/* Return the common module parameter tsif_mode */ +int mpq_dmx_get_param_tsif_mode(void); + +/* Return the common module parameter clock_inv */ +int mpq_dmx_get_param_clock_inv(void); + +/* Return the common module parameter mpq_sdmx_scramble_odd */ +int mpq_dmx_get_param_scramble_odd(void); + +/* Return the common module parameter mpq_sdmx_scramble_even */ +int mpq_dmx_get_param_scramble_even(void); + +/* Return the common module parameter mpq_sdmx_scramble_default_discard */ +int mpq_dmx_get_param_scramble_default_discard(void); + +#endif /* _MPQ_DMX_PLUGIN_COMMON_H */ diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c new file mode 100644 index 0000000000000000000000000000000000000000..a82804aaa2c48feecf6e66486fc1862a86f29b9f --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c @@ -0,0 +1,318 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 +#include +#include "mpq_dvb_debug.h" +#include "mpq_dmx_plugin_common.h" + + +static int mpq_sw_dmx_start_filtering(struct dvb_demux_feed *feed) +{ + int ret = -EINVAL; + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT("%s(pid=%d) executed\n", __func__, feed->pid); + + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid mpq_demux handle\n", __func__); + goto out; + } + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + MPQ_DVB_ERR_PRINT("%s: only DVR source is supported (%d)\n", + __func__, mpq_demux->source); + goto out; + } + + /* + * Always feed sections/PES starting from a new one and + * do not partial transfer data from older one + */ + feed->pusi_seen = 0; + + ret = mpq_dmx_init_mpq_feed(feed); + if (ret) + MPQ_DVB_ERR_PRINT("%s: mpq_dmx_init_mpq_feed failed(%d)\n", + __func__, ret); +out: + return ret; +} + +static int mpq_sw_dmx_stop_filtering(struct dvb_demux_feed *feed) +{ + int ret; + + MPQ_DVB_DBG_PRINT("%s: (pid=%d) executed\n", __func__, feed->pid); + + ret = mpq_dmx_terminate_feed(feed); + if (ret) + MPQ_DVB_ERR_PRINT("%s: mpq_dmx_terminate_feed failed(%d)\n", + __func__, ret); + + return ret; +} + +static int mpq_sw_dmx_write_to_decoder(struct dvb_demux_feed *feed, + const u8 *buf, size_t len) +{ + /* + * It is assumed that this function is called once for each + * TS packet of the relevant feed. + */ + if (len > (TIMESTAMP_LEN + TS_PACKET_SIZE)) + MPQ_DVB_DBG_PRINT( + "%s: warnning - len larger than one packet\n", + __func__); + + if (dvb_dmx_is_video_feed(feed)) + return mpq_dmx_process_video_packet(feed, buf); + + if (dvb_dmx_is_pcr_feed(feed)) + return mpq_dmx_process_pcr_packet(feed, buf); + + return 0; +} + +static int mpq_sw_dmx_set_source(struct dmx_demux *demux, + const dmx_source_t *src) +{ + int ret = -EINVAL; + + if (demux == NULL || demux->priv == NULL || src == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + goto out; + } + + if (*src >= DMX_SOURCE_DVR0 && *src <= DMX_SOURCE_DVR3) { + ret = mpq_dmx_set_source(demux, src); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_set_source(%d) failed, ret=%d\n", + __func__, *src, ret); + } else { + MPQ_DVB_ERR_PRINT("%s: not a DVR source\n", __func__); + } + +out: + return ret; +} + +static int mpq_sw_dmx_get_caps(struct dmx_demux *demux, struct dmx_caps *caps) +{ + struct dvb_demux *dvb_demux = demux->priv; + + if (dvb_demux == NULL || caps == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA | + DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING | + DMX_CAP_AUTO_BUFFER_FLUSH; + caps->recording_max_video_pids_indexed = 0; + caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; + caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->num_pid_filters = MPQ_MAX_DMX_FILES; + caps->num_section_filters = dvb_demux->filternum; + caps->num_section_filters_per_pid = dvb_demux->filternum; + caps->section_filter_length = DMX_FILTER_SIZE; + caps->num_demod_inputs = 0; + caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->max_bitrate = 192; + caps->demod_input_max_bitrate = 96; + caps->memory_input_max_bitrate = 96; + caps->num_cipher_ops = 1; + + /* No STC support */ + caps->max_stc = 0; + + /* Buffer requirements */ + caps->section.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->section.max_buffer_num = 1; + caps->section.max_size = 0xFFFFFFFF; + caps->section.size_alignment = 0; + caps->pes.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->pes.max_buffer_num = 1; + caps->pes.max_size = 0xFFFFFFFF; + caps->pes.size_alignment = 0; + caps->recording_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_188_tsp.max_buffer_num = 1; + caps->recording_188_tsp.max_size = 0xFFFFFFFF; + caps->recording_188_tsp.size_alignment = 0; + caps->recording_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_192_tsp.max_buffer_num = 1; + caps->recording_192_tsp.max_size = 0xFFFFFFFF; + caps->recording_192_tsp.size_alignment = 0; + caps->playback_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_188_tsp.max_buffer_num = 1; + caps->playback_188_tsp.max_size = 0xFFFFFFFF; + caps->playback_188_tsp.size_alignment = 188; + caps->playback_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_192_tsp.max_buffer_num = 1; + caps->playback_192_tsp.max_size = 0xFFFFFFFF; + caps->playback_192_tsp.size_alignment = 192; + caps->decoder.flags = + DMX_BUFFER_SECURED_IF_DECRYPTED | + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_LINEAR_GROUP_SUPPORT | + DMX_BUFFER_CACHED; + caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM; + caps->decoder.max_size = 0xFFFFFFFF; + caps->decoder.size_alignment = SZ_4K; + + return 0; +} + +static int mpq_sw_dmx_init(struct dvb_adapter *mpq_adapter, + struct mpq_demux *mpq_demux) +{ + int ret; + struct dvb_demux *dvb_demux = &mpq_demux->demux; + + /* Set the kernel-demux object capabilities */ + mpq_demux->demux.dmx.capabilities = + DMX_TS_FILTERING | + DMX_PES_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING | + DMX_CRC_CHECKING | + DMX_TS_DESCRAMBLING; + + /* Set dvb-demux "virtual" function pointers */ + dvb_demux->priv = (void *)mpq_demux; + dvb_demux->filternum = MPQ_MAX_DMX_FILES; + dvb_demux->feednum = MPQ_MAX_DMX_FILES; + dvb_demux->start_feed = mpq_sw_dmx_start_filtering; + dvb_demux->stop_feed = mpq_sw_dmx_stop_filtering; + dvb_demux->write_to_decoder = mpq_sw_dmx_write_to_decoder; + dvb_demux->decoder_fullness_init = mpq_dmx_decoder_fullness_init; + dvb_demux->decoder_fullness_wait = mpq_dmx_decoder_fullness_wait; + dvb_demux->decoder_fullness_abort = mpq_dmx_decoder_fullness_abort; + dvb_demux->decoder_buffer_status = mpq_dmx_decoder_buffer_status; + dvb_demux->reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer; + dvb_demux->set_cipher_op = mpq_dmx_set_cipher_ops; + dvb_demux->oob_command = mpq_dmx_oob_command; + dvb_demux->convert_ts = mpq_dmx_convert_tts; + dvb_demux->flush_decoder_buffer = NULL; + + /* Initialize dvb_demux object */ + ret = dvb_dmx_init(dvb_demux); + if (ret) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed, ret=%d\n", + __func__, ret); + goto init_failed; + } + + /* Now initialize the dmx-dev object */ + mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES; + mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx; + mpq_demux->dmxdev.capabilities = DMXDEV_CAP_DUPLEX; + + mpq_demux->dmxdev.demux->set_source = mpq_sw_dmx_set_source; + mpq_demux->dmxdev.demux->get_stc = NULL; + mpq_demux->dmxdev.demux->get_caps = mpq_sw_dmx_get_caps; + mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer; + mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer; + mpq_demux->dmxdev.demux->write = mpq_dmx_write; + ret = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter); + if (ret) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed, ret=%d\n", + __func__, ret); + goto init_failed_dmx_release; + } + + /* Extend dvb-demux debugfs with mpq demux statistics. */ + mpq_dmx_init_debugfs_entries(mpq_demux); + + return 0; + +init_failed_dmx_release: + dvb_dmx_release(dvb_demux); +init_failed: + return ret; +} + + +static int mpq_dmx_sw_plugin_probe(struct platform_device *pdev) +{ + return mpq_dmx_plugin_init(mpq_sw_dmx_init, pdev); +} + +static int mpq_dmx_sw_plugin_remove(struct platform_device *pdev) +{ + mpq_dmx_plugin_exit(); + return 0; +} + + +/*** power management ***/ +static const struct of_device_id msm_match_table[] = { + {.compatible = "qcom,demux"}, + {} +}; + +static struct platform_driver mpq_dmx_sw_plugin_driver = { + .probe = mpq_dmx_sw_plugin_probe, + .remove = mpq_dmx_sw_plugin_remove, + .driver = { + .name = "demux", + .of_match_table = msm_match_table, + }, +}; + + +static int __init mpq_dmx_sw_plugin_init(void) +{ + int rc; + + /* register the driver, and check hardware */ + rc = platform_driver_register(&mpq_dmx_sw_plugin_driver); + if (rc) + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_sw_plugin: platform_driver_register failed: %d\n" + __func__, rc); + + return rc; +} + +static void __exit mpq_dmx_sw_plugin_exit(void) +{ + /* delete low level driver */ + platform_driver_unregister(&mpq_dmx_sw_plugin_driver); +} + + +module_init(mpq_dmx_sw_plugin_init); +module_exit(mpq_dmx_sw_plugin_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. demux software plugin"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c new file mode 100644 index 0000000000000000000000000000000000000000..ea1d1eb27735a2c039231d23586e6774bdbc8b97 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c @@ -0,0 +1,1994 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_dmx_plugin_common.h" + +#define TSIF_COUNT 2 + +/* Max number of PID filters */ +#define TSPP_MAX_PID_FILTER_NUM 128 + +/* Max number of user-defined HW PID filters */ +#define TSPP_MAX_HW_PID_FILTER_NUM 15 + +/* HW index of the last entry in the TSPP HW filter table */ +#define TSPP_LAST_HW_FILTER_INDEX 15 + +/* Number of filters required to accept all packets except NULL packets */ +#define TSPP_BLOCK_NULLS_FILTERS_NUM 13 + +/* Max number of section filters */ +#define TSPP_MAX_SECTION_FILTER_NUM 128 + +/* For each TSIF we use a single pipe holding the data after PID filtering */ +#define TSPP_CHANNEL 0 + +/* the channel_id set to TSPP driver based on TSIF number and channel type */ +#define TSPP_CHANNEL_ID(tsif, ch) ((tsif << 1) + ch) +#define TSPP_GET_TSIF_NUM(ch_id) (ch_id >> 1) + +/* mask that set to care for all bits in pid filter */ +#define TSPP_PID_MASK 0x1FFF + +/* dvb-demux defines pid 0x2000 as full capture pid */ +#define TSPP_PASS_THROUGH_PID 0x2000 + +/* NULL packets pid */ +#define TSPP_NULL_PACKETS_PID 0x1FFF + +#define TSPP_RAW_TTS_SIZE 192 +#define TSPP_RAW_SIZE 188 + +#define MAX_BAM_DESCRIPTOR_SIZE (32 * 1024 - 1) + +#define MAX_BAM_DESCRIPTOR_COUNT (8 * 1024 - 2) + +#define TSPP_BUFFER_SIZE (500 * 1024) /* 500KB */ + +#define TSPP_DEFAULT_DESCRIPTOR_SIZE (TSPP_RAW_TTS_SIZE) + +#define TSPP_BUFFER_COUNT(buffer_size) \ + ((buffer_size) / tspp_desc_size) + +/* When TSPP notifies demux that new packets are received. + * Using max descriptor size (170 packets). + * Assuming 20MBit/sec stream, with 170 packets + * per descriptor there would be about 82 descriptors, + * Meaning about 82 notifications per second. + */ +#define TSPP_NOTIFICATION_SIZE(desc_size) \ + (MAX_BAM_DESCRIPTOR_SIZE / (desc_size)) + +/* Channel timeout in msec */ +#define TSPP_CHANNEL_TIMEOUT 100 + +enum mem_buffer_allocation_mode { + MPQ_DMX_TSPP_INTERNAL_ALLOC = 0, + MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC = 1 +}; + +/* module parameters for load time configuration */ +static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC; +static int tspp_out_buffer_size = TSPP_BUFFER_SIZE; +static int tspp_desc_size = TSPP_DEFAULT_DESCRIPTOR_SIZE; +static int tspp_notification_size = + TSPP_NOTIFICATION_SIZE(TSPP_DEFAULT_DESCRIPTOR_SIZE); +static int tspp_channel_timeout = TSPP_CHANNEL_TIMEOUT; +static int tspp_out_ion_heap = ION_QSECOM_HEAP_ID; + +module_param(allocation_mode, int, 0644); +module_param(tspp_out_buffer_size, int, 0644); +module_param(tspp_desc_size, int, 0644); +module_param(tspp_notification_size, int, 0644); +module_param(tspp_channel_timeout, int, 0644); +module_param(tspp_out_ion_heap, int, 0644); + +/* The following structure hold singleton information + * required for dmx implementation on top of TSPP. + */ +static struct +{ + /* Information for each TSIF input processing */ + struct { + /* + * TSPP pipe holding all TS packets after PID filtering. + * The following is reference count for number of feeds + * allocated on that pipe. + */ + int channel_ref; + + /* Counter for data notifications on the pipe */ + atomic_t data_cnt; + + /* flag to indicate control operation is in progress */ + atomic_t control_op; + + /* ION handle used for TSPP data buffer allocation */ + struct ion_handle *ch_mem_heap_handle; + + /* TSPP data buffer heap virtual base address */ + void *ch_mem_heap_virt_base; + + /* TSPP data buffer heap physical base address */ + phys_addr_t ch_mem_heap_phys_base; + + /* Buffer allocation index */ + int buff_index; + + /* Number of buffers */ + u32 buffer_count; + + /* + * Array holding the IDs of the TSPP buffer descriptors in the + * current aggregate, in order to release these descriptors at + * the end of processing. + */ + int *aggregate_ids; + + /* + * Holds PIDs of allocated filters along with + * how many feeds are opened on the same PID. For + * TSPP HW filters, holds also the filter table index. + * When pid == -1, the entry is free. + */ + struct { + int pid; + int ref_count; + int hw_index; + } filters[TSPP_MAX_PID_FILTER_NUM]; + + /* Indicates available/allocated filter table indexes */ + int hw_indexes[TSPP_MAX_HW_PID_FILTER_NUM]; + + /* Number of currently allocated PID filters */ + u16 current_filter_count; + + /* + * Flag to indicate whether the user added a filter to accept + * NULL packets (PID = 0x1FFF) + */ + int pass_nulls_flag; + + /* + * Flag to indicate whether the user added a filter to accept + * all packets (PID = 0x2000) + */ + int pass_all_flag; + + /* + * Flag to indicate whether the filter that accepts + * all packets has already been added and is + * currently enabled + */ + int accept_all_filter_exists_flag; + + /* Thread processing TS packets from TSPP */ + struct task_struct *thread; + wait_queue_head_t wait_queue; + + /* TSIF alias */ + char name[TSIF_NAME_LENGTH]; + + /* Pointer to the demux connected to this TSIF */ + struct mpq_demux *mpq_demux; + + /* Mutex protecting the data-structure */ + struct mutex mutex; + + /* ion dma buffer mapping structure */ + struct tspp_ion_dma_buf_info ch_ion_dma_buf; + + } tsif[TSIF_COUNT]; + + /* ION client used for TSPP data buffer allocation */ + struct ion_client *ion_client; +} mpq_dmx_tspp_info; + +static void *tspp_mem_allocator(int channel_id, u32 size, + phys_addr_t *phys_base, dma_addr_t *dma_base, + void *user) +{ + void *virt_addr = NULL; + int i = TSPP_GET_TSIF_NUM(channel_id); + + if (mpq_dmx_tspp_info.tsif[i].buff_index == + mpq_dmx_tspp_info.tsif[i].buffer_count) + return NULL; + + virt_addr = + (mpq_dmx_tspp_info.tsif[i].ch_mem_heap_virt_base + + (mpq_dmx_tspp_info.tsif[i].buff_index * size)); + + *phys_base = + (mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base + + (mpq_dmx_tspp_info.tsif[i].buff_index * size)); + + mpq_dmx_tspp_info.tsif[i].buff_index++; + + return virt_addr; +} + +static void tspp_mem_free(int channel_id, u32 size, + void *virt_base, phys_addr_t phys_base, void *user) +{ + int i = TSPP_GET_TSIF_NUM(channel_id); + + /* + * actual buffer heap free is done in mpq_dmx_tspp_plugin_exit(). + * we update index here, so if this function is called repetitively + * for all the buffers, then afterwards tspp_mem_allocator() + * can be called again. + * Note: it would be incorrect to call tspp_mem_allocator() + * a few times, then call tspp_mem_free(), then call + * tspp_mem_allocator() again. + */ + if (mpq_dmx_tspp_info.tsif[i].buff_index > 0) + mpq_dmx_tspp_info.tsif[i].buff_index--; +} + +/** + * Returns a free HW filter index that can be used. + * + * @tsif: The TSIF to allocate filter from + * + * Return HW filter index or -ENOMEM if no filters available + */ +static int mpq_tspp_allocate_hw_filter_index(int tsif) +{ + int i; + + for (i = 0; i < TSPP_MAX_HW_PID_FILTER_NUM; i++) { + if (mpq_dmx_tspp_info.tsif[tsif].hw_indexes[i] == 0) { + mpq_dmx_tspp_info.tsif[tsif].hw_indexes[i] = 1; + return i; + } + } + + return -ENOMEM; +} + +/** + * Releases a HW filter index for future reuse. + * + * @tsif: The TSIF from which the filter should be released + * @hw_index: The HW index to release + * + */ +static inline void mpq_tspp_release_hw_filter_index(int tsif, int hw_index) +{ + if ((hw_index >= 0) && (hw_index < TSPP_MAX_HW_PID_FILTER_NUM)) + mpq_dmx_tspp_info.tsif[tsif].hw_indexes[hw_index] = 0; +} + + +/** + * Returns a free filter slot that can be used. + * + * @tsif: The TSIF to allocate filter from + * + * Return filter index or -ENOMEM if no filters available + */ +static int mpq_tspp_get_free_filter_slot(int tsif) +{ + int slot; + + for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == -1) + return slot; + + return -ENOMEM; +} + +/** + * Returns filter index of specific pid. + * + * @tsif: The TSIF to which the pid is allocated + * @pid: The pid to search for + * + * Return filter index or -1 if no filter available + */ +static int mpq_tspp_get_filter_slot(int tsif, int pid) +{ + int slot; + + for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == pid) + return slot; + + return -EINVAL; +} + +/** + * mpq_dmx_tspp_swfilter_desc - helper function + * + * Takes a tspp buffer descriptor and send it to the SW filter for demuxing, + * one TS packet at a time. + * + * @mpq_demux - mpq demux object + * @tspp_data_desc - tspp buffer descriptor + */ +static inline void mpq_dmx_tspp_swfilter_desc(struct mpq_demux *mpq_demux, + const struct tspp_data_descriptor *tspp_data_desc) +{ + u32 notif_size; + int i; + + notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE; + for (i = 0; i < notif_size; i++) + dvb_dmx_swfilter_packet(&mpq_demux->demux, + ((u8 *)tspp_data_desc->virt_base) + + i * TSPP_RAW_TTS_SIZE, + ((u8 *)tspp_data_desc->virt_base) + + i * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE); +} + +/** + * Demux TS packets from TSPP by secure-demux. + * The function assumes the buffer is physically contiguous + * and that TSPP descriptors are continuous in memory. + * + * @tsif: The TSIF interface to process its packets + * @channel_id: the TSPP output pipe with the TS packets + */ +static void mpq_dmx_tspp_aggregated_process(int tsif, int channel_id) +{ + const struct tspp_data_descriptor *tspp_data_desc; + struct mpq_demux *mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux; + struct sdmx_buff_descr input; + size_t aggregate_len = 0; + size_t aggregate_count = 0; + phys_addr_t buff_start_addr_phys; + phys_addr_t buff_current_addr_phys = 0; + u32 notif_size; + int i; + + while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) { + if (aggregate_count == 0) + buff_current_addr_phys = tspp_data_desc->phys_base; + notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE; + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[aggregate_count] = + tspp_data_desc->id; + aggregate_len += tspp_data_desc->size; + aggregate_count++; + mpq_demux->hw_notification_size += notif_size; + + /* Let SW filter process only if it might be relevant */ + if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds) + mpq_dmx_tspp_swfilter_desc(mpq_demux, tspp_data_desc); + + } + + if (!aggregate_count) + return; + + buff_start_addr_phys = + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base; + + input.base_addr = (u64)buff_start_addr_phys; + input.size = mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size; + + if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) { + MPQ_DVB_DBG_PRINT( + "%s: SDMX Processing %zu descriptors: %zu bytes at start address 0x%llx, read offset %d\n", + __func__, aggregate_count, aggregate_len, + input.base_addr, + (int)(buff_current_addr_phys - buff_start_addr_phys)); + + mpq_sdmx_process(mpq_demux, &input, aggregate_len, + buff_current_addr_phys - buff_start_addr_phys, + TSPP_RAW_TTS_SIZE); + } + + for (i = 0; i < aggregate_count; i++) + tspp_release_buffer(0, channel_id, + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[i]); +} + + +/** + * Demux thread function handling data from specific TSIF. + * + * @arg: TSIF number + */ +static int mpq_dmx_tspp_thread(void *arg) +{ + int tsif = (int)(uintptr_t)arg; + struct mpq_demux *mpq_demux; + const struct tspp_data_descriptor *tspp_data_desc; + atomic_t *data_cnt; + u32 notif_size; + int channel_id; + int ref_count; + int ret; + + do { + ret = wait_event_interruptible( + mpq_dmx_tspp_info.tsif[tsif].wait_queue, + (atomic_read(&mpq_dmx_tspp_info.tsif[tsif].data_cnt) && + !atomic_read(&mpq_dmx_tspp_info.tsif[tsif].control_op)) + || kthread_should_stop()); + + if ((ret < 0) || kthread_should_stop()) { + MPQ_DVB_ERR_PRINT("%s: exit\n", __func__); + break; + } + + /* Lock against the TSPP filters data-structure */ + if (mutex_lock_interruptible( + &mpq_dmx_tspp_info.tsif[tsif].mutex)) + return -ERESTARTSYS; + + channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); + + ref_count = mpq_dmx_tspp_info.tsif[tsif].channel_ref; + data_cnt = &mpq_dmx_tspp_info.tsif[tsif].data_cnt; + + /* Make sure channel is still active */ + if (ref_count == 0) { + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + continue; + } + + atomic_dec(data_cnt); + + mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux; + mpq_demux->hw_notification_size = 0; + + if (allocation_mode != MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC && + mpq_sdmx_is_loaded()) + pr_err_once( + "%s: TSPP Allocation mode does not support secure demux.\n", + __func__); + + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC && + mpq_sdmx_is_loaded()) { + mpq_dmx_tspp_aggregated_process(tsif, channel_id); + } else { + /* + * Go through all filled descriptors + * and perform demuxing on them + */ + do { + if (atomic_read( + &mpq_dmx_tspp_info.tsif[tsif].control_op)) { + /* restore for next iteration */ + atomic_inc(data_cnt); + break; + } + tspp_data_desc = tspp_get_buffer(0, channel_id); + if (!tspp_data_desc) + break; + + notif_size = tspp_data_desc->size / + TSPP_RAW_TTS_SIZE; + mpq_demux->hw_notification_size += notif_size; + + mpq_dmx_tspp_swfilter_desc(mpq_demux, + tspp_data_desc); + /* + * Notify TSPP that the buffer + * is no longer needed + */ + tspp_release_buffer(0, channel_id, + tspp_data_desc->id); + } while (1); + } + + if (mpq_demux->hw_notification_size && + (mpq_demux->hw_notification_size < + mpq_demux->hw_notification_min_size)) + mpq_demux->hw_notification_min_size = + mpq_demux->hw_notification_size; + + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + } while (1); + + return 0; +} + +/** + * Callback function from TSPP when new data is ready. + * + * @channel_id: Channel with new TS packets + * @user: user-data holding TSIF number + */ +static void mpq_tspp_callback(int channel_id, void *user) +{ + int tsif = (int)(uintptr_t)user; + struct mpq_demux *mpq_demux; + + /* Save statistics on TSPP notifications */ + mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux; + mpq_dmx_update_hw_statistics(mpq_demux); + + atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].data_cnt); + wake_up(&mpq_dmx_tspp_info.tsif[tsif].wait_queue); +} + +/** + * Free memory of channel output of specific TSIF. + * + * @tsif: The TSIF id to which memory should be freed. + */ +static void mpq_dmx_channel_mem_free(int tsif) +{ + int size = 0; + + size = (mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size); + size = ALIGN(size, SZ_4K); + + + tspp_free_dma_buffer(0, size, + (void *)mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base, + (dma_addr_t)mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base); + + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base = 0; + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base = NULL; + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle = NULL; +} + +/** + * Allocate memory for channel output of specific TSIF. + * + * @tsif: The TSIF id to which memory should be allocated. + * + * Return error status + */ +static int mpq_dmx_channel_mem_alloc(int tsif) +{ + int size = 0; + + size = (mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size); + + size = ALIGN(size, SZ_4K); + + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base + = tspp_allocate_dma_buffer(0, size, + &mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base); + + if (IS_ERR_OR_NULL( + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base)) { + MPQ_DVB_ERR_PRINT("%s: ion_map_kernel() failed\n", __func__); + mpq_dmx_channel_mem_free(tsif); + return -ENOMEM; + } + return 0; +} + +/** + * Add a filter to accept all packets as the last entry + * of the TSPP HW filter table. + * + * @channel_id: Channel ID number. + * @source: TSPP source. + * + * Return error status + */ +static int mpq_tspp_add_accept_all_filter(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int ret; + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + if (mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag) { + MPQ_DVB_DBG_PRINT("%s: accept all filter already exists\n", + __func__); + return 0; + } + + /* This filter will be the last entry in the table */ + tspp_filter.priority = TSPP_LAST_HW_FILTER_INDEX; + /* Pass all pids - set mask to 0 */ + tspp_filter.pid = 0; + tspp_filter.mask = 0; + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE + * accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = source; + tspp_filter.decrypt = 0; + + ret = tspp_add_filter(0, channel_id, &tspp_filter); + if (!ret) { + mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag = 1; + MPQ_DVB_DBG_PRINT( + "%s: accept all filter added successfully\n", + __func__); + } + + return ret; +} + +/** + * Remove the filter that accepts all packets from the last entry + * of the TSPP HW filter table. + * + * @channel_id: Channel ID number. + * @source: TSPP source. + * + * Return error status + */ +static int mpq_tspp_remove_accept_all_filter(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int ret; + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + if (mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag == 0) { + MPQ_DVB_DBG_PRINT("%s: accept all filter doesn't exist\n", + __func__); + return 0; + } + + tspp_filter.priority = TSPP_LAST_HW_FILTER_INDEX; + + ret = tspp_remove_filter(0, channel_id, &tspp_filter); + if (!ret) { + mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag = 0; + MPQ_DVB_DBG_PRINT( + "%s: accept all filter removed successfully\n", + __func__); + } + + return ret; +} + +/** + * Add filters designed to accept all packets except NULL packets, i.e. + * packets with PID = 0x1FFF. + * This function is called after user-defined filters were removed, + * so it assumes that the first 13 HW filters in the TSPP filter + * table are free for use. + * + * @channel_id: Channel ID number. + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_add_null_blocking_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int ret = 0; + int i, j; + u16 full_pid_mask = 0x1FFF; + u8 mask_shift; + u8 pid_shift; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + /* + * Add a total of 13 filters that will accept packets with + * every PID other than 0x1FFF, which is the NULL PID. + * + * Filter 0: accept all PIDs with bit 12 clear, i.e. + * PID = 0x0000 .. 0x0FFF (4096 PIDs in total): + * Mask = 0x1000, PID = 0x0000. + * + * Filter 12: Accept PID 0x1FFE: + * Mask = 0x1FFF, PID = 0x1FFE. + * + * In general: For N = 0 .. 12, + * Filter : accept all PIDs with MSBits set and bit clear. + * Filter Mask = N+1 MSBits set, others clear. + * Filter PID = MSBits set, others clear. + */ + + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE + * accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = source; + tspp_filter.decrypt = 0; + + for (i = 0; i < TSPP_BLOCK_NULLS_FILTERS_NUM; i++) { + tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); + if (tspp_filter.priority != i) { + MPQ_DVB_ERR_PRINT( + "%s: got unexpected HW index %d, expected %d\n", + __func__, tspp_filter.priority, i); + ret = -1; + break; + } + mask_shift = (TSPP_BLOCK_NULLS_FILTERS_NUM - 1 - i); + pid_shift = (TSPP_BLOCK_NULLS_FILTERS_NUM - i); + tspp_filter.mask = + ((full_pid_mask >> mask_shift) << mask_shift); + tspp_filter.pid = ((full_pid_mask >> pid_shift) << pid_shift); + + if (tspp_add_filter(0, channel_id, &tspp_filter)) { + ret = -1; + break; + } + } + + if (ret) { + /* cleanup on failure */ + for (j = 0; j < i; j++) { + tspp_filter.priority = j; + mpq_tspp_release_hw_filter_index(tsif, j); + tspp_remove_filter(0, channel_id, &tspp_filter); + } + } else { + MPQ_DVB_DBG_PRINT( + "%s: NULL blocking filters added successfully\n", + __func__); + } + + return ret; +} + +/** + * Remove filters designed to accept all packets except NULL packets, i.e. + * packets with PID = 0x1FFF. + * + * @channel_id: Channel ID number. + * + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_remove_null_blocking_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int ret = 0; + int i; + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + for (i = 0; i < TSPP_BLOCK_NULLS_FILTERS_NUM; i++) { + tspp_filter.priority = i; + if (tspp_remove_filter(0, channel_id, &tspp_filter)) { + MPQ_DVB_ERR_PRINT("%s: failed to remove filter %d\n", + __func__, i); + ret = -1; + } + + mpq_tspp_release_hw_filter_index(tsif, i); + } + + return ret; +} + +/** + * Add all current user-defined filters (up to 15) as HW filters + * + * @channel_id: Channel ID number. + * + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_add_all_user_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int slot; + u16 added_count = 0; + u16 total_filters_count = 0; + + MPQ_DVB_DBG_PRINT("%s: executed\n", __func__); + + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE + * accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = source; + tspp_filter.decrypt = 0; + + for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) { + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == -1) + continue; + + /* + * count total number of user filters to verify that it is + * exactly TSPP_MAX_HW_PID_FILTER_NUM as expected. + */ + total_filters_count++; + + if (added_count > TSPP_MAX_HW_PID_FILTER_NUM) + continue; + + tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); + + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == + TSPP_PASS_THROUGH_PID) { + /* pass all pids */ + tspp_filter.pid = 0; + tspp_filter.mask = 0; + } else { + tspp_filter.pid = + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid; + tspp_filter.mask = TSPP_PID_MASK; + } + + MPQ_DVB_DBG_PRINT( + "%s: adding HW filter, PID = %d, mask = 0x%X, index = %d\n", + __func__, tspp_filter.pid, tspp_filter.mask, + tspp_filter.priority); + + if (!tspp_add_filter(0, channel_id, &tspp_filter)) { + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = + tspp_filter.priority; + added_count++; + } else { + MPQ_DVB_ERR_PRINT("%s: tspp_add_filter failed\n", + __func__); + } + } + + if ((added_count != TSPP_MAX_HW_PID_FILTER_NUM) || + (added_count != total_filters_count)) + return -EINVAL; + + return 0; +} + +/** + * Remove all user-defined HW filters + * + * @channel_id: Channel ID number. + * + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_remove_all_user_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int ret = 0; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int i; + + MPQ_DVB_DBG_PRINT("%s: executed\n", __func__); + + for (i = 0; i < TSPP_MAX_HW_PID_FILTER_NUM; i++) { + tspp_filter.priority = i; + MPQ_DVB_DBG_PRINT("%s: Removing HW filter %d\n", + __func__, tspp_filter.priority); + if (tspp_remove_filter(0, channel_id, &tspp_filter)) + ret = -1; + + mpq_tspp_release_hw_filter_index(tsif, i); + mpq_dmx_tspp_info.tsif[tsif].filters[i].hw_index = -1; + } + + return ret; +} + +/** + * Configure TSPP channel to filter the PID of new feed. + * + * @feed: The feed to configure the channel with + * + * Return error status + * + * The function checks if the new PID can be added to an already + * allocated channel, if not, a new channel is allocated and configured. + */ +static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed) +{ + struct mpq_demux *mpq_demux = feed->demux->priv; + struct tspp_select_source tspp_source; + struct tspp_filter tspp_filter; + int tsif; + int tsif_mode = mpq_dmx_get_param_tsif_mode(); + int ret = 0; + int slot; + int channel_id; + int *channel_ref_count; + u32 buffer_size; + int restore_user_filters = 0; + int remove_accept_all_filter = 0; + int remove_null_blocking_filters = 0; + size_t agg_size; + + tspp_source.clk_inverse = mpq_dmx_get_param_clock_inv(); + tspp_source.data_inverse = 0; + tspp_source.sync_inverse = 0; + tspp_source.enable_inverse = 0; + + MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid); + + switch (tsif_mode) { + case 1: + tspp_source.mode = TSPP_TSIF_MODE_1; + break; + case 2: + tspp_source.mode = TSPP_TSIF_MODE_2; + break; + default: + tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK; + break; + } + + /* determine the TSIF we are reading from */ + if (mpq_demux->source == DMX_SOURCE_FRONT0) { + tsif = 0; + tspp_source.source = TSPP_SOURCE_TSIF0; + } else if (mpq_demux->source == DMX_SOURCE_FRONT1) { + tsif = 1; + tspp_source.source = TSPP_SOURCE_TSIF1; + } else { + /* invalid source */ + MPQ_DVB_ERR_PRINT( + "%s: invalid input source (%d)\n", + __func__, + mpq_demux->source); + + return -EINVAL; + } + + atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].control_op); + if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) { + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return -ERESTARTSYS; + } + + /* + * It is possible that this PID was already requested before. + * Can happen if we play and record same PES or PCR + * piggypacked on video packet. + */ + slot = mpq_tspp_get_filter_slot(tsif, feed->pid); + if (slot >= 0) { + /* PID already configured */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; + goto out; + } + + + channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); + channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref; + + /* + * Recalculate 'tspp_notification_size' and buffer count in case + * 'tspp_desc_size' or 'tspp_out_buffer_size' parameters have changed. + */ + buffer_size = tspp_desc_size; + tspp_notification_size = TSPP_NOTIFICATION_SIZE(tspp_desc_size); + mpq_dmx_tspp_info.tsif[tsif].buffer_count = + TSPP_BUFFER_COUNT(tspp_out_buffer_size); + if (mpq_dmx_tspp_info.tsif[tsif].buffer_count > + MAX_BAM_DESCRIPTOR_COUNT) + mpq_dmx_tspp_info.tsif[tsif].buffer_count = + MAX_BAM_DESCRIPTOR_COUNT; + + /* check if required TSPP pipe is already allocated or not */ + if (*channel_ref_count == 0) { + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + agg_size = mpq_dmx_tspp_info.tsif[tsif].buffer_count * + sizeof(int); + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = + vzalloc(agg_size); + if (!mpq_dmx_tspp_info.tsif[tsif].aggregate_ids) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to allocate memory for buffer descriptors aggregation\n", + __func__); + ret = -ENOMEM; + goto out; + } + + ret = mpq_dmx_channel_mem_alloc(tsif); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_channel_mem_alloc(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_failed; + } + } + + ret = tspp_open_channel(0, channel_id); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_open_channel(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_failed; + } + + /* set TSPP source */ + ret = tspp_open_stream(0, channel_id, &tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_select_source(%d,%d) failed (%d)\n", + __func__, + channel_id, + tspp_source.source, + ret); + + goto add_channel_close_ch; + } + + /* register notification on TS packets */ + tspp_register_notification(0, + channel_id, + mpq_tspp_callback, + (void *)(uintptr_t)tsif, + tspp_channel_timeout); + + /* + * Register allocator and provide allocation function + * that allocates from contiguous memory so that we can have + * big notification size, smallest descriptor, and still provide + * TZ with single big buffer based on notification size. + */ + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + ret = tspp_allocate_buffers(0, channel_id, + mpq_dmx_tspp_info.tsif[tsif].buffer_count, + buffer_size, tspp_notification_size, + tspp_mem_allocator, tspp_mem_free, NULL); + } else { + ret = tspp_allocate_buffers(0, channel_id, + mpq_dmx_tspp_info.tsif[tsif].buffer_count, + buffer_size, tspp_notification_size, + NULL, NULL, NULL); + } + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_allocate_buffers(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_unregister_notif; + } + + mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux; + } + + /* add new PID to the existing pipe */ + slot = mpq_tspp_get_free_filter_slot(tsif); + if (slot < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_get_free_filter_slot(%d) failed\n", + __func__, tsif); + + goto add_channel_unregister_notif; + } + + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1; + + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid; + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; + + tspp_filter.priority = -1; + + if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count < + TSPP_MAX_HW_PID_FILTER_NUM) { + /* HW filtering mode */ + tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); + if (tspp_filter.priority < 0) + goto add_channel_free_filter_slot; + + if (feed->pid == TSPP_PASS_THROUGH_PID) { + /* pass all pids */ + tspp_filter.pid = 0; + tspp_filter.mask = 0; + } else { + tspp_filter.pid = feed->pid; + tspp_filter.mask = TSPP_PID_MASK; + } + + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change + * TSPP_RAW_TTS_SIZE accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = tspp_source.source; + tspp_filter.decrypt = 0; + ret = tspp_add_filter(0, channel_id, &tspp_filter); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_add_filter(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_free_filter_slot; + } + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = + tspp_filter.priority; + + MPQ_DVB_DBG_PRINT( + "%s: HW filtering mode: added TSPP HW filter, PID = %d, mask = 0x%X, index = %d\n", + __func__, tspp_filter.pid, tspp_filter.mask, + tspp_filter.priority); + } else if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count == + TSPP_MAX_HW_PID_FILTER_NUM) { + /* Crossing the threshold - from HW to SW filtering mode */ + + /* Add a temporary filter to accept all packets */ + ret = mpq_tspp_add_accept_all_filter(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, tspp_source.source); + + goto add_channel_free_filter_slot; + } + + /* Remove all existing user filters */ + ret = mpq_tspp_remove_all_user_filters(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_all_user_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source.source); + + restore_user_filters = 1; + remove_accept_all_filter = 1; + + goto add_channel_free_filter_slot; + } + + /* Add HW filters to block NULL packets */ + ret = mpq_tspp_add_null_blocking_filters(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_null_blocking_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source.source); + + restore_user_filters = 1; + remove_accept_all_filter = 1; + + goto add_channel_free_filter_slot; + } + + /* Remove filters that accepts all packets, if necessary */ + if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) && + (mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) { + + ret = mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, + tspp_source.source); + + remove_null_blocking_filters = 1; + restore_user_filters = 1; + remove_accept_all_filter = 1; + + goto add_channel_free_filter_slot; + } + } + } else { + /* Already working in SW filtering mode */ + if (mpq_dmx_tspp_info.tsif[tsif].pass_all_flag || + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag) { + + ret = mpq_tspp_add_accept_all_filter(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, + tspp_source.source); + + goto add_channel_free_filter_slot; + } + } + } + + (*channel_ref_count)++; + mpq_dmx_tspp_info.tsif[tsif].current_filter_count++; + + MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n", + __func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count); + + goto out; + +add_channel_free_filter_slot: + /* restore internal database state */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1; + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--; + + /* release HW index if we allocated one */ + if (tspp_filter.priority >= 0) { + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1; + mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority); + } + + /* restore HW filter table state if necessary */ + if (remove_null_blocking_filters) + mpq_tspp_remove_null_blocking_filters(channel_id, + tspp_source.source); + + if (restore_user_filters) + mpq_tspp_add_all_user_filters(channel_id, tspp_source.source); + + if (remove_accept_all_filter) + mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source.source); + + /* restore flags. we can only get here if we changed the flags. */ + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0; + +add_channel_unregister_notif: + if (*channel_ref_count == 0) { + tspp_unregister_notification(0, channel_id); + tspp_close_stream(0, channel_id); + } +add_channel_close_ch: + if (*channel_ref_count == 0) + tspp_close_channel(0, channel_id); +add_channel_failed: + if (*channel_ref_count == 0) + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + vfree(mpq_dmx_tspp_info.tsif[tsif].aggregate_ids); + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = NULL; + mpq_dmx_channel_mem_free(tsif); + } + +out: + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return ret; +} + +/** + * Removes filter from TSPP. + * + * @feed: The feed to remove + * + * Return error status + * + * The function checks if this is the only PID allocated within + * the channel, if so, the channel is closed as well. + */ +static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed) +{ + int tsif; + int ret = 0; + int channel_id; + int slot; + atomic_t *data_cnt; + int *channel_ref_count; + enum tspp_source tspp_source; + struct tspp_filter tspp_filter; + struct mpq_demux *mpq_demux = feed->demux->priv; + int restore_null_blocking_filters = 0; + int remove_accept_all_filter = 0; + int remove_user_filters = 0; + int accept_all_filter_existed = 0; + + MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid); + + /* determine the TSIF we are reading from */ + if (mpq_demux->source == DMX_SOURCE_FRONT0) { + tsif = 0; + tspp_source = TSPP_SOURCE_TSIF0; + } else if (mpq_demux->source == DMX_SOURCE_FRONT1) { + tsif = 1; + tspp_source = TSPP_SOURCE_TSIF1; + } else { + /* invalid source */ + MPQ_DVB_ERR_PRINT( + "%s: invalid input source (%d)\n", + __func__, + mpq_demux->source); + + return -EINVAL; + } + + atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].control_op); + if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) { + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return -ERESTARTSYS; + } + + channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); + channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref; + data_cnt = &mpq_dmx_tspp_info.tsif[tsif].data_cnt; + + /* check if required TSPP pipe is already allocated or not */ + if (*channel_ref_count == 0) { + /* invalid feed provided as the channel is not allocated */ + MPQ_DVB_ERR_PRINT( + "%s: invalid feed (%d)\n", + __func__, + channel_id); + + ret = -EINVAL; + goto out; + } + + slot = mpq_tspp_get_filter_slot(tsif, feed->pid); + + if (slot < 0) { + /* invalid feed provided as it has no filter allocated */ + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_get_filter_slot failed (%d,%d)\n", + __func__, + feed->pid, + tsif); + + ret = -EINVAL; + goto out; + } + + /* since filter was found, ref_count > 0 so it's ok to decrement it */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--; + + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count) { + /* + * there are still references to this pid, do not + * remove the filter yet + */ + goto out; + } + + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0; + + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1; + + if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count <= + TSPP_MAX_HW_PID_FILTER_NUM) { + /* staying in HW filtering mode */ + tspp_filter.priority = + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index; + ret = tspp_remove_filter(0, channel_id, &tspp_filter); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_remove_filter failed (%d,%d)\n", + __func__, + channel_id, + tspp_filter.priority); + + goto remove_channel_failed_restore_count; + } + mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority); + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1; + + MPQ_DVB_DBG_PRINT( + "%s: HW filtering mode: Removed TSPP HW filter, PID = %d, index = %d\n", + __func__, feed->pid, tspp_filter.priority); + } else if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count == + (TSPP_MAX_HW_PID_FILTER_NUM + 1)) { + /* Crossing the threshold - from SW to HW filtering mode */ + + accept_all_filter_existed = + mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag; + + /* Add a temporary filter to accept all packets */ + ret = mpq_tspp_add_accept_all_filter(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + goto remove_channel_failed_restore_count; + } + + ret = mpq_tspp_remove_null_blocking_filters(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_null_blocking_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + restore_null_blocking_filters = 1; + if (!accept_all_filter_existed) + remove_accept_all_filter = 1; + + goto remove_channel_failed_restore_count; + } + + ret = mpq_tspp_add_all_user_filters(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_all_user_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + remove_user_filters = 1; + restore_null_blocking_filters = 1; + if (!accept_all_filter_existed) + remove_accept_all_filter = 1; + + goto remove_channel_failed_restore_count; + } + + ret = mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + remove_user_filters = 1; + restore_null_blocking_filters = 1; + if (!accept_all_filter_existed) + remove_accept_all_filter = 1; + + goto remove_channel_failed_restore_count; + } + } else { + /* staying in SW filtering mode */ + if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) && + (mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) { + + ret = mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, + tspp_source); + + goto remove_channel_failed_restore_count; + } + } + } + + mpq_dmx_tspp_info.tsif[tsif].current_filter_count--; + (*channel_ref_count)--; + + MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n", + __func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count); + + if (*channel_ref_count == 0) { + /* channel is not used any more, release it */ + tspp_unregister_notification(0, channel_id); + tspp_close_stream(0, channel_id); + tspp_close_channel(0, channel_id); + atomic_set(data_cnt, 0); + + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + vfree(mpq_dmx_tspp_info.tsif[tsif].aggregate_ids); + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = NULL; + mpq_dmx_channel_mem_free(tsif); + } + } + + goto out; + +remove_channel_failed_restore_count: + /* restore internal database state */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid; + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; + + if (remove_user_filters) + mpq_tspp_remove_all_user_filters(channel_id, tspp_source); + + if (restore_null_blocking_filters) + mpq_tspp_add_null_blocking_filters(channel_id, tspp_source); + + if (remove_accept_all_filter) + mpq_tspp_remove_accept_all_filter(channel_id, tspp_source); + + /* restore flags. we can only get here if we changed the flags. */ + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1; + +out: + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return ret; +} + +static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed) +{ + int ret; + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT( + "%s(pid=%d) executed\n", + __func__, + feed->pid); + + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: invalid mpq_demux handle\n", + __func__); + + return -EINVAL; + } + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + /* source from TSPP, need to configure tspp pipe */ + ret = mpq_tspp_dmx_add_channel(feed); + + if (ret < 0) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_tspp_dmx_add_channel failed(%d)\n", + __func__, + ret); + return ret; + } + } + + /* + * Always feed sections/PES starting from a new one and + * do not partial transfer data from older one + */ + feed->pusi_seen = 0; + + ret = mpq_dmx_init_mpq_feed(feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_init_mpq_feed failed(%d)\n", + __func__, + ret); + if (mpq_demux->source < DMX_SOURCE_DVR0) + mpq_tspp_dmx_remove_channel(feed); + + return ret; + } + + return 0; +} + +static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed) +{ + int ret = 0; + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT("%s(%d) executed\n", __func__, feed->pid); + + mpq_dmx_terminate_feed(feed); + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + /* source from TSPP, need to configure tspp pipe */ + ret = mpq_tspp_dmx_remove_channel(feed); + } + + return ret; +} + +static int mpq_tspp_dmx_write_to_decoder( + struct dvb_demux_feed *feed, + const u8 *buf, + size_t len) +{ + /* + * It is assumed that this function is called once for each + * TS packet of the relevant feed. + */ + if (len > TSPP_RAW_TTS_SIZE) + MPQ_DVB_DBG_PRINT( + "%s: warnning - len larger than one packet\n", + __func__); + + if (dvb_dmx_is_video_feed(feed)) + return mpq_dmx_process_video_packet(feed, buf); + + if (dvb_dmx_is_pcr_feed(feed)) + return mpq_dmx_process_pcr_packet(feed, buf); + + return 0; +} + +/** + * Returns demux capabilities of TSPPv1 plugin + * + * @demux: demux device + * @caps: Returned capbabilities + * + * Return error code + */ +static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux, + struct dmx_caps *caps) +{ + struct dvb_demux *dvb_demux = demux->priv; + + if ((dvb_demux == NULL) || (caps == NULL)) { + MPQ_DVB_ERR_PRINT( + "%s: invalid parameters\n", + __func__); + + return -EINVAL; + } + + caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA | + DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING | + DMX_CAP_AUTO_BUFFER_FLUSH; + caps->recording_max_video_pids_indexed = 0; + caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; + caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM; + caps->num_section_filters = dvb_demux->filternum; + caps->num_section_filters_per_pid = dvb_demux->filternum; + caps->section_filter_length = DMX_FILTER_SIZE; + caps->num_demod_inputs = TSIF_COUNT; + caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->max_bitrate = 192; + caps->demod_input_max_bitrate = 96; + caps->memory_input_max_bitrate = 96; + caps->num_cipher_ops = 1; + + /* TSIF reports 3 bytes STC at unit of 27MHz/256 */ + caps->max_stc = (u64)0xFFFFFF * 256; + + /* Buffer requirements */ + caps->section.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->section.max_buffer_num = 1; + caps->section.max_size = 0xFFFFFFFF; + caps->section.size_alignment = 0; + caps->pes.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->pes.max_buffer_num = 1; + caps->pes.max_size = 0xFFFFFFFF; + caps->pes.size_alignment = 0; + caps->recording_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_188_tsp.max_buffer_num = 1; + caps->recording_188_tsp.max_size = 0xFFFFFFFF; + caps->recording_188_tsp.size_alignment = 0; + caps->recording_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_192_tsp.max_buffer_num = 1; + caps->recording_192_tsp.max_size = 0xFFFFFFFF; + caps->recording_192_tsp.size_alignment = 0; + caps->playback_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_188_tsp.max_buffer_num = 1; + caps->playback_188_tsp.max_size = 0xFFFFFFFF; + caps->playback_188_tsp.size_alignment = 188; + caps->playback_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_192_tsp.max_buffer_num = 1; + caps->playback_192_tsp.max_size = 0xFFFFFFFF; + caps->playback_192_tsp.size_alignment = 192; + caps->decoder.flags = + DMX_BUFFER_SECURED_IF_DECRYPTED | + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_LINEAR_GROUP_SUPPORT | + DMX_BUFFER_CACHED; + caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM; + caps->decoder.max_size = 0xFFFFFFFF; + caps->decoder.size_alignment = SZ_4K; + + return 0; +} + + +/** + * Reads TSIF STC from TSPP + * + * @demux: demux device + * @num: STC number. 0 for TSIF0 and 1 for TSIF1. + * @stc: STC value + * @base: divisor to get 90KHz value + * + * Return error code + */ +static int mpq_tspp_dmx_get_stc(struct dmx_demux *demux, unsigned int num, + u64 *stc, unsigned int *base) +{ + enum tspp_source source; + u32 tcr_counter; + u64 avtimer_stc = 0; + int tts_source = 0; + + if (!demux || !stc || !base) + return -EINVAL; + + if (num == 0) + source = TSPP_SOURCE_TSIF0; + else if (num == 1) + source = TSPP_SOURCE_TSIF1; + else + return -EINVAL; + + if (tspp_get_tts_source(0, &tts_source) < 0) + tts_source = TSIF_TTS_TCR; + + if (tts_source != TSIF_TTS_LPASS_TIMER) { + tspp_get_ref_clk_counter(0, source, &tcr_counter); + *stc = ((u64)tcr_counter) * 256; /* conversion to 27MHz */ + *base = 300; /* divisor to get 90KHz clock from stc value */ + } else { + if (tspp_get_lpass_time_counter(0, source, &avtimer_stc) < 0) + return -EINVAL; + *stc = avtimer_stc; + } + return 0; +} + +static int mpq_tspp_dmx_init( + struct dvb_adapter *mpq_adapter, + struct mpq_demux *mpq_demux) +{ + int result; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + mpq_dmx_tspp_info.ion_client = mpq_demux->ion_client; + + /* Set the kernel-demux object capabilities */ + mpq_demux->demux.dmx.capabilities = + DMX_TS_FILTERING | + DMX_PES_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING | + DMX_CRC_CHECKING | + DMX_TS_DESCRAMBLING; + + /* Set dvb-demux "virtual" function pointers */ + mpq_demux->demux.priv = (void *)mpq_demux; + mpq_demux->demux.filternum = TSPP_MAX_SECTION_FILTER_NUM; + mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES; + mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering; + mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering; + mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder; + mpq_demux->demux.decoder_fullness_init = mpq_dmx_decoder_fullness_init; + mpq_demux->demux.decoder_fullness_wait = mpq_dmx_decoder_fullness_wait; + mpq_demux->demux.decoder_fullness_abort = + mpq_dmx_decoder_fullness_abort; + mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status; + mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer; + mpq_demux->demux.set_cipher_op = mpq_dmx_set_cipher_ops; + mpq_demux->demux.oob_command = mpq_dmx_oob_command; + mpq_demux->demux.convert_ts = mpq_dmx_convert_tts; + mpq_demux->demux.flush_decoder_buffer = NULL; + + /* Initialize dvb_demux object */ + result = dvb_dmx_init(&mpq_demux->demux); + if (result < 0) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__); + goto init_failed; + } + + /* Now initailize the dmx-dev object */ + mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES; + mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx; + mpq_demux->dmxdev.capabilities = DMXDEV_CAP_DUPLEX; + + mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source; + mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc; + mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps; + mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer; + mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer; + mpq_demux->dmxdev.demux->write = mpq_dmx_write; + result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter); + if (result < 0) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n", + __func__, + result); + goto init_failed_dmx_release; + } + + /* Extend dvb-demux debugfs with TSPP statistics. */ + mpq_dmx_init_debugfs_entries(mpq_demux); + + /* Get the TSIF TTS info */ + if (tspp_get_tts_source(0, &mpq_demux->ts_packet_timestamp_source) < 0) + mpq_demux->ts_packet_timestamp_source = TSIF_TTS_TCR; + + return 0; + +init_failed_dmx_release: + dvb_dmx_release(&mpq_demux->demux); +init_failed: + return result; +} + +static int mpq_dmx_tspp_plugin_probe(struct platform_device *pdev) +{ + int i; + int j; + int ret; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + for (i = 0; i < TSIF_COUNT; i++) { + mpq_dmx_tspp_info.tsif[i].aggregate_ids = NULL; + mpq_dmx_tspp_info.tsif[i].channel_ref = 0; + mpq_dmx_tspp_info.tsif[i].buff_index = 0; + mpq_dmx_tspp_info.tsif[i].ch_mem_heap_handle = NULL; + mpq_dmx_tspp_info.tsif[i].ch_mem_heap_virt_base = NULL; + mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base = 0; + atomic_set(&mpq_dmx_tspp_info.tsif[i].data_cnt, 0); + atomic_set(&mpq_dmx_tspp_info.tsif[i].control_op, 0); + + for (j = 0; j < TSPP_MAX_PID_FILTER_NUM; j++) { + mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1; + mpq_dmx_tspp_info.tsif[i].filters[j].ref_count = 0; + mpq_dmx_tspp_info.tsif[i].filters[j].hw_index = -1; + } + + for (j = 0; j < TSPP_MAX_HW_PID_FILTER_NUM; j++) + mpq_dmx_tspp_info.tsif[i].hw_indexes[j] = 0; + + mpq_dmx_tspp_info.tsif[i].current_filter_count = 0; + mpq_dmx_tspp_info.tsif[i].pass_nulls_flag = 0; + mpq_dmx_tspp_info.tsif[i].pass_all_flag = 0; + mpq_dmx_tspp_info.tsif[i].accept_all_filter_exists_flag = 0; + + snprintf(mpq_dmx_tspp_info.tsif[i].name, + TSIF_NAME_LENGTH, + "dmx_tsif%d", + i); + + init_waitqueue_head(&mpq_dmx_tspp_info.tsif[i].wait_queue); + mpq_dmx_tspp_info.tsif[i].thread = + kthread_run( + mpq_dmx_tspp_thread, (void *)(uintptr_t)i, + mpq_dmx_tspp_info.tsif[i].name); + + if (IS_ERR(mpq_dmx_tspp_info.tsif[i].thread)) { + for (j = 0; j < i; j++) { + kthread_stop(mpq_dmx_tspp_info.tsif[j].thread); + mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex); + } + + MPQ_DVB_ERR_PRINT( + "%s: kthread_run failed\n", + __func__); + + return -ENOMEM; + } + + mutex_init(&mpq_dmx_tspp_info.tsif[i].mutex); + } + + ret = mpq_dmx_plugin_init(mpq_tspp_dmx_init, pdev); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_plugin_init failed (errno=%d)\n", + __func__, + ret); + + for (i = 0; i < TSIF_COUNT; i++) { + kthread_stop(mpq_dmx_tspp_info.tsif[i].thread); + mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex); + } + } + + return ret; +} + +static int mpq_dmx_tspp_plugin_remove(struct platform_device *pdev) +{ + int i; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + for (i = 0; i < TSIF_COUNT; i++) { + mutex_lock(&mpq_dmx_tspp_info.tsif[i].mutex); + + /* + * Note: tspp_close_channel will also free the TSPP buffers + * even if we allocated them ourselves, + * using our free function. + */ + if (mpq_dmx_tspp_info.tsif[i].channel_ref) { + tspp_unregister_notification(0, + TSPP_CHANNEL_ID(i, TSPP_CHANNEL)); + tspp_close_channel(0, + TSPP_CHANNEL_ID(i, TSPP_CHANNEL)); + + if (allocation_mode == + MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + vfree(mpq_dmx_tspp_info.tsif[i].aggregate_ids); + mpq_dmx_tspp_info.tsif[i].aggregate_ids = NULL; + mpq_dmx_channel_mem_free(i); + } + } + + mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex); + kthread_stop(mpq_dmx_tspp_info.tsif[i].thread); + mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex); + } + + mpq_dmx_plugin_exit(); + return 0; +} + +static const struct of_device_id msm_match_table[] = { + {.compatible = "qcom,demux"}, + {} +}; + +static struct platform_driver mpq_dmx_tspp_plugin_driver = { + .probe = mpq_dmx_tspp_plugin_probe, + .remove = mpq_dmx_tspp_plugin_remove, + .driver = { + .name = "demux", + .of_match_table = msm_match_table, + }, +}; + + +static int __init mpq_dmx_tspp_plugin_init(void) +{ + int rc; + + /* register the driver, and check hardware */ + rc = platform_driver_register(&mpq_dmx_tspp_plugin_driver); + if (rc) + pr_err("%s: platform_driver_register failed: %d\n", + __func__, rc); + + return rc; +} + +static void __exit mpq_dmx_tspp_plugin_exit(void) +{ + /* delete low level driver */ + platform_driver_unregister(&mpq_dmx_tspp_plugin_driver); +} + + +module_init(mpq_dmx_tspp_plugin_init); +module_exit(mpq_dmx_tspp_plugin_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. demux TSPP version 1 HW Plugin"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c new file mode 100644 index 0000000000000000000000000000000000000000..1cfade7e8a55defa9d941b8e5a2a3cad74006f53 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c @@ -0,0 +1,1025 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "qseecom_kernel.h" +#include "mpq_sdmx.h" + +static struct qseecom_handle *sdmx_qseecom_handles[SDMX_MAX_SESSIONS]; +static struct mutex sdmx_lock[SDMX_MAX_SESSIONS]; + +#define QSEECOM_SBUFF_SIZE SZ_128K + +enum sdmx_cmd_id { + SDMX_OPEN_SESSION_CMD, + SDMX_CLOSE_SESSION_CMD, + SDMX_SET_SESSION_CFG_CMD, + SDMX_ADD_FILTER_CMD, + SDMX_REMOVE_FILTER_CMD, + SDMX_SET_KL_IDX_CMD, + SDMX_ADD_RAW_PID_CMD, + SDMX_REMOVE_RAW_PID_CMD, + SDMX_PROCESS_CMD, + SDMX_GET_DBG_COUNTERS_CMD, + SDMX_RESET_DBG_COUNTERS_CMD, + SDMX_GET_VERSION_CMD, + SDMX_INVALIDATE_KL_CMD, + SDMX_SET_LOG_LEVEL_CMD +}; + +#pragma pack(push, sdmx, 1) + +struct sdmx_proc_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u8 flags; + struct sdmx_buff_descr in_buf_descr; + u32 inp_fill_cnt; + u32 in_rd_offset; + u32 num_filters; + struct sdmx_filter_status filters_status[]; +}; + +struct sdmx_proc_rsp { + enum sdmx_status ret; + u32 inp_fill_cnt; + u32 in_rd_offset; + u32 err_indicators; + u32 status_indicators; +}; + +struct sdmx_open_ses_req { + enum sdmx_cmd_id cmd_id; +}; + +struct sdmx_open_ses_rsp { + enum sdmx_status ret; + u32 session_handle; +}; + +struct sdmx_close_ses_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; +}; + +struct sdmx_close_ses_rsp { + enum sdmx_status ret; +}; + +struct sdmx_ses_cfg_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + enum sdmx_proc_mode process_mode; + enum sdmx_inp_mode input_mode; + enum sdmx_pkt_format packet_len; + u8 odd_scramble_bits; + u8 even_scramble_bits; +}; + +struct sdmx_ses_cfg_rsp { + enum sdmx_status ret; +}; + +struct sdmx_set_kl_ind_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 pid; + u32 kl_index; +}; + +struct sdmx_set_kl_ind_rsp { + enum sdmx_status ret; +}; + +struct sdmx_add_filt_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 pid; + enum sdmx_filter filter_type; + struct sdmx_buff_descr meta_data_buf; + enum sdmx_buf_mode buffer_mode; + enum sdmx_raw_out_format ts_out_format; + u32 flags; + u32 num_data_bufs; + struct sdmx_data_buff_descr data_bufs[]; +}; + +struct sdmx_add_filt_rsp { + enum sdmx_status ret; + u32 filter_handle; +}; + +struct sdmx_rem_filt_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 filter_handle; +}; + +struct sdmx_rem_filt_rsp { + enum sdmx_status ret; +}; + +struct sdmx_add_raw_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 filter_handle; + u32 pid; +}; + +struct sdmx_add_raw_rsp { + enum sdmx_status ret; +}; + +struct sdmx_rem_raw_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 filter_handle; + u32 pid; +}; + +struct sdmx_rem_raw_rsp { + enum sdmx_status ret; +}; + +struct sdmx_get_counters_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 num_filters; +}; + +struct sdmx_get_counters_rsp { + enum sdmx_status ret; + struct sdmx_session_dbg_counters session_counters; + u32 num_filters; + struct sdmx_filter_dbg_counters filter_counters[]; +}; + +struct sdmx_rst_counters_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; +}; + +struct sdmx_rst_counters_rsp { + enum sdmx_status ret; +}; + +struct sdmx_get_version_req { + enum sdmx_cmd_id cmd_id; +}; + +struct sdmx_get_version_rsp { + enum sdmx_status ret; + int32_t version; +}; + +struct sdmx_set_log_level_req { + enum sdmx_cmd_id cmd_id; + enum sdmx_log_level level; + u32 session_handle; +}; + +struct sdmx_set_log_level_rsp { + enum sdmx_status ret; +}; + +#pragma pack(pop, sdmx) + +static int get_cmd_rsp_buffers(int handle_index, + void **cmd, + int *cmd_len, + void **rsp, + int *rsp_len) +{ + 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: shared buffer too small to hold cmd=%d and rsp=%d\n", + __func__, *cmd_len, *rsp_len); + return SDMX_STATUS_OUT_OF_MEM; + } + + *cmd = sdmx_qseecom_handles[handle_index]->sbuf; + *rsp = sdmx_qseecom_handles[handle_index]->sbuf + *cmd_len; + return SDMX_SUCCESS; +} + +/* + * Returns version of secure-demux app. + * + * @session_handle: Returned instance handle. Must not be NULL. + * Return error code + */ +int sdmx_get_version(int session_handle, int32_t *version) +{ + int res, cmd_len, rsp_len; + struct sdmx_get_version_req *cmd; + struct sdmx_get_version_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (version == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_get_version_req); + rsp_len = sizeof(struct sdmx_get_version_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_GET_VERSION_CMD; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; + *version = rsp->version; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; + +} +EXPORT_SYMBOL(sdmx_get_version); + +/* + * Initializes a new secure demux instance and returns a handle of the instance. + * + * @session_handle: handle of a secure demux instance to get its version. + * Return the version if successful or an error code. + */ +int sdmx_open_session(int *session_handle) +{ + int res, cmd_len, rsp_len; + enum sdmx_status ret, version_ret; + struct sdmx_open_ses_req *cmd; + struct sdmx_open_ses_rsp *rsp; + struct qseecom_handle *qseecom_handle = NULL; + int32_t version; + + /* Input validation */ + if (session_handle == NULL) + return SDMX_STATUS_GENERAL_FAILURE; + + /* Start the TZ app */ + res = qseecom_start_app(&qseecom_handle, "securemm", + QSEECOM_SBUFF_SIZE); + + if (res < 0) { + pr_debug("%s: Fail to load securemm app\n", __func__); + return SDMX_STATUS_GENERAL_FAILURE; + } + + cmd_len = sizeof(struct sdmx_open_ses_req); + rsp_len = sizeof(struct sdmx_open_ses_rsp); + + /* Get command and response buffers */ + cmd = (struct sdmx_open_ses_req *)qseecom_handle->sbuf; + + if (cmd_len & QSEECOM_ALIGN_MASK) + cmd_len = QSEECOM_ALIGN(cmd_len); + + rsp = (struct sdmx_open_ses_rsp *)qseecom_handle->sbuf + cmd_len; + + if (rsp_len & QSEECOM_ALIGN_MASK) + rsp_len = QSEECOM_ALIGN(rsp_len); + + /* Will be later overridden by SDMX response */ + *session_handle = SDMX_INVALID_SESSION_HANDLE; + + /* Populate command struct */ + cmd->cmd_id = SDMX_OPEN_SESSION_CMD; + + /* Issue QSEECom command */ + res = qseecom_send_command(qseecom_handle, (void *)cmd, cmd_len, + (void *)rsp, rsp_len); + + if (res < 0) { + qseecom_shutdown_app(&qseecom_handle); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *session_handle = rsp->session_handle; + + /* Initialize handle and mutex */ + sdmx_qseecom_handles[*session_handle] = qseecom_handle; + mutex_init(&sdmx_lock[*session_handle]); + ret = rsp->ret; + + /* Get and print the app version */ + version_ret = sdmx_get_version(*session_handle, &version); + if (version_ret == SDMX_SUCCESS) + pr_info("%s: TZ SDMX version is %x.%x\n", version >> 8, + __func__, version & 0xFF); + else + pr_err("%s: Error reading TZ SDMX version\n", __func__); + + return ret; +} +EXPORT_SYMBOL(sdmx_open_session); + +/* + * Closes a secure demux instance. + * + * @session_handle: handle of a secure demux instance to close. + * Return error code + */ +int sdmx_close_session(int session_handle) +{ + int res, cmd_len, rsp_len; + struct sdmx_close_ses_req *cmd; + struct sdmx_close_ses_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_close_ses_req); + rsp_len = sizeof(struct sdmx_close_ses_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_CLOSE_SESSION_CMD; + cmd->session_handle = session_handle; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; + + /* Shutdown the TZ app (or at least free the current handle) */ + res = qseecom_shutdown_app(&sdmx_qseecom_handles[session_handle]); + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + sdmx_qseecom_handles[session_handle] = NULL; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_close_session); + +/* + * Configures an open secure demux instance. + * + * @session_handle: secure demux instance + * @proc_mode: Defines secure demux's behavior in case of output + * buffer overflow. + * @inp_mode: Defines the input encryption settings. + * @pkt_format: TS packet length in input buffer. + * @odd_scramble_bits: Value of the scramble bits indicating the ODD key. + * @even_scramble_bits: Value of the scramble bits indicating the EVEN key. + * Return error code + */ +int sdmx_set_session_cfg(int session_handle, + enum sdmx_proc_mode proc_mode, + enum sdmx_inp_mode inp_mode, + enum sdmx_pkt_format pkt_format, + u8 odd_scramble_bits, + u8 even_scramble_bits) +{ + int res, cmd_len, rsp_len; + struct sdmx_ses_cfg_req *cmd; + struct sdmx_ses_cfg_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_ses_cfg_req); + rsp_len = sizeof(struct sdmx_ses_cfg_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_SET_SESSION_CFG_CMD; + cmd->session_handle = session_handle; + cmd->process_mode = proc_mode; + cmd->input_mode = inp_mode; + cmd->packet_len = pkt_format; + cmd->odd_scramble_bits = odd_scramble_bits; + cmd->even_scramble_bits = even_scramble_bits; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_set_session_cfg); + +/* + * Creates a new secure demux filter and returns a filter handle + * + * @session_handle: secure demux instance + * @pid: pid to filter + * @filter_type: type of filtering + * @meta_data_buf: meta data buffer descriptor + * @data_buf_mode: data buffer mode (ring/linear) + * @num_data_bufs: number of data buffers (use 1 for a ring buffer) + * @data_bufs: data buffers descriptors array + * @filter_handle: returned filter handle + * @ts_out_format: output format for raw filters + * @flags: optional flags for filter + * (currently only clear section CRC verification is supported) + * + * Return error code + */ +int sdmx_add_filter(int session_handle, + u16 pid, + enum sdmx_filter filterype, + struct sdmx_buff_descr *meta_data_buf, + enum sdmx_buf_mode d_buf_mode, + u32 num_data_bufs, + struct sdmx_data_buff_descr *data_bufs, + int *filter_handle, + enum sdmx_raw_out_format ts_out_format, + u32 flags) +{ + int res, cmd_len, rsp_len; + struct sdmx_add_filt_req *cmd; + struct sdmx_add_filt_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (filter_handle == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_add_filt_req) + + num_data_bufs * sizeof(struct sdmx_data_buff_descr); + rsp_len = sizeof(struct sdmx_add_filt_rsp); + + /* Will be later overridden by SDMX response */ + *filter_handle = SDMX_INVALID_FILTER_HANDLE; + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_ADD_FILTER_CMD; + cmd->session_handle = session_handle; + cmd->pid = (u32)pid; + cmd->filter_type = filterype; + cmd->ts_out_format = ts_out_format; + cmd->flags = flags; + if (meta_data_buf != NULL) + memcpy(&(cmd->meta_data_buf), meta_data_buf, + sizeof(struct sdmx_buff_descr)); + else + memset(&(cmd->meta_data_buf), 0, sizeof(cmd->meta_data_buf)); + + cmd->buffer_mode = d_buf_mode; + cmd->num_data_bufs = num_data_bufs; + memcpy(cmd->data_bufs, data_bufs, + num_data_bufs * sizeof(struct sdmx_data_buff_descr)); + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *filter_handle = rsp->filter_handle; + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_add_filter); + +/* + * Removes a secure demux filter + * + * @session_handle: secure demux instance + * @filter_handle: filter handle to remove + * + * Return error code + */ +int sdmx_remove_filter(int session_handle, int filter_handle) +{ + int res, cmd_len, rsp_len; + struct sdmx_rem_filt_req *cmd; + struct sdmx_rem_filt_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_rem_filt_req); + rsp_len = sizeof(struct sdmx_rem_filt_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_REMOVE_FILTER_CMD; + cmd->session_handle = session_handle; + cmd->filter_handle = filter_handle; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_remove_filter); + +/* + * Associates a key ladder index for the specified pid + * + * @session_handle: secure demux instance + * @pid: pid + * @key_ladder_index: key ladder index to associate to the pid + * + * Return error code + * + * Note: if pid already has some key ladder index associated, it will be + * overridden. + */ +int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index) +{ + int res, cmd_len, rsp_len; + struct sdmx_set_kl_ind_req *cmd; + struct sdmx_set_kl_ind_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_set_kl_ind_req); + rsp_len = sizeof(struct sdmx_set_kl_ind_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_SET_KL_IDX_CMD; + cmd->session_handle = session_handle; + cmd->pid = (u32)pid; + cmd->kl_index = key_ladder_index; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_set_kl_ind); + +/* + * Adds the specified pid to an existing raw (recording) filter + * + * @session_handle: secure demux instance + * @filter_handle: raw filter handle + * @pid: pid + * + * Return error code + */ +int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid) +{ + int res, cmd_len, rsp_len; + struct sdmx_add_raw_req *cmd; + struct sdmx_add_raw_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_add_raw_req); + rsp_len = sizeof(struct sdmx_add_raw_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_ADD_RAW_PID_CMD; + cmd->session_handle = session_handle; + cmd->filter_handle = filter_handle; + cmd->pid = (u32)pid; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_add_raw_pid); + +/* + * Removes the specified pid from a raw (recording) filter + * + * @session_handle: secure demux instance + * @filter_handle: raw filter handle + * @pid: pid + * + * Return error code + */ +int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid) +{ + int res, cmd_len, rsp_len; + struct sdmx_rem_raw_req *cmd; + struct sdmx_rem_raw_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_rem_raw_req); + rsp_len = sizeof(struct sdmx_rem_raw_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_REMOVE_RAW_PID_CMD; + cmd->session_handle = session_handle; + cmd->filter_handle = filter_handle; + cmd->pid = (u32)pid; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_remove_raw_pid); + +/* + * Call secure demux to perform processing on the specified input buffer + * + * @session_handle: secure demux instance + * @flags: input flags. Currently only EOS marking is supported. + * @input_buf_desc: input buffer descriptor + * @input_fill_count: number of bytes available in input buffer + * @input_read_offset: offset inside input buffer where data starts + * @error_indicators: returned general error indicators + * @status_indicators: returned general status indicators + * @num_filters: number of filters in filter status array + * @filter_status: filter status descriptor array + * + * Return error code + */ +int sdmx_process(int session_handle, u8 flags, + struct sdmx_buff_descr *input_buf_desc, + u32 *input_fill_count, + u32 *input_read_offset, + u32 *error_indicators, + u32 *status_indicators, + u32 num_filters, + struct sdmx_filter_status *filter_status) +{ + int res, cmd_len, rsp_len; + struct sdmx_proc_req *cmd; + struct sdmx_proc_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (input_buf_desc == NULL) || + (input_fill_count == NULL) || (input_read_offset == NULL) || + (error_indicators == NULL) || (status_indicators == NULL) || + (filter_status == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_proc_req) + + num_filters * sizeof(struct sdmx_filter_status); + rsp_len = sizeof(struct sdmx_proc_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_PROCESS_CMD; + cmd->session_handle = session_handle; + cmd->flags = flags; + cmd->in_buf_descr.base_addr = input_buf_desc->base_addr; + cmd->in_buf_descr.size = input_buf_desc->size; + cmd->inp_fill_cnt = *input_fill_count; + cmd->in_rd_offset = *input_read_offset; + cmd->num_filters = num_filters; + memcpy(cmd->filters_status, filter_status, + num_filters * sizeof(struct sdmx_filter_status)); + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *input_fill_count = rsp->inp_fill_cnt; + *input_read_offset = rsp->in_rd_offset; + *error_indicators = rsp->err_indicators; + *status_indicators = rsp->status_indicators; + memcpy(filter_status, cmd->filters_status, + num_filters * sizeof(struct sdmx_filter_status)); + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_process); + +/* + * Returns session-level & filter-level debug counters + * + * @session_handle: secure demux instance + * @session_counters: returned session-level debug counters + * @num_filters: returned number of filters reported in filter_counters + * @filter_counters: returned filter-level debug counters array + * + * Return error code + */ +int sdmx_get_dbg_counters(int session_handle, + struct sdmx_session_dbg_counters *session_counters, + u32 *num_filters, + struct sdmx_filter_dbg_counters *filter_counters) +{ + int res, cmd_len, rsp_len; + struct sdmx_get_counters_req *cmd; + struct sdmx_get_counters_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (session_counters == NULL) || (num_filters == NULL) || + (filter_counters == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_get_counters_req); + rsp_len = sizeof(struct sdmx_get_counters_rsp) + + *num_filters * sizeof(struct sdmx_filter_dbg_counters); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_GET_DBG_COUNTERS_CMD; + cmd->session_handle = session_handle; + cmd->num_filters = *num_filters; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *session_counters = rsp->session_counters; + *num_filters = rsp->num_filters; + memcpy(filter_counters, rsp->filter_counters, + *num_filters * sizeof(struct sdmx_filter_dbg_counters)); + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_get_dbg_counters); + +/* + * Reset debug counters + * + * @session_handle: secure demux instance + * + * Return error code + */ +int sdmx_reset_dbg_counters(int session_handle) +{ + int res, cmd_len, rsp_len; + struct sdmx_rst_counters_req *cmd; + struct sdmx_rst_counters_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_rst_counters_req); + rsp_len = sizeof(struct sdmx_rst_counters_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_RESET_DBG_COUNTERS_CMD; + cmd->session_handle = session_handle; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_reset_dbg_counters); + +/* + * Set debug log verbosity level + * + * @session_handle: secure demux instance + * @level: requested log level + * + * Return error code + */ +int sdmx_set_log_level(int session_handle, enum sdmx_log_level level) +{ + int res, cmd_len, rsp_len; + struct sdmx_set_log_level_req *cmd; + struct sdmx_set_log_level_rsp *rsp; + enum sdmx_status ret; + + cmd_len = sizeof(struct sdmx_set_log_level_req); + rsp_len = sizeof(struct sdmx_set_log_level_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_SET_LOG_LEVEL_CMD; + cmd->session_handle = session_handle; + cmd->level = level; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + ret = rsp->ret; +out: + /* Unlock */ + mutex_unlock(&sdmx_lock[session_handle]); + return ret; +} diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h new file mode 100644 index 0000000000000000000000000000000000000000..08a23a59d42546cd81e2a0c3ad69c4e4adf85e82 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h @@ -0,0 +1,377 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_SDMX_H +#define _MPQ_SDMX_H + +#include + +/* Constant declarations */ +#define SDMX_MAX_SESSIONS (4) +#define SDMX_LOOPBACK_PID (0x2000) + +#define SDMX_MAX_PHYSICAL_CHUNKS (256) + +/* Filter-level error indicators */ +#define SDMX_FILTER_SUCCESS (0) +#define SDMX_FILTER_ERR_MD_BUF_FULL BIT(0) +#define SDMX_FILTER_ERR_D_BUF_FULL BIT(1) +#define SDMX_FILTER_ERR_D_LIN_BUFS_FULL BIT(2) +#define SDMX_FILTER_ERR_INVALID_SCRAMBLE_BITS BIT(3) +#define SDMX_FILTER_ERR_KL_IND_NOT_SET BIT(4) +#define SDMX_FILTER_ERR_CAS_DECRYPT_ERROR BIT(5) +#define SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL BIT(6) +#define SDMX_FILTER_ERR_SEC_INTERNAL_MALLOC_FAIL BIT(7) +#define SDMX_FILTER_ERR_SEC_LEN_INVALID BIT(8) +#define SDMX_FILTER_ERR_SEC_PUSI_PTR_INVALID BIT(9) +#define SDMX_FILTER_ERR_TS_SYNC_BYTE_INVALID BIT(10) +#define SDMX_FILTER_ERR_TS_TRANSPORT_ERR BIT(11) +#define SDMX_FILTER_ERR_CONT_CNT_INVALID BIT(12) +#define SDMX_FILTER_ERR_CONT_CNT_DUPLICATE BIT(13) +#define SDMX_FILTER_ERR_INVALID_PES_HDR BIT(14) +#define SDMX_FILTER_ERR_INVALID_PES_LEN BIT(15) +#define SDMX_FILTER_ERR_INVALID_PES_ENCRYPTION BIT(16) +#define SDMX_FILTER_ERR_SECURITY_FAULT BIT(17) +#define SDMX_FILTER_ERR_IN_NS_BUFFER BIT(18) + +/* Filter-level status indicators */ +#define SDMX_FILTER_STATUS_EOS BIT(0) +#define SDMX_FILTER_STATUS_WR_PTR_CHANGED BIT(1) + +/* Filter-level flags */ +#define SDMX_FILTER_FLAG_VERIFY_SECTION_CRC BIT(0) + +#define SDMX_INVALID_SESSION_HANDLE (-1) +#define SDMX_INVALID_FILTER_HANDLE (-1) + +/* Input flags */ +#define SDMX_INPUT_FLAG_EOS BIT(0) +#define SDMX_INPUT_FLAG_DBG_ENABLE BIT(1) + + +enum sdmx_buf_mode { + SDMX_RING_BUF, + SDMX_LINEAR_GROUP_BUF, +}; + +enum sdmx_proc_mode { + SDMX_PUSH_MODE, + SDMX_PULL_MODE, +}; + +enum sdmx_inp_mode { + SDMX_PKT_ENC_MODE, + SDMX_BULK_ENC_MODE, + SDMX_CLEAR_MODE, +}; + +enum sdmx_pkt_format { + SDMX_188_BYTE_PKT = 188, + SDMX_192_BYTE_PKT = 192, + SDMX_195_BYTE_PKT = 195, +}; + +enum sdmx_log_level { + SDMX_LOG_NO_PRINT, + SDMX_LOG_MSG_ERROR, + SDMX_LOG_DEBUG, + SDMX_LOG_VERBOSE +}; + +enum sdmx_status { + SDMX_SUCCESS = 0, + SDMX_STATUS_GENERAL_FAILURE = -1, + SDMX_STATUS_MAX_OPEN_SESSIONS_REACHED = -2, + SDMX_STATUS_INVALID_SESSION_HANDLE = -3, + SDMX_STATUS_INVALID_INPUT_PARAMS = -4, + SDMX_STATUS_UNSUPPORTED_MODE = -5, + SDMX_STATUS_INVALID_PID = -6, + SDMX_STATUS_OUT_OF_MEM = -7, + SDMX_STATUS_FILTER_EXISTS = -8, + SDMX_STATUS_INVALID_FILTER_HANDLE = -9, + SDMX_STATUS_MAX_RAW_PIDS_REACHED = -10, + SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11, + SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12, + SDMX_STATUS_INVALID_FILTER_CFG = -13, + SDMX_STATUS_STALLED_IN_PULL_MODE = -14, + SDMX_STATUS_SECURITY_FAULT = -15, + SDMX_STATUS_NS_BUFFER_ERROR = -16, +}; + +enum sdmx_filter { + SDMX_PES_FILTER, /* Other PES */ + SDMX_SEPARATED_PES_FILTER, /* Separated PES (for decoder) */ + SDMX_SECTION_FILTER, /* Section */ + SDMX_PCR_FILTER, /* PCR */ + SDMX_RAW_FILTER, /* Recording */ +}; + +enum sdmx_raw_out_format { + SDMX_188_OUTPUT, + SDMX_192_HEAD_OUTPUT, + SDMX_192_TAIL_OUTPUT +}; + +struct sdmx_buff_descriptor { + void *virt_base; /* logical address of the actual data */ + phys_addr_t phys_base; /* physical address of the actual data */ + dma_addr_t dma_base; /* DMA address of the actual data */ + u32 size; /* size of buffer in bytes */ + int id; /* unique identifier */ + void *user; /* user-defined data */ +}; + +#pragma pack(push, sdmx, 1) + +struct sdmx_session_dbg_counters { + /* Total number of TS-packets input to SDMX. */ + u32 ts_pkt_in; + + /* Total number of TS-packets filtered out by SDMX. */ + u32 ts_pkt_out; +}; + +struct sdmx_filter_dbg_counters { + int filter_handle; + + /* Number of TS-packets filtered. */ + u32 ts_pkt_count; + + /* Number of TS-packets with adaptation field only (no payload). */ + u32 ts_pkt_no_payload; + + /* Number of TS-packets with the discontinuity indicator set. */ + u32 ts_pkt_discont; + + /* Number of duplicate TS-packets detected. */ + u32 ts_pkt_dup; + + /* Number of packets not decrypted because the key wasn't ready. */ + u32 ts_pkt_key_not_ready; +}; + +struct sdmx_pes_counters { + /* Number of TS packets with the TEI flag set */ + u32 transport_err_count; + + /* Number of TS packets with continuity counter errors */ + u32 continuity_err_count; + + /* Number of TS packets composing this PES frame */ + u32 pes_ts_count; + + /* Number of TS packets dropped due to full buffer */ + u32 drop_count; +}; + +struct sdmx_buff_descr { + /* Physical address where buffer starts */ + u64 base_addr; + + /* Size of buffer */ + u32 size; +}; + +struct sdmx_data_buff_descr { + /* Physical chunks of the buffer */ + struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS]; + + /* Length of buffer */ + u32 length; +}; + +/* + * Data payload residing in the data buffers is described using this meta-data + * header. The meta data header specifies where the payload is located in the + * data buffer and how big it is. + * The meta data header optionally carries additional relevant meta data + * immediately following the meta-data header. + */ +struct sdmx_metadata_header { + /* + * Payload start offset inside data buffer. In case data is managed + * as a linear buffer group, this specifies buffer index. + */ + u32 payload_start; + + /* Payload length */ + u32 payload_length; + + /* Number of meta data bytes immediately following this header */ + u32 metadata_length; +}; + + +struct sdmx_filter_status { + /* Secure demux filter handle */ + int filter_handle; + + /* + * Number of pending bytes in filter's output data buffer. + * For linear buffer mode, this is number of buffers pending. + */ + u32 data_fill_count; + + /* + * Offset in data buffer for next data payload to be written. + * For linear buffer mode, this is a buffer index. + */ + u32 data_write_offset; + + /* Number of pending bytes in filter's output meta data buffer */ + u32 metadata_fill_count; + + /* Offset in meta data buffer for next metadata header to be written */ + u32 metadata_write_offset; + + /* Errors (bitmap) reported by secure demux for this filter */ + u32 error_indicators; + + /* General status (bitmap) reported by secure demux for this filter */ + u32 status_indicators; +}; +#pragma pack(pop, sdmx) + +#ifdef CONFIG_QSEECOM + +int sdmx_open_session(int *session_handle); + +int sdmx_close_session(int session_handle); + +int sdmx_get_version(int session_handle, int32_t *version); + +int sdmx_set_session_cfg(int session_handle, enum sdmx_proc_mode proc_mode, + enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format, + u8 odd_scramble_bits, u8 even_scramble_bits); + +int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type, + struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode, + u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs, + int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags); + +int sdmx_remove_filter(int session_handle, int filter_handle); + +int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index); + +int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid); + +int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid); + +int sdmx_process(int session_handle, u8 flags, + struct sdmx_buff_descr *input_buf_desc, + u32 *input_fill_count, u32 *input_read_offset, + u32 *error_indicators, + u32 *status_indicators, + u32 num_filters, + struct sdmx_filter_status *filter_status); + +int sdmx_get_dbg_counters(int session_handle, + struct sdmx_session_dbg_counters *session_counters, + u32 *num_filters, + struct sdmx_filter_dbg_counters *filter_counters); + +int sdmx_reset_dbg_counters(int session_handle); + +int sdmx_set_log_level(int session_handle, enum sdmx_log_level level); + +#else + +static inline int sdmx_open_session(int *session_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_close_session(int session_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_get_version(int session_handle, int32_t *version) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_set_session_cfg(int session_handle, + enum sdmx_proc_mode proc_mode, + enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format, + u8 odd_scramble_bits, u8 even_scramble_bits) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_add_filter(int session_handle, u16 pid, + enum sdmx_filter filter_type, + struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode, + u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs, + int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_remove_filter(int session_handle, int filter_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_set_kl_ind(int session_handle, u16 pid, + u32 key_ladder_index) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_add_raw_pid(int session_handle, int filter_handle, + u16 pid) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_remove_raw_pid(int session_handle, int filter_handle, + u16 pid) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_process(int session_handle, u8 flags, + struct sdmx_buff_descr *input_buf_desc, + u32 *input_fill_count, u32 *input_read_offset, + u32 *error_indicators, + u32 *status_indicators, + u32 num_filters, + struct sdmx_filter_status *filter_status) +{ + *status_indicators = 0; + *error_indicators = 0; + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_get_dbg_counters(int session_handle, + struct sdmx_session_dbg_counters *session_counters, + u32 *num_filters, + struct sdmx_filter_dbg_counters *filter_counters) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_reset_dbg_counters(int session_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_set_log_level(int session_handle, + enum sdmx_log_level level) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +#endif + +#endif /* _MPQ_SDMX_H */ diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..212083a91344b28b34c856aa1190626e4c1e40c6 --- /dev/null +++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.h @@ -0,0 +1,222 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_ADAPTER_H +#define _MPQ_ADAPTER_H + +#include "dvbdev.h" +#include "dvb_demux.h" +#include "mpq_stream_buffer.h" + + + +/** IDs of interfaces holding stream-buffers */ +enum mpq_adapter_stream_if { + /** Interface holding stream-buffer for video0 stream */ + MPQ_ADAPTER_VIDEO0_STREAM_IF = 0, + + /** Interface holding stream-buffer for video1 stream */ + MPQ_ADAPTER_VIDEO1_STREAM_IF = 1, + + /** Interface holding stream-buffer for video2 stream */ + MPQ_ADAPTER_VIDEO2_STREAM_IF = 2, + + /** Interface holding stream-buffer for video3 stream */ + MPQ_ADAPTER_VIDEO3_STREAM_IF = 3, + + /** Interface holding stream-buffer for audio0 stream */ + MPQ_ADAPTER_AUDIO0_STREAM_IF = 4, + + /** Interface holding stream-buffer for audio1 stream */ + MPQ_ADAPTER_AUDIO1_STREAM_IF = 5, + + /** Interface holding stream-buffer for audio2 stream */ + MPQ_ADAPTER_AUDIO2_STREAM_IF = 6, + + /** Interface holding stream-buffer for audio3 stream */ + MPQ_ADAPTER_AUDIO3_STREAM_IF = 7, + + /** Maximum number of interfaces holding stream-buffers */ + MPQ_ADAPTER_MAX_NUM_OF_INTERFACES, +}; + +enum dmx_packet_type { + DMX_PES_PACKET, + DMX_FRAMING_INFO_PACKET, + DMX_EOS_PACKET, + DMX_MARKER_PACKET +}; + +struct dmx_pts_dts_info { + /** Indication whether PTS exist */ + int pts_exist; + + /** Indication whether DTS exist */ + int dts_exist; + + /** PTS value associated with the PES data if any */ + u64 pts; + + /** DTS value associated with the PES data if any */ + u64 dts; +}; + +struct dmx_framing_packet_info { + /** framing pattern type, one of DMX_IDX_* definitions */ + u64 pattern_type; + + /** PTS/DTS information */ + struct dmx_pts_dts_info pts_dts_info; + + /** STC value attached to first TS packet holding the pattern */ + u64 stc; + + /* + * Number of TS packets with Transport Error Indicator (TEI) + * found while constructing the frame. + */ + __u32 transport_error_indicator_counter; + + /* Number of continuity errors found while constructing the frame */ + __u32 continuity_error_counter; + + /* + * Number of dropped bytes due to insufficient buffer space, + * since last reported frame. + */ + __u32 ts_dropped_bytes; + + /* Total number of TS packets holding the frame */ + __u32 ts_packets_num; +}; + +struct dmx_pes_packet_info { + /** PTS/DTS information */ + struct dmx_pts_dts_info pts_dts_info; + + /** STC value attached to first TS packet holding the PES */ + u64 stc; +}; + +struct dmx_marker_info { + /* marker id */ + u64 id; +}; + +/** The meta-data used for video interface */ +struct mpq_adapter_video_meta_data { + /** meta-data packet type */ + enum dmx_packet_type packet_type; + + /** packet-type specific information */ + union { + struct dmx_framing_packet_info framing; + struct dmx_pes_packet_info pes; + struct dmx_marker_info marker; + } info; +} __packed; + +/** The meta-data used for audio interface */ +struct mpq_adapter_audio_meta_data { + /** meta-data packet type */ + enum dmx_packet_type packet_type; + + /** packet-type specific information */ + union { + struct dmx_pes_packet_info pes; + struct dmx_marker_info marker; + } info; +} __packed; + +/** Callback function to notify on registrations of specific interfaces */ +typedef void (*mpq_adapter_stream_if_callback)( + enum mpq_adapter_stream_if interface_id, + void *user_param); + + +/** + * mpq_adapter_get - Returns pointer to Qualcomm Technologies Inc. DVB adapter + * + * Return dvb adapter or NULL if not exist. + */ +struct dvb_adapter *mpq_adapter_get(void); + + +/** + * mpq_adapter_register_stream_if - Register a stream interface. + * + * @interface_id: The interface id + * @stream_buffer: The buffer used for the interface + * + * Return error status + * + * Stream interface used to connect between two units in tunneling + * mode using mpq_streambuffer implementation. + * The producer of the interface should register the new interface, + * consumer may get the interface using mpq_adapter_get_stream_if. + * + * Note that the function holds a pointer to this interface, + * stream_buffer pointer assumed to be valid as long as interface + * is active. + */ +int mpq_adapter_register_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer *stream_buffer); + + +/** + * mpq_adapter_unregister_stream_if - Un-register a stream interface. + * + * @interface_id: The interface id + * + * Return error status + */ +int mpq_adapter_unregister_stream_if( + enum mpq_adapter_stream_if interface_id); + + +/** + * mpq_adapter_get_stream_if - Get buffer used for a stream interface. + * + * @interface_id: The interface id + * @stream_buffer: The returned stream buffer + * + * Return error status + */ +int mpq_adapter_get_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer **stream_buffer); + + +/** + * mpq_adapter_notify_stream_if - Register notification + * to be triggered when a stream interface is registered. + * + * @interface_id: The interface id + * @callback: The callback to be triggered when the interface is registered + * @user_param: A parameter that is passed back to the callback function + * when triggered. + * + * Return error status + * + * Producer may use this to register notification when desired + * interface registered in the system and query its information + * afterwards using mpq_adapter_get_stream_if. + * To remove the callback, this function should be called with NULL + * value in callback parameter. + */ +int mpq_adapter_notify_stream_if( + enum mpq_adapter_stream_if interface_id, + mpq_adapter_stream_if_callback callback, + void *user_param); + +#endif /* _MPQ_ADAPTER_H */ diff --git a/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h b/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..47d2e6ea8ad163a9f9cbf5ae6be8d3f87d4679c9 --- /dev/null +++ b/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_DVB_DEBUG_H +#define _MPQ_DVB_DEBUG_H + +/* Enable this line if you want to output debug printouts */ +#define MPG_DVB_DEBUG_ENABLE + +#undef MPQ_DVB_DBG_PRINT /* undef it, just in case */ + +#ifdef MPG_DVB_DEBUG_ENABLE +#define MPQ_DVB_ERR_PRINT(fmt, args...) pr_err(fmt, ## args) +#define MPQ_DVB_WARN_PRINT(fmt, args...) pr_warn(fmt, ## args) +#define MPQ_DVB_NOTICE_PRINT(fmt, args...) pr_notice(fmt, ## args) +#define MPQ_DVB_DBG_PRINT(fmt, args...) pr_debug(fmt, ## args) +#else /* MPG_DVB_DEBUG_ENABLE */ +#define MPQ_DVB_ERR_PRINT(fmt, args...) +#define MPQ_DVB_WARN_PRINT(fmt, args...) +#define MPQ_DVB_NOTICE_PRINT(fmt, args...) +#define MPQ_DVB_DBG_PRINT(fmt, args...) +#endif /* MPG_DVB_DEBUG_ENABLE */ + + +/* + * The following can be used to disable specific printout + * by adding a letter to the end of MPQ_DVB_DBG_PRINT + */ +#undef MPQ_DVB_DBG_PRINTT +#define MPQ_DVB_DBG_PRINTT(fmt, args...) + +#endif /* _MPQ_DVB_DEBUG_H */ diff --git a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..13d4eb8d975ff427b416d74a2cde2d636dc43ca2 --- /dev/null +++ b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h @@ -0,0 +1,494 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_STREAM_BUFFER_H +#define _MPQ_STREAM_BUFFER_H + +#include "dvb_ringbuffer.h" + +/** + * DOC: MPQ Stream Buffer + * + * A stream buffer implementation is used to transfer data between two units + * such as demux and decoders. The implementation relies on dvb_ringbuffer + * implementation. Refer to dvb_ringbuffer.h for details. + * + * The implementation uses two dvb_ringbuffers, one to pass the + * raw-data (PES payload for example) and the other to pass + * meta-data (information from PES header for example). + * + * The meta-data uses dvb_ringbuffer packet interface. Each meta-data + * packet points to the data buffer, and includes the offset to the data in the + * buffer, the size of raw-data described by the meta-data packet, and also the + * size of user's own parameters if any required. + * + * Data can be managed in two ways: ring-buffer & linear buffers, as specified + * in initialization when calling the mpq_streambuffer_init function. + * For managing data as a ring buffer exactly 1 data buffer descriptor must be + * specified in initialization. For this mode, dvb_ringbuffer is used "as-is". + * For managing data in several linear buffers, an array of buffer descriptors + * must be passed. + * For both modes, data descriptor(s) must be remain valid throughout the life + * span of the mpq_streambuffer object. + * Apart from initialization API remains the same for both modes. + * + * Contrary to dvb_ringbuffer implementation, this API makes sure there's + * enough data to read/write when making read/write operations. + * Users interested to flush/reset specific buffer, check for bytes + * ready or space available for write should use the respective services + * in dvb_ringbuffer (dvb_ringbuffer_avail, dvb_ringbuffer_free, + * dvb_ringbuffer_reset, dvb_ringbuffer_flush, + * dvb_ringbuffer_flush_spinlock_wakeup). + * + * Concurrency protection is handled in the same manner as in + * dvb_ringbuffer implementation. + * + * Typical call flow from producer: + * + * - Start writing the raw-data of new packet, the following call is + * repeated until end of data of the specific packet + * + * mpq_streambuffer_data_write(...) + * + * - Now write a new packet describing the new available raw-data + * mpq_streambuffer_pkt_write(...) + * + * For linear buffer mode, writing a new packet with data size > 0, causes the + * current buffer to be marked as pending for reading, and triggers moving to + * the next available buffer, that shall now be the current write buffer. + * + * Typical call flow from consumer: + * + * - Poll for next available packet: + * mpq_streambuffer_pkt_next(&streambuff,-1,&len) + * + * In different approach, consumer can wait on event for new data and then + * call mpq_streambuffer_pkt_next, waiting for data can be done as follows: + * + * wait_event_interruptible( + * streambuff->packet_data->queue, + * !dvb_ringbuffer_empty(&streambuff->packet_data) || + * (streambuff->packet_data.error != 0); + * + * - Get the new packet information: + * mpq_streambuffer_pkt_read(..) + * + * - Read the raw-data of the new packet. Here you can use two methods: + * + * 1. Read the data to a user supplied buffer: + * mpq_streambuffer_data_read() + * + * In this case memory copy is done, read pointer is updated in the raw + * data buffer, the amount of raw-data is provided part of the + * packet's information. User should then call mpq_streambuffer_pkt_dispose + * with dispose_data set to 0 as the raw-data was already disposed. + * Note that secure buffer cannot be accessed directly and an error will + * occur. + * + * 2. Access the data directly using the raw-data address. The address + * of the raw data is provided part of the packet's information. User + * then should call mpq_streambuffer_pkt_dispose with dispose_data set + * to 1 to dispose the packet along with it's raw-data. + * + * - Disposal of packets: + * mpq_streambuffer_pkt_dispose(...) + * + * For linear buffer mode, disposing of a packet with data size > 0, + * regardless of the 'dispose_data' parameter, causes the current buffer's + * data to be disposed and marked as free for writing, and triggers moving to + * the next available buffer, that shall now be the current read buffer. + */ + +struct mpq_streambuffer; +struct mpq_streambuffer_packet_header; + +typedef void (*mpq_streambuffer_dispose_cb) ( + struct mpq_streambuffer *sbuff, + u32 offset, + size_t len, + void *user_data); + +enum mpq_streambuffer_mode { + MPQ_STREAMBUFFER_BUFFER_MODE_RING, + MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR +}; + +/** + * struct mpq_streambuffer - mpq stream buffer representation + * + * @raw_data: The buffer used to hold raw-data, or linear buffer descriptors + * @packet_data: The buffer user to hold the meta-data + * @buffers: array of buffer descriptor(s) holding buffer initial & dynamic + * buffer information + * @mode: mpq_streambuffer buffer management work mode - Ring-buffer or Linear + * buffers + * @buffers_num: number of data buffers to manage + * @pending_buffers_count: for linear buffer management, counts the number of + * buffer that has been + */ +struct mpq_streambuffer { + struct dvb_ringbuffer raw_data; + struct dvb_ringbuffer packet_data; + struct mpq_streambuffer_buffer_desc *buffers; + enum mpq_streambuffer_mode mode; + u32 buffers_num; + u32 pending_buffers_count; + mpq_streambuffer_dispose_cb cb; + void *cb_user_data; +}; + +/** + * mpq_streambuffer_linear_desc + * @handle: ION handle's file descriptor of buffer + * @base: kernel mapped address to start of buffer. + * Can be NULL for secured buffers + * @size: size of buffer + * @read_ptr: initial read pointer value (should normally be 0) + * @write_ptr: initial write pointer value (should normally be 0) + */ +struct mpq_streambuffer_buffer_desc { + int handle; + void *base; + u32 size; + u32 read_ptr; + u32 write_ptr; +}; + +/** + * struct mpq_streambuffer_packet_header - packet header saved in packet buffer + * @user_data_len: length of private user (meta) data + * @raw_data_handle: ION handle's file descriptor of raw-data buffer + * @raw_data_offset: offset of raw-data from start of buffer (0 for linear) + * @raw_data_len: size of raw-data in the raw-data buffer (can be 0) + * + * The packet structure that is saved in each packet-buffer: + * user_data_len + * raw_data_handle + * raw_data_offset + * raw_data_len + * private user-data bytes + */ +struct mpq_streambuffer_packet_header { + u32 user_data_len; + int raw_data_handle; + u32 raw_data_offset; + u32 raw_data_len; +} __packed; + +/** + * mpq_streambuffer_init - Initialize a new stream buffer + * + * @sbuff: The buffer to initialize + * @data_buffers: array of data buffer descriptor(s). + * Data descriptor(s) must be remain valid throughout the life + * span of the mpq_streambuffer object + * @data_buff_num: number of data buffer in array + * @packet_buff: The buffer holding meta-data + * @packet_buff_size: Size of meta-data buffer + * + * Return Error status, -EINVAL if any of the arguments are invalid + * + * Note: + * for data_buff_num > 1, mpq_streambuffer object manages these buffers as a + * separated set of linear buffers. A linear buffer cannot wrap-around and one + * can only write as many data bytes as the buffer's size. Data will not be + * written to the next free buffer. + */ +int mpq_streambuffer_init( + struct mpq_streambuffer *sbuff, + enum mpq_streambuffer_mode mode, + struct mpq_streambuffer_buffer_desc *data_buffers, + u32 data_buff_num, + void *packet_buff, + size_t packet_buff_size); + +/** + * mpq_streambuffer_terminate - Terminate stream buffer + * + * @sbuff: The buffer to terminate + * + * The function sets the the buffers error flags to ENODEV + * and wakeup any waiting threads on the buffer queues. + * Threads waiting on the buffer queues should check if + * error was set. + */ +void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_packet_next - Returns index of next available packet. + * + * @sbuff: The stream buffer + * @idx: Previous packet index or -1 to return index of the the first + * available packet. + * @pktlen: The length of the ready packet + * + * Return index to the packet-buffer, -1 if buffer is empty + * + * After getting the index, the user of this function can either + * access the packet buffer directly using the returned index + * or ask to read the data back from the buffer using mpq_ringbuffer_pkt_read + */ +ssize_t mpq_streambuffer_pkt_next( + struct mpq_streambuffer *sbuff, + ssize_t idx, size_t *pktlen); + +/** + * mpq_streambuffer_pkt_read - Reads out the packet from the provided index. + * + * @sbuff: The stream buffer + * @idx: The index of the packet to be read + * @packet: The read packet's header + * @user_data: The read private user data + * + * Return The actual number of bytes read, -EINVAL if the packet is + * already disposed or the packet-data is invalid. + * + * The packet is not disposed after this function is called, to dispose it + * along with the raw-data it points to use mpq_streambuffer_pkt_dispose. + * If there are no private user-data, the user-data pointer can be NULL. + * The caller of this function must make sure that the private user-data + * buffer has enough space for the private user-data length + */ +ssize_t mpq_streambuffer_pkt_read( + struct mpq_streambuffer *sbuff, + size_t idx, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data); + +/** + * mpq_streambuffer_pkt_dispose - Disposes a packet from the packet buffer + * + * @sbuff: The stream buffer + * @idx: The index of the packet to be disposed + * @dispose_data: Indicates whether to update the read pointer inside the + * raw-data buffer for the respective data pointed by the packet. + * + * Return error status, -EINVAL if the packet-data is invalid + * + * The function updates the read pointer inside the raw-data buffer + * for the respective data pointed by the packet if dispose_data is set. + */ +int mpq_streambuffer_pkt_dispose( + struct mpq_streambuffer *sbuff, + size_t idx, + int dispose_data); + +/** + * mpq_streambuffer_pkt_write - Write a new packet to the packet buffer. + * + * @sbuff: The stream buffer + * @packet: The packet header to write + * @user_data: The private user-data to be written + * + * Return error status, -ENOSPC if there's no space to write the packet + */ +int mpq_streambuffer_pkt_write( + struct mpq_streambuffer *sbuff, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data); + +/** + * mpq_streambuffer_data_write - Write data to raw-data buffer + * + * @sbuff: The stream buffer + * @buf: The buffer holding the data to be written + * @len: The length of the data buffer + * + * Return The actual number of bytes written or -ENOSPC if + * no space to write the data + */ +ssize_t mpq_streambuffer_data_write( + struct mpq_streambuffer *sbuff, + const u8 *buf, size_t len); + +/** + * mpq_streambuffer_data_write_deposit - Advances the raw-buffer write pointer. + * Assumes the raw-data was written by the user directly + * + * @sbuff: The stream buffer + * @len: The length of the raw-data that was already written + * + * Return error status + */ +int mpq_streambuffer_data_write_deposit( + struct mpq_streambuffer *sbuff, + size_t len); + +/** + * mpq_streambuffer_data_read - Reads out raw-data to the provided buffer. + * + * @sbuff: The stream buffer + * @buf: The buffer to read the raw-data data to + * @len: The length of the buffer that will hold the raw-data + * + * Return The actual number of bytes read or error code + * + * This function copies the data from the ring-buffer to the + * provided buf parameter. The user can save the extra copy by accessing + * the data pointer directly and reading from it, then update the + * read pointer by the amount of data that was read using + * mpq_streambuffer_data_read_dispose + */ +ssize_t mpq_streambuffer_data_read( + struct mpq_streambuffer *sbuff, + u8 *buf, size_t len); + +/** + * mpq_streambuffer_data_read_user + * + * Same as mpq_streambuffer_data_read except data can be copied to user-space + * buffer. + */ +ssize_t mpq_streambuffer_data_read_user( + struct mpq_streambuffer *sbuff, + u8 __user *buf, size_t len); + +/** + * mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer. + * Assumes the raw-data was read by the user directly. + * + * @sbuff: The stream buffer + * @len: The length of the raw-data to be disposed + * + * Return error status, -EINVAL if buffer there's no enough data to + * be disposed + * + * The user can instead dispose a packet along with the data in the + * raw-data buffer using mpq_streambuffer_pkt_dispose. + */ +int mpq_streambuffer_data_read_dispose( + struct mpq_streambuffer *sbuff, + size_t len); +/** + * mpq_streambuffer_get_buffer_handle - Returns the current linear buffer + * ION handle. + * @sbuff: The stream buffer + * @read_buffer: specifies if a read buffer handle is requested (when set), + * or a write buffer handle is requested. + * For linear buffer mode read & write buffers may be different + * buffers. For ring buffer mode, the same (single) buffer handle + * is returned. + * buffer handle + * @handle: returned handle + * + * Return error status + * -EINVAL is arguments are invalid. + * -EPERM if stream buffer specified was not initialized with linear support. + */ +int mpq_streambuffer_get_buffer_handle( + struct mpq_streambuffer *sbuff, + int read_buffer, + int *handle); + +/** + * mpq_streambuffer_data_free - Returns number of free bytes in data buffer. + * @sbuff: The stream buffer object + * + * Note: for linear buffer management this return number of free bytes in the + * current write buffer only. + */ +ssize_t mpq_streambuffer_data_free( + struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_data_avail - Returns number of bytes in data buffer that + * can be read. + * @sbuff: The stream buffer object + * + * Note: for linear buffer management this return number of data bytes in the + * current read buffer only. + */ +ssize_t mpq_streambuffer_data_avail( + struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_register_pkt_dispose - Registers a callback to notify on + * packet disposal events. + * can be read. + * @sbuff: The stream buffer object + * @cb_func: user callback function + * @user_data: user data to be passed to callback function. + * + * Returns error status + * -EINVAL if arguments are invalid + */ +int mpq_streambuffer_register_data_dispose( + struct mpq_streambuffer *sbuff, + mpq_streambuffer_dispose_cb cb_func, + void *user_data); + +/** + * mpq_streambuffer_data_rw_offset - returns read/write offsets of current data + * buffer. + * @sbuff: The stream buffer object + * @read_offset: returned read offset + * @write_offset: returned write offset + * + * Note: read offset or write offset may be NULL if not required. + * Returns error status + * -EINVAL if arguments are invalid + */ +int mpq_streambuffer_get_data_rw_offset( + struct mpq_streambuffer *sbuff, + u32 *read_offset, + u32 *write_offset); + +/** + * mpq_streambuffer_metadata_free - returns number of free bytes in the meta + * data buffer, or error status. + * @sbuff: the stream buffer object + */ +ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_flush - flush both pending packets and data in buffer + * + * @sbuff: the stream buffer object + * + * Returns error status + */ +int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff); + +/* + * ------------------------------------------------------ + * Consumer or AV Decoder Stream Interface to Ring Buffer + * ------------------------------------------------------ + * Producer is Demux Driver + * ------------------------ + * + * call from Audio/Video Decoder Driver to find Audio/Video + * streambuffer AV handles, "DMX_PES_AUDIO0 through 3" or + * DMX_PES_VIDEO0 through 3" interfaces corresponding to 4 programs. + */ + +/* call from Audio/Video Decoder Driver via POLLING to consume + * Headers and Compressed data from ring buffer using streambuffer handle. + * hdrdata[] and cdata[] buffers have to be malloc'd by consumer + * + * -------------------------- + * Consumer Calling Sequence + * -------------------------- + * Find the streambuffer corresponding to a DMX TS PES stream instance. + * 1. consumer_audio_streambuffer() or consumer_video_streambuffer() + * Process the packet headers if required. + * 2. mpq_read_new_packet_hdr_data() + * Process the compressed data by forwarding to AV decoder. + * 3. mpq_read_new_packet_compressed_data() + * Dispose the packet. + * 4. mpq_dispose_new_packet_read() + * + * The Audio/Video drivers (or consumers) require the stream_buffer information + * for consuming packet headers and compressed AV data from the + * ring buffer filled by demux driver which is the producer + */ + +#endif /* _MPQ_STREAM_BUFFER_H */ diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 8639e7cd7e032ec895e7f751027b51d22da4c7f8..63c4fc1c1493a842d6b321b01859be02b8cef417 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -169,7 +169,7 @@ struct npu_irq { }; struct npu_device { - struct mutex ctx_lock; + struct mutex dev_lock; struct platform_device *pdev; @@ -190,8 +190,6 @@ struct npu_device { struct npu_irq irq[NPU_MAX_IRQ]; - struct npu_ion_buf mapped_buffers; - struct device *cb_device; struct npu_host_ctx host_ctx; @@ -208,6 +206,20 @@ struct npu_device { uint32_t execute_v2_flag; }; +struct npu_kevent { + struct list_head list; + struct msm_npu_event evt; + uint64_t reserved[4]; +}; + +struct npu_client { + struct npu_device *npu_dev; + wait_queue_head_t wait; + + struct mutex list_lock; + struct list_head evt_list; + struct list_head mapped_buffer_list; +}; /* ------------------------------------------------------------------------- * Function Prototypes diff --git a/drivers/media/platform/msm/npu/npu_dbg.c b/drivers/media/platform/msm/npu/npu_dbg.c index 38643391153064f782abab9c9cd1738b3f2b4328..67ded1ecd5e1aa203f61aa80dbcafce7249ca56d 100644 --- a/drivers/media/platform/msm/npu/npu_dbg.c +++ b/drivers/media/platform/msm/npu/npu_dbg.c @@ -305,7 +305,6 @@ void npu_dump_debug_timeout_stats(struct npu_device *npu_dev) pr_info("fw jobs execute finished count = %d\n", reg_val); reg_val = REGR(npu_dev, REG_NPU_FW_DEBUG_DATA); pr_info("fw jobs aco parser debug = %d\n", reg_val); - npu_dump_cal_state(npu_dev); } void npu_dump_cal_state(struct npu_device *npu_dev) diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 1539e848fb872bb0451019a0eccbe79ca5d4f0d5..9e68687fe6286b6336a63422708a2d67269a7d31 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -75,16 +76,25 @@ static int npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state); static int npu_open(struct inode *inode, struct file *file); static int npu_close(struct inode *inode, struct file *file); -static int npu_get_info(struct npu_device *npu_dev, unsigned long arg); -static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg); -static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg); -static int npu_load_network(struct npu_device *npu_dev, unsigned long arg); -static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg); -static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg); -static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg); -static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg); +static int npu_get_info(struct npu_client *client, unsigned long arg); +static int npu_map_buf(struct npu_client *client, unsigned long arg); +static int npu_unmap_buf(struct npu_client *client, + unsigned long arg); +static int npu_load_network(struct npu_client *client, + unsigned long arg); +static int npu_load_network_v2(struct npu_client *client, + unsigned long arg); +static int npu_unload_network(struct npu_client *client, + unsigned long arg); +static int npu_exec_network(struct npu_client *client, + unsigned long arg); +static int npu_exec_network_v2(struct npu_client *client, + unsigned long arg); +static int npu_receive_event(struct npu_client *client, + unsigned long arg); static long npu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static unsigned int npu_poll(struct file *filp, struct poll_table_struct *p); static int npu_parse_dt_clock(struct npu_device *npu_dev); static int npu_parse_dt_regulator(struct npu_device *npu_dev); static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, @@ -207,6 +217,7 @@ static const struct file_operations npu_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = npu_ioctl, #endif + .poll = npu_poll, }; static const struct thermal_cooling_device_ops npu_cooling_ops = { @@ -793,14 +804,36 @@ static int npu_open(struct inode *inode, struct file *file) { struct npu_device *npu_dev = container_of(inode->i_cdev, struct npu_device, cdev); + struct npu_client *client; - file->private_data = npu_dev; + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->npu_dev = npu_dev; + init_waitqueue_head(&client->wait); + mutex_init(&client->list_lock); + INIT_LIST_HEAD(&client->evt_list); + INIT_LIST_HEAD(&(client->mapped_buffer_list)); + file->private_data = client; return 0; } static int npu_close(struct inode *inode, struct file *file) { + struct npu_client *client = file->private_data; + struct npu_kevent *kevent; + + while (!list_empty(&client->evt_list)) { + kevent = list_first_entry(&client->evt_list, + struct npu_kevent, list); + list_del(&kevent->list); + kfree(kevent); + } + + mutex_destroy(&client->list_lock); + kfree(client); return 0; } @@ -808,8 +841,9 @@ static int npu_close(struct inode *inode, struct file *file) * IOCTL Implementations * ------------------------------------------------------------------------- */ -static int npu_get_info(struct npu_device *npu_dev, unsigned long arg) +static int npu_get_info(struct npu_client *client, unsigned long arg) { + struct npu_device *npu_dev = client->npu_dev; struct msm_npu_get_info_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; @@ -837,7 +871,7 @@ static int npu_get_info(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg) +static int npu_map_buf(struct npu_client *client, unsigned long arg) { struct msm_npu_map_buf_ioctl req; void __user *argp = (void __user *)arg; @@ -850,7 +884,7 @@ static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - ret = npu_host_map_buf(npu_dev, &req); + ret = npu_host_map_buf(client, &req); if (ret) { pr_err("npu_host_map_buf failed\n"); @@ -866,7 +900,7 @@ static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg) +static int npu_unmap_buf(struct npu_client *client, unsigned long arg) { struct msm_npu_unmap_buf_ioctl req; void __user *argp = (void __user *)arg; @@ -879,7 +913,7 @@ static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - ret = npu_host_unmap_buf(npu_dev, &req); + ret = npu_host_unmap_buf(client, &req); if (ret) { pr_err("npu_host_unmap_buf failed\n"); @@ -895,7 +929,8 @@ static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) +static int npu_load_network(struct npu_client *client, + unsigned long arg) { struct msm_npu_load_network_ioctl req; void __user *argp = (void __user *)arg; @@ -910,7 +945,7 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) pr_debug("network load with perf request %d\n", req.perf_mode); - ret = npu_host_load_network(npu_dev, &req); + ret = npu_host_load_network(client, &req); if (ret) { pr_err("network load failed: %d\n", ret); return -EFAULT; @@ -924,7 +959,8 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg) +static int npu_load_network_v2(struct npu_client *client, + unsigned long arg) { struct msm_npu_load_network_ioctl_v2 req; void __user *argp = (void __user *)arg; @@ -956,7 +992,7 @@ static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg) pr_debug("network load with perf request %d\n", req.perf_mode); - ret = npu_host_load_network_v2(npu_dev, &req, patch_info); + ret = npu_host_load_network_v2(client, &req, patch_info); if (ret) { pr_err("network load failed: %d\n", ret); } else { @@ -969,7 +1005,8 @@ static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg) return ret; } -static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) +static int npu_unload_network(struct npu_client *client, + unsigned long arg) { struct msm_npu_unload_network_ioctl req; void __user *argp = (void __user *)arg; @@ -982,7 +1019,7 @@ static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - ret = npu_host_unload_network(npu_dev, &req); + ret = npu_host_unload_network(client, &req); if (ret) { pr_err("npu_host_unload_network failed\n"); @@ -998,7 +1035,8 @@ static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) +static int npu_exec_network(struct npu_client *client, + unsigned long arg) { struct msm_npu_exec_network_ioctl req; void __user *argp = (void __user *)arg; @@ -1011,7 +1049,15 @@ static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - ret = npu_host_exec_network(npu_dev, &req); + if ((req.input_layer_num > MSM_NPU_MAX_INPUT_LAYER_NUM) || + (req.output_layer_num > MSM_NPU_MAX_OUTPUT_LAYER_NUM)) { + pr_err("Invalid input/out layer num %d[max:%d] %d[max:%d]\n", + req.input_layer_num, MSM_NPU_MAX_INPUT_LAYER_NUM, + req.output_layer_num, MSM_NPU_MAX_OUTPUT_LAYER_NUM); + return -EINVAL; + } + + ret = npu_host_exec_network(client, &req); if (ret) { pr_err("npu_host_exec_network failed\n"); @@ -1027,7 +1073,8 @@ static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg) +static int npu_exec_network_v2(struct npu_client *client, + unsigned long arg) { struct msm_npu_exec_network_ioctl_v2 req; void __user *argp = (void __user *)arg; @@ -1063,7 +1110,7 @@ static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg) req.patch_buf_info_num * sizeof(*patch_buf_info)); } - ret = npu_host_exec_network_v2(npu_dev, &req, patch_buf_info); + ret = npu_host_exec_network_v2(client, &req, patch_buf_info); if (ret) { pr_err("npu_host_exec_network failed\n"); } else { @@ -1076,36 +1123,90 @@ static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg) return ret; } +static int npu_process_kevent(struct npu_kevent *kevt) +{ + int ret = 0; + + switch (kevt->evt.type) { + case MSM_NPU_EVENT_TYPE_EXEC_V2_DONE: + ret = copy_to_user((void __user *)kevt->reserved[1], + (void *)&kevt->reserved[0], + kevt->evt.u.exec_v2_done.stats_buf_size); + if (ret) { + pr_err("fail to copy to user\n"); + kevt->evt.u.exec_v2_done.stats_buf_size = 0; + ret = -EFAULT; + } + break; + default: + break; + } + + return ret; +} + +static int npu_receive_event(struct npu_client *client, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct npu_kevent *kevt; + int ret = 0; + + mutex_lock(&client->list_lock); + if (list_empty(&client->evt_list)) { + pr_err("event list is empty\n"); + ret = -EINVAL; + } else { + kevt = list_first_entry(&client->evt_list, + struct npu_kevent, list); + list_del(&kevt->list); + npu_process_kevent(kevt); + ret = copy_to_user(argp, &kevt->evt, + sizeof(struct msm_npu_event)); + if (ret) { + pr_err("fail to copy to user\n"); + ret = -EFAULT; + } + kfree(kevt); + } + mutex_unlock(&client->list_lock); + + return ret; +} + static long npu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; - struct npu_device *npu_dev = file->private_data; + struct npu_client *client = file->private_data; switch (cmd) { case MSM_NPU_GET_INFO: - ret = npu_get_info(npu_dev, arg); + ret = npu_get_info(client, arg); break; case MSM_NPU_MAP_BUF: - ret = npu_map_buf(npu_dev, arg); + ret = npu_map_buf(client, arg); break; case MSM_NPU_UNMAP_BUF: - ret = npu_unmap_buf(npu_dev, arg); + ret = npu_unmap_buf(client, arg); break; case MSM_NPU_LOAD_NETWORK: - ret = npu_load_network(npu_dev, arg); + ret = npu_load_network(client, arg); break; case MSM_NPU_LOAD_NETWORK_V2: - ret = npu_load_network_v2(npu_dev, arg); + ret = npu_load_network_v2(client, arg); break; case MSM_NPU_UNLOAD_NETWORK: - ret = npu_unload_network(npu_dev, arg); + ret = npu_unload_network(client, arg); break; case MSM_NPU_EXEC_NETWORK: - ret = npu_exec_network(npu_dev, arg); + ret = npu_exec_network(client, arg); break; case MSM_NPU_EXEC_NETWORK_V2: - ret = npu_exec_network_v2(npu_dev, arg); + ret = npu_exec_network_v2(client, arg); + break; + case MSM_NPU_RECEIVE_EVENT: + ret = npu_receive_event(client, arg); break; default: pr_err("unexpected IOCTL %x\n", cmd); @@ -1114,6 +1215,23 @@ static long npu_ioctl(struct file *file, unsigned int cmd, return ret; } +static unsigned int npu_poll(struct file *filp, struct poll_table_struct *p) +{ + struct npu_client *client = filp->private_data; + int rc = 0; + + poll_wait(filp, &client->wait, p); + + mutex_lock(&client->list_lock); + if (!list_empty(&client->evt_list)) { + pr_debug("poll cmd done\n"); + rc = POLLIN | POLLRDNORM; + } + mutex_unlock(&client->list_lock); + + return rc; +} + /* ------------------------------------------------------------------------- * Device Tree Parsing * ------------------------------------------------------------------------- @@ -1514,7 +1632,7 @@ static int npu_probe(struct platform_device *pdev) goto error_driver_init; } - INIT_LIST_HEAD(&(npu_dev->mapped_buffers.list)); + mutex_init(&npu_dev->dev_lock); rc = npu_host_init(npu_dev); if (rc) { diff --git a/drivers/media/platform/msm/npu/npu_hw_access.c b/drivers/media/platform/msm/npu/npu_hw_access.c index a4c24fa5fd119a8da6c2739cefa36b0b3850507f..c233bd964161b06057866b7dc483ba2ef6343557 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.c +++ b/drivers/media/platform/msm/npu/npu_hw_access.c @@ -151,69 +151,94 @@ int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev) * Functions - ION Memory * ------------------------------------------------------------------------- */ -static struct npu_ion_buf *npu_get_npu_ion_buffer(struct npu_device - *npu_dev) +static struct npu_ion_buf *npu_alloc_npu_ion_buffer(struct npu_client + *client, int buf_hdl, uint32_t size) { - struct npu_ion_buf *ret_val = 0; + struct npu_ion_buf *ret_val = NULL, *tmp; + struct list_head *pos = NULL; + + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { + tmp = list_entry(pos, struct npu_ion_buf, list); + if (tmp->fd == buf_hdl) { + ret_val = tmp; + break; + } + } - ret_val = kmalloc(sizeof(struct npu_ion_buf), GFP_KERNEL); - if (ret_val) - list_add(&(ret_val->list), &(npu_dev->mapped_buffers.list)); + if (ret_val) { + /* mapped already, treat as invalid request */ + pr_err("ion buf %x has been mapped\n"); + ret_val = NULL; + } else { + ret_val = kmalloc(sizeof(struct npu_ion_buf), GFP_KERNEL); + if (ret_val) { + ret_val->fd = buf_hdl; + ret_val->size = size; + ret_val->iova = 0; + list_add(&(ret_val->list), + &(client->mapped_buffer_list)); + } + } + mutex_unlock(&client->list_lock); return ret_val; } -static struct npu_ion_buf *npu_get_existing_ion_buffer(struct npu_device - *npu_dev, int buf_hdl) +static struct npu_ion_buf *npu_get_npu_ion_buffer(struct npu_client + *client, int buf_hdl) { - struct list_head *pos = 0; - struct npu_ion_buf *npu_ion_buf = 0; - - list_for_each(pos, &(npu_dev->mapped_buffers.list)) { - npu_ion_buf = list_entry(pos, struct npu_ion_buf, list); - if (npu_ion_buf->fd == buf_hdl) - return npu_ion_buf; + struct list_head *pos = NULL; + struct npu_ion_buf *ret_val = NULL, *tmp; + + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { + tmp = list_entry(pos, struct npu_ion_buf, list); + if (tmp->fd == buf_hdl) { + ret_val = tmp; + break; + } } + mutex_unlock(&client->list_lock); - return NULL; + return ret_val; } -static struct npu_ion_buf *npu_clear_npu_ion_buffer(struct npu_device - *npu_dev, int buf_hdl, uint64_t addr) +static void npu_free_npu_ion_buffer(struct npu_client + *client, int buf_hdl) { - struct list_head *pos = 0; - struct npu_ion_buf *npu_ion_buf = 0; + struct list_head *pos = NULL; + struct npu_ion_buf *npu_ion_buf = NULL; - list_for_each(pos, &(npu_dev->mapped_buffers.list)) { + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { npu_ion_buf = list_entry(pos, struct npu_ion_buf, list); - if (npu_ion_buf->fd == buf_hdl && - npu_ion_buf->iova == addr) { + if (npu_ion_buf->fd == buf_hdl) { list_del(&npu_ion_buf->list); - return npu_ion_buf; + kfree(npu_ion_buf); + break; } } - - return NULL; + mutex_unlock(&client->list_lock); } -int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, +int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size, uint64_t *addr) { int ret = 0; - - struct npu_ion_buf *ion_buf = npu_get_npu_ion_buffer(npu_dev); + struct npu_device *npu_dev = client->npu_dev; + struct npu_ion_buf *ion_buf = NULL; struct npu_smmu_ctx *smmu_ctx = &npu_dev->smmu_ctx; + if (buf_hdl == 0) + return -EINVAL; + + ion_buf = npu_alloc_npu_ion_buffer(client, buf_hdl, size); if (!ion_buf) { - pr_err("%s no more table space\n", __func__); + pr_err("%s fail to alloc npu_ion_buffer\n", __func__); ret = -ENOMEM; return ret; } - ion_buf->fd = buf_hdl; - ion_buf->size = size; - - if (ion_buf->fd == 0) - return -EINVAL; smmu_ctx->attach_cnt++; @@ -250,15 +275,16 @@ int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, ion_buf->size = ion_buf->table->sgl->dma_length; map_end: if (ret) - npu_mem_unmap(npu_dev, buf_hdl, 0); + npu_mem_unmap(client, buf_hdl, 0); *addr = ion_buf->iova; return ret; } -void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl) +void npu_mem_invalidate(struct npu_client *client, int buf_hdl) { - struct npu_ion_buf *ion_buf = npu_get_existing_ion_buffer(npu_dev, + struct npu_device *npu_dev = client->npu_dev; + struct npu_ion_buf *ion_buf = npu_get_npu_ion_buffer(client, buf_hdl); if (!ion_buf) @@ -268,29 +294,50 @@ void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl) ion_buf->table->nents, DMA_BIDIRECTIONAL); } -void npu_mem_unmap(struct npu_device *npu_dev, int buf_hdl, uint64_t addr) +bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr) { struct npu_ion_buf *ion_buf = 0; + struct list_head *pos = NULL; + bool valid = false; + + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { + ion_buf = list_entry(pos, struct npu_ion_buf, list); + if (ion_buf->iova == addr) { + valid = true; + break; + } + } + mutex_unlock(&client->list_lock); - /* clear entry and retrieve the corresponding buffer */ - ion_buf = npu_clear_npu_ion_buffer(npu_dev, buf_hdl, addr); + return valid; +} +void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr) +{ + struct npu_device *npu_dev = client->npu_dev; + struct npu_ion_buf *ion_buf = 0; + + /* clear entry and retrieve the corresponding buffer */ + ion_buf = npu_get_npu_ion_buffer(client, buf_hdl); if (!ion_buf) { pr_err("%s could not find buffer\n", __func__); return; } + + if (ion_buf->iova != addr) + pr_warn("unmap address %lu doesn't match %lu\n", addr, + ion_buf->iova); + if (ion_buf->table) dma_buf_unmap_attachment(ion_buf->attachment, ion_buf->table, DMA_BIDIRECTIONAL); - ion_buf->table = 0; if (ion_buf->dma_buf && ion_buf->attachment) dma_buf_detach(ion_buf->dma_buf, ion_buf->attachment); - ion_buf->attachment = 0; if (ion_buf->dma_buf) dma_buf_put(ion_buf->dma_buf); - ion_buf->dma_buf = 0; npu_dev->smmu_ctx.attach_cnt--; - kfree(ion_buf); + npu_free_npu_ion_buffer(client, buf_hdl); } /* ------------------------------------------------------------------------- diff --git a/drivers/media/platform/msm/npu/npu_hw_access.h b/drivers/media/platform/msm/npu/npu_hw_access.h index 8f3eb332139ad1eae9ab0648338ac9cab5c608b9..96dc48af3e482a27b590e18c8d376f1d8b322667 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.h +++ b/drivers/media/platform/msm/npu/npu_hw_access.h @@ -43,6 +43,7 @@ struct npu_device; struct npu_ion_buf_t; struct npu_host_ctx; +struct npu_client; typedef irqreturn_t (*intr_hdlr_fn)(int32_t irq, void *ptr); typedef void (*wq_hdlr_fn) (struct work_struct *work); @@ -57,10 +58,11 @@ void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src, int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst, uint32_t size); -int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, +int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size, uint64_t *addr); -void npu_mem_unmap(struct npu_device *npu_dev, int buf_hdl, uint64_t addr); -void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl); +void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr); +void npu_mem_invalidate(struct npu_client *client, int buf_hdl); +bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr); void *npu_ipc_addr(void); void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num); diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index c5f84644a199fe9b7b1b79a9f361889b9e2c8dbf..6315156a4b2b29d3d6e98160370974b54863af58 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -42,7 +42,8 @@ static void host_irq_wq(struct work_struct *work); static void turn_off_fw_logging(struct npu_device *npu_dev); static int wait_for_fw_ready(struct npu_device *npu_dev, uint32_t status_bits); -static struct npu_network *alloc_network(struct npu_host_ctx *ctx); +static struct npu_network *alloc_network(struct npu_host_ctx *ctx, + struct npu_client *client); static struct npu_network *get_network_by_hdl(struct npu_host_ctx *ctx, uint32_t hdl); static struct npu_network *get_network_by_id(struct npu_host_ctx *ctx, @@ -54,9 +55,10 @@ static void host_session_msg_hdlr(struct npu_device *npu_dev); static void host_session_log_hdlr(struct npu_device *npu_dev); static int host_error_hdlr(struct npu_device *npu_dev); static int npu_send_network_cmd(struct npu_device *npu_dev, - struct npu_network *network, void *cmd_ptr); + struct npu_network *network, void *cmd_ptr, bool async); static int npu_send_misc_cmd(struct npu_device *npu_dev, uint32_t q_idx, void *cmd_ptr); +static int npu_queue_event(struct npu_client *client, struct npu_kevent *evt); /* ------------------------------------------------------------------------- * Function Definitions - Init / Deinit @@ -298,6 +300,7 @@ static int host_error_hdlr(struct npu_device *npu_dev) struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; struct npu_network *network = NULL; bool fw_alive = true; + struct npu_kevent kevt; int i; if ((host_ctx->wdg_irq_sts == 0) && (host_ctx->err_irq_sts == 0)) @@ -317,8 +320,17 @@ static int host_error_hdlr(struct npu_device *npu_dev) network = &host_ctx->networks[i]; if (network->is_valid && network->cmd_pending && network->fw_error) { - pr_debug("complete network %x\n", network->id); - complete(&network->cmd_done); + if (network->cmd_async) { + pr_debug("async cmd, queue ssr event\n"); + kevt.evt.type = MSM_NPU_EVENT_TYPE_SSR; + kevt.evt.u.ssr.network_hdl = + network->network_hdl; + if (npu_queue_event(network->client, &kevt)) + pr_err("queue npu event failed\n"); + } else { + pr_debug("complete network %x\n", network->id); + complete(&network->cmd_done); + } } } complete_all(&host_ctx->loopback_done); @@ -391,7 +403,8 @@ static int wait_for_fw_ready(struct npu_device *npu_dev, uint32_t status_bits) * Function Definitions - Network Management * ------------------------------------------------------------------------- */ -static struct npu_network *alloc_network(struct npu_host_ctx *ctx) +static struct npu_network *alloc_network(struct npu_host_ctx *ctx, + struct npu_client *client) { int32_t i; struct npu_network *network = ctx->networks; @@ -416,6 +429,13 @@ static struct npu_network *alloc_network(struct npu_host_ctx *ctx) network->is_valid = true; network->fw_error = false; network->cmd_pending = false; + network->client = client; + network->stats_buf = kzalloc(MSM_NPU_MAX_STATS_BUF_SIZE, + GFP_KERNEL); + if (!network->stats_buf) { + free_network(ctx, network->id); + network = NULL; + } } return network; @@ -458,6 +478,7 @@ static void free_network(struct npu_host_ctx *ctx, int64_t id) struct npu_network *network = get_network_by_id(ctx, id); if (network) { + kfree(network->stats_buf); mutex_lock(&ctx->lock); memset(network, 0, sizeof(struct npu_network)); ctx->network_num--; @@ -469,10 +490,28 @@ static void free_network(struct npu_host_ctx *ctx, int64_t id) * Function Definitions - IPC * ------------------------------------------------------------------------- */ +static int npu_queue_event(struct npu_client *client, struct npu_kevent *evt) +{ + struct npu_kevent *kevt = kmalloc(sizeof(*kevt), GFP_KERNEL); + + if (!kevt) + return -ENOMEM; + + *kevt = *evt; + INIT_LIST_HEAD(&kevt->list); + mutex_lock(&client->list_lock); + list_add_tail(&kevt->list, &client->evt_list); + mutex_unlock(&client->list_lock); + wake_up_interruptible(&client->wait); + + return 0; +} + static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) { uint32_t msg_id; struct npu_network *network = NULL; + struct npu_kevent kevt; msg_id = msg[1]; switch (msg_id) { @@ -501,7 +540,20 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } network->cmd_pending = false; - complete(&network->cmd_done); + + if (!network->cmd_async) { + complete(&network->cmd_done); + } else { + pr_debug("async cmd, queue event\n"); + kevt.evt.type = MSM_NPU_EVENT_TYPE_EXEC_DONE; + kevt.evt.u.exec_done.network_hdl = + exe_rsp_pkt->network_hdl; + kevt.evt.u.exec_done.exec_result = + exe_rsp_pkt->header.status; + if (npu_queue_event(network->client, &kevt)) + pr_err("queue npu event failed\n"); + } + break; } case NPU_IPC_MSG_EXECUTE_V2_DONE: @@ -522,18 +574,33 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } + pr_debug("network id : %d", network->id); stats_size = exe_rsp_pkt->header.size - sizeof(*exe_rsp_pkt); pr_debug("stats_size %d:%d\n", exe_rsp_pkt->header.size, stats_size); stats_size = stats_size < network->stats_buf_size ? stats_size : network->stats_buf_size; - network->stats_buf_size = stats_size; if (stats_size) memcpy(network->stats_buf, exe_rsp_pkt->stats_data, stats_size); + network->stats_buf_size = stats_size; network->cmd_pending = false; - complete(&network->cmd_done); + if (network->cmd_async) { + pr_debug("async cmd, queue event\n"); + kevt.evt.type = MSM_NPU_EVENT_TYPE_EXEC_V2_DONE; + kevt.evt.u.exec_v2_done.network_hdl = + exe_rsp_pkt->network_hdl; + kevt.evt.u.exec_v2_done.exec_result = + exe_rsp_pkt->header.status; + kevt.evt.u.exec_v2_done.stats_buf_size = stats_size; + kevt.reserved[0] = (uint64_t)network->stats_buf; + kevt.reserved[1] = (uint64_t)network->stats_buf_u; + if (npu_queue_event(network->client, &kevt)) + pr_err("queue npu event failed\n"); + } else { + complete(&network->cmd_done); + } break; } case NPU_IPC_MSG_LOAD_DONE: @@ -662,24 +729,23 @@ int32_t npu_host_get_info(struct npu_device *npu_dev, return 0; } -int32_t npu_host_map_buf(struct npu_device *npu_dev, +int32_t npu_host_map_buf(struct npu_client *client, struct msm_npu_map_buf_ioctl *map_ioctl) { - npu_mem_map(npu_dev, map_ioctl->buf_ion_hdl, map_ioctl->size, + return npu_mem_map(client, map_ioctl->buf_ion_hdl, map_ioctl->size, &map_ioctl->npu_phys_addr); - return 0; } -int32_t npu_host_unmap_buf(struct npu_device *npu_dev, +int32_t npu_host_unmap_buf(struct npu_client *client, struct msm_npu_unmap_buf_ioctl *unmap_ioctl) { - npu_mem_unmap(npu_dev, unmap_ioctl->buf_ion_hdl, + npu_mem_unmap(client, unmap_ioctl->buf_ion_hdl, unmap_ioctl->npu_phys_addr); return 0; } static int npu_send_network_cmd(struct npu_device *npu_dev, - struct npu_network *network, void *cmd_ptr) + struct npu_network *network, void *cmd_ptr, bool async) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret = 0; @@ -689,9 +755,14 @@ static int npu_send_network_cmd(struct npu_device *npu_dev, (host_ctx->fw_state == FW_DISABLED)) { pr_err("fw is in error state or disabled, can't send network cmd\n"); ret = -EIO; + } else if (network->cmd_pending) { + pr_err("Another cmd is pending\n"); + ret = -EBUSY; } else { - pr_debug("Send cmd %d\n", - ((struct ipc_cmd_header_pkt *)cmd_ptr)->cmd_type); + pr_debug("Send cmd %d network id %d\n", + ((struct ipc_cmd_header_pkt *)cmd_ptr)->cmd_type, + network->id); + network->cmd_async = async; ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_APPS_EXEC, cmd_ptr); if (!ret) @@ -783,10 +854,11 @@ static uint32_t find_networks_perf_mode(struct npu_host_ctx *host_ctx) return max_perf_mode; } -int32_t npu_host_load_network(struct npu_device *npu_dev, +int32_t npu_host_load_network(struct npu_client *client, struct msm_npu_load_network_ioctl *load_ioctl) { int ret = 0; + struct npu_device *npu_dev = client->npu_dev; struct npu_network *network; struct ipc_cmd_load_pkt load_packet; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; @@ -796,7 +868,7 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, if (ret) return ret; - network = alloc_network(host_ctx); + network = alloc_network(host_ctx, client); if (!network) { ret = -ENOMEM; goto err_deinit_fw; @@ -809,6 +881,12 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, network->priority = load_ioctl->priority; network->perf_mode = load_ioctl->perf_mode; + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, network->phy_add)) { + ret = -EINVAL; + goto error_free_network; + } + networks_perf_mode = find_networks_perf_mode(host_ctx); ret = npu_set_uc_power_level(npu_dev, networks_perf_mode); @@ -830,7 +908,7 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, /* NPU_IPC_CMD_LOAD will go onto IPC_QUEUE_APPS_EXEC */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, &load_packet); + ret = npu_send_network_cmd(npu_dev, network, &load_packet, false); if (ret) { pr_err("NPU_IPC_CMD_LOAD sent failed: %d\n", ret); goto error_free_network; @@ -860,11 +938,12 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, return ret; } -int32_t npu_host_load_network_v2(struct npu_device *npu_dev, +int32_t npu_host_load_network_v2(struct npu_client *client, struct msm_npu_load_network_ioctl_v2 *load_ioctl, struct msm_npu_patch_info_v2 *patch_info) { int ret = 0, i; + struct npu_device *npu_dev = client->npu_dev; struct npu_network *network; struct ipc_cmd_load_pkt_v2 *load_packet = NULL; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; @@ -875,7 +954,7 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, if (ret) return ret; - network = alloc_network(host_ctx); + network = alloc_network(host_ctx, client); if (!network) { ret = -ENOMEM; goto err_deinit_fw; @@ -903,6 +982,12 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, network->perf_mode = load_ioctl->perf_mode; network->num_layers = load_ioctl->num_layers; + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, network->phy_add)) { + ret = -EINVAL; + goto error_free_network; + } + networks_perf_mode = find_networks_perf_mode(host_ctx); ret = npu_set_uc_power_level(npu_dev, networks_perf_mode); @@ -926,7 +1011,7 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, /* NPU_IPC_CMD_LOAD_V2 will go onto IPC_QUEUE_APPS_EXEC */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, load_packet); + ret = npu_send_network_cmd(npu_dev, network, load_packet, false); if (ret) { pr_debug("NPU_IPC_CMD_LOAD_V2 sent failed: %d\n", ret); goto error_free_network; @@ -957,10 +1042,11 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, return ret; } -int32_t npu_host_unload_network(struct npu_device *npu_dev, +int32_t npu_host_unload_network(struct npu_client *client, struct msm_npu_unload_network_ioctl *unload) { int ret = 0; + struct npu_device *npu_dev = client->npu_dev; struct ipc_cmd_unload_pkt unload_packet; struct npu_network *network; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; @@ -985,7 +1071,7 @@ int32_t npu_host_unload_network(struct npu_device *npu_dev, /* NPU_IPC_CMD_UNLOAD will go onto IPC_QUEUE_APPS_EXEC */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, &unload_packet); + ret = npu_send_network_cmd(npu_dev, network, &unload_packet, false); if (ret) { pr_err("NPU_IPC_CMD_UNLOAD sent failed: %d\n", ret); @@ -1010,17 +1096,17 @@ int32_t npu_host_unload_network(struct npu_device *npu_dev, return ret; } -int32_t npu_host_exec_network(struct npu_device *npu_dev, +int32_t npu_host_exec_network(struct npu_client *client, struct msm_npu_exec_network_ioctl *exec_ioctl) { + struct npu_device *npu_dev = client->npu_dev; struct ipc_cmd_execute_pkt exec_packet; /* npu mapped addr */ - uint64_t input_addr = 0, output_addr = 0; uint64_t input_off, output_off; int32_t ret; struct npu_network *network; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; - int i = 0; + bool async_ioctl = !!exec_ioctl->async; network = get_network_by_hdl(host_ctx, exec_ioctl->network_hdl); @@ -1032,14 +1118,22 @@ int32_t npu_host_exec_network(struct npu_device *npu_dev, memset(&exec_packet, 0, sizeof(exec_packet)); if (exec_ioctl->patching_required) { - if (exec_ioctl->input_layer_num == 1) - input_addr = exec_ioctl->input_layers[0].buf_phys_addr; - if (exec_ioctl->output_layer_num == 1) - output_addr = - exec_ioctl->output_layers[0].buf_phys_addr; + if ((exec_ioctl->input_layer_num != 1) || + (exec_ioctl->output_layer_num != 1)) { + pr_err("Invalid input/output layer num\n"); + return -EINVAL; + } + + input_off = exec_ioctl->input_layers[0].buf_phys_addr; + output_off = exec_ioctl->output_layers[0].buf_phys_addr; + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, input_off) || + !npu_mem_verify_addr(client, output_off)) { + pr_err("Invalid patch buf address\n"); + return -EINVAL; + } + exec_packet.patch_params.num_params = 2; - input_off = (uint64_t)input_addr; - output_off = (uint64_t)output_addr; host_copy_patch_data(&exec_packet.patch_params.param[0], (uint32_t)input_off, &exec_ioctl->input_layers[0]); host_copy_patch_data(&exec_packet.patch_params.param[1], @@ -1057,10 +1151,12 @@ int32_t npu_host_exec_network(struct npu_device *npu_dev, /* Send it on the high priority queue */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, &exec_packet); + ret = npu_send_network_cmd(npu_dev, network, &exec_packet, async_ioctl); if (ret) { pr_err("NPU_IPC_CMD_EXECUTE sent failed: %d\n", ret); + } else if (async_ioctl) { + pr_debug("Async ioctl, return now\n"); } else if (!wait_for_completion_interruptible_timeout( &network->cmd_done, (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? @@ -1072,28 +1168,22 @@ int32_t npu_host_exec_network(struct npu_device *npu_dev, } else if (network->fw_error) { ret = -EIO; pr_err("execute cmd returns with error\n"); - } else { - /* Invalidate output buffers */ - for (i = 0; i < exec_ioctl->output_layer_num; i++) { - if (exec_ioctl->output_layer_num == 1) { - npu_mem_invalidate(npu_dev, - exec_ioctl->output_layers[i].buf_hdl); - } - } } return ret; } -int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, +int32_t npu_host_exec_network_v2(struct npu_client *client, struct msm_npu_exec_network_ioctl_v2 *exec_ioctl, struct msm_npu_patch_buf_info *patch_buf_info) { + struct npu_device *npu_dev = client->npu_dev; struct ipc_cmd_execute_pkt_v2 *exec_packet; int32_t ret; struct npu_network *network; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; uint32_t num_patch_params, pkt_size; + bool async_ioctl = !!exec_ioctl->async; int i; network = get_network_by_hdl(host_ctx, exec_ioctl->network_hdl); @@ -1120,6 +1210,14 @@ int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, patch_buf_info[i].buf_phys_addr; pr_debug("%d: patch value: %x\n", i, exec_packet->patch_params[i].value); + + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, + patch_buf_info[i].buf_phys_addr)) { + pr_err("Invalid patch value\n"); + kfree(exec_packet); + return -EINVAL; + } } exec_packet->header.cmd_type = NPU_IPC_CMD_EXECUTE_V2; @@ -1131,22 +1229,20 @@ int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, exec_packet->network_hdl = network->network_hdl; exec_packet->num_patch_params = num_patch_params; - /* allocate stats_buf to be filled after execution */ - network->stats_buf = kzalloc(exec_ioctl->stats_buf_size, GFP_KERNEL); - if (!network->stats_buf) - network->stats_buf_size = 0; - else - network->stats_buf_size = exec_ioctl->stats_buf_size; + network->stats_buf_u = (void __user *)exec_ioctl->stats_buf_addr; + network->stats_buf_size = exec_ioctl->stats_buf_size; pr_debug("Execute_v2 flags %x stats_buf_size %d\n", exec_packet->header.flags, exec_ioctl->stats_buf_size); /* Send it on the high priority queue */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, exec_packet); + ret = npu_send_network_cmd(npu_dev, network, exec_packet, async_ioctl); if (ret) { pr_err("NPU_IPC_CMD_EXECUTE_V2 sent failed: %d\n", ret); + } else if (async_ioctl) { + pr_debug("Async ioctl, return now\n"); } else if (!wait_for_completion_interruptible_timeout( &network->cmd_done, (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? @@ -1160,15 +1256,13 @@ int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, pr_err("execute cmd returns with error\n"); } else { exec_ioctl->stats_buf_size = network->stats_buf_size; - if (exec_ioctl->stats_buf_size) { - if (copy_to_user( - (void __user *)exec_ioctl->stats_buf_addr, - network->stats_buf, exec_ioctl->stats_buf_size)) - pr_err("copy stats to user failed\n"); + if (copy_to_user((void __user *)exec_ioctl->stats_buf_addr, + network->stats_buf, exec_ioctl->stats_buf_size)) { + pr_err("copy stats to user failed\n"); + exec_ioctl->stats_buf_size = 0; } } - kfree(network->stats_buf); kfree(exec_packet); return ret; } diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h index 5d04dca131cdb64d43813f39013069e8e53522bd..0a49893d69dcb5922c3bdd6b7d65236464923fca 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.h +++ b/drivers/media/platform/msm/npu/npu_mgr.h @@ -19,6 +19,7 @@ */ #include #include "npu_hw_access.h" +#include "npu_common.h" /* ------------------------------------------------------------------------- * Defines @@ -50,11 +51,14 @@ struct npu_network { uint32_t perf_mode; uint32_t num_layers; void *stats_buf; + void __user *stats_buf_u; uint32_t stats_buf_size; bool is_valid; bool fw_error; bool cmd_pending; + bool cmd_async; struct completion cmd_done; + struct npu_client *client; }; enum fw_state { @@ -103,20 +107,20 @@ int npu_host_ipc_read_msg(struct npu_device *npu_dev, uint32_t queueIndex, int32_t npu_host_get_info(struct npu_device *npu_dev, struct msm_npu_get_info_ioctl *get_info_ioctl); -int32_t npu_host_map_buf(struct npu_device *npu_dev, +int32_t npu_host_map_buf(struct npu_client *client, struct msm_npu_map_buf_ioctl *map_ioctl); -int32_t npu_host_unmap_buf(struct npu_device *npu_dev, +int32_t npu_host_unmap_buf(struct npu_client *client, struct msm_npu_unmap_buf_ioctl *unmap_ioctl); -int32_t npu_host_load_network(struct npu_device *npu_dev, +int32_t npu_host_load_network(struct npu_client *client, struct msm_npu_load_network_ioctl *load_ioctl); -int32_t npu_host_load_network_v2(struct npu_device *npu_dev, +int32_t npu_host_load_network_v2(struct npu_client *client, struct msm_npu_load_network_ioctl_v2 *load_ioctl, struct msm_npu_patch_info_v2 *patch_info); -int32_t npu_host_unload_network(struct npu_device *npu_dev, +int32_t npu_host_unload_network(struct npu_client *client, struct msm_npu_unload_network_ioctl *unload); -int32_t npu_host_exec_network(struct npu_device *npu_dev, +int32_t npu_host_exec_network(struct npu_client *client, struct msm_npu_exec_network_ioctl *exec_ioctl); -int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, +int32_t npu_host_exec_network_v2(struct npu_client *client, struct msm_npu_exec_network_ioctl_v2 *exec_ioctl, struct msm_npu_patch_buf_info *patch_buf_info); int32_t npu_host_loopback_test(struct npu_device *npu_dev); diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c index 94a79ad672d3952b2cce48fc1b66773fc4518eeb..0f2dd3af7949a360adb7f13140eea2c8da363748 100644 --- a/drivers/media/platform/msm/vidc/msm_smem.c +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -522,12 +522,22 @@ int msm_smem_cache_operations(struct dma_buf *dbuf, enum smem_cache_ops cache_op, unsigned long offset, unsigned long size) { int rc = 0; + unsigned long flags = 0; if (!dbuf) { dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); return -EINVAL; } + /* Return if buffer doesn't support caching */ + rc = dma_buf_get_flags(dbuf, &flags); + if (rc) { + dprintk(VIDC_ERR, "%s: dma_buf_get_flags failed, err %d\n", rc); + return rc; + } else if (!(flags & ION_FLAG_CACHED)) { + return rc; + } + switch (cache_op) { case SMEM_CACHE_CLEAN: case SMEM_CACHE_CLEAN_INVALIDATE: diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 376f204815cc27393b3b0b18b751ef9b66c47fe6..e25689f79f360418f3d9d52dcee525de83d22e5c 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -496,7 +496,34 @@ static const struct of_device_id msm_vidc_dt_match[] = { {.compatible = "qcom,msm-vidc,mem-cdsp"}, {} }; +static int msm_vidc_register_video_device(enum session_type sess_type, + int nr, struct msm_vidc_core *core, struct device *dev) +{ + int rc = 0; + core->vdev[sess_type].vdev.release = + msm_vidc_release_video_device; + core->vdev[sess_type].vdev.fops = &msm_v4l2_vidc_fops; + core->vdev[sess_type].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; + core->vdev[sess_type].vdev.vfl_dir = VFL_DIR_M2M; + core->vdev[sess_type].type = sess_type; + core->vdev[sess_type].vdev.v4l2_dev = &core->v4l2_dev; + rc = video_register_device(&core->vdev[sess_type].vdev, + VFL_TYPE_GRABBER, nr); + if (rc) { + dprintk(VIDC_ERR, "Failed to register the video device\n"); + return rc; + } + video_set_drvdata(&core->vdev[sess_type].vdev, core); + dev = &core->vdev[sess_type].vdev.dev; + rc = device_create_file(dev, &dev_attr_link_name); + if (rc) { + dprintk(VIDC_ERR, "Failed to create video device file\n"); + video_unregister_device(&core->vdev[sess_type].vdev); + return rc; + } + return 0; +} static int msm_vidc_probe_vidc_device(struct platform_device *pdev) { int rc = 0; @@ -536,75 +563,29 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) } /* setup the decoder device */ - core->vdev[MSM_VIDC_DECODER].vdev.release = - msm_vidc_release_video_device; - core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops; - core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; - core->vdev[MSM_VIDC_DECODER].vdev.vfl_dir = VFL_DIR_M2M; - core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER; - core->vdev[MSM_VIDC_DECODER].vdev.v4l2_dev = &core->v4l2_dev; - rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev, - VFL_TYPE_GRABBER, nr); + rc = msm_vidc_register_video_device(MSM_VIDC_DECODER, + nr, core, dev); if (rc) { - dprintk(VIDC_ERR, "Failed to register video decoder device"); - goto err_dec_register; - } - - video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core); - dev = &core->vdev[MSM_VIDC_DECODER].vdev.dev; - rc = device_create_file(dev, &dev_attr_link_name); - if (rc) { - dprintk(VIDC_ERR, - "Failed to create link name sysfs for decoder"); - goto err_dec_attr_link_name; + dprintk(VIDC_ERR, "Failed to register video decoder\n"); + goto err_dec; } /* setup the encoder device */ - core->vdev[MSM_VIDC_ENCODER].vdev.release = - msm_vidc_release_video_device; - core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops; - core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; - core->vdev[MSM_VIDC_ENCODER].vdev.vfl_dir = VFL_DIR_M2M; - core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER; - core->vdev[MSM_VIDC_ENCODER].vdev.v4l2_dev = &core->v4l2_dev; - rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev, - VFL_TYPE_GRABBER, nr + 1); + rc = msm_vidc_register_video_device(MSM_VIDC_ENCODER, + nr + 1, core, dev); if (rc) { - dprintk(VIDC_ERR, "Failed to register video encoder device"); - goto err_enc_register; - } - - video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core); - dev = &core->vdev[MSM_VIDC_ENCODER].vdev.dev; - rc = device_create_file(dev, &dev_attr_link_name); - if (rc) { - dprintk(VIDC_ERR, - "Failed to create link name sysfs for encoder"); - goto err_enc_attr_link_name; + dprintk(VIDC_ERR, "Failed to register video encoder\n"); + goto err_enc; } /* setup the cvp device */ - core->vdev[MSM_VIDC_CVP].vdev.release = - msm_vidc_release_video_device; - core->vdev[MSM_VIDC_CVP].vdev.fops = &msm_v4l2_vidc_fops; - core->vdev[MSM_VIDC_CVP].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; - core->vdev[MSM_VIDC_CVP].vdev.vfl_dir = VFL_DIR_M2M; - core->vdev[MSM_VIDC_CVP].type = MSM_VIDC_CVP; - core->vdev[MSM_VIDC_CVP].vdev.v4l2_dev = &core->v4l2_dev; - rc = video_register_device(&core->vdev[MSM_VIDC_CVP].vdev, - VFL_TYPE_GRABBER, nr + 2); - if (rc) { - dprintk(VIDC_ERR, "Failed to register video cvp device"); - goto err_cvp_register; - } - - video_set_drvdata(&core->vdev[MSM_VIDC_CVP].vdev, core); - dev = &core->vdev[MSM_VIDC_CVP].vdev.dev; - rc = device_create_file(dev, &dev_attr_link_name); - if (rc) { - dprintk(VIDC_ERR, - "Failed to create link name sysfs for cvp"); - goto err_cvp_attr_link_name; + if (core->resources.domain_cvp) { + rc = msm_vidc_register_video_device(MSM_VIDC_CVP, + nr + 2, core, dev); + if (rc) { + dprintk(VIDC_ERR, "Failed to register video CVP\n"); + goto err_cvp; + } } /* finish setting up the 'core' */ @@ -661,21 +642,20 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) err_fail_sub_device_probe: vidc_hfi_deinitialize(core->hfi_type, core->device); err_cores_exceeded: - device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, + if (core->resources.domain_cvp) { + device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, &dev_attr_link_name); -err_cvp_attr_link_name: - video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); -err_cvp_register: + video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + } +err_cvp: device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev, &dev_attr_link_name); -err_enc_attr_link_name: video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev); -err_enc_register: +err_enc: device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev, &dev_attr_link_name); -err_dec_attr_link_name: video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev); -err_dec_register: +err_dec: v4l2_device_unregister(&core->v4l2_dev); err_v4l2_register: sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); @@ -745,9 +725,11 @@ static int msm_vidc_remove(struct platform_device *pdev) venus_boot_deinit(); vidc_hfi_deinitialize(core->hfi_type, core->device); - device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, + if (core->resources.domain_cvp) { + device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, &dev_attr_link_name); - video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + } device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev, &dev_attr_link_name); video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 965ef037f284be252a98cc9a9d1c1a9bd2ae6456..b480f05e3d093454f544d170c517268f6e3b9f6b 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -81,6 +81,8 @@ static const char *const vp9_level[] = { "4.1", "5.0", "5.1", + "6.0", + "6.1", }; static const char *const mpeg2_profile[] = { @@ -248,8 +250,8 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .name = "VP9 Level", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED, - .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51, - .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61, .menu_skip_mask = 0, .qmenu = vp9_level, .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, @@ -1192,7 +1194,7 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; rc = msm_comm_set_buffer_count(inst, - bufreq_out2->buffer_count_min_host, + bufreq_out2->buffer_count_min, bufreq_out2->buffer_count_actual, HAL_BUFFER_OUTPUT2); if (rc) { diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 13a862691b907304357589c126ca21ed5661575e..6107712ed4348df0fe4a6f2edb6bdbda93755de4 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1296,7 +1296,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) enum hal_h264_entropy h264_entropy; struct hal_intra_period intra_period; struct hal_idr_period idr_period; - struct hal_vpe_rotation vpe_rotation; struct hal_intra_refresh intra_refresh; struct hal_multi_slice_control multi_slice_control; struct hal_h264_db_control h264_db_control; @@ -1435,14 +1434,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY: { - struct v4l2_ctrl *rc_mode = TRY_GET_CTRL( - V4L2_CID_MPEG_VIDEO_BITRATE_MODE); - if (rc_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) { - dprintk(VIDC_ERR, - "Frame quality supported only for CQ\n"); - rc = -ENOTSUPP; - break; - } if (ctrl->val < MIN_FRAME_QUALITY || ctrl->val > MAX_FRAME_QUALITY) { dprintk(VIDC_ERR, @@ -1459,15 +1450,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_IMG_GRID_ENABLE: { - struct v4l2_ctrl *rc_mode = TRY_GET_CTRL( - V4L2_CID_MPEG_VIDEO_BITRATE_MODE); - if (rc_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ && - ctrl->val) { - dprintk(VIDC_ERR, - "Grid enable supported only for CQ\n"); - rc = -ENOTSUPP; - break; - } property_id = HAL_CONFIG_HEIC_GRID_ENABLE; grid_enable.grid_enable = ctrl->val; inst->grid_enable = ctrl->val; @@ -1594,31 +1576,17 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; case V4L2_CID_ROTATE: { - temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FLIP); - property_id = HAL_PARAM_VPE_ROTATION; - if (ctrl->val != 0 && ctrl->val != 90 && ctrl->val != 180 && ctrl->val != 270) { dprintk(VIDC_ERR, "Invalid rotation angle"); rc = -ENOTSUPP; } - - vpe_rotation.rotate = ctrl->val; - vpe_rotation.flip = msm_comm_v4l2_to_hal( - V4L2_CID_MPEG_VIDC_VIDEO_FLIP, - temp_ctrl->val); - pdata = &vpe_rotation; + dprintk(VIDC_DBG, "Rotation %d\n", ctrl->val); break; } case V4L2_CID_MPEG_VIDC_VIDEO_FLIP: { - temp_ctrl = TRY_GET_CTRL(V4L2_CID_ROTATE); - property_id = HAL_PARAM_VPE_ROTATION; - vpe_rotation.rotate = temp_ctrl->val; - vpe_rotation.flip = msm_comm_v4l2_to_hal( - V4L2_CID_MPEG_VIDC_VIDEO_FLIP, - ctrl->val); - pdata = &vpe_rotation; + dprintk(VIDC_DBG, "Flip %d\n", ctrl->val); break; } case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: { diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index b00d7ee75f33d5a808527c41fd643852ac9959f3..23fc44e16c25d9ec68d55198cd6c87010eff34be 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -777,7 +777,7 @@ static int msm_vidc_queue_setup(struct vb2_queue *q, bufreq->buffer_count_actual = *num_buffers; rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, HAL_BUFFER_INPUT); } break; @@ -811,7 +811,7 @@ static int msm_vidc_queue_setup(struct vb2_queue *q, bufreq->buffer_count_actual = *num_buffers; rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, buffer_type); } break; @@ -918,11 +918,19 @@ int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) (void *)&rc_mode); } + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + fps = inst->prop.fps; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); if ((rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) && (codec != V4L2_PIX_FMT_VP8)) { - hrd_buf_size.vbv_hdr_buf_size = 1000; - dprintk(VIDC_DBG, "Enable cbr+ hdr_buf_size %d :\n", + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps < CBR_MB_LIMIT) + hrd_buf_size.vbv_hdr_buf_size = 500; + else + hrd_buf_size.vbv_hdr_buf_size = 1000; + dprintk(VIDC_DBG, "Enable hdr_buf_size %d :\n", hrd_buf_size.vbv_hdr_buf_size); rc = call_hfi_op(hdev, session_set_property, (void *)inst->session, HAL_CONFIG_VENC_VBV_HRD_BUF_SIZE, @@ -942,13 +950,8 @@ int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) if ((codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC) && slice_mode != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) { - - output_height = inst->prop.height[CAPTURE_PORT]; - output_width = inst->prop.width[CAPTURE_PORT]; - fps = inst->prop.fps; bitrate = inst->clk_data.bitrate; mb_per_frame = NUM_MBS_PER_FRAME(output_height, output_width); - mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); if (rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_RC_OFF && rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR && @@ -994,6 +997,57 @@ int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) return rc; } +static int msm_vidc_set_rotation(struct msm_vidc_inst *inst) +{ + int rc = 0; + int value = 0; + struct hfi_device *hdev; + struct hal_vpe_rotation vpe_rotation; + struct hal_frame_size frame_sz; + + hdev = inst->core->device; + + /* Set rotation and flip first */ + value = msm_comm_g_ctrl_for_id(inst, V4L2_CID_ROTATE); + if (value < 0) { + dprintk(VIDC_ERR, "Get control for rotation failed\n"); + return value; + } + vpe_rotation.rotate = value; + value = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDC_VIDEO_FLIP); + if (value < 0) { + dprintk(VIDC_ERR, "Get control for flip failed\n"); + return value; + } + vpe_rotation.flip = value; + dprintk(VIDC_DBG, "Set rotation = %d, flip = %d for capture port.\n", + vpe_rotation.rotate, vpe_rotation.flip); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_PARAM_VPE_ROTATION, &vpe_rotation); + if (rc) { + dprintk(VIDC_ERR, "Set rotation/flip at start stream failed\n"); + return rc; + } + + /* flip the output resolution if required */ + if (vpe_rotation.rotate == 90 || vpe_rotation.rotate == 270) { + frame_sz.buffer_type = HAL_BUFFER_OUTPUT; + frame_sz.width = inst->prop.height[CAPTURE_PORT]; + frame_sz.height = inst->prop.width[CAPTURE_PORT]; + dprintk(VIDC_DBG, "CAPTURE port width = %d, height = %d\n", + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set framesize for CAPTURE port\n"); + return rc; + } + } + return rc; +} + static inline int start_streaming(struct msm_vidc_inst *inst) { int rc = 0; @@ -1005,6 +1059,15 @@ static inline int start_streaming(struct msm_vidc_inst *inst) hash32_ptr(inst->session), inst); hdev = inst->core->device; + if (inst->session_type == MSM_VIDC_ENCODER) { + rc = msm_vidc_set_rotation(inst); + if (rc) { + dprintk(VIDC_ERR, + "Set rotation for encoder failed %pK\n"); + goto fail_start; + } + } + rc_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDEO_BITRATE_MODE); /* HEIC HW/FWK tiling encode is supported only for CQ RC mode */ diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 912ed07de814f936a6b5ba23fcc356985784f9a5..a5dec9c9ef200806fe3dd1e60136b3237562ba4d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -241,8 +241,7 @@ int msm_comm_vote_bus(struct msm_vidc_core *core) list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) { if (temp->vvb.vb2_buf.type == - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - temp->flags & MSM_VIDC_FLAG_DEFERRED) { + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { filled_len = max(filled_len, temp->vvb.vb2_buf.planes[0].bytesused); device_addr = temp->smem[0].device_addr; @@ -257,7 +256,8 @@ int msm_comm_vote_bus(struct msm_vidc_core *core) if ((!filled_len || !device_addr) && (inst->session_type != MSM_VIDC_CVP)) { - dprintk(VIDC_DBG, "%s No ETBs\n", __func__); + dprintk(VIDC_DBG, "%s: no input for session %x\n", + __func__, hash32_ptr(inst->session)); continue; } @@ -920,8 +920,7 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst) mutex_lock(&inst->registeredbufs.lock); list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) { if (temp->vvb.vb2_buf.type == - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - temp->flags & MSM_VIDC_FLAG_DEFERRED) { + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { filled_len = max(filled_len, temp->vvb.vb2_buf.planes[0].bytesused); if (inst->session_type == MSM_VIDC_ENCODER && @@ -935,7 +934,8 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst) mutex_unlock(&inst->registeredbufs.lock); if (!filled_len || !device_addr) { - dprintk(VIDC_DBG, "%s No ETBs\n", __func__); + dprintk(VIDC_DBG, "%s no input for session %x\n", + __func__, hash32_ptr(inst->session)); goto no_clock_change; } @@ -1189,6 +1189,7 @@ int msm_vidc_decide_work_route(struct msm_vidc_inst *inst) } else if (inst->session_type == MSM_VIDC_ENCODER) { u32 slice_mode = 0; u32 rc_mode = 0; + u32 output_width, output_height, fps, mbps; switch (inst->fmts[CAPTURE_PORT].fourcc) { case V4L2_PIX_FMT_VP8: @@ -1206,9 +1207,16 @@ int msm_vidc_decide_work_route(struct msm_vidc_inst *inst) } slice_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + fps = inst->prop.fps; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); if (slice_mode == - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES || + (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps < CBR_MB_LIMIT)) { pdata.video_work_route = 1; + dprintk(VIDC_DBG, "Configured work route = 1"); } } else { return -EINVAL; @@ -1311,6 +1319,7 @@ int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst) if (inst->clk_data.low_latency_mode) { pdata.video_work_mode = VIDC_WORK_MODE_1; + dprintk(VIDC_DBG, "Configured work mode = 1"); goto decision_done; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index cbfeea486d654985a31aa90f55eeac7f2a042a83..b7e027251625dccf2e95a312f68d7e23f28b95fd 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -300,6 +300,10 @@ int msm_comm_hal_to_v4l2(int id, int value) return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5; case HAL_VP9_LEVEL_51: return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51; + case HAL_VP9_LEVEL_6: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6; + case HAL_VP9_LEVEL_61: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61; case HAL_VP9_LEVEL_UNUSED: return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED; default: @@ -2322,9 +2326,13 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( return NULL; } - q = &inst->bufq[port].vb2_bufq; mutex_lock(&inst->bufq[port].lock); found = false; + q = &inst->bufq[port].vb2_bufq; + if (!q->streaming) { + dprintk(VIDC_ERR, "port %d is not streaming", port); + goto unlock; + } list_for_each_entry(vb, &q->queued_list, queued_entry) { if (vb->state != VB2_BUF_STATE_ACTIVE) continue; @@ -2333,6 +2341,7 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( break; } } +unlock: mutex_unlock(&inst->bufq[port].lock); if (!found) { print_vidc_buffer(VIDC_ERR, "vb2 not found for", inst, mbuf); @@ -2343,28 +2352,52 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( } int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, - struct vb2_buffer *vb) + struct msm_vidc_buffer *mbuf) { - u32 port; + struct vb2_buffer *vb2; + struct vb2_v4l2_buffer *vbuf; + u32 i, port; - if (!inst || !vb) { + if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", - __func__, inst, vb); + __func__, inst, mbuf); return -EINVAL; } - if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) port = CAPTURE_PORT; - } else if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) port = OUTPUT_PORT; - } else { - dprintk(VIDC_ERR, "%s: invalid type %d\n", - __func__, vb->type); + else return -EINVAL; - } + vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); + if (!vb2) + return -EINVAL; + + /* + * access vb2 buffer under q->lock and if streaming only to + * ensure the buffer was not free'd by vb2 framework while + * we are accessing it here. + */ mutex_lock(&inst->bufq[port].lock); - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + if (inst->bufq[port].vb2_bufq.streaming) { + vbuf = to_vb2_v4l2_buffer(vb2); + vbuf->flags = mbuf->vvb.flags; + vb2->timestamp = mbuf->vvb.vb2_buf.timestamp; + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + vb2->planes[i].bytesused = + mbuf->vvb.vb2_buf.planes[i].bytesused; + vb2->planes[i].data_offset = + mbuf->vvb.vb2_buf.planes[i].data_offset; + } + vb2_buffer_done(vb2, VB2_BUF_STATE_DONE); + } else { + dprintk(VIDC_ERR, "%s: port %d is not streaming\n", + __func__, port); + } mutex_unlock(&inst->bufq[port].lock); return 0; @@ -2402,10 +2435,10 @@ bool heic_encode_session_supported(struct msm_vidc_inst *inst) n_bframes == 0 && n_pframes == 0) { if (inst->grid_enable > 0) { - if (!(inst->prop.height[CAPTURE_PORT] == - inst->prop.width[CAPTURE_PORT] && - inst->prop.width[CAPTURE_PORT] == - HEIC_GRID_DIMENSION)) + if (inst->prop.width[CAPTURE_PORT] < + HEIC_GRID_DIMENSION || + inst->prop.height[CAPTURE_PORT] < + HEIC_GRID_DIMENSION) return false; } return true; @@ -2438,12 +2471,11 @@ static void handle_ebd(enum hal_command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; struct msm_vidc_buffer *mbuf; - struct vb2_buffer *vb, *vb2; + struct vb2_buffer *vb; struct msm_vidc_inst *inst; struct vidc_hal_ebd *empty_buf_done; - struct vb2_v4l2_buffer *vbuf; u32 planes[VIDEO_MAX_PLANES] = {0}; - u32 extra_idx = 0, i; + u32 extra_idx = 0; if (!response) { dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); @@ -2476,15 +2508,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data) __func__, planes[0], planes[1]); goto exit; } - vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); - - /* - * take registeredbufs.lock to update mbuf & vb2 variables together - * so that both are in sync else if mbuf and vb2 variables are not - * in sync msm_comm_compare_vb2_planes() returns false for the - * right buffer due to data_offset field mismatch. - */ - mutex_lock(&inst->registeredbufs.lock); vb = &mbuf->vvb.vb2_buf; vb->planes[0].bytesused = response->input_done.filled_len; @@ -2501,7 +2524,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) } if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) { dprintk(VIDC_INFO, "Failed : Corrupted input stream\n"); - mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT; + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; } if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME) mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; @@ -2510,18 +2533,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data) if (extra_idx && extra_idx < VIDEO_MAX_PLANES) vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length; - if (vb2) { - vbuf = to_vb2_v4l2_buffer(vb2); - vbuf->flags |= mbuf->vvb.flags; - for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { - vb2->planes[i].bytesused = - mbuf->vvb.vb2_buf.planes[i].bytesused; - vb2->planes[i].data_offset = - mbuf->vvb.vb2_buf.planes[i].data_offset; - } - } - mutex_unlock(&inst->registeredbufs.lock); - update_recon_stats(inst, &empty_buf_done->recon_stats); msm_vidc_clear_freq_entry(inst, mbuf->smem[0].device_addr); /* @@ -2535,7 +2546,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) * in put_buffer. */ msm_comm_put_vidc_buffer(inst, mbuf); - msm_comm_vb2_buffer_done(inst, vb2); + msm_comm_vb2_buffer_done(inst, mbuf); msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD); kref_put_mbuf(mbuf); exit: @@ -2589,13 +2600,12 @@ static void handle_fbd(enum hal_command_response cmd, void *data) struct msm_vidc_cb_data_done *response = data; struct msm_vidc_buffer *mbuf; struct msm_vidc_inst *inst; - struct vb2_buffer *vb, *vb2; + struct vb2_buffer *vb; struct vidc_hal_fbd *fill_buf_done; - struct vb2_v4l2_buffer *vbuf; enum hal_buffer buffer_type; u64 time_usec = 0; u32 planes[VIDEO_MAX_PLANES] = {0}; - u32 extra_idx, i; + u32 extra_idx; if (!response) { dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); @@ -2623,7 +2633,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) __func__, planes[0], planes[1]); goto exit; } - vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); } else { if (handle_multi_stream_buffers(inst, fill_buf_done->packet_buffer1)) @@ -2632,14 +2641,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) &fill_buf_done->packet_buffer1); goto exit; } - - /* - * take registeredbufs.lock to update mbuf & vb2 variables together - * so that both are in sync else if mbuf and vb2 variables are not - * in sync msm_comm_compare_vb2_planes() returns false for the - * right buffer due to data_offset field mismatch. - */ - mutex_lock(&inst->registeredbufs.lock); vb = &mbuf->vvb.vb2_buf; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME) @@ -2681,12 +2682,8 @@ static void handle_fbd(enum hal_command_response cmd, void *data) if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME) mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT) - mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT; + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; switch (fill_buf_done->picture_type) { - case HAL_PICTURE_IDR: - case HAL_PICTURE_I: - mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; - break; case HAL_PICTURE_P: mbuf->vvb.flags |= V4L2_BUF_FLAG_PFRAME; break; @@ -2702,19 +2699,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) break; } - if (vb2) { - vbuf = to_vb2_v4l2_buffer(vb2); - vbuf->flags = mbuf->vvb.flags; - vb2->timestamp = mbuf->vvb.vb2_buf.timestamp; - for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { - vb2->planes[i].bytesused = - mbuf->vvb.vb2_buf.planes[i].bytesused; - vb2->planes[i].data_offset = - mbuf->vvb.vb2_buf.planes[i].data_offset; - } - } - mutex_unlock(&inst->registeredbufs.lock); - /* * dma cache operations need to be performed before dma_unmap * which is done inside msm_comm_put_vidc_buffer() @@ -2726,7 +2710,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data) * in put_buffer. */ msm_comm_put_vidc_buffer(inst, mbuf); - msm_comm_vb2_buffer_done(inst, vb2); + msm_comm_vb2_buffer_done(inst, mbuf); msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD); kref_put_mbuf(mbuf); @@ -3196,7 +3180,7 @@ static int msm_comm_init_buffer_count(struct msm_vidc_inst *inst) bufreq->buffer_count_actual); rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, HAL_BUFFER_INPUT); if (rc) { dprintk(VIDC_ERR, @@ -3230,7 +3214,7 @@ static int msm_comm_init_buffer_count(struct msm_vidc_inst *inst) bufreq->buffer_count_actual); rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, HAL_BUFFER_OUTPUT); if (rc) { dprintk(VIDC_ERR, @@ -5437,7 +5421,6 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) { u32 x_min, x_max, y_min, y_max; u32 input_height, input_width, output_height, output_width; - u32 rotation; if (inst->grid_enable > 0) { dprintk(VIDC_DBG, "Skip scaling check for HEIC\n"); @@ -5478,20 +5461,6 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) return 0; } - rotation = msm_comm_g_ctrl_for_id(inst, - V4L2_CID_ROTATE); - - if ((output_width != output_height) && - (rotation == 90 || - rotation == 270)) { - - output_width = inst->prop.height[CAPTURE_PORT]; - output_height = inst->prop.width[CAPTURE_PORT]; - dprintk(VIDC_DBG, - "Rotation=%u Swapped Output W=%u H=%u to check scaling", - rotation, output_width, output_height); - } - x_min = (1<<16)/inst->capability.scale_x.min; y_min = (1<<16)/inst->capability.scale_y.min; x_max = inst->capability.scale_x.max >> 16; @@ -5537,7 +5506,6 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) struct hfi_device *hdev; struct msm_vidc_core *core; u32 output_height, output_width, input_height, input_width; - u32 rotation; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__); @@ -5576,23 +5544,9 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) rc = -ENOTSUPP; } - rotation = msm_comm_g_ctrl_for_id(inst, - V4L2_CID_ROTATE); - output_height = ALIGN(inst->prop.height[CAPTURE_PORT], 16); output_width = ALIGN(inst->prop.width[CAPTURE_PORT], 16); - if ((output_width != output_height) && - (rotation == 90 || - rotation == 270)) { - - output_width = ALIGN(inst->prop.height[CAPTURE_PORT], 16); - output_height = ALIGN(inst->prop.width[CAPTURE_PORT], 16); - dprintk(VIDC_DBG, - "Rotation=%u Swapped Output W=%u H=%u to check capability", - rotation, output_width, output_height); - } - if (!rc) { if (output_width < capability->width.min || output_height < capability->height.min) { @@ -6134,7 +6088,6 @@ bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst, vb = &mbuf->vvb.vb2_buf; if (vb->planes[i].m.fd == vb2->planes[i].m.fd && - vb->planes[i].data_offset == vb2->planes[i].data_offset && vb->planes[i].length == vb2->planes[i].length) { return true; } @@ -6266,6 +6219,7 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, { int rc; struct vb2_buffer *vb; + u32 port; if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", @@ -6280,11 +6234,24 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, return -EINVAL; } - vb->planes[0].bytesused = 0; - rc = msm_comm_vb2_buffer_done(inst, vb); - if (rc) - print_vidc_buffer(VIDC_ERR, - "vb2_buffer_done failed for", inst, mbuf); + if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + port = CAPTURE_PORT; + else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + port = OUTPUT_PORT; + else + return -EINVAL; + + mutex_lock(&inst->bufq[port].lock); + if (inst->bufq[port].vb2_bufq.streaming) { + vb->planes[0].bytesused = 0; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } else { + dprintk(VIDC_ERR, "%s: port %d is not streaming\n", + __func__, port); + } + mutex_unlock(&inst->bufq[port].lock); return rc; } @@ -6449,23 +6416,24 @@ struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst, } mutex_lock(&inst->registeredbufs.lock); - if (inst->session_type == MSM_VIDC_DECODER) { + /* + * for encoder input, client may queue the same buffer with different + * fd before driver returned old buffer to the client. This buffer + * should be treated as new buffer Search the list with fd so that + * it will be treated as new msm_vidc_buffer. + */ + if (is_encode_session(inst) && vb2->type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { - if (msm_comm_compare_dma_planes(inst, mbuf, - dma_planes)) { + if (msm_comm_compare_vb2_planes(inst, mbuf, vb2)) { found = true; break; } } } else { - /* - * for encoder, client may queue the same buffer with different - * fd before driver returned old buffer to the client. This - * buffer should be treated as new buffer. Search the list with - * fd so that it will be treated as new msm_vidc_buffer. - */ list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { - if (msm_comm_compare_vb2_planes(inst, mbuf, vb2)) { + if (msm_comm_compare_dma_planes(inst, mbuf, + dma_planes)) { found = true; break; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index c0dfc729ffc68944b138270ab5329a5178c0b8b1..6d329ca950121b9d7c053ce95a779d5e3bd7418c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -24,6 +24,7 @@ #define DEFAULT_FRAME_QUALITY 80 #define FRAME_QUALITY_STEP 1 #define HEIC_GRID_DIMENSION 512 +#define CBR_MB_LIMIT (1280*720/256*30) struct vb2_buf_entry { struct list_head list; @@ -213,7 +214,7 @@ void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst, void handle_release_buffer_reference(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, - struct vb2_buffer *vb); + struct msm_vidc_buffer *mbuf); int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index e40622acba821ddad99608103cc6aaa348bc2e3f..5d9e7698ebc6e261969eb810d4c482c4da8bf4c5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -192,7 +192,14 @@ static struct msm_vidc_common_data sm8150_common_data[] = { }, { .key = "qcom,max-secure-instances", - .value = 5, + .value = 2, /* + * As per design driver allows 3rd + * instance as well since the secure + * flags were updated later for the + * current instance. Hence total + * secure sessions would be + * max-secure-instances + 1. + */ }, { .key = "qcom,max-hw-load", diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index f5b3604c1a5d6d8461162af219fee1322d03150f..cb4fd19e1aa4ebae704759e2fd017c0b5cff3f27 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -3689,6 +3689,12 @@ static void venus_hfi_core_work_handler(struct work_struct *work) i < num_responses; ++i) { struct msm_vidc_cb_info *r = &device->response_pkt[i]; + if (!__core_in_valid_state(device)) { + dprintk(VIDC_ERR, + "Ignore responses from %d to %d as device is in invalid state", + (i + 1), num_responses); + break; + } dprintk(VIDC_DBG, "Processing response %d of %d, type %d\n", (i + 1), num_responses, r->response_type); device->callback(r->response_type, &r->response); diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 0efa9b88848a231c55a6aecf9d7676da058b4f89..083f6d5cc705a08eb9f7a98cf73f49580d4de8f5 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -406,6 +406,8 @@ enum hal_vp9_level { HAL_VP9_LEVEL_41 = 0x00000080, HAL_VP9_LEVEL_5 = 0x00000100, HAL_VP9_LEVEL_51 = 0x00000200, + HAL_VP9_LEVEL_6 = 0x00000400, + HAL_VP9_LEVEL_61 = 0x00000800, }; struct hal_frame_rate { diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 1a428fe9f07077e9c8c02fea1cfce723b247cb85..9f023bc6e1b7e4dafd861a4a0344bb4868dec6b1 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1945,6 +1945,7 @@ static int isp_initialize_modules(struct isp_device *isp) static void isp_detach_iommu(struct isp_device *isp) { + arm_iommu_detach_device(isp->dev); arm_iommu_release_mapping(isp->mapping); isp->mapping = NULL; } @@ -1961,8 +1962,7 @@ static int isp_attach_iommu(struct isp_device *isp) mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); if (IS_ERR(mapping)) { dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); - ret = PTR_ERR(mapping); - goto error; + return PTR_ERR(mapping); } isp->mapping = mapping; @@ -1977,7 +1977,8 @@ static int isp_attach_iommu(struct isp_device *isp) return 0; error: - isp_detach_iommu(isp); + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; return ret; } diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index 070bac36d766891dabeb01e1f1bf064eb989de58..2e2b8c409150547d9c998a10bf8f55ff881a10a2 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -1280,7 +1280,7 @@ static int jpu_open(struct file *file) /* ...issue software reset */ ret = jpu_reset(jpu); if (ret) - goto device_prepare_rollback; + goto jpu_reset_rollback; } jpu->ref_count++; @@ -1288,6 +1288,8 @@ static int jpu_open(struct file *file) mutex_unlock(&jpu->mutex); return 0; +jpu_reset_rollback: + clk_disable_unprepare(jpu->clk); device_prepare_rollback: mutex_unlock(&jpu->mutex); v4l_prepare_rollback: diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index b3034f80163fb349d50dd7cd8da1b725741cc418..8ce6f9cff74633a5aab9fb87bbe37cca33919874 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -92,7 +92,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); */ int si470x_get_register(struct si470x_device *radio, int regnr) { - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -117,7 +117,7 @@ int si470x_get_register(struct si470x_device *radio, int regnr) int si470x_set_register(struct si470x_device *radio, int regnr) { int i; - u16 buf[WRITE_REG_NUM]; + __be16 buf[WRITE_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -147,7 +147,7 @@ int si470x_set_register(struct si470x_device *radio, int regnr) static int si470x_get_all_registers(struct si470x_device *radio) { int i; - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 72f381522cb26dfa64662ab0b6a4f61adc91a11c..a22828713c1cab4c481a09e7d1f507f4b6347949 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1824,11 +1824,11 @@ void rc_unregister_device(struct rc_dev *dev) if (!dev) return; - del_timer_sync(&dev->timer_keyup); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + del_timer_sync(&dev->timer_keyup); + rc_free_rx_device(dev); device_del(&dev->dev); diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 0e7e4fdf9e50b72c0b3ce8bca7b5273c3040a4f4..05701240b5d17dc8613bd12fdd3eda7ef99c98f9 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -906,7 +906,7 @@ static void xc5000_config_tv(struct dvb_frontend *fe, static int xc5000_set_tv_freq(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; - u16 pll_lock_status; + u16 pll_lock_status = 0; int ret; tune_channel: @@ -1108,7 +1108,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id); const struct firmware *fw; int ret, i; - u16 pll_lock_status; + u16 pll_lock_status = 0; u16 fw_ck; cancel_delayed_work(&priv->timer_sleep); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index ffbb178c6918e746b29b05ede7cbf5b80d253f79..2dbf632c10de350d72dc61f1a0b63343deee84ba 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -912,9 +912,12 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) dprintk(4, "done processing on buffer %d, state: %d\n", vb->index, state); - /* sync buffers */ - for (plane = 0; plane < vb->num_planes; ++plane) - call_void_memop(vb, finish, vb->planes[plane].mem_priv); + if (state != VB2_BUF_STATE_QUEUED && + state != VB2_BUF_STATE_REQUEUEING) { + /* sync buffers */ + for (plane = 0; plane < vb->num_planes; ++plane) + call_void_memop(vb, finish, vb->planes[plane].mem_priv); + } spin_lock_irqsave(&q->done_lock, flags); if (state == VB2_BUF_STATE_QUEUED || diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index a4803ac192bbc86f550d35f4e8eb236c77aeafd6..1d49a8dd4a374df623a7bfdddda4874ddeaf47ee 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -20,14 +20,6 @@ #include "mc.h" #define MC_INTSTATUS 0x000 -#define MC_INT_DECERR_MTS (1 << 16) -#define MC_INT_SECERR_SEC (1 << 13) -#define MC_INT_DECERR_VPR (1 << 12) -#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) -#define MC_INT_INVALID_SMMU_PAGE (1 << 10) -#define MC_INT_ARBITRATION_EMEM (1 << 9) -#define MC_INT_SECURITY_VIOLATION (1 << 8) -#define MC_INT_DECERR_EMEM (1 << 6) #define MC_INTMASK 0x004 @@ -248,12 +240,13 @@ static const char *const error_names[8] = { static irqreturn_t tegra_mc_irq(int irq, void *data) { struct tegra_mc *mc = data; - unsigned long status, mask; + unsigned long status; unsigned int bit; /* mask all interrupts to avoid flooding */ - status = mc_readl(mc, MC_INTSTATUS); - mask = mc_readl(mc, MC_INTMASK); + status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; + if (!status) + return IRQ_NONE; for_each_set_bit(bit, &status, 32) { const char *error = status_names[bit] ?: "unknown"; @@ -346,7 +339,6 @@ static int tegra_mc_probe(struct platform_device *pdev) const struct of_device_id *match; struct resource *res; struct tegra_mc *mc; - u32 value; int err; match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); @@ -414,11 +406,7 @@ static int tegra_mc_probe(struct platform_device *pdev) WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); - value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | - MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | - MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM; - - mc_writel(mc, value, MC_INTMASK); + mc_writel(mc, mc->soc->intmask, MC_INTMASK); return 0; } diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index ddb16676c3af4d99b59e62b84d77d0bdb30b5158..24e020b4609be7c571c0be7616491f46cb945994 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -14,6 +14,15 @@ #include +#define MC_INT_DECERR_MTS (1 << 16) +#define MC_INT_SECERR_SEC (1 << 13) +#define MC_INT_DECERR_VPR (1 << 12) +#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) +#define MC_INT_INVALID_SMMU_PAGE (1 << 10) +#define MC_INT_ARBITRATION_EMEM (1 << 9) +#define MC_INT_SECURITY_VIOLATION (1 << 8) +#define MC_INT_DECERR_EMEM (1 << 6) + static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) { return readl(mc->regs + offset); diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index ba8fff3d66a655d0875a50f4abb7ea863ea0099c..6d2a5a849d928b1d25ee712ddf1e1535fb203ed7 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -930,4 +930,6 @@ const struct tegra_mc_soc tegra114_mc_soc = { .atom_size = 32, .client_id_mask = 0x7f, .smmu = &tegra114_smmu_soc, + .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | + MC_INT_DECERR_EMEM, }; diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 5a58e440f4a7bd58ec87cd2cbaa4b60993b74667..9f68a56f2727b9d045d5b7ac6076df7e9bf932ad 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -1020,6 +1020,9 @@ const struct tegra_mc_soc tegra124_mc_soc = { .smmu = &tegra124_smmu_soc, .emem_regs = tegra124_mc_emem_regs, .num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs), + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, }; #endif /* CONFIG_ARCH_TEGRA_124_SOC */ @@ -1042,5 +1045,8 @@ const struct tegra_mc_soc tegra132_mc_soc = { .atom_size = 32, .client_id_mask = 0x7f, .smmu = &tegra132_smmu_soc, + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, }; #endif /* CONFIG_ARCH_TEGRA_132_SOC */ diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index 5e144abe4c181eea8fb330ec9f68acb9735fe46f..47c78a6d8f00926d51d5724432a172938f36a2a9 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -1077,4 +1077,7 @@ const struct tegra_mc_soc tegra210_mc_soc = { .atom_size = 64, .client_id_mask = 0xff, .smmu = &tegra210_smmu_soc, + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, }; diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index b44737840e70c188344c3d51e5edc08ffb02b256..d0689428ea1a5b932e8b071508ec4de43d3f3b39 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -952,4 +952,6 @@ const struct tegra_mc_soc tegra30_mc_soc = { .atom_size = 16, .client_id_mask = 0x7f, .smmu = &tegra30_smmu_soc, + .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | + MC_INT_DECERR_EMEM, }; diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index b0ca5a4c841e0c98828efbcebf42caca3223006b..c5528ae982f26ab90721fa33525d60cf5df731a9 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -112,7 +112,11 @@ int cros_ec_register(struct cros_ec_device *ec_dev) mutex_init(&ec_dev->lock); - cros_ec_query_all(ec_dev); + err = cros_ec_query_all(ec_dev); + if (err) { + dev_err(dev, "Cannot identify the EC: error %d\n", err); + return err; + } if (ec_dev->irq) { err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index a0c44d16bf30c58559a6ed0489cb762c13593e32..c75daba57fd77ffd6bce5a78f88c7ab9c16498b2 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -102,15 +102,15 @@ static struct file *cxl_getfile(const char *name, d_instantiate(path.dentry, inode); file = alloc_file(&path, OPEN_FMODE(flags), fops); - if (IS_ERR(file)) - goto err_dput; + if (IS_ERR(file)) { + path_put(&path); + goto err_fs; + } file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; return file; -err_dput: - path_put(&path); err_inode: iput(inode); err_fs: diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index c7001596f025d7a2934f835d2d2833db77dfbf2a..9a47f6d5bc85767b7b10855702b6c767b9e3d5f4 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1773,8 +1773,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, int rc = 0; uint32_t lstnr; unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -1872,67 +1873,80 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, } err_resp: qseecom.send_resp_flag = 0; - ptr_svc->send_resp_flag = 0; - table = ptr_svc->sglistinfo_ptr; + if (ptr_svc) { + ptr_svc->send_resp_flag = 0; + table = ptr_svc->sglistinfo_ptr; + } if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, - QSEECOM_CACHE_CLEAN); - if (ret) - return ret; - if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) return ret; } - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + if (ptr_svc) { + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + QSEECOM_CACHE_CLEAN); + if (ret) + goto exit; + + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); - if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) - __qseecom_disable_clk(CLK_QSEE); + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - return ret; + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + QSEECOM_CACHE_INVALIDATE); + if (ret) + goto exit; + } else { + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + cmd_buf, cmd_len, resp, sizeof(*resp)); + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } } - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, - QSEECOM_CACHE_INVALIDATE); - if (ret) - return ret; - pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n", status, resp->result, data->client.app_id, lstnr); if ((resp->result != QSEOS_RESULT_SUCCESS) && @@ -1941,6 +1955,10 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, resp->result, data->client.app_id, lstnr); ret = -EINVAL; } +exit: + if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) + __qseecom_disable_clk(CLK_QSEE); + } if (rc) return rc; @@ -2075,8 +2093,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd( int rc = 0; uint32_t lstnr; unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -2167,30 +2186,36 @@ static int __qseecom_reentrancy_process_incomplete_cmd( status = QSEOS_RESULT_SUCCESS; } err_resp: - table = ptr_svc->sglistinfo_ptr; + if (ptr_svc) + table = ptr_svc->sglistinfo_ptr; if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = @@ -2202,26 +2227,36 @@ static int __qseecom_reentrancy_process_incomplete_cmd( return ret; } - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + if (ptr_svc) { + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, QSEECOM_CACHE_CLEAN); - if (ret) - goto exit; + if (ret) + goto exit; - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); - wake_up_interruptible(&ptr_svc->listener_block_app_wq); + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); + wake_up_interruptible(&ptr_svc->listener_block_app_wq); - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - goto exit; - } - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, QSEECOM_CACHE_INVALIDATE); - if (ret) - goto exit; + if (ret) + goto exit; + } else { + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + cmd_buf, cmd_len, resp, sizeof(*resp)); + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } + } switch (resp->result) { case QSEOS_RESULT_BLOCKED_ON_LISTENER: @@ -2746,6 +2781,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, } } +unload_exit: if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); if (app_crash) { @@ -2768,7 +2804,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags1); } -unload_exit: + if (data->client.dmabuf) qseecom_vaddr_unmap(data->client.sb_virt, data->client.sgt, data->client.attach, data->client.dmabuf); @@ -7648,6 +7684,17 @@ static inline long qseecom_ioctl(struct file *file, atomic_dec(&data->ioctl_count); break; } + case QSEECOM_IOCTL_SET_ICE_INFO: { + struct qseecom_ice_data_t ice_data; + + ret = copy_from_user(&ice_data, argp, sizeof(ice_data)); + if (ret) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + qcom_ice_set_fde_flag(ice_data.flag); + break; + } default: pr_err("Invalid IOCTL: 0x%x\n", cmd); return -EINVAL; diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index a84c2ce7161aa52b9b6bda5ecebc810f39d2e734..20462d098ef9d044fbe5fe98f1ef21faffacbd9d 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -908,6 +908,12 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev, goto idata_free; } + /* + * Ensure rpmb_req_pending flag is synchronized between multiple + * entities which may use rpmb ioclts with a lock. + */ + mutex_lock(&card->host->rpmb_req_mutex); + atomic_set(&card->host->rpmb_req_pending, 1); mmc_get_card(card); if (mmc_card_doing_bkops(card)) { @@ -1023,6 +1029,8 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev, cmd_rel_host: mmc_put_card(card); + atomic_set(&card->host->rpmb_req_pending, 0); + mutex_unlock(&card->host->rpmb_req_mutex); idata_free: for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) { @@ -2633,11 +2641,11 @@ static struct mmc_cmdq_req *mmc_blk_cmdq_rw_prep( static void mmc_blk_cmdq_requeue_rw_rq(struct mmc_queue *mq, struct request *req) { - struct mmc_card *card = mq->card; - struct mmc_host *host = card->host; + struct request_queue *q = req->q; - blk_requeue_request(req->q, req); - mmc_put_card(host->card); + spin_lock_irq(q->queue_lock); + blk_requeue_request(q, req); + spin_unlock_irq(q->queue_lock); } static int mmc_blk_cmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req) @@ -3543,9 +3551,23 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) * If issuing of the request fails with eitehr EBUSY or * EAGAIN error, re-queue the request. * This case would occur with ICE calls. + * For request which gets completed successfully or + * errored out, we release host lock in completion or + * error handling softirq context. But here the request + * is neither completed nor erred-out, so release the + * host lock explicitly. */ - if (ret == -EBUSY || ret == -EAGAIN) + if (ret == -EBUSY || ret == -EAGAIN) { mmc_blk_cmdq_requeue_rw_rq(mq, req); + mmc_put_card(host->card); + } else if (ret == -ENOMEM) { + /* + * Elaborate error handling is not needed for + * system errors. Let the higher layer decide + * on the next steps. + */ + goto out; + } } } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index e3b3c9164d0764edfbe5ca63b5f7b75836104c10..aecdfeaea9b2cd21986922830881f3ded3df6d5b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -468,6 +468,9 @@ int mmc_recovery_fallback_lower_speed(struct mmc_host *host) mmc_host_clear_sdr104(host); err = mmc_hw_reset(host); host->card->sdr104_blocked = true; + } else if (mmc_card_sd(host->card)) { + /* If sdr104_wa is not present, just return status */ + err = host->bus_ops->alive(host); } if (err) pr_err("%s: %s: Fallback to lower speed mode failed with err=%d\n", diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index d89dc8ecb00952692473d9bd964b7c312aea67d8..a6fc7f68ec0c52d585e2f7ec93d1a80d7460bb3b 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -698,6 +698,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work); setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); + mutex_init(&host->rpmb_req_mutex); + /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index 13ef162cf066a63363106e40a513f3317205d10d..a8b9fee4d62a1e2c16a463cc02c0a8802c186a29 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, struct gpio_descs *reset_gpios = pwrseq->reset_gpios; if (!IS_ERR(reset_gpios)) { - int i; - int values[reset_gpios->ndescs]; + int i, *values; + int nvalues = reset_gpios->ndescs; - for (i = 0; i < reset_gpios->ndescs; i++) + values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); + if (!values) + return; + + for (i = 0; i < nvalues; i++) values[i] = value; - gpiod_set_array_value_cansleep( - reset_gpios->ndescs, reset_gpios->desc, values); + gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values); + kfree(values); } } diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 67fa942ec544968f02b1fdbd89dae60533632248..e2dd4c03b20e430195addfe71daa965b2fd9ff55 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -84,7 +84,9 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, * be any other direct command active. * 3. cmdq state should be unhalted. * 4. cmdq state shouldn't be in error state. - * 5. free tag available to process the new request. + * 5. There is no outstanding RPMB request pending. + * 6. free tag available to process the new request. + * (This must be the last condtion to check) */ wait_event(ctx->wait, kthread_should_stop() || (mmc_peek_request(mq) && @@ -96,6 +98,7 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, && !(!host->card->part_curr && mmc_host_cq_disable(host) && !mmc_card_suspended(host->card)) && !test_bit(CMDQ_STATE_ERR, &ctx->curr_state) + && !atomic_read(&host->rpmb_req_pending) && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked))); } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 6a2cbbba29aadf317ad13c825c5c1602f0efd9fb..5252885e5cda5e87c9e3e49ce66bacf823e033b1 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1255,6 +1255,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) if (host->state == STATE_WAITING_CMD11_DONE) sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; + slot->mmc->actual_clock = 0; + if (!clock) { mci_writel(host, CLKENA, 0); mci_send_cmd(slot, sdmmc_cmd_bits, 0); @@ -1313,6 +1315,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* keep the last clock value that was requested from core */ slot->__clk_old = clock; + slot->mmc->actual_clock = div ? ((host->bus_hz / div) >> 1) : + host->bus_hz; } host->current_speed = clock; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 56e2e177644d6c3d9b0301b50ed780c51509a9bb..3f4f4aea0e8b6dfe3f3c10082db7d87219cc8aec 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -122,7 +122,11 @@ static int denali_dt_probe(struct platform_device *pdev) if (ret) return ret; - denali->clk_x_rate = clk_get_rate(dt->clk); + /* + * Hardcode the clock rate for the backward compatibility. + * This works for both SOCFPGA and UniPhier. + */ + denali->clk_x_rate = 200000000; ret = denali_init(denali); if (ret) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 4005b427023c31f48a562494a8a3258135e362b0..16deba1a2385876ae8002eab2c6df14f1294a576 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -342,9 +342,16 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, case NAND_CMD_READID: case NAND_CMD_PARAM: { + /* + * For READID, read 8 bytes that are currently used. + * For PARAM, read all 3 copies of 256-bytes pages. + */ + int len = 8; int timing = IFC_FIR_OP_RB; - if (command == NAND_CMD_PARAM) + if (command == NAND_CMD_PARAM) { timing = IFC_FIR_OP_RBCD; + len = 256 * 3; + } ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | @@ -354,12 +361,8 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, &ifc->ifc_nand.nand_fcr0); ifc_out32(column, &ifc->ifc_nand.row3); - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - ifc_out32(256, &ifc->ifc_nand.nand_fbcr); - ifc_nand_ctrl->read_bytes = 256; + ifc_out32(len, &ifc->ifc_nand.nand_fbcr); + ifc_nand_ctrl->read_bytes = len; set_addr(mtd, 0, 0, 0); fsl_ifc_run_command(mtd); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 00245b73c224cbd1eb8343b664f2fc1fd6fc81cb..15aedb64a02be03bd15e4726f824d6b19946e54a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1687,6 +1687,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_upper_unlink; } + bond->nest_level = dev_get_nest_level(bond_dev) + 1; + /* If the mode uses primary, then the following is handled by * bond_change_active_slave(). */ @@ -1734,7 +1736,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond_mode_uses_xmit_hash(bond)) bond_update_slave_arr(bond, NULL); - bond->nest_level = dev_get_nest_level(bond_dev); netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n", slave_dev->name, @@ -3379,6 +3380,13 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res, } } +static int bond_get_nest_level(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + + return bond->nest_level; +} + static void bond_get_stats(struct net_device *bond_dev, struct rtnl_link_stats64 *stats) { @@ -3387,7 +3395,7 @@ static void bond_get_stats(struct net_device *bond_dev, struct list_head *iter; struct slave *slave; - spin_lock(&bond->stats_lock); + spin_lock_nested(&bond->stats_lock, bond_get_nest_level(bond_dev)); memcpy(stats, &bond->bond_stats, sizeof(*stats)); rcu_read_lock(); @@ -4182,6 +4190,7 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_neigh_setup = bond_neigh_setup, .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, + .ndo_get_lock_subclass = bond_get_nest_level, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_netpoll_setup = bond_netpoll_setup, .ndo_netpoll_cleanup = bond_netpoll_cleanup, @@ -4680,6 +4689,7 @@ static int bond_init(struct net_device *bond_dev) if (!bond->wq) return -ENOMEM; + bond->nest_level = SINGLE_DEPTH_NESTING; netdev_lockdep_set_classes(bond_dev); list_add_tail(&bond->bond_list, &bn->dev_list); diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 61084ba69a99f2ce2b1992d22608539c5675eba4..3d154eb63dcf2557f27b7564c966f37e176f6aa5 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -743,15 +743,20 @@ const struct bond_option *bond_opt_get(unsigned int option) static int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) { - if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) { - netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", - newval->string); - /* disable arp monitoring */ - bond->params.arp_interval = 0; - /* set miimon to default value */ - bond->params.miimon = BOND_DEFAULT_MIIMON; - netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n", - bond->params.miimon); + if (!bond_mode_uses_arp(newval->value)) { + if (bond->params.arp_interval) { + netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", + newval->string); + /* disable arp monitoring */ + bond->params.arp_interval = 0; + } + + if (!bond->params.miimon) { + /* set miimon to default value */ + bond->params.miimon = BOND_DEFAULT_MIIMON; + netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n", + bond->params.miimon); + } } if (newval->value == BOND_MODE_ALB) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 5d4e61741476660b925e80a81ca1d41c17587f3b..ca3fa82316c2a9940865c4b7b056f76fd268db55 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1073,7 +1073,8 @@ static void m_can_chip_config(struct net_device *dev) } else { /* Version 3.1.x or 3.2.x */ - cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE); + cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE | + CCCR_NISO); /* Only 3.2.x has NISO Bit implemented */ if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index 3c51a884db87bc90e71d5df8d5b0a91eadf69cdb..fa689854f16b310012f2240f2a9ed98486e809ff 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -58,6 +58,10 @@ MODULE_LICENSE("GPL v2"); #define PCIEFD_REG_SYS_VER1 0x0040 /* version reg #1 */ #define PCIEFD_REG_SYS_VER2 0x0044 /* version reg #2 */ +#define PCIEFD_FW_VERSION(x, y, z) (((u32)(x) << 24) | \ + ((u32)(y) << 16) | \ + ((u32)(z) << 8)) + /* System Control Registers Bits */ #define PCIEFD_SYS_CTL_TS_RST 0x00000001 /* timestamp clock */ #define PCIEFD_SYS_CTL_CLK_EN 0x00000002 /* system clock */ @@ -783,6 +787,21 @@ static int peak_pciefd_probe(struct pci_dev *pdev, "%ux CAN-FD PCAN-PCIe FPGA v%u.%u.%u:\n", can_count, hw_ver_major, hw_ver_minor, hw_ver_sub); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + /* FW < v3.3.0 DMA logic doesn't handle correctly the mix of 32-bit and + * 64-bit logical addresses: this workaround forces usage of 32-bit + * DMA addresses only when such a fw is detected. + */ + if (PCIEFD_FW_VERSION(hw_ver_major, hw_ver_minor, hw_ver_sub) < + PCIEFD_FW_VERSION(3, 3, 0)) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + dev_warn(&pdev->dev, + "warning: can't set DMA mask %llxh (err %d)\n", + DMA_BIT_MASK(32), err); + } +#endif + /* stop system clock */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN, PCIEFD_REG_SYS_CTL_CLR); diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index b00358297424604634489a9b106bf313c06b7fc9..d0846ae9e0e4084f3d57358c29d705d1c933a8a4 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1071,6 +1071,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) usb_free_urb(dev->intr_urb); kfree(dev->intr_in_buffer); + kfree(dev->tx_msg_buffer); } } diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 89aec07c225f58d26a80ce4795afbaa6c19d9d84..5a24039733efd23255142c4abc0d2b758d188554 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -2,6 +2,7 @@ * * Copyright (C) 2012 - 2014 Xilinx, Inc. * Copyright (C) 2009 PetaLogix. All rights reserved. + * Copyright (C) 2017 Sandvik Mining and Construction Oy * * Description: * This driver is developed for Axi CAN IP and for Zynq CANPS Controller. @@ -25,8 +26,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -101,7 +104,7 @@ enum xcan_reg { #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK) /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ @@ -118,6 +121,7 @@ enum xcan_reg { /** * struct xcan_priv - This definition define CAN driver instance * @can: CAN private data structure. + * @tx_lock: Lock for synchronizing TX interrupt handling * @tx_head: Tx CAN packets ready to send on the queue * @tx_tail: Tx CAN packets successfully sended on the queue * @tx_max: Maximum number packets the driver can send @@ -132,6 +136,7 @@ enum xcan_reg { */ struct xcan_priv { struct can_priv can; + spinlock_t tx_lock; unsigned int tx_head; unsigned int tx_tail; unsigned int tx_max; @@ -159,6 +164,11 @@ static const struct can_bittiming_const xcan_bittiming_const = { .brp_inc = 1, }; +#define XCAN_CAP_WATERMARK 0x0001 +struct xcan_devtype_data { + unsigned int caps; +}; + /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -238,6 +248,10 @@ static int set_reset_mode(struct net_device *ndev) usleep_range(500, 10000); } + /* reset clears FIFOs */ + priv->tx_head = 0; + priv->tx_tail = 0; + return 0; } @@ -392,6 +406,7 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct net_device_stats *stats = &ndev->stats; struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc, data[2] = {0, 0}; + unsigned long flags; if (can_dropped_invalid_skb(ndev, skb)) return NETDEV_TX_OK; @@ -439,6 +454,9 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); + + spin_lock_irqsave(&priv->tx_lock, flags); + priv->tx_head++; /* Write the Frame to Xilinx CAN TX FIFO */ @@ -454,10 +472,16 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) stats->tx_bytes += cf->can_dlc; } + /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ + if (priv->tx_max > 1) + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); + /* Check if the TX buffer is full */ if ((priv->tx_head - priv->tx_tail) == priv->tx_max) netif_stop_queue(ndev); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_OK; } @@ -529,6 +553,123 @@ static int xcan_rx(struct net_device *ndev) return 1; } +/** + * xcan_current_error_state - Get current error state from HW + * @ndev: Pointer to net_device structure + * + * Checks the current CAN error state from the HW. Note that this + * only checks for ERROR_PASSIVE and ERROR_WARNING. + * + * Return: + * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE + * otherwise. + */ +static enum can_state xcan_current_error_state(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 status = priv->read_reg(priv, XCAN_SR_OFFSET); + + if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) + return CAN_STATE_ERROR_PASSIVE; + else if (status & XCAN_SR_ERRWRN_MASK) + return CAN_STATE_ERROR_WARNING; + else + return CAN_STATE_ERROR_ACTIVE; +} + +/** + * xcan_set_error_state - Set new CAN error state + * @ndev: Pointer to net_device structure + * @new_state: The new CAN state to be set + * @cf: Error frame to be populated or NULL + * + * Set new CAN error state for the device, updating statistics and + * populating the error frame if given. + */ +static void xcan_set_error_state(struct net_device *ndev, + enum can_state new_state, + struct can_frame *cf) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET); + u32 txerr = ecr & XCAN_ECR_TEC_MASK; + u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT; + + priv->can.state = new_state; + + if (cf) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[6] = txerr; + cf->data[7] = rxerr; + } + + switch (new_state) { + case CAN_STATE_ERROR_PASSIVE: + priv->can.can_stats.error_passive++; + if (cf) + cf->data[1] = (rxerr > 127) ? + CAN_ERR_CRTL_RX_PASSIVE : + CAN_ERR_CRTL_TX_PASSIVE; + break; + case CAN_STATE_ERROR_WARNING: + priv->can.can_stats.error_warning++; + if (cf) + cf->data[1] |= (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + break; + case CAN_STATE_ERROR_ACTIVE: + if (cf) + cf->data[1] |= CAN_ERR_CRTL_ACTIVE; + break; + default: + /* non-ERROR states are handled elsewhere */ + WARN_ON(1); + break; + } +} + +/** + * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX + * @ndev: Pointer to net_device structure + * + * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if + * the performed RX/TX has caused it to drop to a lesser state and set + * the interface state accordingly. + */ +static void xcan_update_error_state_after_rxtx(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + enum can_state old_state = priv->can.state; + enum can_state new_state; + + /* changing error state due to successful frame RX/TX can only + * occur from these states + */ + if (old_state != CAN_STATE_ERROR_WARNING && + old_state != CAN_STATE_ERROR_PASSIVE) + return; + + new_state = xcan_current_error_state(ndev); + + if (new_state != old_state) { + struct sk_buff *skb; + struct can_frame *cf; + + skb = alloc_can_err_skb(ndev, &cf); + + xcan_set_error_state(ndev, new_state, skb ? cf : NULL); + + if (skb) { + struct net_device_stats *stats = &ndev->stats; + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } + } +} + /** * xcan_err_interrupt - error frame Isr * @ndev: net_device pointer @@ -544,16 +685,12 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb; - u32 err_status, status, txerr = 0, rxerr = 0; + u32 err_status; skb = alloc_can_err_skb(ndev, &cf); err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); - txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; - rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & - XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); - status = priv->read_reg(priv, XCAN_SR_OFFSET); if (isr & XCAN_IXR_BSOFF_MASK) { priv->can.state = CAN_STATE_BUS_OFF; @@ -563,28 +700,10 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) can_bus_off(ndev); if (skb) cf->can_id |= CAN_ERR_BUSOFF; - } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) { - priv->can.state = CAN_STATE_ERROR_PASSIVE; - priv->can.can_stats.error_passive++; - if (skb) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (rxerr > 127) ? - CAN_ERR_CRTL_RX_PASSIVE : - CAN_ERR_CRTL_TX_PASSIVE; - cf->data[6] = txerr; - cf->data[7] = rxerr; - } - } else if (status & XCAN_SR_ERRWRN_MASK) { - priv->can.state = CAN_STATE_ERROR_WARNING; - priv->can.can_stats.error_warning++; - if (skb) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] |= (txerr > rxerr) ? - CAN_ERR_CRTL_TX_WARNING : - CAN_ERR_CRTL_RX_WARNING; - cf->data[6] = txerr; - cf->data[7] = rxerr; - } + } else { + enum can_state new_state = xcan_current_error_state(ndev); + + xcan_set_error_state(ndev, new_state, skb ? cf : NULL); } /* Check for Arbitration lost interrupt */ @@ -600,7 +719,6 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) if (isr & XCAN_IXR_RXOFLW_MASK) { stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); if (skb) { cf->can_id |= CAN_ERR_CRTL; cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; @@ -709,26 +827,20 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { - if (isr & XCAN_IXR_RXOK_MASK) { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXOK_MASK); - work_done += xcan_rx(ndev); - } else { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXNEMP_MASK); - break; - } + work_done += xcan_rx(ndev); priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } - if (work_done) + if (work_done) { can_led_event(ndev, CAN_LED_EVENT_RX); + xcan_update_error_state_after_rxtx(ndev); + } if (work_done < quota) { napi_complete_done(napi, work_done); ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK); + ier |= XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); } return work_done; @@ -743,18 +855,71 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) { struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; + unsigned int frames_in_fifo; + int frames_sent = 1; /* TXOK => at least 1 frame was sent */ + unsigned long flags; + int retries = 0; + + /* Synchronize with xmit as we need to know the exact number + * of frames in the FIFO to stay in sync due to the TXFEMP + * handling. + * This also prevents a race between netif_wake_queue() and + * netif_stop_queue(). + */ + spin_lock_irqsave(&priv->tx_lock, flags); + + frames_in_fifo = priv->tx_head - priv->tx_tail; + + if (WARN_ON_ONCE(frames_in_fifo == 0)) { + /* clear TXOK anyway to avoid getting back here */ + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return; + } + + /* Check if 2 frames were sent (TXOK only means that at least 1 + * frame was sent). + */ + if (frames_in_fifo > 1) { + WARN_ON(frames_in_fifo > priv->tx_max); + + /* Synchronize TXOK and isr so that after the loop: + * (1) isr variable is up-to-date at least up to TXOK clear + * time. This avoids us clearing a TXOK of a second frame + * but not noticing that the FIFO is now empty and thus + * marking only a single frame as sent. + * (2) No TXOK is left. Having one could mean leaving a + * stray TXOK as we might process the associated frame + * via TXFEMP handling as we read TXFEMP *after* TXOK + * clear to satisfy (1). + */ + while ((isr & XCAN_IXR_TXOK_MASK) && !WARN_ON(++retries == 100)) { + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } - while ((priv->tx_head - priv->tx_tail > 0) && - (isr & XCAN_IXR_TXOK_MASK)) { + if (isr & XCAN_IXR_TXFEMP_MASK) { + /* nothing in FIFO anymore */ + frames_sent = frames_in_fifo; + } + } else { + /* single frame in fifo, just clear TXOK */ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + } + + while (frames_sent--) { can_get_echo_skb(ndev, priv->tx_tail % priv->tx_max); priv->tx_tail++; stats->tx_packets++; - isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } - can_led_event(ndev, CAN_LED_EVENT_TX); + netif_wake_queue(ndev); + + spin_unlock_irqrestore(&priv->tx_lock, flags); + + can_led_event(ndev, CAN_LED_EVENT_TX); + xcan_update_error_state_after_rxtx(ndev); } /** @@ -773,6 +938,7 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) struct net_device *ndev = (struct net_device *)dev_id; struct xcan_priv *priv = netdev_priv(ndev); u32 isr, ier; + u32 isr_errors; /* Get the interrupt status from Xilinx CAN */ isr = priv->read_reg(priv, XCAN_ISR_OFFSET); @@ -791,18 +957,17 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) xcan_tx_interrupt(ndev, isr); /* Check for the type of error interrupt and Processing it */ - if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | - XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) { - priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK | - XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK | - XCAN_IXR_ARBLST_MASK)); + isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | + XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK); + if (isr_errors) { + priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors); xcan_err_interrupt(ndev, isr); } /* Check for the type of receive interrupt and Processing it */ - if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) { + if (isr & XCAN_IXR_RXNEMP_MASK) { ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK); + ier &= ~XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); napi_schedule(&priv->napi); } @@ -819,13 +984,9 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) static void xcan_chip_stop(struct net_device *ndev) { struct xcan_priv *priv = netdev_priv(ndev); - u32 ier; /* Disable interrupts and leave the can in configuration mode */ - ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier &= ~XCAN_INTR_ALL; - priv->write_reg(priv, XCAN_IER_OFFSET, ier); - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + set_reset_mode(ndev); priv->can.state = CAN_STATE_STOPPED; } @@ -958,10 +1119,15 @@ static const struct net_device_ops xcan_netdev_ops = { */ static int __maybe_unused xcan_suspend(struct device *dev) { - if (!device_may_wakeup(dev)) - return pm_runtime_force_suspend(dev); + struct net_device *ndev = dev_get_drvdata(dev); - return 0; + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + xcan_chip_stop(ndev); + } + + return pm_runtime_force_suspend(dev); } /** @@ -973,11 +1139,27 @@ static int __maybe_unused xcan_suspend(struct device *dev) */ static int __maybe_unused xcan_resume(struct device *dev) { - if (!device_may_wakeup(dev)) - return pm_runtime_force_resume(dev); + struct net_device *ndev = dev_get_drvdata(dev); + int ret; - return 0; + ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(dev, "pm_runtime_force_resume failed on resume\n"); + return ret; + } + + if (netif_running(ndev)) { + ret = xcan_chip_start(ndev); + if (ret) { + dev_err(dev, "xcan_chip_start failed on resume\n"); + return ret; + } + + netif_device_attach(ndev); + netif_start_queue(ndev); + } + return 0; } /** @@ -992,14 +1174,6 @@ static int __maybe_unused xcan_runtime_suspend(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct xcan_priv *priv = netdev_priv(ndev); - if (netif_running(ndev)) { - netif_stop_queue(ndev); - netif_device_detach(ndev); - } - - priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK); - priv->can.state = CAN_STATE_SLEEPING; - clk_disable_unprepare(priv->bus_clk); clk_disable_unprepare(priv->can_clk); @@ -1018,7 +1192,6 @@ static int __maybe_unused xcan_runtime_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct xcan_priv *priv = netdev_priv(ndev); int ret; - u32 isr, status; ret = clk_prepare_enable(priv->bus_clk); if (ret) { @@ -1032,27 +1205,6 @@ static int __maybe_unused xcan_runtime_resume(struct device *dev) return ret; } - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); - isr = priv->read_reg(priv, XCAN_ISR_OFFSET); - status = priv->read_reg(priv, XCAN_SR_OFFSET); - - if (netif_running(ndev)) { - if (isr & XCAN_IXR_BSOFF_MASK) { - priv->can.state = CAN_STATE_BUS_OFF; - priv->write_reg(priv, XCAN_SRR_OFFSET, - XCAN_SRR_RESET_MASK); - } else if ((status & XCAN_SR_ESTAT_MASK) == - XCAN_SR_ESTAT_MASK) { - priv->can.state = CAN_STATE_ERROR_PASSIVE; - } else if (status & XCAN_SR_ERRWRN_MASK) { - priv->can.state = CAN_STATE_ERROR_WARNING; - } else { - priv->can.state = CAN_STATE_ERROR_ACTIVE; - } - netif_device_attach(ndev); - netif_start_queue(ndev); - } - return 0; } @@ -1061,6 +1213,18 @@ static const struct dev_pm_ops xcan_dev_pm_ops = { SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL) }; +static const struct xcan_devtype_data xcan_zynq_data = { + .caps = XCAN_CAP_WATERMARK, +}; + +/* Match table for OF platform binding */ +static const struct of_device_id xcan_of_match[] = { + { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, + { .compatible = "xlnx,axi-can-1.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xcan_of_match); + /** * xcan_probe - Platform registration call * @pdev: Handle to the platform device structure @@ -1075,8 +1239,10 @@ static int xcan_probe(struct platform_device *pdev) struct resource *res; /* IO mem resources */ struct net_device *ndev; struct xcan_priv *priv; + const struct of_device_id *of_id; + int caps = 0; void __iomem *addr; - int ret, rx_max, tx_max; + int ret, rx_max, tx_max, tx_fifo_depth; /* Get the virtual base address for the device */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1086,7 +1252,8 @@ static int xcan_probe(struct platform_device *pdev) goto err; } - ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max); + ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", + &tx_fifo_depth); if (ret < 0) goto err; @@ -1094,6 +1261,30 @@ static int xcan_probe(struct platform_device *pdev) if (ret < 0) goto err; + of_id = of_match_device(xcan_of_match, &pdev->dev); + if (of_id) { + const struct xcan_devtype_data *devtype_data = of_id->data; + + if (devtype_data) + caps = devtype_data->caps; + } + + /* There is no way to directly figure out how many frames have been + * sent when the TXOK interrupt is processed. If watermark programming + * is supported, we can have 2 frames in the FIFO and use TXFEMP + * to determine if 1 or 2 frames have been sent. + * Theoretically we should be able to use TXFWMEMP to determine up + * to 3 frames, but it seems that after putting a second frame in the + * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less + * than 2 frames in FIFO) is set anyway with no TXOK (a frame was + * sent), which is not a sensible state - possibly TXFWMEMP is not + * completely synchronized with the rest of the bits? + */ + if (caps & XCAN_CAP_WATERMARK) + tx_max = min(tx_fifo_depth, 2); + else + tx_max = 1; + /* Create a CAN device instance */ ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); if (!ndev) @@ -1108,6 +1299,7 @@ static int xcan_probe(struct platform_device *pdev) CAN_CTRLMODE_BERR_REPORTING; priv->reg_base = addr; priv->tx_max = tx_max; + spin_lock_init(&priv->tx_lock); /* Get IRQ for the device */ ndev->irq = platform_get_irq(pdev, 0); @@ -1172,9 +1364,9 @@ static int xcan_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); - netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", + netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n", priv->reg_base, ndev->irq, priv->can.clock.freq, - priv->tx_max); + tx_fifo_depth, priv->tx_max); return 0; @@ -1208,14 +1400,6 @@ static int xcan_remove(struct platform_device *pdev) return 0; } -/* Match table for OF platform binding */ -static const struct of_device_id xcan_of_match[] = { - { .compatible = "xlnx,zynq-can-1.0", }, - { .compatible = "xlnx,axi-can-1.00.a", }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, xcan_of_match); - static struct platform_driver xcan_driver = { .probe = xcan_probe, .remove = xcan_remove, diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 5ada7a41449c46b2dd8161f806ef55f05cdf2fc9..9645c8f05c7fa1c570110f7ee7e2ce9c93823ba6 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -473,7 +473,7 @@ qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) static void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) { - u32 mask = QCA8K_PORT_STATUS_TXMAC; + u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; /* Port 0 and 6 have no internal PHY */ if ((port > 0) && (port < 6)) @@ -490,6 +490,7 @@ qca8k_setup(struct dsa_switch *ds) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; int ret, i, phy_mode = -1; + u32 mask; /* Make sure that port 0 is the cpu port */ if (!dsa_is_cpu_port(ds, 0)) { @@ -515,7 +516,10 @@ qca8k_setup(struct dsa_switch *ds) if (ret < 0) return ret; - /* Enable CPU Port */ + /* Enable CPU Port, force it to maximum bandwidth and full-duplex */ + mask = QCA8K_PORT_STATUS_SPEED_1000 | QCA8K_PORT_STATUS_TXFLOW | + QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_DUPLEX; + qca8k_write(priv, QCA8K_REG_PORT_STATUS(QCA8K_CPU_PORT), mask); qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); qca8k_port_set_status(priv, QCA8K_CPU_PORT, 1); @@ -584,6 +588,47 @@ qca8k_setup(struct dsa_switch *ds) return 0; } +static void +qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy) +{ + struct qca8k_priv *priv = ds->priv; + u32 reg; + + /* Force fixed-link setting for CPU port, skip others. */ + if (!phy_is_pseudo_fixed_link(phy)) + return; + + /* Set port speed */ + switch (phy->speed) { + case 10: + reg = QCA8K_PORT_STATUS_SPEED_10; + break; + case 100: + reg = QCA8K_PORT_STATUS_SPEED_100; + break; + case 1000: + reg = QCA8K_PORT_STATUS_SPEED_1000; + break; + default: + dev_dbg(priv->dev, "port%d link speed %dMbps not supported.\n", + port, phy->speed); + return; + } + + /* Set duplex mode */ + if (phy->duplex == DUPLEX_FULL) + reg |= QCA8K_PORT_STATUS_DUPLEX; + + /* Force flow control */ + if (dsa_is_cpu_port(ds, port)) + reg |= QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_TXFLOW; + + /* Force link down before changing MAC options */ + qca8k_port_set_status(priv, port, 0); + qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); + qca8k_port_set_status(priv, port, 1); +} + static int qca8k_phy_read(struct dsa_switch *ds, int phy, int regnum) { @@ -832,6 +877,7 @@ qca8k_get_tag_protocol(struct dsa_switch *ds) static const struct dsa_switch_ops qca8k_switch_ops = { .get_tag_protocol = qca8k_get_tag_protocol, .setup = qca8k_setup, + .adjust_link = qca8k_adjust_link, .get_strings = qca8k_get_strings, .phy_read = qca8k_phy_read, .phy_write = qca8k_phy_write, @@ -863,6 +909,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) return -ENOMEM; priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; /* read the switches ID register */ id = qca8k_read(priv, QCA8K_REG_MASK_CTRL); @@ -934,6 +981,7 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, qca8k_suspend, qca8k_resume); static const struct of_device_id qca8k_of_match[] = { + { .compatible = "qca,qca8334" }, { .compatible = "qca,qca8337" }, { /* sentinel */ }, }; diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 1cf8a920d4ffc5ed84b8fd0948fa088b2b3ebf1b..613fe5c50236c50cfbc6659b5a7d895b21409ec9 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -51,8 +51,10 @@ #define QCA8K_GOL_MAC_ADDR0 0x60 #define QCA8K_GOL_MAC_ADDR1 0x64 #define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) -#define QCA8K_PORT_STATUS_SPEED GENMASK(2, 0) -#define QCA8K_PORT_STATUS_SPEED_S 0 +#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) +#define QCA8K_PORT_STATUS_SPEED_10 0 +#define QCA8K_PORT_STATUS_SPEED_100 0x1 +#define QCA8K_PORT_STATUS_SPEED_1000 0x2 #define QCA8K_PORT_STATUS_TXMAC BIT(2) #define QCA8K_PORT_STATUS_RXMAC BIT(3) #define QCA8K_PORT_STATUS_TXFLOW BIT(4) @@ -165,6 +167,7 @@ struct qca8k_priv { struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; struct dsa_switch *ds; struct mutex reg_mutex; + struct device *dev; }; struct qca8k_mib_desc { diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 52beba8c7a39990d3a9d6fb5910c689905a3a6a9..e3b7a71fcad940bad61802a2c77157b9b965713d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -331,6 +331,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); + io_sq->dma_addr_bits = ena_dev->dma_addr_bits; io_sq->desc_entry_size = (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? sizeof(struct ena_eth_io_tx_desc) : diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 1b45cd73a258f05211bfc2ca6e69124c5347bda8..119777986ea48ab26f148b372dd9702613422092 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -1128,14 +1128,14 @@ static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) if (pdata->tx_pause != pdata->phy.tx_pause) { new_state = 1; - pdata->hw_if.config_tx_flow_control(pdata); pdata->tx_pause = pdata->phy.tx_pause; + pdata->hw_if.config_tx_flow_control(pdata); } if (pdata->rx_pause != pdata->phy.rx_pause) { new_state = 1; - pdata->hw_if.config_rx_flow_control(pdata); pdata->rx_pause = pdata->phy.rx_pause; + pdata->hw_if.config_rx_flow_control(pdata); } /* Speed support */ diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 567ee54504bcd6eba897009259f691b74b77609e..5e5022fa1d047be078be911bc4f6cd0631f04de7 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1897,13 +1897,19 @@ static int alx_resume(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct alx_priv *alx = pci_get_drvdata(pdev); struct alx_hw *hw = &alx->hw; + int err; alx_reset_phy(hw); if (!netif_running(alx->dev)) return 0; netif_device_attach(alx->dev); - return __alx_open(alx, true); + + rtnl_lock(); + err = __alx_open(alx, true); + rtnl_unlock(); + + return err; } static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 4f3845a581269e84738ed4f2f487d1dd755efc2b..68470c7c630a8e86bfbb9e2e97b54b0f60ad7a68 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1062,7 +1062,8 @@ static int bcm_enet_open(struct net_device *dev) val = enet_readl(priv, ENET_CTL_REG); val |= ENET_CTL_ENABLE_MASK; enet_writel(priv, val, ENET_CTL_REG); - enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); + if (priv->dma_has_sram) + enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); enet_dmac_writel(priv, priv->dma_chan_en_mask, ENETDMAC_CHANCFG, priv->rx_chan); @@ -1773,7 +1774,9 @@ static int bcm_enet_probe(struct platform_device *pdev) ret = PTR_ERR(priv->mac_clk); goto out; } - clk_prepare_enable(priv->mac_clk); + ret = clk_prepare_enable(priv->mac_clk); + if (ret) + goto out_put_clk_mac; /* initialize default and fetch platform data */ priv->rx_ring_size = BCMENET_DEF_RX_DESC; @@ -1805,9 +1808,11 @@ static int bcm_enet_probe(struct platform_device *pdev) if (IS_ERR(priv->phy_clk)) { ret = PTR_ERR(priv->phy_clk); priv->phy_clk = NULL; - goto out_put_clk_mac; + goto out_disable_clk_mac; } - clk_prepare_enable(priv->phy_clk); + ret = clk_prepare_enable(priv->phy_clk); + if (ret) + goto out_put_clk_phy; } /* do minimal hardware init to be able to probe mii bus */ @@ -1901,13 +1906,16 @@ static int bcm_enet_probe(struct platform_device *pdev) out_uninit_hw: /* turn off mdc clock */ enet_writel(priv, 0, ENET_MIISC_REG); - if (priv->phy_clk) { + if (priv->phy_clk) clk_disable_unprepare(priv->phy_clk); + +out_put_clk_phy: + if (priv->phy_clk) clk_put(priv->phy_clk); - } -out_put_clk_mac: +out_disable_clk_mac: clk_disable_unprepare(priv->mac_clk); +out_put_clk_mac: clk_put(priv->mac_clk); out: free_netdev(dev); @@ -2752,7 +2760,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev) ret = PTR_ERR(priv->mac_clk); goto out_unmap; } - clk_enable(priv->mac_clk); + ret = clk_prepare_enable(priv->mac_clk); + if (ret) + goto out_put_clk; priv->rx_chan = 0; priv->tx_chan = 1; @@ -2773,7 +2783,7 @@ static int bcm_enetsw_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret) - goto out_put_clk; + goto out_disable_clk; netif_carrier_off(dev); platform_set_drvdata(pdev, dev); @@ -2782,6 +2792,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev) return 0; +out_disable_clk: + clk_disable_unprepare(priv->mac_clk); + out_put_clk: clk_put(priv->mac_clk); @@ -2813,6 +2826,9 @@ static int bcm_enetsw_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); + clk_disable_unprepare(priv->mac_clk); + clk_put(priv->mac_clk); + free_netdev(dev); return 0; } diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 1e856e8b9a92dc57753944a1e142654617150ae9..0fff2432ab4cdff1983adf518acdb29ad84267fe 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1851,8 +1851,8 @@ static int bcm_sysport_open(struct net_device *dev) if (!priv->is_lite) priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); else - priv->crc_fwd = !!(gib_readl(priv, GIB_CONTROL) & - GIB_FCS_STRIP); + priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) & + GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT); phydev = of_phy_connect(dev, priv->phy_dn, bcm_sysport_adj_link, 0, priv->phy_interface); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index a2006f5fc26f8f6f1c213acebe4e834b6a71c57c..86ae751ccb5c16d268c05bbdeeafa35f7a2515f9 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -277,7 +277,8 @@ struct bcm_rsb { #define GIB_GTX_CLK_EXT_CLK (0 << GIB_GTX_CLK_SEL_SHIFT) #define GIB_GTX_CLK_125MHZ (1 << GIB_GTX_CLK_SEL_SHIFT) #define GIB_GTX_CLK_250MHZ (2 << GIB_GTX_CLK_SEL_SHIFT) -#define GIB_FCS_STRIP (1 << 6) +#define GIB_FCS_STRIP_SHIFT 6 +#define GIB_FCS_STRIP (1 << GIB_FCS_STRIP_SHIFT) #define GIB_LCL_LOOP_EN (1 << 7) #define GIB_LCL_LOOP_TXEN (1 << 8) #define GIB_RMT_LOOP_EN (1 << 9) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index bfd2d0382f4cfca593e4de42b9852b278978d8c3..94931318587c141c81658c6088c2ce76f9654896 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5927,6 +5927,9 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) } mutex_unlock(&bp->hwrm_cmd_lock); + if (!BNXT_SINGLE_PF(bp)) + return 0; + diff = link_info->support_auto_speeds ^ link_info->advertising; if ((link_info->support_auto_speeds | diff) != link_info->support_auto_speeds) { diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 9a8ef630466f2f12d1053ed71f0f4b264ab08260..1b1d2a67f412c50819ab84900a30f3b285440f2f 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -9279,6 +9279,15 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_restore_clk(tp); + /* Increase the core clock speed to fix tx timeout issue for 5762 + * with 100Mbps link speed. + */ + if (tg3_asic_rev(tp) == ASIC_REV_5762) { + val = tr32(TG3_CPMU_CLCK_ORIDE_ENABLE); + tw32(TG3_CPMU_CLCK_ORIDE_ENABLE, val | + TG3_CPMU_MAC_ORIDE_ENABLE); + } + /* Reprobe ASF enable state. */ tg3_flag_clear(tp, ENABLE_ASF); tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK | diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c index 2220c771092b46e8fb583d46ea99d5829e1793d0..678835136bf8069326067feaa46f8465db4e38d4 100755 --- a/drivers/net/ethernet/cadence/macb_ptp.c +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -170,10 +170,7 @@ static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) if (delta > TSU_NSEC_MAX_VAL) { gem_tsu_get_time(&bp->ptp_clock_info, &now); - if (sign) - now = timespec64_sub(now, then); - else - now = timespec64_add(now, then); + now = timespec64_add(now, then); gem_tsu_set_time(&bp->ptp_clock_info, (const struct timespec64 *)&now); diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 6a015362c34066bf054aeb0f5f7168fbee190858..bf291e90cdb0f44fb56f0769182c409c27662ba6 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "common.h" #include "cxgb3_ioctl.h" @@ -2268,6 +2269,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) if (t.qset_idx >= nqsets) return -EINVAL; + t.qset_idx = array_index_nospec(t.qset_idx, nqsets); q = &adapter->params.sge.qset[q1 + t.qset_idx]; t.rspq_size = q->rspq_size; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ff7a70ffafc65f22fd3ef51416b6487d74f37824..c133491ad9fa0ab3e5bbd3a5356ff64e8e856627 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1272,8 +1272,11 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) /* We need to alloc a vport for main NIC of PF */ num_vport = hdev->num_vmdq_vport + hdev->num_req_vfs + 1; - if (hdev->num_tqps < num_vport) - num_vport = hdev->num_tqps; + if (hdev->num_tqps < num_vport) { + dev_err(&hdev->pdev->dev, "tqps(%d) is less than vports(%d)", + hdev->num_tqps, num_vport); + return -EINVAL; + } /* Alloc the same number of TQPs for every vport */ tqp_per_vport = hdev->num_tqps / num_vport; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index d1e4dcec5db27a68617796e4aa5ab2c39a6d5f91..69726908e72c49e1cf532abce4e4cc4561718670 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -1598,6 +1598,7 @@ static void hns3_replace_buffer(struct hns3_enet_ring *ring, int i, hns3_unmap_buffer(ring, &ring->desc_cb[i]); ring->desc_cb[i] = *res_cb; ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma); + ring->desc[i].rx.bd_base_info = 0; } static void hns3_reuse_buffer(struct hns3_enet_ring *ring, int i) @@ -1605,6 +1606,7 @@ static void hns3_reuse_buffer(struct hns3_enet_ring *ring, int i) ring->desc_cb[i].reuse_flag = 0; ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma + ring->desc_cb[i].page_offset); + ring->desc[i].rx.bd_base_info = 0; } static void hns3_nic_reclaim_one_desc(struct hns3_enet_ring *ring, int *bytes, @@ -2881,6 +2883,8 @@ static int __init hns3_init_module(void) client.ops = &client_ops; + INIT_LIST_HEAD(&client.node); + ret = hnae3_register_client(&client); if (ret) return ret; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 7a226537877b29a877c86ebbb6a4d4699a44db2c..6265ce8915b66132f4e8aee12388491b517b8689 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3558,15 +3558,12 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) } break; case e1000_pch_spt: - if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { - /* Stable 24MHz frequency */ - incperiod = INCPERIOD_24MHZ; - incvalue = INCVALUE_24MHZ; - shift = INCVALUE_SHIFT_24MHZ; - adapter->cc.shift = shift; - break; - } - return -EINVAL; + /* Stable 24MHz frequency */ + incperiod = INCPERIOD_24MHZ; + incvalue = INCVALUE_24MHZ; + shift = INCVALUE_SHIFT_24MHZ; + adapter->cc.shift = shift; + break; case e1000_pch_cnp: if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { /* Stable 24MHz frequency */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index d8456c381c99d47b5de90e4680c9af7aaba5bfbd..ef242dbae116b5afbb2f88bfe0aeab6cc82f65a1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -337,6 +337,8 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf) **/ void i40e_ptp_tx_hang(struct i40e_pf *pf) { + struct sk_buff *skb; + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) return; @@ -349,9 +351,12 @@ void i40e_ptp_tx_hang(struct i40e_pf *pf) * within a second it is reasonable to assume that we never will. */ if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) { - dev_kfree_skb_any(pf->ptp_tx_skb); + skb = pf->ptp_tx_skb; pf->ptp_tx_skb = NULL; clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + + /* Free the skb after we clear the bitlock */ + dev_kfree_skb_any(skb); pf->tx_hwtstamp_timeouts++; } } diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6ca580cdfd843e792783daedb085835838358180..1c027f9d9af54cfca8faceca572fb10dc207ba76 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -8376,12 +8376,17 @@ static void igb_rar_set_index(struct igb_adapter *adapter, u32 index) if (is_valid_ether_addr(addr)) rar_high |= E1000_RAH_AV; - if (hw->mac.type == e1000_82575) + switch (hw->mac.type) { + case e1000_82575: + case e1000_i210: rar_high |= E1000_RAH_POOL_1 * adapter->mac_table[index].queue; - else + break; + default: rar_high |= E1000_RAH_POOL_1 << adapter->mac_table[index].queue; + break; + } } wr32(E1000_RAL(index), rar_low); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 20a8018d41ef6b9875ca1003b6cc46e5dfecc7ee..b68d94b49a8a690416eb9e44db7301906ce07327 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2211,9 +2211,10 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring, return skb; } -#define IXGBE_XDP_PASS 0 -#define IXGBE_XDP_CONSUMED 1 -#define IXGBE_XDP_TX 2 +#define IXGBE_XDP_PASS 0 +#define IXGBE_XDP_CONSUMED BIT(0) +#define IXGBE_XDP_TX BIT(1) +#define IXGBE_XDP_REDIR BIT(2) static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, struct xdp_buff *xdp); @@ -2242,7 +2243,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter, case XDP_REDIRECT: err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog); if (!err) - result = IXGBE_XDP_TX; + result = IXGBE_XDP_REDIR; else result = IXGBE_XDP_CONSUMED; break; @@ -2302,7 +2303,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, unsigned int mss = 0; #endif /* IXGBE_FCOE */ u16 cleaned_count = ixgbe_desc_unused(rx_ring); - bool xdp_xmit = false; + unsigned int xdp_xmit = 0; while (likely(total_rx_packets < budget)) { union ixgbe_adv_rx_desc *rx_desc; @@ -2342,8 +2343,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, } if (IS_ERR(skb)) { - if (PTR_ERR(skb) == -IXGBE_XDP_TX) { - xdp_xmit = true; + unsigned int xdp_res = -PTR_ERR(skb); + + if (xdp_res & (IXGBE_XDP_TX | IXGBE_XDP_REDIR)) { + xdp_xmit |= xdp_res; ixgbe_rx_buffer_flip(rx_ring, rx_buffer, size); } else { rx_buffer->pagecnt_bias++; @@ -2415,7 +2418,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, total_rx_packets++; } - if (xdp_xmit) { + if (xdp_xmit & IXGBE_XDP_REDIR) + xdp_do_flush_map(); + + if (xdp_xmit & IXGBE_XDP_TX) { struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()]; /* Force memory writes to complete before letting h/w @@ -2423,8 +2429,6 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, */ wmb(); writel(ring->next_to_use, ring->tail); - - xdp_do_flush_map(); } u64_stats_update_begin(&rx_ring->syncp); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 90ecc4b0646210bc9daba9ac15eb47e1b4574b32..90be4385bf368c446c020289008f7800de738f78 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3737,6 +3737,7 @@ static int ixgbevf_set_mac(struct net_device *netdev, void *p) return -EPERM; ether_addr_copy(hw->mac.addr, addr->sa_data); + ether_addr_copy(hw->mac.perm_addr, addr->sa_data); ether_addr_copy(netdev->dev_addr, addr->sa_data); return 0; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d28f873169a9041129853cdd1e82f0f64878a669..3deaa341331370bf7e88e8e3583d7b4f0fd2b104 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1959,7 +1959,7 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo, rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE); index = rx_desc - rxq->descs; data = rxq->buf_virt_addr[index]; - phys_addr = rx_desc->buf_phys_addr; + phys_addr = rx_desc->buf_phys_addr - pp->rx_offset_correction; if (!mvneta_rxq_desc_is_first_last(rx_status) || (rx_status & MVNETA_RXD_ERR_SUMMARY)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index b97a55c827ebc7eb8109a293bc86ee419d42563b..ab2a9dbb46c7fcd5743169b8b18be8e1a4fb0a6a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -472,10 +472,10 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, { const struct mlx4_en_frag_info *frag_info = priv->frag_info; unsigned int truesize = 0; + bool release = true; int nr, frag_size; struct page *page; dma_addr_t dma; - bool release; /* Collect used fragments while replacing them in the HW descriptors */ for (nr = 0;; frags++) { @@ -498,7 +498,11 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, release = page_count(page) != 1 || page_is_pfmemalloc(page) || page_to_nid(page) != numa_mem_id(); - } else { + } else if (!priv->rx_headroom) { + /* rx_headroom for non XDP setup is always 0. + * When XDP is set, the above condition will + * guarantee page is always released. + */ u32 sz_align = ALIGN(frag_size, SMP_CACHE_BYTES); frags->page_offset += sz_align; diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index a069fcc823c30f765d65d5b638b4449b2e41acd1..b26da0952a4dd6a13a60bff63797a6d88d1d98b0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2957,7 +2957,7 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, u32 srqn = qp_get_srqn(qpc) & 0xffffff; int use_srq = (qp_get_srqn(qpc) >> 24) & 1; struct res_srq *srq; - int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; + int local_qpn = vhcr->in_modifier & 0xffffff; err = adjust_qp_sched_queue(dev, slave, qpc, inbox); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 3efe45bc247127bfbf15567c5204c91d1c396ea3..cf94fdf25155f9882eb3d5d3395644a22259b982 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -801,6 +801,7 @@ static void cmd_work_handler(struct work_struct *work) unsigned long flags; bool poll_cmd = ent->polling; int alloc_ret; + int cmd_mode; sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem; down(sem); @@ -847,6 +848,7 @@ static void cmd_work_handler(struct work_struct *work) set_signature(ent, !cmd->checksum_disabled); dump_command(dev, ent, 1); ent->ts1 = ktime_get_ns(); + cmd_mode = cmd->mode; if (ent->callback) schedule_delayed_work(&ent->cb_timeout_work, cb_timeout); @@ -871,7 +873,7 @@ static void cmd_work_handler(struct work_struct *work) iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell); mmiowb(); /* if not in polling don't use ent after this point */ - if (cmd->mode == CMD_MODE_POLLING || poll_cmd) { + if (cmd_mode == CMD_MODE_POLLING || poll_cmd) { poll_timeout(ent); /* make sure we read the descriptor after ownership is SW */ rmb(); @@ -1272,7 +1274,7 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf, { struct mlx5_core_dev *dev = filp->private_data; struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; - char outlen_str[8]; + char outlen_str[8] = {0}; int outlen; void *ptr; int err; @@ -1287,8 +1289,6 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf, if (copy_from_user(outlen_str, buf, count)) return -EFAULT; - outlen_str[7] = 0; - err = sscanf(outlen_str, "%d", &outlen); if (err < 0) return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index 12d3ced611145858c2ac67141b3d1179ad7f59f9..e87923e046c98cbc7b07971c707c40b6c02c7e41 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -381,14 +381,14 @@ static void arfs_may_expire_flow(struct mlx5e_priv *priv) HLIST_HEAD(del_list); spin_lock_bh(&priv->fs.arfs.arfs_lock); mlx5e_for_each_arfs_rule(arfs_rule, htmp, priv->fs.arfs.arfs_tables, i, j) { - if (quota++ > MLX5E_ARFS_EXPIRY_QUOTA) - break; if (!work_pending(&arfs_rule->arfs_work) && rps_may_expire_flow(priv->netdev, arfs_rule->rxq, arfs_rule->flow_id, arfs_rule->filter_id)) { hlist_del_init(&arfs_rule->hlist); hlist_add_head(&arfs_rule->hlist, &del_list); + if (quota++ > MLX5E_ARFS_EXPIRY_QUOTA) + break; } } spin_unlock_bh(&priv->fs.arfs.arfs_lock); @@ -711,6 +711,9 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, skb->protocol != htons(ETH_P_IPV6)) return -EPROTONOSUPPORT; + if (skb->encapsulation) + return -EPROTONOSUPPORT; + arfs_t = arfs_get_table(arfs, arfs_get_ip_proto(skb), skb->protocol); if (!arfs_t) return -EPROTONOSUPPORT; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c index 84dd63e740414e75d5aa5ac1ebf871c801718bda..27040009d87a67b71f26e77f6bdf7ceb4ae3cd9a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c @@ -545,6 +545,7 @@ void mlx5e_pps_event_handler(struct mlx5e_priv *priv, void mlx5e_timestamp_init(struct mlx5e_priv *priv) { struct mlx5e_tstamp *tstamp = &priv->tstamp; + u64 overflow_cycles; u64 ns; u64 frac = 0; u32 dev_freq; @@ -569,10 +570,17 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv) /* Calculate period in seconds to call the overflow watchdog - to make * sure counter is checked at least once every wrap around. + * The period is calculated as the minimum between max HW cycles count + * (The clock source mask) and max amount of cycles that can be + * multiplied by clock multiplier where the result doesn't exceed + * 64bits. */ - ns = cyclecounter_cyc2ns(&tstamp->cycles, tstamp->cycles.mask, + overflow_cycles = div64_u64(~0ULL >> 1, tstamp->cycles.mult); + overflow_cycles = min(overflow_cycles, tstamp->cycles.mask >> 1); + + ns = cyclecounter_cyc2ns(&tstamp->cycles, overflow_cycles, frac, &frac); - do_div(ns, NSEC_PER_SEC / 2 / HZ); + do_div(ns, NSEC_PER_SEC / HZ); tstamp->overflow_period = ns; INIT_WORK(&tstamp->pps_info.out_work, mlx5e_pps_out); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 337ce94237946b7bc34d51896585ac2cc15e386d..bf34264c734b5c1a0ac3210cfca401fe2737de29 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2626,7 +2626,7 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv *priv) mlx5e_activate_channels(&priv->channels); netif_tx_start_all_queues(priv->netdev); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_add_sqs_fwd_rules(priv); mlx5e_wait_channels_min_rx_wqes(&priv->channels); @@ -2637,7 +2637,7 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv) { mlx5e_redirect_rqts_to_drop(priv); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_remove_sqs_fwd_rules(priv); /* FIXME: This is a W/A only for tx timeout watch dog false alarm when @@ -4127,7 +4127,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) mlx5e_set_netdev_dev_addr(netdev); #if IS_ENABLED(CONFIG_MLX5_ESWITCH) - if (MLX5_VPORT_MANAGER(mdev)) + if (MLX5_ESWITCH_MANAGER(mdev)) netdev->switchdev_ops = &mlx5e_switchdev_ops; #endif @@ -4273,7 +4273,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) mlx5e_enable_async_events(priv); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_register_vport_reps(priv); if (netdev->reg_state != NETREG_REGISTERED) @@ -4300,7 +4300,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv) queue_work(priv->wq, &priv->set_rx_mode_work); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_unregister_vport_reps(priv); mlx5e_disable_async_events(priv); @@ -4483,7 +4483,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev) return NULL; #ifdef CONFIG_MLX5_ESWITCH - if (MLX5_VPORT_MANAGER(mdev)) { + if (MLX5_ESWITCH_MANAGER(mdev)) { rpriv = mlx5e_alloc_nic_rep_priv(mdev); if (!rpriv) { mlx5_core_warn(mdev, "Failed to alloc NIC rep priv data\n"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 4727e7390834f1e3cc77dcfd821867792df69159..281911698f72fbff76be3f2d98d6b69ddab3438e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -710,7 +710,7 @@ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv) struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep; - if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager)) + if (!MLX5_ESWITCH_MANAGER(priv->mdev)) return false; rep = rpriv->rep; @@ -724,8 +724,12 @@ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv) static bool mlx5e_is_vf_vport_rep(struct mlx5e_priv *priv) { struct mlx5e_rep_priv *rpriv = priv->ppriv; - struct mlx5_eswitch_rep *rep = rpriv->rep; + struct mlx5_eswitch_rep *rep; + if (!MLX5_ESWITCH_MANAGER(priv->mdev)) + return false; + + rep = rpriv->rep; if (rep && rep->vport != FDB_UPLINK_VPORT) return true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 82e37250ed01c4c65a4e6ed5a4486027bc613137..f697084937c381113632317f263d0af6abef3eee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1535,7 +1535,7 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) if (!ESW_ALLOWED(esw)) return 0; - if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) || + if (!MLX5_ESWITCH_MANAGER(esw->dev) || !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) { esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n"); return -EOPNOTSUPP; @@ -1616,7 +1616,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) int vport_num; int err; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; esw_info(dev, @@ -1689,7 +1689,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) { - if (!esw || !MLX5_VPORT_MANAGER(esw->dev)) + if (!esw || !MLX5_ESWITCH_MANAGER(esw->dev)) return; esw_info(esw->dev, "cleanup\n"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 565c8b7a399af7559c910faabbec4e8d99738bb6..10bf770675f32aa24c7b005f8b786cc288bf9120 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -39,6 +39,8 @@ #include #include "lib/mpfs.h" +#define MLX5_ESWITCH_MANAGER(mdev) MLX5_CAP_GEN(mdev, eswitch_manager) + enum { SRIOV_NONE, SRIOV_LEGACY, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index d9fd8570b07c8344bb1dc04934392e20f7628245..c699055c0ffdecde6ddaac99a10b2f6dbe1af4ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -912,8 +912,8 @@ static int mlx5_devlink_eswitch_check(struct devlink *devlink) if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) return -EOPNOTSUPP; - if (!MLX5_CAP_GEN(dev, vport_group_manager)) - return -EOPNOTSUPP; + if(!MLX5_ESWITCH_MANAGER(dev)) + return -EPERM; if (dev->priv.eswitch->mode == SRIOV_NONE) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 33e5ff081e36ee14e58558bbd5e4e18ae1e4ea8f..dd05cf14884543db45abdf932645d685e4ee6714 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -36,6 +36,7 @@ #include "mlx5_core.h" #include "fs_core.h" #include "fs_cmd.h" +#include "eswitch.h" #include "diag/fs_tracepoint.h" #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\ @@ -2211,7 +2212,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev) goto err; } - if (MLX5_CAP_GEN(dev, eswitch_flow_table)) { + if (MLX5_ESWITCH_MANAGER(dev)) { if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ft_support)) { err = init_fdb_root_ns(steering); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 2c71557d1cee724c6b12b2033133060661dabbfc..d69897a1e2cedbe53abffc35cf6d245387b273d4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -34,6 +34,7 @@ #include #include #include "mlx5_core.h" +#include "eswitch.h" #include "../../mlxfw/mlxfw.h" static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out, @@ -152,13 +153,13 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) } if (MLX5_CAP_GEN(dev, vport_group_manager) && - MLX5_CAP_GEN(dev, eswitch_flow_table)) { + MLX5_ESWITCH_MANAGER(dev)) { err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE); if (err) return err; } - if (MLX5_CAP_GEN(dev, eswitch_flow_table)) { + if (MLX5_ESWITCH_MANAGER(dev)) { err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c index 7cb67122e8b5f04371651e1c1e2757acb281a36e..22811ecd8fcde1bc96a15087753ed09257a7c5ea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c @@ -34,6 +34,7 @@ #include #include #include "mlx5_core.h" +#include "eswitch.h" #include "lib/mpfs.h" /* HW L2 Table (MPFS) management */ @@ -98,7 +99,7 @@ int mlx5_mpfs_init(struct mlx5_core_dev *dev) int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table); struct mlx5_mpfs *mpfs; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL); @@ -122,7 +123,7 @@ void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev) { struct mlx5_mpfs *mpfs = dev->priv.mpfs; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return; WARN_ON(!hlist_empty(mpfs->hash)); @@ -137,7 +138,7 @@ int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac) u32 index; int err; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; mutex_lock(&mpfs->lock); @@ -179,7 +180,7 @@ int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac) int err = 0; u32 index; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; mutex_lock(&mpfs->lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index e07061f565d6432d1c6c88b78468e038f20572cc..ccb6287aeeb74445db238f11d91cdde970ee771a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -641,7 +641,7 @@ EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc); static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, int inlen) { - u32 out[MLX5_ST_SZ_DW(qtct_reg)]; + u32 out[MLX5_ST_SZ_DW(qetc_reg)]; if (!MLX5_CAP_GEN(mdev, ets)) return -EOPNOTSUPP; @@ -653,7 +653,7 @@ static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, int outlen) { - u32 in[MLX5_ST_SZ_DW(qtct_reg)]; + u32 in[MLX5_ST_SZ_DW(qetc_reg)]; if (!MLX5_CAP_GEN(mdev, ets)) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 2a8b529ce6dd176cbc29b9bb4b74cd1d1c48f671..a0674962f02c4d2a35d05c98f84436967703101c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -88,6 +88,9 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) return -EBUSY; } + if (!MLX5_ESWITCH_MANAGER(dev)) + goto enable_vfs_hca; + err = mlx5_eswitch_enable_sriov(dev->priv.eswitch, num_vfs, SRIOV_LEGACY); if (err) { mlx5_core_warn(dev, @@ -95,6 +98,7 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) return err; } +enable_vfs_hca: for (vf = 0; vf < num_vfs; vf++) { err = mlx5_core_enable_hca(dev, vf + 1); if (err) { @@ -140,7 +144,8 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev) } out: - mlx5_eswitch_disable_sriov(dev->priv.eswitch); + if (MLX5_ESWITCH_MANAGER(dev)) + mlx5_eswitch_disable_sriov(dev->priv.eswitch); if (mlx5_wait_for_vf_pages(dev)) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 42a6afcaae03ffc233af1852c986a3f78f097dd3..7924f241e3ad068ed68ef295e967384ac559a08d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -912,8 +912,10 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, int err; /* No need to continue if only VLAN flags were changed */ - if (mlxsw_sp_port_vlan->bridge_port) + if (mlxsw_sp_port_vlan->bridge_port) { + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return 0; + } err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port); if (err) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 8f6ccc0c39e5e8682aa7ac677f576b4cdd970d6f..b306961b02fdf40aef89db7d5ed1e535a98a65a1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -700,9 +700,9 @@ qed_dcbx_get_local_lldp_params(struct qed_hwfn *p_hwfn, p_local = &p_hwfn->p_dcbx_info->lldp_local[LLDP_NEAREST_BRIDGE]; memcpy(params->lldp_local.local_chassis_id, p_local->local_chassis_id, - ARRAY_SIZE(p_local->local_chassis_id)); + sizeof(p_local->local_chassis_id)); memcpy(params->lldp_local.local_port_id, p_local->local_port_id, - ARRAY_SIZE(p_local->local_port_id)); + sizeof(p_local->local_port_id)); } static void @@ -714,9 +714,9 @@ qed_dcbx_get_remote_lldp_params(struct qed_hwfn *p_hwfn, p_remote = &p_hwfn->p_dcbx_info->lldp_remote[LLDP_NEAREST_BRIDGE]; memcpy(params->lldp_remote.peer_chassis_id, p_remote->peer_chassis_id, - ARRAY_SIZE(p_remote->peer_chassis_id)); + sizeof(p_remote->peer_chassis_id)); memcpy(params->lldp_remote.peer_port_id, p_remote->peer_port_id, - ARRAY_SIZE(p_remote->peer_port_id)); + sizeof(p_remote->peer_port_id)); } static int diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 58a689fb04db6c494f9ba3b6452f53a0d0a6fb69..ef237469972676637d0e40657635be2ad88e07b0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1782,7 +1782,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) DP_INFO(p_hwfn, "Failed to update driver state\n"); rc = qed_mcp_ov_update_eswitch(p_hwfn, p_hwfn->p_main_ptt, - QED_OV_ESWITCH_VEB); + QED_OV_ESWITCH_NONE); if (rc) DP_INFO(p_hwfn, "Failed to update eswitch mode\n"); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 27832885a87fdb6614d4d646d5ae25e45a253f8a..2c958921dfb36f876594b6b0f7f22d67628731fb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -779,6 +779,14 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, /* We want a minimum of one slowpath and one fastpath vector per hwfn */ cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; + if (is_kdump_kernel()) { + DP_INFO(cdev, + "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", + cdev->int_params.in.min_msix_cnt); + cdev->int_params.in.num_vectors = + cdev->int_params.in.min_msix_cnt; + } + rc = qed_set_int_mode(cdev, false); if (rc) { DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 3f40b1de79570991bf76bfe42d1eb9f2720882b2..d08fe350ab6cd3f925ce2de8768c893b82796c93 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -4396,6 +4396,8 @@ static void qed_sriov_enable_qid_config(struct qed_hwfn *hwfn, static int qed_sriov_enable(struct qed_dev *cdev, int num) { struct qed_iov_vf_init_params params; + struct qed_hwfn *hwfn; + struct qed_ptt *ptt; int i, j, rc; if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) { @@ -4408,8 +4410,8 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num) /* Initialize HW for VF access */ for_each_hwfn(cdev, j) { - struct qed_hwfn *hwfn = &cdev->hwfns[j]; - struct qed_ptt *ptt = qed_ptt_acquire(hwfn); + hwfn = &cdev->hwfns[j]; + ptt = qed_ptt_acquire(hwfn); /* Make sure not to use more than 16 queues per VF */ params.num_queues = min_t(int, @@ -4445,6 +4447,19 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num) goto err; } + hwfn = QED_LEADING_HWFN(cdev); + ptt = qed_ptt_acquire(hwfn); + if (!ptt) { + DP_ERR(hwfn, "Failed to acquire ptt\n"); + rc = -EBUSY; + goto err; + } + + rc = qed_mcp_ov_update_eswitch(hwfn, ptt, QED_OV_ESWITCH_VEB); + if (rc) + DP_INFO(cdev, "Failed to update eswitch mode\n"); + qed_ptt_release(hwfn, ptt); + return num; err: diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c index 9b2280badaf77666ceab5cf0409f484ed08719b8..475f6ae5d4b396341caa959cb7475f03b2752750 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c @@ -337,8 +337,14 @@ int qede_ptp_get_ts_info(struct qede_dev *edev, struct ethtool_ts_info *info) { struct qede_ptp *ptp = edev->ptp; - if (!ptp) - return -EIO; + if (!ptp) { + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + + return 0; + } info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE | diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index 5516d0f169de034d6d032f511da87a4d32d77cce..2def5e5d3cd09c028e41cd36bdbfa983fcdc0681 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -71,6 +71,7 @@ struct rmnet_port { /* dl marker elements */ struct list_head dl_list; struct rmnet_port_priv_stats stats; + int dl_marker_flush; }; extern struct rtnl_link_ops rmnet_link_ops; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 19fbddbcdef44e17ad933400d08c31ff964a6bad..244dd1f41841499484cb0223e02b52df051770bd 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -77,8 +77,8 @@ EXPORT_SYMBOL(rmnet_shs_skb_entry); void rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) { - struct rmnet_priv *priv = netdev_priv(skb->dev); int (*rmnet_shs_stamp)(struct sk_buff *skb, struct rmnet_port *port); + struct rmnet_priv *priv = netdev_priv(skb->dev); skb_reset_transport_header(skb); skb_reset_network_header(skb); @@ -88,13 +88,27 @@ rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) skb_set_mac_header(skb, 0); rmnet_shs_stamp = rcu_dereference(rmnet_shs_skb_entry); - if (rmnet_shs_stamp) + if (rmnet_shs_stamp) { rmnet_shs_stamp(skb, port); + return; + } + + if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) { + if (!rmnet_check_skb_can_gro(skb) && + port->dl_marker_flush >= 0) { + struct napi_struct *napi = get_current_napi_context(); - if (!rmnet_check_skb_can_gro(skb)) - gro_cells_receive(&priv->gro_cells, skb); - else - netif_receive_skb(skb); + napi_gro_receive(napi, skb); + port->dl_marker_flush++; + } else { + netif_receive_skb(skb); + } + } else { + if (!rmnet_check_skb_can_gro(skb)) + gro_cells_receive(&priv->gro_cells, skb); + else + netif_receive_skb(skb); + } } EXPORT_SYMBOL(rmnet_deliver_skb); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c index ce17e2749888763a684e63515be624f47e161ffd..56457f72a3c675ab328a6a842ded9328f910ea67 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -99,6 +99,8 @@ static void rmnet_map_dl_hdr_notify(struct rmnet_port *port, { struct rmnet_map_dl_ind *tmp; + port->dl_marker_flush = 0; + list_for_each_entry(tmp, &port->dl_list, list) tmp->dl_hdr_handler(dlhdr); } @@ -107,9 +109,17 @@ static void rmnet_map_dl_trl_notify(struct rmnet_port *port, struct rmnet_map_dl_ind_trl *dltrl) { struct rmnet_map_dl_ind *tmp; + struct napi_struct *napi; list_for_each_entry(tmp, &port->dl_list, list) tmp->dl_trl_handler(dltrl); + + if (port->dl_marker_flush) { + napi = get_current_napi_context(); + napi_gro_flush(napi, false); + } + + port->dl_marker_flush = -1; } static void rmnet_map_process_flow_start(struct sk_buff *skb, @@ -253,6 +263,8 @@ void rmnet_map_cmd_exit(struct rmnet_port *port) void rmnet_map_cmd_init(struct rmnet_port *port) { INIT_LIST_HEAD(&port->dl_list); + + port->dl_marker_flush = -1; } int rmnet_map_dl_ind_register(struct rmnet_port *port, diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index e5f991c26bfcb699b42e234bb36e6921bb954787..98199521f6f8f3aa03d359c171e82a9117e766c7 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -533,10 +533,8 @@ static void rmnet_map_flush_tx_packet_work(struct work_struct *work) } spin_unlock_irqrestore(&port->agg_lock, flags); - if (skb) { - skb->protocol = htons(ETH_P_MAP); + if (skb) dev_queue_xmit(skb); - } kfree(work); } @@ -598,6 +596,7 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) dev_queue_xmit(skb); return; } + port->agg_skb->protocol = htons(ETH_P_MAP); port->agg_count = 1; getnstimeofday(&port->agg_time); dev_kfree_skb_any(skb); @@ -616,7 +615,6 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) port->agg_state = 0; spin_unlock_irqrestore(&port->agg_lock, flags); hrtimer_cancel(&port->hrtimer); - agg_skb->protocol = htons(ETH_P_MAP); dev_queue_xmit(agg_skb); goto new_packet; } @@ -663,3 +661,31 @@ void rmnet_map_tx_aggregate_exit(struct rmnet_port *port) spin_unlock_irqrestore(&port->agg_lock, flags); } + +void rmnet_map_tx_qmap_cmd(struct sk_buff *qmap_skb) +{ + struct rmnet_port *port; + struct sk_buff *agg_skb; + unsigned long flags; + + port = rmnet_get_port(qmap_skb->dev); + + if (port->data_format & RMNET_EGRESS_FORMAT_AGGREGATION) { + spin_lock_irqsave(&port->agg_lock, flags); + if (port->agg_skb) { + agg_skb = port->agg_skb; + port->agg_skb = 0; + port->agg_count = 0; + memset(&port->agg_time, 0, sizeof(struct timespec)); + port->agg_state = 0; + spin_unlock_irqrestore(&port->agg_lock, flags); + hrtimer_cancel(&port->hrtimer); + dev_queue_xmit(agg_skb); + } else { + spin_unlock_irqrestore(&port->agg_lock, flags); + } + } + + dev_queue_xmit(qmap_skb); +} +EXPORT_SYMBOL(rmnet_map_tx_qmap_cmd); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 798984e060b547cf7082179576343f3d90b1518f..e965dbea2e7aa9f1982bfa7e5f8c3b256e474220 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -231,10 +231,27 @@ static void rmnet_get_ethtool_stats(struct net_device *dev, ARRAY_SIZE(rmnet_port_gstrings_stats) * sizeof(u64)); } +static int rmnet_stats_reset(struct net_device *dev) +{ + struct rmnet_priv *priv = netdev_priv(dev); + struct rmnet_port_priv_stats *stp; + struct rmnet_port *port; + + port = rmnet_get_port(priv->real_dev); + if (!port) + return -EINVAL; + + stp = &port->stats; + + memset(stp, 0, sizeof(*stp)); + return 0; +} + static const struct ethtool_ops rmnet_ethtool_ops = { .get_ethtool_stats = rmnet_get_ethtool_stats, .get_strings = rmnet_get_strings, .get_sset_count = rmnet_get_sset_count, + .nway_reset = rmnet_stats_reset, }; /* Called by kernel whenever a new rmnet device is created. Sets MTU, diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 3df872f56289a2be0de52e98e641501d51fbf174..37026473cf6dad834165ecc40af0c300fff6b963 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -376,7 +376,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) * because generally mcdi responses are fast. After that, back off * and poll once a jiffy (approximately) */ - spins = TICK_USEC; + spins = USER_TICK_USEC; finish = jiffies + MCDI_RPC_TIMEOUT; while (1) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9866d2e34cdd8165fce6ad75c859566496c272d5..1a9a382bf1c4b764ed32257061e5ab801be5d134 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -51,7 +51,7 @@ #include #include "dwmac1000.h" -#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) +#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES) #define TSO_MAX_BUFF_SIZE (SZ_16K - 1) /* Module parameters */ @@ -914,6 +914,7 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) static int stmmac_init_phy(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); + u32 tx_cnt = priv->plat->tx_queues_to_use; struct phy_device *phydev; char phy_id_fmt[MII_BUS_ID_SIZE + 3]; char bus_id[MII_BUS_ID_SIZE]; @@ -954,6 +955,15 @@ static int stmmac_init_phy(struct net_device *dev) phydev->advertising &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); + /* + * Half-duplex mode not supported with multiqueue + * half-duplex can only works with single queue + */ + if (tx_cnt > 1) + phydev->supported &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_100baseT_Half | + SUPPORTED_10baseT_Half); + /* * Broken HW is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 8d375e51a5265104d515f5622696dc2e0cae1ea2..6a393b16a1fcaf924473e7a56968d69e57f12f7e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -257,7 +257,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev, return -ENOMEM; /* Enable pci device */ - ret = pcim_enable_device(pdev); + ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__); @@ -300,9 +300,45 @@ static int stmmac_pci_probe(struct pci_dev *pdev, static void stmmac_pci_remove(struct pci_dev *pdev) { stmmac_dvr_remove(&pdev->dev); + pci_disable_device(pdev); } -static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_suspend, stmmac_resume); +static int stmmac_pci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = stmmac_suspend(dev); + if (ret) + return ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_disable_device(pdev); + pci_wake_from_d3(pdev, true); + return 0; +} + +static int stmmac_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return stmmac_resume(dev); +} + +static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); /* synthetic ID, no official vendor */ #define PCI_VENDOR_ID_STMMAC 0x700 diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index fa607d062cb3130eff15295f61a8efce7c6a969c..15cd086e3f4718c2f2c6ceaabd9d6ac285b73736 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -59,8 +59,7 @@ #include #include "sungem.h" -/* Stripping FCS is causing problems, disabled for now */ -#undef STRIP_FCS +#define STRIP_FCS #define DEFAULT_MSG (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ @@ -434,7 +433,7 @@ static int gem_rxmac_reset(struct gem *gp) writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) writel(((5 & RXDMA_BLANK_IPKTS) | @@ -759,7 +758,6 @@ static int gem_rx(struct gem *gp, int work_to_do) struct net_device *dev = gp->dev; int entry, drops, work_done = 0; u32 done; - __sum16 csum; if (netif_msg_rx_status(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", @@ -854,9 +852,13 @@ static int gem_rx(struct gem *gp, int work_to_do) skb = copy_skb; } - csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); - skb->csum = csum_unfold(csum); - skb->ip_summed = CHECKSUM_COMPLETE; + if (likely(dev->features & NETIF_F_RXCSUM)) { + __sum16 csum; + + csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); + skb->csum = csum_unfold(csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } skb->protocol = eth_type_trans(skb, gp->dev); napi_gro_receive(&gp->napi, skb); @@ -1760,7 +1762,7 @@ static void gem_init_dma(struct gem *gp) writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); @@ -2986,8 +2988,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); /* We can do scatter/gather and HW checksum */ - dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; - dev->features |= dev->hw_features | NETIF_F_RXCSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + dev->features = dev->hw_features; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index 18013645e76c8be4a460e50d7edd31abda29900f..0c1adad7415da7d9b858925d0ec5715e9ca7dfec 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -177,12 +177,18 @@ void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave) } dev = bus_find_device(&platform_bus_type, NULL, node, match); - of_node_put(node); + if (!dev) { + dev_err(dev, "unable to find platform device for %pOF\n", node); + goto out; + } + priv = dev_get_drvdata(dev); priv->cpsw_phy_sel(priv, phy_mode, slave); put_device(dev); +out: + of_node_put(node); } EXPORT_SYMBOL_GPL(cpsw_phy_sel); diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index fbc825ac97ab3f9a91b3021aa8f8149fe9ed6249..cb51448389a17e035a8271738baa766107fe72a1 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -474,7 +474,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 01017dd88802bb8829f7d4c29baf80692676e77a..e33a6c672a0a4357e565fa5e1f1b5d12e28d0088 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -207,7 +207,7 @@ int netvsc_recv_callback(struct net_device *net, void netvsc_channel_cb(void *context); int netvsc_poll(struct napi_struct *napi, int budget); -void rndis_set_subchannel(struct work_struct *w); +int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev); int rndis_filter_open(struct netvsc_device *nvdev); int rndis_filter_close(struct netvsc_device *nvdev); struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, @@ -724,6 +724,8 @@ struct net_device_context { struct hv_device *device_ctx; /* netvsc_device */ struct netvsc_device __rcu *nvdev; + /* list of netvsc net_devices */ + struct list_head list; /* reconfigure work */ struct delayed_work dwork; /* last reconfig time */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4647ecbe6f36df2f9410c3474fe18717ed089eb2..806239b89990d31820d54faa98d8e6e892e53437 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -62,6 +62,41 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf) VM_PKT_DATA_INBAND, 0); } +/* Worker to setup sub channels on initial setup + * Initial hotplug event occurs in softirq context + * and can't wait for channels. + */ +static void netvsc_subchan_work(struct work_struct *w) +{ + struct netvsc_device *nvdev = + container_of(w, struct netvsc_device, subchan_work); + struct rndis_device *rdev; + int i, ret; + + /* Avoid deadlock with device removal already under RTNL */ + if (!rtnl_trylock()) { + schedule_work(w); + return; + } + + rdev = nvdev->extension; + if (rdev) { + ret = rndis_set_subchannel(rdev->ndev, nvdev); + if (ret == 0) { + netif_device_attach(rdev->ndev); + } else { + /* fallback to only primary channel */ + for (i = 1; i < nvdev->num_chn; i++) + netif_napi_del(&nvdev->chan_table[i].napi); + + nvdev->max_chn = 1; + nvdev->num_chn = 1; + } + } + + rtnl_unlock(); +} + static struct netvsc_device *alloc_net_device(void) { struct netvsc_device *net_device; @@ -78,7 +113,7 @@ static struct netvsc_device *alloc_net_device(void) init_completion(&net_device->channel_init_wait); init_waitqueue_head(&net_device->subchan_open); - INIT_WORK(&net_device->subchan_work, rndis_set_subchannel); + INIT_WORK(&net_device->subchan_work, netvsc_subchan_work); return net_device; } @@ -1215,6 +1250,7 @@ int netvsc_poll(struct napi_struct *napi, int budget) struct hv_device *device = netvsc_channel_to_device(channel); struct net_device *ndev = hv_get_drvdata(device); int work_done = 0; + int ret; /* If starting a new interval */ if (!nvchan->desc) @@ -1226,16 +1262,18 @@ int netvsc_poll(struct napi_struct *napi, int budget) nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc); } - /* If send of pending receive completions suceeded - * and did not exhaust NAPI budget this time - * and not doing busy poll + /* Send any pending receive completions */ + ret = send_recv_completions(ndev, net_device, nvchan); + + /* If it did not exhaust NAPI budget this time + * and not doing busy poll * then re-enable host interrupts - * and reschedule if ring is not empty. + * and reschedule if ring is not empty + * or sending receive completion failed. */ - if (send_recv_completions(ndev, net_device, nvchan) == 0 && - work_done < budget && + if (work_done < budget && napi_complete_done(napi, work_done) && - hv_end_read(&channel->inbound) && + (ret || hv_end_read(&channel->inbound)) && napi_schedule_prep(napi)) { hv_begin_read(&channel->inbound); __napi_schedule(napi); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 6890478a085167379d4f2bf2a8ac38a83982dd1a..6a77ef38c5495cc62b4c547c95f42a22051cdf2a 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -66,6 +66,8 @@ static int debug = -1; module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +static LIST_HEAD(netvsc_dev_list); + static void netvsc_change_rx_flags(struct net_device *net, int change) { struct net_device_context *ndev_ctx = netdev_priv(net); @@ -911,8 +913,20 @@ static int netvsc_attach(struct net_device *ndev, if (IS_ERR(nvdev)) return PTR_ERR(nvdev); - /* Note: enable and attach happen when sub-channels setup */ + if (nvdev->num_chn > 1) { + ret = rndis_set_subchannel(ndev, nvdev); + + /* if unavailable, just proceed with one queue */ + if (ret) { + nvdev->max_chn = 1; + nvdev->num_chn = 1; + } + } + /* In any case device is now ready */ + netif_device_attach(ndev); + + /* Note: enable and attach happen when sub-channels setup */ netif_carrier_off(ndev); if (netif_running(ndev)) { @@ -1737,13 +1751,10 @@ static void netvsc_link_change(struct work_struct *w) static struct net_device *get_netvsc_bymac(const u8 *mac) { - struct net_device *dev; - - ASSERT_RTNL(); + struct net_device_context *ndev_ctx; - for_each_netdev(&init_net, dev) { - if (dev->netdev_ops != &device_ops) - continue; /* not a netvsc device */ + list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { + struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx); if (ether_addr_equal(mac, dev->perm_addr)) return dev; @@ -1754,25 +1765,18 @@ static struct net_device *get_netvsc_bymac(const u8 *mac) static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) { + struct net_device_context *net_device_ctx; struct net_device *dev; - ASSERT_RTNL(); + dev = netdev_master_upper_dev_get(vf_netdev); + if (!dev || dev->netdev_ops != &device_ops) + return NULL; /* not a netvsc device */ - for_each_netdev(&init_net, dev) { - struct net_device_context *net_device_ctx; + net_device_ctx = netdev_priv(dev); + if (!rtnl_dereference(net_device_ctx->nvdev)) + return NULL; /* device is removed */ - if (dev->netdev_ops != &device_ops) - continue; /* not a netvsc device */ - - net_device_ctx = netdev_priv(dev); - if (!rtnl_dereference(net_device_ctx->nvdev)) - continue; /* device is removed */ - - if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev) - return dev; /* a match */ - } - - return NULL; + return dev; } /* Called when VF is injecting data into network stack. @@ -2035,6 +2039,9 @@ static int netvsc_probe(struct hv_device *dev, memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); + if (nvdev->num_chn > 1) + schedule_work(&nvdev->subchan_work); + /* hw_features computed in rndis_netdev_set_hwcaps() */ net->features = net->hw_features | NETIF_F_HIGHDMA | NETIF_F_SG | @@ -2050,15 +2057,19 @@ static int netvsc_probe(struct hv_device *dev, else net->max_mtu = ETH_DATA_LEN; - ret = register_netdev(net); + rtnl_lock(); + ret = register_netdevice(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); goto register_failed; } - return ret; + list_add(&net_device_ctx->list, &netvsc_dev_list); + rtnl_unlock(); + return 0; register_failed: + rtnl_unlock(); rndis_filter_device_remove(dev, nvdev); rndis_failed: free_percpu(net_device_ctx->vf_stats); @@ -2104,6 +2115,7 @@ static int netvsc_remove(struct hv_device *dev) rndis_filter_device_remove(dev, nvdev); unregister_netdevice(net); + list_del(&ndev_ctx->list); rtnl_unlock(); rcu_read_unlock(); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index d1ae184008b41866d642561c21b5ead9983c449b..cb03a6ea076a66c7ca856e912ed42a97741e05da 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1055,29 +1055,15 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) * This breaks overlap of processing the host message for the * new primary channel with the initialization of sub-channels. */ -void rndis_set_subchannel(struct work_struct *w) +int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev) { - struct netvsc_device *nvdev - = container_of(w, struct netvsc_device, subchan_work); struct nvsp_message *init_packet = &nvdev->channel_init_pkt; - struct net_device_context *ndev_ctx; - struct rndis_device *rdev; - struct net_device *ndev; - struct hv_device *hv_dev; + struct net_device_context *ndev_ctx = netdev_priv(ndev); + struct hv_device *hv_dev = ndev_ctx->device_ctx; + struct rndis_device *rdev = nvdev->extension; int i, ret; - if (!rtnl_trylock()) { - schedule_work(w); - return; - } - - rdev = nvdev->extension; - if (!rdev) - goto unlock; /* device was removed */ - - ndev = rdev->ndev; - ndev_ctx = netdev_priv(ndev); - hv_dev = ndev_ctx->device_ctx; + ASSERT_RTNL(); memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL; @@ -1091,13 +1077,13 @@ void rndis_set_subchannel(struct work_struct *w) VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret) { netdev_err(ndev, "sub channel allocate send failed: %d\n", ret); - goto failed; + return ret; } wait_for_completion(&nvdev->channel_init_wait); if (init_packet->msg.v5_msg.subchn_comp.status != NVSP_STAT_SUCCESS) { netdev_err(ndev, "sub channel request failed\n"); - goto failed; + return -EIO; } nvdev->num_chn = 1 + @@ -1116,21 +1102,7 @@ void rndis_set_subchannel(struct work_struct *w) for (i = 0; i < VRSS_SEND_TAB_SIZE; i++) ndev_ctx->tx_table[i] = i % nvdev->num_chn; - netif_device_attach(ndev); - rtnl_unlock(); - return; - -failed: - /* fallback to only primary channel */ - for (i = 1; i < nvdev->num_chn; i++) - netif_napi_del(&nvdev->chan_table[i].napi); - - nvdev->max_chn = 1; - nvdev->num_chn = 1; - - netif_device_attach(ndev); -unlock: - rtnl_unlock(); + return 0; } static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, @@ -1321,21 +1293,12 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, netif_napi_add(net, &net_device->chan_table[i].napi, netvsc_poll, NAPI_POLL_WEIGHT); - if (net_device->num_chn > 1) - schedule_work(&net_device->subchan_work); + return net_device; out: - /* if unavailable, just proceed with one queue */ - if (ret) { - net_device->max_chn = 1; - net_device->num_chn = 1; - } - - /* No sub channels, device is ready */ - if (net_device->num_chn == 1) - netif_device_attach(net); - - return net_device; + /* setting up multiple channels failed */ + net_device->max_chn = 1; + net_device->num_chn = 1; err_dev_remv: rndis_filter_device_remove(dev, net_device); diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index c74893c1e6200849fcd6293e19a7813e21a6ebae..e7f7a1a002ee05bace0a05aab920eb3537a1d40b 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -546,7 +546,8 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev, ipvlan->dev = dev; ipvlan->port = port; ipvlan->sfeatures = IPVLAN_FEATURES; - ipvlan_adjust_mtu(ipvlan, phy_dev); + if (!tb[IFLA_MTU]) + ipvlan_adjust_mtu(ipvlan, phy_dev); INIT_LIST_HEAD(&ipvlan->addrs); /* If the port-id base is at the MAX value, then wrap it around and diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c index 0831b7142df7a334b889296688cc3218d8efa2a1..0c5b68e7da51aa8d0c7c73e7c6b3cc632b1e3510 100644 --- a/drivers/net/phy/mdio-mux-bcm-iproc.c +++ b/drivers/net/phy/mdio-mux-bcm-iproc.c @@ -218,7 +218,7 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev) static int mdio_mux_iproc_remove(struct platform_device *pdev) { - struct iproc_mdiomux_desc *md = dev_get_platdata(&pdev->dev); + struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev); mdio_mux_uninit(md->mux_handle); mdiobus_unregister(md->mii_bus); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index dba6d17ad885e5e66076c4741e357f482bfbe8ff..47d2ef2fb9b33102b9b96805b54fa1743ec2aaf1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -511,7 +511,7 @@ static int phy_start_aneg_priv(struct phy_device *phydev, bool sync) * negotiation may already be done and aneg interrupt may not be * generated. */ - if (phy_interrupt_is_valid(phydev) && (phydev->state == PHY_AN)) { + if (phydev->irq != PHY_POLL && phydev->state == PHY_AN) { err = phy_aneg_done(phydev); if (err > 0) { trigger = true; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a1e7ea4d4b16ed3a87a2fb8507918f1b6e640b55..a174d05a975226c22ff50b5085bc7689083ebfa6 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1686,11 +1686,8 @@ EXPORT_SYMBOL(genphy_loopback); static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) { - /* The default values for phydev->supported are provided by the PHY - * driver "features" member, we want to reset to sane defaults first - * before supporting higher speeds. - */ - phydev->supported &= PHY_DEFAULT_FEATURES; + phydev->supported &= ~(PHY_1000BT_FEATURES | PHY_100BT_FEATURES | + PHY_10BT_FEATURES); switch (max_speed) { default: diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 1b2fe74a44eab81b0c2b690745cbbaa8df53e645..e4a6ed88b9cf0253efdfd98a53aa7d9ec799f94d 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -561,6 +561,8 @@ void phylink_destroy(struct phylink *pl) { if (pl->sfp_bus) sfp_unregister_upstream(pl->sfp_bus); + if (!IS_ERR(pl->link_gpio)) + gpiod_put(pl->link_gpio); cancel_work_sync(&pl->resolve); kfree(pl); diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 3d4f7959dabb9c39e17754df4f72013c89743d5a..b1b3d8f7e67dd052eae618e33698c633751df60a 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -642,10 +642,12 @@ static void ax88772_restore_phy(struct usbnet *dev) priv->presvd_phy_advertise); /* Restore BMCR */ + if (priv->presvd_phy_bmcr & BMCR_ANENABLE) + priv->presvd_phy_bmcr |= BMCR_ANRESTART; + asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_BMCR, priv->presvd_phy_bmcr); - mii_nway_restart(&dev->mii); priv->presvd_phy_advertise = 0; priv->presvd_phy_bmcr = 0; } diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 9881edc568ba7803a967ae2608b93d36e27da979..9e3f632e22f1411dda03da5284e54b1de77a0836 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1216,6 +1216,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) mod_timer(&dev->stat_monitor, jiffies + STAT_UPDATE_TIMER); } + + tasklet_schedule(&dev->bh); } return ret; @@ -3197,6 +3199,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) pkt_cnt = 0; count = 0; length = 0; + spin_lock_irqsave(&tqp->lock, flags); for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { if (skb_is_gso(skb)) { if (pkt_cnt) { @@ -3205,7 +3208,8 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) } count = 1; length = skb->len - TX_OVERHEAD; - skb2 = skb_dequeue(tqp); + __skb_unlink(skb, tqp); + spin_unlock_irqrestore(&tqp->lock, flags); goto gso_skb; } @@ -3214,6 +3218,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) skb_totallen = skb->len + roundup(skb_totallen, sizeof(u32)); pkt_cnt++; } + spin_unlock_irqrestore(&tqp->lock, flags); /* copy to a single skb */ skb = alloc_skb(skb_totallen, GFP_ATOMIC); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index b23ee948e7c955dc3c5a64302bf7940a8c6d8be3..6d3811c869fdddeadd3110f320b2ee5cb2c18f96 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1245,12 +1245,14 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ + {QMI_FIXED_INTF(0x413c, 0x81d7, 1)}, /* Dell Wireless 5821e */ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)}, /* Quectel EP06 Mini PCIe */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index aa88b640cb6c22c7e897f1f309dbc31d37c13769..0fa64cc1a01182d0592b13997d2a3e4cae24f018 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3959,7 +3959,8 @@ static int rtl8152_close(struct net_device *netdev) #ifdef CONFIG_PM_SLEEP unregister_pm_notifier(&tp->pm_notifier); #endif - napi_disable(&tp->napi); + if (!test_bit(RTL8152_UNPLUG, &tp->flags)) + napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 3d9c5b35a4a753e4052fd41686f5332bcbc43ed9..13d39a72fe0d0c48feb054c0140b827aa0041f24 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -623,9 +623,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk, flush = 0; out: - skb_gro_remcsum_cleanup(skb, &grc); - skb->remcsum_offload = 0; - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final_remcsum(skb, pp, flush, &grc); return pp; } @@ -638,8 +636,61 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff) return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr)); } -/* Add new entry to forwarding table -- assumes lock held */ +static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, + const u8 *mac, __u16 state, + __be32 src_vni, __u8 ndm_flags) +{ + struct vxlan_fdb *f; + + f = kmalloc(sizeof(*f), GFP_ATOMIC); + if (!f) + return NULL; + f->state = state; + f->flags = ndm_flags; + f->updated = f->used = jiffies; + f->vni = src_vni; + INIT_LIST_HEAD(&f->remotes); + memcpy(f->eth_addr, mac, ETH_ALEN); + + return f; +} + static int vxlan_fdb_create(struct vxlan_dev *vxlan, + const u8 *mac, union vxlan_addr *ip, + __u16 state, __be16 port, __be32 src_vni, + __be32 vni, __u32 ifindex, __u8 ndm_flags, + struct vxlan_fdb **fdb) +{ + struct vxlan_rdst *rd = NULL; + struct vxlan_fdb *f; + int rc; + + if (vxlan->cfg.addrmax && + vxlan->addrcnt >= vxlan->cfg.addrmax) + return -ENOSPC; + + netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); + f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags); + if (!f) + return -ENOMEM; + + rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); + if (rc < 0) { + kfree(f); + return rc; + } + + ++vxlan->addrcnt; + hlist_add_head_rcu(&f->hlist, + vxlan_fdb_head(vxlan, mac, src_vni)); + + *fdb = f; + + return 0; +} + +/* Add new entry to forwarding table -- assumes lock held */ +static int vxlan_fdb_update(struct vxlan_dev *vxlan, const u8 *mac, union vxlan_addr *ip, __u16 state, __u16 flags, __be16 port, __be32 src_vni, __be32 vni, @@ -689,37 +740,17 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, if (!(flags & NLM_F_CREATE)) return -ENOENT; - if (vxlan->cfg.addrmax && - vxlan->addrcnt >= vxlan->cfg.addrmax) - return -ENOSPC; - /* Disallow replace to add a multicast entry */ if ((flags & NLM_F_REPLACE) && (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac))) return -EOPNOTSUPP; netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); - f = kmalloc(sizeof(*f), GFP_ATOMIC); - if (!f) - return -ENOMEM; - - notify = 1; - f->state = state; - f->flags = ndm_flags; - f->updated = f->used = jiffies; - f->vni = src_vni; - INIT_LIST_HEAD(&f->remotes); - memcpy(f->eth_addr, mac, ETH_ALEN); - - rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); - if (rc < 0) { - kfree(f); + rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, + vni, ifindex, ndm_flags, &f); + if (rc < 0) return rc; - } - - ++vxlan->addrcnt; - hlist_add_head_rcu(&f->hlist, - vxlan_fdb_head(vxlan, mac, src_vni)); + notify = 1; } if (notify) { @@ -743,13 +774,15 @@ static void vxlan_fdb_free(struct rcu_head *head) kfree(f); } -static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f) +static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, + bool do_notify) { netdev_dbg(vxlan->dev, "delete %pM\n", f->eth_addr); --vxlan->addrcnt; - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH); + if (do_notify) + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH); hlist_del_rcu(&f->hlist); call_rcu(&f->rcu, vxlan_fdb_free); @@ -865,7 +898,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -EAFNOSUPPORT; spin_lock_bh(&vxlan->hash_lock); - err = vxlan_fdb_create(vxlan, addr, &ip, ndm->ndm_state, flags, + err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags, port, src_vni, vni, ifindex, ndm->ndm_flags); spin_unlock_bh(&vxlan->hash_lock); @@ -899,7 +932,7 @@ static int __vxlan_fdb_delete(struct vxlan_dev *vxlan, goto out; } - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); out: return 0; @@ -1008,7 +1041,7 @@ static bool vxlan_snoop(struct net_device *dev, /* close off race between vxlan_flush and incoming packets */ if (netif_running(dev)) - vxlan_fdb_create(vxlan, src_mac, src_ip, + vxlan_fdb_update(vxlan, src_mac, src_ip, NUD_REACHABLE, NLM_F_EXCL|NLM_F_CREATE, vxlan->cfg.dst_port, @@ -2362,7 +2395,7 @@ static void vxlan_cleanup(unsigned long arg) "garbage collect %pM\n", f->eth_addr); f->state = NUD_STALE; - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); } else if (time_before(timeout, next_timer)) next_timer = timeout; } @@ -2413,7 +2446,7 @@ static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni) spin_lock_bh(&vxlan->hash_lock); f = __vxlan_find_mac(vxlan, all_zeros_mac, vni); if (f) - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); spin_unlock_bh(&vxlan->hash_lock); } @@ -2467,7 +2500,7 @@ static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all) continue; /* the all_zeros_mac entry is deleted at vxlan_uninit */ if (!is_zero_ether_addr(f->eth_addr)) - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); } } spin_unlock_bh(&vxlan->hash_lock); @@ -3159,6 +3192,7 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, { struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_fdb *f = NULL; int err; err = vxlan_dev_configure(net, dev, conf, false, extack); @@ -3172,24 +3206,35 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, err = vxlan_fdb_create(vxlan, all_zeros_mac, &vxlan->default_dst.remote_ip, NUD_REACHABLE | NUD_PERMANENT, - NLM_F_EXCL | NLM_F_CREATE, vxlan->cfg.dst_port, vxlan->default_dst.remote_vni, vxlan->default_dst.remote_vni, vxlan->default_dst.remote_ifindex, - NTF_SELF); + NTF_SELF, &f); if (err) return err; } err = register_netdevice(dev); + if (err) + goto errout; + + err = rtnl_configure_link(dev, NULL); if (err) { - vxlan_fdb_delete_default(vxlan, vxlan->default_dst.remote_vni); - return err; + unregister_netdevice(dev); + goto errout; } + /* notify default fdb entry */ + if (f) + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); + list_add(&vxlan->next, &vn->vxlan_list); return 0; +errout: + if (f) + vxlan_fdb_destroy(vxlan, f, false); + return err; } static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], @@ -3418,6 +3463,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], struct vxlan_rdst *dst = &vxlan->default_dst; struct vxlan_rdst old_dst; struct vxlan_config conf; + struct vxlan_fdb *f = NULL; int err; err = vxlan_nl2conf(tb, data, @@ -3446,16 +3492,16 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], err = vxlan_fdb_create(vxlan, all_zeros_mac, &dst->remote_ip, NUD_REACHABLE | NUD_PERMANENT, - NLM_F_CREATE | NLM_F_APPEND, vxlan->cfg.dst_port, dst->remote_vni, dst->remote_vni, dst->remote_ifindex, - NTF_SELF); + NTF_SELF, &f); if (err) { spin_unlock_bh(&vxlan->hash_lock); return err; } + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); } spin_unlock_bh(&vxlan->hash_lock); } diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 5d80be213fac0ec9c05d01bc49c6bfd190e68a16..869f276cc1d8d3446b1589cb6546b597a152bd13 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -68,12 +68,14 @@ enum CountryCode { CTRY_AUSTRALIA = 36, CTRY_AUSTRIA = 40, CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, CTRY_BAHRAIN = 48, CTRY_BANGLADESH = 50, CTRY_BARBADOS = 52, CTRY_BELARUS = 112, CTRY_BELGIUM = 56, CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, CTRY_BOLIVIA = 68, CTRY_BOSNIA_HERZ = 70, CTRY_BRAZIL = 76, @@ -159,6 +161,7 @@ enum CountryCode { CTRY_ROMANIA = 642, CTRY_RUSSIA = 643, CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA = 688, CTRY_SERBIA_MONTENEGRO = 891, CTRY_SINGAPORE = 702, CTRY_SLOVAKIA = 703, @@ -170,11 +173,13 @@ enum CountryCode { CTRY_SWITZERLAND = 756, CTRY_SYRIA = 760, CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, CTRY_THAILAND = 764, CTRY_TRINIDAD_Y_TOBAGO = 780, CTRY_TUNISIA = 788, CTRY_TURKEY = 792, CTRY_UAE = 784, + CTRY_UGANDA = 800, CTRY_UKRAINE = 804, CTRY_UNITED_KINGDOM = 826, CTRY_UNITED_STATES = 840, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index bdd2b4d61f2f0f797dc40f9fe49b5d549ed6c129..15bbd1e0d912f5c799661b5adbb6c48e99da2819 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -35,6 +35,7 @@ enum EnumRd { FRANCE_RES = 0x31, FCC3_FCCA = 0x3A, FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, ETSI1_WORLD = 0x37, ETSI3_ETSIA = 0x32, @@ -44,6 +45,7 @@ enum EnumRd { ETSI4_ETSIC = 0x38, ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, + ETSI8_WORLD = 0x3D, ETSI_RESERVED = 0x33, MKK1_MKKA = 0x40, @@ -59,6 +61,7 @@ enum EnumRd { MKK1_MKKA1 = 0x4A, MKK1_MKKA2 = 0x4B, MKK1_MKKC = 0x4C, + APL2_FCCA = 0x4D, APL3_FCCA = 0x50, APL1_WORLD = 0x52, @@ -67,6 +70,7 @@ enum EnumRd { APL1_ETSIC = 0x55, APL2_ETSIC = 0x56, APL5_WORLD = 0x58, + APL13_WORLD = 0x5A, APL6_WORLD = 0x5B, APL7_FCCA = 0x5C, APL8_WORLD = 0x5D, @@ -168,6 +172,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, {FCC3_FCCA, CTL_FCC, CTL_FCC}, {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, {FCC4_FCCA, CTL_FCC, CTL_FCC}, {FCC5_FCCA, CTL_FCC, CTL_FCC}, {FCC6_FCCA, CTL_FCC, CTL_FCC}, @@ -179,6 +184,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, @@ -188,9 +194,11 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC1_FCCA, CTL_FCC, CTL_FCC}, {APL1_WORLD, CTL_FCC, CTL_ETSI}, {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_FCCA, CTL_FCC, CTL_FCC}, {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL13_WORLD, CTL_ETSI, CTL_ETSI}, {APL6_WORLD, CTL_ETSI, CTL_ETSI}, {APL8_WORLD, CTL_ETSI, CTL_ETSI}, {APL9_WORLD, CTL_ETSI, CTL_ETSI}, @@ -298,6 +306,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, {CTRY_BARBADOS, FCC2_WORLD, "BB"}, @@ -305,6 +314,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM"}, {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, @@ -444,6 +454,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, {CTRY_SINGAPORE, APL6_WORLD, "SG"}, {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, @@ -455,10 +466,12 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ"}, {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UGANDA, FCC3_WORLD, "UG"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"}, {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 0e254f073ca1af507aea2c754523b9c5ad3477cb..cc8bfbc4b76a1e15624325f0f7d351a0cddbe11d 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -61,7 +61,7 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(1, 0), CHAN60G(2, 0), CHAN60G(3, 0), -/* channel 4 not supported yet */ + CHAN60G(4, 0), }; enum wil_nl_60g_cmd_type { @@ -107,6 +107,26 @@ struct wil_nl_60g_debug_force_wmi { u32 enable; } __packed; +static int wil_num_supported_channels(struct wil6210_priv *wil) +{ + int num_channels = ARRAY_SIZE(wil_60ghz_channels); + + if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities)) + num_channels--; + + return num_channels; +} + +void update_supported_bands(struct wil6210_priv *wil) +{ + struct wiphy *wiphy = wil_to_wiphy(wil); + + wil_dbg_misc(wil, "update supported bands"); + + wiphy->bands[NL80211_BAND_60GHZ]->n_channels = + wil_num_supported_channels(wil); +} + /* Vendor id to be used in vendor specific command and events * to user space. * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, @@ -943,11 +963,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, wil_dbg_misc(wil, "scan: wdev=0x%p iftype=%d\n", wdev, wdev->iftype); - /* check we are client side */ + /* scan is supported on client interfaces and on AP interface */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_DEVICE: + case NL80211_IFTYPE_AP: break; default: return -EOPNOTSUPP; @@ -1353,18 +1374,51 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, int rc; bool tx_status; - /* Note, currently we do not support the "wait" parameter, user-space - * must call remain_on_channel before mgmt_tx or listen on a channel - * another way (AP/PCP or connected station) - * in addition we need to check if specified "chan" argument is - * different from currently "listened" channel and fail if it is. + wil_dbg_misc(wil, "mgmt_tx: channel %d offchan %d, wait %d\n", + params->chan ? params->chan->hw_value : -1, + params->offchan, + params->wait); + + /* Note, currently we support the "wait" parameter only on AP mode. + * In other modes, user-space must call remain_on_channel before + * mgmt_tx or listen on a channel other than active one. */ - rc = wmi_mgmt_tx(vif, buf, len); - tx_status = (rc == 0); + if (params->chan && params->chan->hw_value == 0) { + wil_err(wil, "invalid channel\n"); + return -EINVAL; + } + if (wdev->iftype != NL80211_IFTYPE_AP) { + wil_dbg_misc(wil, + "send WMI_SW_TX_REQ_CMDID on non-AP interfaces\n"); + rc = wmi_mgmt_tx(vif, buf, len); + goto out; + } + + if (!params->chan || params->chan->hw_value == vif->channel) { + wil_dbg_misc(wil, + "send WMI_SW_TX_REQ_CMDID for on-channel\n"); + rc = wmi_mgmt_tx(vif, buf, len); + goto out; + } + + if (params->offchan == 0) { + wil_err(wil, + "invalid channel params: current %d requested %d, off-channel not allowed\n", + vif->channel, params->chan->hw_value); + return -EBUSY; + } + + /* use the wmi_mgmt_tx_ext only on AP mode and off-channel */ + rc = wmi_mgmt_tx_ext(vif, buf, len, params->chan->hw_value, + params->wait); + +out: + tx_status = (rc == 0); cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, tx_status, GFP_KERNEL); + return rc; } diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index ed43d955a2b7cfb26d3f2c7cbddbca45cb618444..bb7a7fdfa75506a7ca95808117b03215fec134bf 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1433,7 +1433,7 @@ static const struct file_operations fops_ssid = { }; /*---------temp------------*/ -static void print_temp(struct seq_file *s, const char *prefix, u32 t) +static void print_temp(struct seq_file *s, const char *prefix, s32 t) { switch (t) { case 0: @@ -1441,7 +1441,8 @@ static void print_temp(struct seq_file *s, const char *prefix, u32 t) seq_printf(s, "%s N/A\n", prefix); break; default: - seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000); + seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""), + abs(t / 1000), abs(t % 1000)); break; } } @@ -1449,7 +1450,7 @@ static void print_temp(struct seq_file *s, const char *prefix, u32 t) static int wil_temp_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - u32 t_m, t_r; + s32 t_m, t_r; int rc = wmi_get_temperature(wil, &t_m, &t_r); if (rc) { @@ -1840,6 +1841,343 @@ static const struct file_operations fops_mids = { .llseek = seq_lseek, }; +static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data) +__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) +{ + struct wil6210_priv *wil = s->private; + int i, bin; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + u8 aid = 0; + u8 mid; + + if (!p->tx_latency_bins) + continue; + + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + aid = p->aid; + break; + } + mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; + seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, + mid, aid); + + if (p->status == wil_sta_connected) { + u64 num_packets = 0; + u64 tx_latency_avg = p->stats.tx_latency_total_us; + + seq_puts(s, "Tx/Latency bin:"); + for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) { + seq_printf(s, " %lld", + p->tx_latency_bins[bin]); + num_packets += p->tx_latency_bins[bin]; + } + seq_puts(s, "\n"); + if (!num_packets) + continue; + do_div(tx_latency_avg, num_packets); + seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d", + p->stats.tx_latency_min_us, + tx_latency_avg, + p->stats.tx_latency_max_us); + + seq_puts(s, "\n"); + } + } + + return 0; +} + +static int wil_tx_latency_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_tx_latency_debugfs_show, + inode->i_private); +} + +static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct wil6210_priv *wil = s->private; + int val, rc, i; + bool enable; + + rc = kstrtoint_from_user(buf, len, 0, &val); + if (rc) { + wil_err(wil, "Invalid argument\n"); + return rc; + } + if (val == 1) + /* default resolution */ + val = 500; + if (val && (val < 50 || val > 1000)) { + wil_err(wil, "Invalid resolution %d\n", val); + return -EINVAL; + } + + enable = !!val; + if (wil->tx_latency == enable) + return len; + + wil_info(wil, "%s TX latency measurements (resolution %dusec)\n", + enable ? "Enabling" : "Disabling", val); + + if (enable) { + size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS; + + wil->tx_latency_res = val; + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *sta = &wil->sta[i]; + + kfree(sta->tx_latency_bins); + sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL); + if (!sta->tx_latency_bins) + return -ENOMEM; + sta->stats.tx_latency_min_us = U32_MAX; + sta->stats.tx_latency_max_us = 0; + sta->stats.tx_latency_total_us = 0; + } + } + wil->tx_latency = enable; + + return len; +} + +static const struct file_operations fops_tx_latency = { + .open = wil_tx_latency_seq_open, + .release = single_release, + .read = seq_read, + .write = wil_tx_latency_write, + .llseek = seq_lseek, +}; + +static void wil_link_stats_print_basic(struct wil6210_vif *vif, + struct seq_file *s, + struct wmi_link_stats_basic *basic) +{ + char per[5] = "?"; + + if (basic->per_average != 0xff) + snprintf(per, sizeof(per), "%d%%", basic->per_average); + + seq_printf(s, "CID %d {\n" + "\tTxMCS %d TxTpt %d\n" + "\tGoodput(rx:tx) %d:%d\n" + "\tRxBcastFrames %d\n" + "\tRSSI %d SQI %d SNR %d PER %s\n" + "\tRx RFC %d Ant num %d\n" + "\tSectors(rx:tx) my %d:%d peer %d:%d\n" + "}\n", + basic->cid, + basic->bf_mcs, le32_to_cpu(basic->tx_tpt), + le32_to_cpu(basic->rx_goodput), + le32_to_cpu(basic->tx_goodput), + le32_to_cpu(basic->rx_bcast_frames), + basic->rssi, basic->sqi, basic->snr, per, + basic->selected_rfc, basic->rx_effective_ant_num, + basic->my_rx_sector, basic->my_tx_sector, + basic->other_rx_sector, basic->other_tx_sector); +} + +static void wil_link_stats_print_global(struct wil6210_priv *wil, + struct seq_file *s, + struct wmi_link_stats_global *global) +{ + seq_printf(s, "Frames(rx:tx) %d:%d\n" + "BA Frames(rx:tx) %d:%d\n" + "Beacons %d\n" + "Rx Errors (MIC:CRC) %d:%d\n" + "Tx Errors (no ack) %d\n", + le32_to_cpu(global->rx_frames), + le32_to_cpu(global->tx_frames), + le32_to_cpu(global->rx_ba_frames), + le32_to_cpu(global->tx_ba_frames), + le32_to_cpu(global->tx_beacons), + le32_to_cpu(global->rx_mic_errors), + le32_to_cpu(global->rx_crc_errors), + le32_to_cpu(global->tx_fail_no_ack)); +} + +static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif, + struct seq_file *s) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wmi_link_stats_basic *stats; + int i; + + if (!vif->fw_stats_ready) { + seq_puts(s, "no statistics\n"); + return; + } + + seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf); + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if (wil->sta[i].status == wil_sta_unused) + continue; + if (wil->sta[i].mid != vif->mid) + continue; + + stats = &wil->sta[i].fw_stats_basic; + wil_link_stats_print_basic(vif, s, stats); + } +} + +static int wil_link_stats_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct wil6210_vif *vif; + int i, rc; + + rc = mutex_lock_interruptible(&wil->vif_mutex); + if (rc) + return rc; + + /* iterate over all MIDs and show per-cid statistics. Then show the + * global statistics + */ + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + + seq_printf(s, "MID %d ", i); + if (!vif) { + seq_puts(s, "unused\n"); + continue; + } + + wil_link_stats_debugfs_show_vif(vif, s); + } + + mutex_unlock(&wil->vif_mutex); + + return 0; +} + +static int wil_link_stats_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_link_stats_debugfs_show, inode->i_private); +} + +static ssize_t wil_link_stats_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct wil6210_priv *wil = s->private; + int cid, interval, rc, i; + struct wil6210_vif *vif; + char *kbuf = kmalloc(len + 1, GFP_KERNEL); + + if (!kbuf) + return -ENOMEM; + + rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); + if (rc != len) { + kfree(kbuf); + return rc >= 0 ? -EIO : rc; + } + + kbuf[len] = '\0'; + /* specify cid (use -1 for all cids) and snapshot interval in ms */ + rc = sscanf(kbuf, "%d %d", &cid, &interval); + kfree(kbuf); + if (rc < 0) + return rc; + if (rc < 2 || interval < 0) + return -EINVAL; + + wil_info(wil, "request link statistics, cid %d interval %d\n", + cid, interval); + + rc = mutex_lock_interruptible(&wil->vif_mutex); + if (rc) + return rc; + + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (!vif) + continue; + + rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC, + (cid == -1 ? 0xff : cid), interval); + if (rc) + wil_err(wil, "link statistics failed for mid %d\n", i); + } + mutex_unlock(&wil->vif_mutex); + + return len; +} + +static const struct file_operations fops_link_stats = { + .open = wil_link_stats_seq_open, + .release = single_release, + .read = seq_read, + .write = wil_link_stats_write, + .llseek = seq_lseek, +}; + +static int +wil_link_stats_global_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + + if (!wil->fw_stats_global.ready) + return 0; + + seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf); + wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats); + + return 0; +} + +static int +wil_link_stats_global_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_link_stats_global_debugfs_show, + inode->i_private); +} + +static ssize_t +wil_link_stats_global_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct wil6210_priv *wil = s->private; + int interval, rc; + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + + /* specify snapshot interval in ms */ + rc = kstrtoint_from_user(buf, len, 0, &interval); + if (rc || interval < 0) { + wil_err(wil, "Invalid argument\n"); + return -EINVAL; + } + + wil_info(wil, "request global link stats, interval %d\n", interval); + + rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval); + if (rc) + wil_err(wil, "global link stats failed %d\n", rc); + + return rc ? rc : len; +} + +static const struct file_operations fops_link_stats_global = { + .open = wil_link_stats_global_seq_open, + .release = single_release, + .read = seq_read, + .write = wil_link_stats_global_write, + .llseek = seq_lseek, +}; + static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2174,6 +2512,9 @@ static const struct { {"srings", 0444, &fops_srings}, {"status_msg", 0444, &fops_status_msg}, {"rx_buff_mgmt", 0444, &fops_rx_buff_mgmt}, + {"tx_latency", 0644, &fops_tx_latency}, + {"link_stats", 0644, &fops_link_stats}, + {"link_stats_global", 0644, &fops_link_stats_global}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -2292,10 +2633,14 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) void wil6210_debugfs_remove(struct wil6210_priv *wil) { + int i; + debugfs_remove_recursive(wil->debug); wil->debug = NULL; kfree(wil->dbg_data.data_arr); + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) + kfree(wil->sta[i].tx_latency_bins); /* free pmc memory without sending command to fw, as it will * be reset on the way down anyway diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 30c42a7d5555f5f060672230598dfc12f7d43575..d749ed8d3bcf47df83dd953792f305846ba7bff2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -281,6 +281,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } /* statistics */ memset(&sta->stats, 0, sizeof(sta->stats)); + sta->stats.tx_latency_min_us = U32_MAX; } static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) @@ -1133,6 +1134,9 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wiphy->max_sched_scan_plans = WMI_MAX_PLANS_NUM; } + if (test_bit(WMI_FW_CAPABILITY_TX_REQ_EXT, wil->fw_capabilities)) + wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX; + if (wil->platform_ops.set_features) { features = (test_bit(WMI_FW_CAPABILITY_REF_CLOCK_CONTROL, wil->fw_capabilities) && @@ -1154,6 +1158,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wil->max_agg_wsize = WIL_MAX_AGG_WSIZE; wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE; } + + update_supported_bands(wil); } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) @@ -1330,7 +1336,7 @@ static int wil_get_otp_info(struct wil6210_priv *wil) static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { - ulong to = msecs_to_jiffies(1000); + ulong to = msecs_to_jiffies(2000); ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); if (0 == left) { diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b6c0fb59258d3a391a01405a18a831f15a7dbfd3..7020e5f48578572adfebcbbcd3ca344730a4105b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1735,6 +1735,11 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, */ wmb(); + if (wil->tx_latency) + *(ktime_t *)&skb->cb = ktime_get(); + else + memset(skb->cb, 0, sizeof(ktime_t)); + wil_w(wil, vring->hwtail, vring->swhead); return 0; @@ -1886,6 +1891,11 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, */ wmb(); + if (wil->tx_latency) + *(ktime_t *)&skb->cb = ktime_get(); + else + memset(skb->cb, 0, sizeof(ktime_t)); + wil_w(wil, ring->hwtail, ring->swhead); return 0; @@ -2108,6 +2118,31 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } +void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb, + struct wil_sta_info *sta) +{ + int skb_time_us; + int bin; + + if (!wil->tx_latency) + return; + + if (ktime_to_ms(*(ktime_t *)&skb->cb) == 0) + return; + + skb_time_us = ktime_us_delta(ktime_get(), *(ktime_t *)&skb->cb); + bin = skb_time_us / wil->tx_latency_res; + bin = min_t(int, bin, WIL_NUM_LATENCY_BINS - 1); + + wil_dbg_txrx(wil, "skb time %dus => bin %d\n", skb_time_us, bin); + sta->tx_latency_bins[bin]++; + sta->stats.tx_latency_total_us += skb_time_us; + if (skb_time_us < sta->stats.tx_latency_min_us) + sta->stats.tx_latency_min_us = skb_time_us; + if (skb_time_us > sta->stats.tx_latency_max_us) + sta->stats.tx_latency_max_us = skb_time_us; +} + /** * Clean up transmitted skb's from the Tx VRING * @@ -2194,6 +2229,9 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid) if (stats) { stats->tx_packets++; stats->tx_bytes += skb->len; + + wil_tx_latency_calc(wil, skb, + &wil->sta[cid]); } } else { ndev->stats.tx_errors++; diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 3dfd7f91613729a611fd9b8ec5b43203e01f205b..9d83be4818399c8779ab3cafc9da4759d594b316 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -620,5 +620,7 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *r); void wil_tx_data_init(struct wil_ring_tx_data *txdata); void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil); +void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb, + struct wil_sta_info *sta); #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index e9a1a50ee79843248df671698352408aeb7d2637..e44629f56b51609cbb61f4883642fa223df94c2b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -1230,6 +1230,9 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, if (stats) { stats->tx_packets++; stats->tx_bytes += skb->len; + + wil_tx_latency_calc(wil, skb, + &wil->sta[cid]); } } else { ndev->stats.tx_errors++; @@ -1480,6 +1483,11 @@ static int __wil_tx_ring_tso_edma(struct wil6210_priv *wil, */ wmb(); + if (wil->tx_latency) + *(ktime_t *)&skb->cb = ktime_get(); + else + memset(skb->cb, 0, sizeof(ktime_t)); + wil_w(wil, ring->hwtail, ring->swhead); return 0; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 3f0909df541c230818ee9bc00edab33f01a32d3a..e03ab272daa848f71e6f8b169919e8d0c59cdfd0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -62,6 +62,8 @@ union wil_tx_desc; #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ +#define WIL_NUM_LATENCY_BINS 200 + /* maximum number of virtual interfaces the driver supports * (including the main interface) */ @@ -562,6 +564,9 @@ struct wil_net_stats { unsigned long rx_bytes; unsigned long tx_bytes; unsigned long tx_errors; + u32 tx_latency_min_us; + u32 tx_latency_max_us; + u64 tx_latency_total_us; unsigned long rx_dropped; unsigned long rx_non_data_frame; unsigned long rx_short_frame; @@ -723,6 +728,14 @@ struct wil_sta_info { u8 mid; enum wil_sta_status status; struct wil_net_stats stats; + /** + * 20 latency bins. 1st bin counts packets with latency + * of 0..tx_latency_res, last bin counts packets with latency + * of 19*tx_latency_res and above. + * tx_latency_res is configured from "tx_latency" debug-fs. + */ + u64 *tx_latency_bins; + struct wmi_link_stats_basic fw_stats_basic; /* Rx BACK */ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; spinlock_t tid_rx_lock; /* guarding tid_rx array */ @@ -840,6 +853,8 @@ struct wil6210_vif { struct mutex probe_client_mutex; /* protect @probe_client_pending */ struct work_struct probe_client_worker; int net_queue_stopped; /* netif_tx_stop_all_queues invoked */ + bool fw_stats_ready; /* per-cid statistics are ready inside sta_info */ + u64 fw_stats_tsf; /* measurement timestamp */ }; /** @@ -867,6 +882,12 @@ struct wil_rx_buff_mgmt { unsigned long free_list_empty_cnt; /* statistics */ }; +struct wil_fw_stats_global { + bool ready; + u64 tsf; /* measurement timestamp */ + struct wmi_link_stats_global stats; +}; + struct wil6210_priv { struct pci_dev *pdev; u32 bar_size; @@ -960,6 +981,8 @@ struct wil6210_priv { struct wil_suspend_stats suspend_stats; struct wil_debugfs_data dbg_data; u8 force_edmg_channel; + bool tx_latency; /* collect TX latency measurements */ + size_t tx_latency_res; /* bin resolution in usec */ void *platform_handle; struct wil_platform_ops platform_ops; @@ -1021,6 +1044,8 @@ struct wil6210_priv { u32 max_agg_wsize; u32 max_ampdu_size; + + struct wil_fw_stats_global fw_stats_global; }; #define wil_to_wiphy(i) (i->wiphy) @@ -1226,6 +1251,7 @@ int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data); int wmi_port_allocate(struct wil6210_priv *wil, u8 mid, const u8 *mac, enum nl80211_iftype iftype); int wmi_port_delete(struct wil6210_priv *wil, u8 mid); +int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval); int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl); @@ -1380,6 +1406,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len); +int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, + u8 channel, u16 duration_ms); int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch); int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch); @@ -1399,4 +1427,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout); +void update_supported_bands(struct wil6210_priv *wil); + #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 0212c17c0343cbcd6a394c8eec946c93848e215f..ba0efb11687693c43fc94e1d6be94e749110163f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -465,6 +465,10 @@ static const char *cmdid2name(u16 cmdid) return "WMI_BCAST_DESC_RING_ADD_CMD"; case WMI_CFG_DEF_RX_OFFLOAD_CMDID: return "WMI_CFG_DEF_RX_OFFLOAD_CMD"; + case WMI_LINK_STATS_CMDID: + return "WMI_LINK_STATS_CMD"; + case WMI_SW_TX_REQ_EXT_CMDID: + return "WMI_SW_TX_REQ_EXT_CMDID"; default: return "Untracked CMD"; } @@ -599,6 +603,10 @@ static const char *eventid2name(u16 eventid) return "WMI_RX_DESC_RING_CFG_DONE_EVENT"; case WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID: return "WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENT"; + case WMI_LINK_STATS_CONFIG_DONE_EVENTID: + return "WMI_LINK_STATS_CONFIG_DONE_EVENT"; + case WMI_LINK_STATS_EVENTID: + return "WMI_LINK_STATS_EVENT"; default: return "Untracked EVENT"; } @@ -1372,6 +1380,130 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len) cfg80211_sched_scan_results(wiphy, 0); } +static void wil_link_stats_store_basic(struct wil6210_vif *vif, + struct wmi_link_stats_basic *basic) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + u8 cid = basic->cid; + struct wil_sta_info *sta; + + if (cid < 0 || cid >= WIL6210_MAX_CID) { + wil_err(wil, "invalid cid %d\n", cid); + return; + } + + sta = &wil->sta[cid]; + sta->fw_stats_basic = *basic; +} + +static void wil_link_stats_store_global(struct wil6210_vif *vif, + struct wmi_link_stats_global *global) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + + wil->fw_stats_global.stats = *global; +} + +static void wmi_link_stats_parse(struct wil6210_vif *vif, u64 tsf, + bool has_next, void *payload, + size_t payload_size) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + size_t hdr_size = sizeof(struct wmi_link_stats_record); + size_t stats_size, record_size, expected_size; + struct wmi_link_stats_record *hdr; + + if (payload_size < hdr_size) { + wil_err(wil, "link stats wrong event size %zu\n", payload_size); + return; + } + + while (payload_size >= hdr_size) { + hdr = payload; + stats_size = le16_to_cpu(hdr->record_size); + record_size = hdr_size + stats_size; + + if (payload_size < record_size) { + wil_err(wil, "link stats payload ended unexpectedly, size %zu < %zu\n", + payload_size, record_size); + return; + } + + switch (hdr->record_type_id) { + case WMI_LINK_STATS_TYPE_BASIC: + expected_size = sizeof(struct wmi_link_stats_basic); + if (stats_size < expected_size) { + wil_err(wil, "link stats invalid basic record size %zu < %zu\n", + stats_size, expected_size); + return; + } + if (vif->fw_stats_ready) { + /* clean old statistics */ + vif->fw_stats_tsf = 0; + vif->fw_stats_ready = 0; + } + + wil_link_stats_store_basic(vif, payload + hdr_size); + + if (!has_next) { + vif->fw_stats_tsf = tsf; + vif->fw_stats_ready = 1; + } + + break; + case WMI_LINK_STATS_TYPE_GLOBAL: + expected_size = sizeof(struct wmi_link_stats_global); + if (stats_size < sizeof(struct wmi_link_stats_global)) { + wil_err(wil, "link stats invalid global record size %zu < %zu\n", + stats_size, expected_size); + return; + } + + if (wil->fw_stats_global.ready) { + /* clean old statistics */ + wil->fw_stats_global.tsf = 0; + wil->fw_stats_global.ready = 0; + } + + wil_link_stats_store_global(vif, payload + hdr_size); + + if (!has_next) { + wil->fw_stats_global.tsf = tsf; + wil->fw_stats_global.ready = 1; + } + + break; + default: + break; + } + + /* skip to next record */ + payload += record_size; + payload_size -= record_size; + } +} + +static void +wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wmi_link_stats_event *evt = d; + size_t payload_size; + + if (len < offsetof(struct wmi_link_stats_event, payload)) { + wil_err(wil, "stats event way too short %d\n", len); + return; + } + payload_size = le16_to_cpu(evt->payload_size); + if (len < sizeof(struct wmi_link_stats_event) + payload_size) { + wil_err(wil, "stats event too short %d\n", len); + return; + } + + wmi_link_stats_parse(vif, le64_to_cpu(evt->tsf), evt->has_next, + evt->payload, payload_size); +} + /** * Some events are ignored for purpose; and need not be interpreted as * "unhandled events" @@ -1409,6 +1541,7 @@ static const struct { {WMI_TOF_FTM_PER_DEST_RES_EVENTID, wmi_evt_per_dest_res}, {WMI_TOF_CHANNEL_INFO_EVENTID, wmi_evt_ignore}, {WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result}, + {WMI_LINK_STATS_EVENTID, wmi_evt_link_stats}, }; /* @@ -3199,6 +3332,60 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len) return rc; } +int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, + u8 channel, u16 duration_ms) +{ + size_t total; + struct wil6210_priv *wil = vif_to_wil(vif); + struct ieee80211_mgmt *mgmt_frame = (void *)buf; + struct wmi_sw_tx_req_ext_cmd *cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_sw_tx_complete_event evt; + } __packed evt = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + int rc; + + wil_dbg_wmi(wil, "mgmt_tx_ext mid %d channel %d duration %d\n", + vif->mid, channel, duration_ms); + wil_hex_dump_wmi("mgmt_tx_ext frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, + len, true); + + if (len < sizeof(struct ieee80211_hdr_3addr)) { + wil_err(wil, "short frame. len %zu\n", len); + return -EINVAL; + } + + total = sizeof(*cmd) + len; + if (total < len) { + wil_err(wil, "mgmt_tx_ext invalid len %zu\n", len); + return -EINVAL; + } + + cmd = kzalloc(total, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); + cmd->len = cpu_to_le16(len); + memcpy(cmd->payload, buf, len); + cmd->channel = channel - 1; + cmd->duration_ms = cpu_to_le16(duration_ms); + + rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total, + WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); + if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "mgmt_tx_ext failed with status %d\n", + evt.evt.status); + rc = -EINVAL; + } + + kfree(cmd); + + return rc; +} + int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id) { int rc; @@ -3453,3 +3640,37 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id) return 0; } + +int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wmi_link_stats_cmd cmd = { + .record_type_mask = cpu_to_le32(type), + .cid = cid, + .action = WMI_LINK_STATS_SNAPSHOT, + .interval_msec = cpu_to_le32(interval), + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_link_stats_config_done_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + int rc; + + rc = wmi_call(wil, WMI_LINK_STATS_CMDID, vif->mid, &cmd, sizeof(cmd), + WMI_LINK_STATS_CONFIG_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_LINK_STATS_CMDID failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "Link statistics config failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index b198a1f809d9ce24b748e8f9525374c17d5b8c63..c07fca09818f5361990bdb1b0f63b41a993b741a 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -53,6 +53,17 @@ * must always be kept equal to (WMI_RF_RX2TX_LENGTH+1) */ #define WMI_RF_RX2TX_CONF_LENGTH (4) +/* Qos configuration */ +#define WMI_QOS_NUM_OF_PRIORITY (4) +#define WMI_QOS_MIN_DEFAULT_WEIGHT (10) +#define WMI_QOS_VRING_SLOT_MIN_MS (2) +#define WMI_QOS_VRING_SLOT_MAX_MS (10) +/* (WMI_QOS_MIN_DEFAULT_WEIGHT * WMI_QOS_VRING_SLOT_MAX_MS / + * WMI_QOS_VRING_SLOT_MIN_MS) + */ +#define WMI_QOS_MAX_WEIGHT 50 +#define WMI_QOS_SET_VIF_PRIORITY (0xFF) +#define WMI_QOS_DEFAULT_PRIORITY (WMI_QOS_NUM_OF_PRIORITY) /* Mailbox interface * used for commands and events @@ -88,8 +99,13 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_CHANNEL_BONDING = 17, WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18, WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19, + WMI_FW_CAPABILITY_MULTI_VIFS = 20, + WMI_FW_CAPABILITY_FT_ROAMING = 21, WMI_FW_CAPABILITY_BACK_WIN_SIZE_64 = 22, WMI_FW_CAPABILITY_AMSDU = 23, + WMI_FW_CAPABILITY_RAW_MODE = 24, + WMI_FW_CAPABILITY_TX_REQ_EXT = 25, + WMI_FW_CAPABILITY_CHANNEL_4 = 26, WMI_FW_CAPABILITY_MAX, }; @@ -113,6 +129,9 @@ enum wmi_command_id { WMI_SET_PROBED_SSID_CMDID = 0x0A, /* deprecated */ WMI_SET_LISTEN_INT_CMDID = 0x0B, + WMI_FT_AUTH_CMDID = 0x0C, + WMI_FT_REASSOC_CMDID = 0x0D, + WMI_UPDATE_FT_IES_CMDID = 0x0E, WMI_BCON_CTRL_CMDID = 0x0F, WMI_ADD_CIPHER_KEY_CMDID = 0x16, WMI_DELETE_CIPHER_KEY_CMDID = 0x17, @@ -121,6 +140,12 @@ enum wmi_command_id { WMI_SET_WSC_STATUS_CMDID = 0x41, WMI_PXMT_RANGE_CFG_CMDID = 0x42, WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43, + WMI_RADAR_GENERAL_CONFIG_CMDID = 0x100, + WMI_RADAR_CONFIG_SELECT_CMDID = 0x101, + WMI_RADAR_PARAMS_CONFIG_CMDID = 0x102, + WMI_RADAR_SET_MODE_CMDID = 0x103, + WMI_RADAR_CONTROL_CMDID = 0x104, + WMI_RADAR_PCI_CONTROL_CMDID = 0x105, WMI_MEM_READ_CMDID = 0x800, WMI_MEM_WR_CMDID = 0x801, WMI_ECHO_CMDID = 0x803, @@ -161,6 +186,10 @@ enum wmi_command_id { WMI_SET_PCP_CHANNEL_CMDID = 0x829, WMI_GET_PCP_CHANNEL_CMDID = 0x82A, WMI_SW_TX_REQ_CMDID = 0x82B, + /* Event is shared between WMI_SW_TX_REQ_CMDID and + * WMI_SW_TX_REQ_EXT_CMDID + */ + WMI_SW_TX_REQ_EXT_CMDID = 0x82C, WMI_MLME_PUSH_CMDID = 0x835, WMI_BEAMFORMING_MGMT_CMDID = 0x836, WMI_BF_TXSS_MGMT_CMDID = 0x837, @@ -210,7 +239,12 @@ enum wmi_command_id { WMI_GET_PCP_FACTOR_CMDID = 0x91B, /* Power Save Configuration Commands */ WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C, + WMI_RS_ENABLE_CMDID = 0x91E, + WMI_RS_CFG_EX_CMDID = 0x91F, + WMI_GET_DETAILED_RS_RES_EX_CMDID = 0x920, + /* deprecated */ WMI_RS_CFG_CMDID = 0x921, + /* deprecated */ WMI_GET_DETAILED_RS_RES_CMDID = 0x922, WMI_AOA_MEAS_CMDID = 0x923, WMI_BRP_SET_ANT_LIMIT_CMDID = 0x924, @@ -239,7 +273,9 @@ enum wmi_command_id { WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, + /* deprecated */ WMI_BF_CONTROL_CMDID = 0x9AA, + WMI_BF_CONTROL_EX_CMDID = 0x9AB, WMI_TX_STATUS_RING_ADD_CMDID = 0x9C0, WMI_RX_STATUS_RING_ADD_CMDID = 0x9C1, WMI_TX_DESC_RING_ADD_CMDID = 0x9C2, @@ -255,6 +291,11 @@ enum wmi_command_id { WMI_GET_CCA_INDICATIONS_CMDID = 0xA07, WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_CMDID = 0xA08, WMI_INTERNAL_FW_IOCTL_CMDID = 0xA0B, + WMI_LINK_STATS_CMDID = 0xA0C, + WMI_SET_GRANT_MCS_CMDID = 0xA0E, + WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F, + WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10, + WMI_SET_VRING_PRIORITY_CMDID = 0xA11, WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_ABORT_SCAN_CMDID = 0xF007, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, @@ -470,6 +511,30 @@ struct wmi_start_sched_scan_cmd { struct wmi_sched_scan_plan scan_plans[WMI_MAX_PLANS_NUM]; } __packed; +/* WMI_FT_AUTH_CMDID */ +struct wmi_ft_auth_cmd { + u8 bssid[WMI_MAC_LEN]; + /* enum wmi_channel */ + u8 channel; + /* enum wmi_channel */ + u8 edmg_channel; + u8 reserved[4]; +} __packed; + +/* WMI_FT_REASSOC_CMDID */ +struct wmi_ft_reassoc_cmd { + u8 bssid[WMI_MAC_LEN]; + u8 reserved[2]; +} __packed; + +/* WMI_UPDATE_FT_IES_CMDID */ +struct wmi_update_ft_ies_cmd { + /* Length of the FT IEs */ + __le16 ie_len; + u8 reserved[2]; + u8 ie_info[0]; +} __packed; + /* WMI_SET_PROBED_SSID_CMDID */ #define MAX_PROBED_SSID_INDEX (3) @@ -526,6 +591,109 @@ struct wmi_pxmt_snr2_range_cfg_cmd { s8 snr2range_arr[2]; } __packed; +/* WMI_RADAR_GENERAL_CONFIG_CMDID */ +struct wmi_radar_general_config_cmd { + /* Number of pulses (CIRs) in FW FIFO to initiate pulses transfer + * from FW to Host + */ + __le32 fifo_watermark; + /* In unit of us, in the range [100, 1000000] */ + __le32 t_burst; + /* Valid in the range [1, 32768], 0xFFFF means infinite */ + __le32 n_bursts; + /* In unit of 330Mhz clk, in the range [4, 2000]*330 */ + __le32 t_pulse; + /* In the range of [1,4096] */ + __le16 n_pulses; + /* Number of taps after cTap per CIR */ + __le16 n_samples; + /* Offset from the main tap (0 = zero-distance). In the range of [0, + * 255] + */ + u8 first_sample_offset; + /* Number of Pulses to average, 1, 2, 4, 8 */ + u8 pulses_to_avg; + /* Number of adjacent taps to average, 1, 2, 4, 8 */ + u8 samples_to_avg; + /* The index to config general params */ + u8 general_index; + u8 reserved[4]; +} __packed; + +/* WMI_RADAR_CONFIG_SELECT_CMDID */ +struct wmi_radar_config_select_cmd { + /* Select the general params index to use */ + u8 general_index; + u8 reserved[3]; + /* 0 means don't update burst_active_vector */ + __le32 burst_active_vector; + /* 0 means don't update pulse_active_vector */ + __le32 pulse_active_vector; +} __packed; + +/* WMI_RADAR_PARAMS_CONFIG_CMDID */ +struct wmi_radar_params_config_cmd { + /* The burst index selected to config */ + u8 burst_index; + /* 0-not active, 1-active */ + u8 burst_en; + /* The pulse index selected to config */ + u8 pulse_index; + /* 0-not active, 1-active */ + u8 pulse_en; + /* TX RF to use on current pulse */ + u8 tx_rfc_idx; + u8 tx_sector; + /* Offset from calibrated value.(expected to be 0)(value is row in + * Gain-LUT, not dB) + */ + s8 tx_rf_gain_comp; + /* expected to be 0 */ + s8 tx_bb_gain_comp; + /* RX RF to use on current pulse */ + u8 rx_rfc_idx; + u8 rx_sector; + /* Offset from calibrated value.(expected to be 0)(value is row in + * Gain-LUT, not dB) + */ + s8 rx_rf_gain_comp; + /* Value in dB.(expected to be 0) */ + s8 rx_bb_gain_comp; + /* Offset from calibrated value.(expected to be 0) */ + s8 rx_timing_offset; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_SET_MODE_CMDID */ +struct wmi_radar_set_mode_cmd { + /* 0-disable/1-enable */ + u8 enable; + /* enum wmi_channel */ + u8 channel; + /* In the range of [0,7], 0xff means use default */ + u8 tx_rfc_idx; + /* In the range of [0,7], 0xff means use default */ + u8 rx_rfc_idx; +} __packed; + +/* WMI_RADAR_CONTROL_CMDID */ +struct wmi_radar_control_cmd { + /* 0-stop/1-start */ + u8 start; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_PCI_CONTROL_CMDID */ +struct wmi_radar_pci_control_cmd { + /* pcie host buffer start address */ + __le64 base_addr; + /* pcie host control block address */ + __le64 control_block_addr; + /* pcie host buffer size */ + __le32 buffer_size; + __le32 reserved; +} __packed; + /* WMI_RF_MGMT_CMDID */ enum wmi_rf_mgmt_type { WMI_RF_MGMT_W_DISABLE = 0x00, @@ -665,7 +833,8 @@ struct wmi_pcp_start_cmd { u8 is_go; /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */ u8 edmg_channel; - u8 reserved[4]; + u8 raw_mode; + u8 reserved[3]; /* A-BFT length override if non-0 */ u8 abft_len; /* enum wmi_ap_sme_offload_mode_e */ @@ -686,6 +855,17 @@ struct wmi_sw_tx_req_cmd { u8 payload[0]; } __packed; +/* WMI_SW_TX_REQ_EXT_CMDID */ +struct wmi_sw_tx_req_ext_cmd { + u8 dst_mac[WMI_MAC_LEN]; + __le16 len; + __le16 duration_ms; + /* Channel to use, 0xFF for currently active channel */ + u8 channel; + u8 reserved[5]; + u8 payload[0]; +} __packed; + /* WMI_VRING_SWITCH_TIMING_CONFIG_CMDID */ struct wmi_vring_switch_timing_config_cmd { /* Set vring timing configuration: @@ -712,6 +892,7 @@ struct wmi_vring_cfg_schd { enum wmi_vring_cfg_encap_trans_type { WMI_VRING_ENC_TYPE_802_3 = 0x00, WMI_VRING_ENC_TYPE_NATIVE_WIFI = 0x01, + WMI_VRING_ENC_TYPE_NONE = 0x02, }; enum wmi_vring_cfg_ds_cfg { @@ -769,7 +950,11 @@ struct wmi_vring_cfg { u8 cid; /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ u8 tid; - u8 reserved[2]; + /* Update the vring's priority for Qos purpose. Set to + * WMI_QOS_DEFAULT_PRIORITY to use MID's QoS priority + */ + u8 qos_priority; + u8 reserved; } __packed; enum wmi_vring_cfg_cmd_action { @@ -800,20 +985,6 @@ struct wmi_bcast_vring_cfg_cmd { struct wmi_bcast_vring_cfg vring_cfg; } __packed; -/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */ -struct wmi_lo_power_calib_from_otp_cmd { - /* index to read from OTP. zero based */ - u8 index; - u8 reserved[3]; -} __packed; - -/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */ -struct wmi_lo_power_calib_from_otp_event { - /* wmi_fw_status */ - u8 status; - u8 reserved[3]; -} __packed; - struct wmi_edma_ring_cfg { __le64 ring_mem_base; /* size in number of items */ @@ -886,6 +1057,20 @@ struct wmi_bcast_desc_ring_add_cmd { u8 reserved[4]; } __packed; +/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */ +struct wmi_lo_power_calib_from_otp_cmd { + /* index to read from OTP. zero based */ + u8 index; + u8 reserved[3]; +} __packed; + +/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */ +struct wmi_lo_power_calib_from_otp_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_RING_BA_EN_CMDID */ struct wmi_ring_ba_en_cmd { u8 ring_id; @@ -1119,8 +1304,8 @@ struct wmi_echo_cmd { } __packed; /* WMI_DEEP_ECHO_CMDID - * Check FW and ucode are alive - * Returned event: WMI_ECHO_RSP_EVENTID + * Check FW and uCode is alive + * Returned event: WMI_DEEP_ECHO_RSP_EVENTID */ struct wmi_deep_echo_cmd { __le32 value; @@ -1444,6 +1629,10 @@ struct wmi_fixed_scheduling_config_complete_event { u8 reserved[3]; } __packed; +/* This value exists for backwards compatibility only. + * Do not use it in new commands. + * Use dynamic arrays where possible. + */ #define WMI_NUM_MCS (13) /* WMI_FIXED_SCHEDULING_CONFIG_CMDID */ @@ -1491,6 +1680,52 @@ struct wmi_set_multi_directed_omnis_config_event { u8 reserved[3]; } __packed; +/* WMI_RADAR_GENERAL_CONFIG_EVENTID */ +struct wmi_radar_general_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_CONFIG_SELECT_EVENTID */ +struct wmi_radar_config_select_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; + /* In unit of bytes */ + __le32 fifo_size; + /* In unit of bytes */ + __le32 pulse_size; +} __packed; + +/* WMI_RADAR_PARAMS_CONFIG_EVENTID */ +struct wmi_radar_params_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_SET_MODE_EVENTID */ +struct wmi_radar_set_mode_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_CONTROL_EVENTID */ +struct wmi_radar_control_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_PCI_CONTROL_EVENTID */ +struct wmi_radar_pci_control_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_SET_LONG_RANGE_CONFIG_CMDID */ struct wmi_set_long_range_config_cmd { __le32 reserved; @@ -1503,12 +1738,12 @@ struct wmi_set_long_range_config_complete_event { u8 reserved[3]; } __packed; -/* payload max size is 236 bytes: max event buffer size (256) - WMI headers +/* payload max size is 1024 bytes: max event buffer size (1044) - WMI headers * (16) - prev struct field size (4) */ -#define WMI_MAX_IOCTL_PAYLOAD_SIZE (236) -#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (236) -#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (236) +#define WMI_MAX_IOCTL_PAYLOAD_SIZE (1024) +#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (1024) +#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (1024) enum wmi_internal_fw_ioctl_code { WMI_INTERNAL_FW_CODE_NONE = 0x0, @@ -1548,7 +1783,37 @@ struct wmi_internal_fw_event_event { __le32 payload[0]; } __packed; -/* WMI_BF_CONTROL_CMDID */ +/* WMI_SET_VRING_PRIORITY_WEIGHT_CMDID */ +struct wmi_set_vring_priority_weight_cmd { + /* Array of weights. Valid values are + * WMI_QOS_MIN_DEFAULT_WEIGHT...WMI_QOS_MAX_WEIGHT. Weight #0 is + * hard-coded WMI_QOS_MIN_WEIGHT. This array provide the weights + * #1..#3 + */ + u8 weight[3]; + u8 reserved; +} __packed; + +/* WMI_SET_VRING_PRIORITY_CMDID */ +struct wmi_vring_priority { + u8 vring_idx; + /* Weight index. Valid value is 0-3 */ + u8 priority; + u8 reserved[2]; +} __packed; + +/* WMI_SET_VRING_PRIORITY_CMDID */ +struct wmi_set_vring_priority_cmd { + /* number of entries in vring_priority. Set to + * WMI_QOS_SET_VIF_PRIORITY to update the VIF's priority, and there + * will be only one entry in vring_priority + */ + u8 num_of_vrings; + u8 reserved[3]; + struct wmi_vring_priority vring_priority[0]; +} __packed; + +/* WMI_BF_CONTROL_CMDID - deprecated */ struct wmi_bf_control_cmd { /* wmi_bf_triggers */ __le32 triggers; @@ -1590,6 +1855,95 @@ struct wmi_bf_control_cmd { u8 reserved2[2]; } __packed; +/* BF configuration for each MCS */ +struct wmi_bf_control_ex_mcs { + /* Long term throughput threshold [Mbps] */ + u8 long_term_mbps_th_tbl; + u8 reserved; + /* Long term timeout threshold table [msec] */ + __le16 long_term_trig_timeout_per_mcs; +} __packed; + +/* WMI_BF_CONTROL_EX_CMDID */ +struct wmi_bf_control_ex_cmd { + /* wmi_bf_triggers */ + __le32 triggers; + /* enum wmi_edmg_tx_mode */ + u8 tx_mode; + /* DISABLED = 0, ENABLED = 1 , DRY_RUN = 2 */ + u8 txss_mode; + /* DISABLED = 0, ENABLED = 1, DRY_RUN = 2 */ + u8 brp_mode; + /* Max cts threshold (correspond to + * WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP) + */ + u8 bf_trigger_max_cts_failure_thr; + /* Max cts threshold in dense (correspond to + * WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP) + */ + u8 bf_trigger_max_cts_failure_dense_thr; + /* Max b-ack threshold (correspond to + * WMI_BF_TRIGGER_MAX_BACK_FAILURE) + */ + u8 bf_trigger_max_back_failure_thr; + /* Max b-ack threshold in dense (correspond to + * WMI_BF_TRIGGER_MAX_BACK_FAILURE) + */ + u8 bf_trigger_max_back_failure_dense_thr; + u8 reserved0; + /* Wrong sectors threshold */ + __le32 wrong_sector_bis_thr; + /* BOOL to enable/disable long term trigger */ + u8 long_term_enable; + /* 1 = Update long term thresholds from the long_term_mbps_th_tbl and + * long_term_trig_timeout_per_mcs arrays, 0 = Ignore + */ + u8 long_term_update_thr; + u8 each_mcs_cfg_size; + u8 reserved1; + /* Configuration for each MCS */ + struct wmi_bf_control_ex_mcs each_mcs_cfg[0]; +} __packed; + +/* WMI_LINK_STATS_CMD */ +enum wmi_link_stats_action { + WMI_LINK_STATS_SNAPSHOT = 0x00, + WMI_LINK_STATS_PERIODIC = 0x01, + WMI_LINK_STATS_STOP_PERIODIC = 0x02, +}; + +/* WMI_LINK_STATS_EVENT record identifiers */ +enum wmi_link_stats_record_type { + WMI_LINK_STATS_TYPE_BASIC = 0x01, + WMI_LINK_STATS_TYPE_GLOBAL = 0x02, +}; + +/* WMI_LINK_STATS_CMDID */ +struct wmi_link_stats_cmd { + /* bitmask of required record types + * (wmi_link_stats_record_type_e) + */ + __le32 record_type_mask; + /* 0xff for all cids */ + u8 cid; + /* wmi_link_stats_action_e */ + u8 action; + u8 reserved[6]; + /* range = 100 - 10000 */ + __le32 interval_msec; +} __packed; + +/* WMI_SET_GRANT_MCS_CMDID */ +struct wmi_set_grant_mcs_cmd { + u8 mcs; + u8 reserved[3]; +} __packed; + +/* WMI_SET_AP_SLOT_SIZE_CMDID */ +struct wmi_set_ap_slot_size_cmd { + __le32 slot_size; +} __packed; + /* WMI Events * List of Events (target to host) */ @@ -1602,10 +1956,19 @@ enum wmi_event_id { WMI_SCHED_SCAN_RESULT_EVENTID = 0x1007, WMI_SCAN_COMPLETE_EVENTID = 0x100A, WMI_REPORT_STATISTICS_EVENTID = 0x100B, + WMI_FT_AUTH_STATUS_EVENTID = 0x100C, + WMI_FT_REASSOC_STATUS_EVENTID = 0x100D, + WMI_RADAR_GENERAL_CONFIG_EVENTID = 0x1100, + WMI_RADAR_CONFIG_SELECT_EVENTID = 0x1101, + WMI_RADAR_PARAMS_CONFIG_EVENTID = 0x1102, + WMI_RADAR_SET_MODE_EVENTID = 0x1103, + WMI_RADAR_CONTROL_EVENTID = 0x1104, + WMI_RADAR_PCI_CONTROL_EVENTID = 0x1105, WMI_RD_MEM_RSP_EVENTID = 0x1800, WMI_FW_READY_EVENTID = 0x1801, WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, WMI_ECHO_RSP_EVENTID = 0x1803, + WMI_DEEP_ECHO_RSP_EVENTID = 0x1804, /* deprecated */ WMI_FS_TUNE_DONE_EVENTID = 0x180A, /* deprecated */ @@ -1631,6 +1994,9 @@ enum wmi_event_id { WMI_DELBA_EVENTID = 0x1826, WMI_GET_SSID_EVENTID = 0x1828, WMI_GET_PCP_CHANNEL_EVENTID = 0x182A, + /* Event is shared between WMI_SW_TX_REQ_CMDID and + * WMI_SW_TX_REQ_EXT_CMDID + */ WMI_SW_TX_COMPLETE_EVENTID = 0x182B, WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, @@ -1678,7 +2044,12 @@ enum wmi_event_id { WMI_PCP_FACTOR_EVENTID = 0x191A, /* Power Save Configuration Events */ WMI_PS_DEV_PROFILE_CFG_EVENTID = 0x191C, + WMI_RS_ENABLE_EVENTID = 0x191E, + WMI_RS_CFG_EX_EVENTID = 0x191F, + WMI_GET_DETAILED_RS_RES_EX_EVENTID = 0x1920, + /* deprecated */ WMI_RS_CFG_DONE_EVENTID = 0x1921, + /* deprecated */ WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922, WMI_AOA_MEAS_EVENTID = 0x1923, WMI_BRP_SET_ANT_LIMIT_EVENTID = 0x1924, @@ -1706,7 +2077,9 @@ enum wmi_event_id { WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, + /* deprecated */ WMI_BF_CONTROL_EVENTID = 0x19AA, + WMI_BF_CONTROL_EX_EVENTID = 0x19AB, WMI_TX_STATUS_RING_CFG_DONE_EVENTID = 0x19C0, WMI_RX_STATUS_RING_CFG_DONE_EVENTID = 0x19C1, WMI_TX_DESC_RING_CFG_DONE_EVENTID = 0x19C2, @@ -1722,6 +2095,12 @@ enum wmi_event_id { WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_EVENTID = 0x1A08, WMI_INTERNAL_FW_EVENT_EVENTID = 0x1A0A, WMI_INTERNAL_FW_IOCTL_EVENTID = 0x1A0B, + WMI_LINK_STATS_CONFIG_DONE_EVENTID = 0x1A0C, + WMI_LINK_STATS_EVENTID = 0x1A0D, + WMI_SET_GRANT_MCS_EVENTID = 0x1A0E, + WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F, + WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10, + WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, @@ -1990,6 +2369,33 @@ struct wmi_scan_complete_event { __le32 status; } __packed; +/* WMI_FT_AUTH_STATUS_EVENTID */ +struct wmi_ft_auth_status_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; + u8 mac_addr[WMI_MAC_LEN]; + __le16 ie_len; + u8 ie_info[0]; +} __packed; + +/* WMI_FT_REASSOC_STATUS_EVENTID */ +struct wmi_ft_reassoc_status_event { + /* enum wmi_fw_status */ + u8 status; + /* association id received from new AP */ + u8 aid; + /* enum wmi_channel */ + u8 channel; + /* enum wmi_channel */ + u8 edmg_channel; + u8 mac_addr[WMI_MAC_LEN]; + __le16 beacon_ie_len; + __le16 reassoc_req_ie_len; + __le16 reassoc_resp_ie_len; + u8 ie_info[0]; +} __packed; + /* wmi_rx_mgmt_info */ struct wmi_rx_mgmt_info { u8 mcs; @@ -2346,6 +2752,11 @@ struct wmi_echo_rsp_event { __le32 echoed_value; } __packed; +/* WMI_DEEP_ECHO_RSP_EVENTID */ +struct wmi_deep_echo_rsp_event { + __le32 echoed_value; +} __packed; + /* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */ struct wmi_rf_pwr_on_delay_rsp_event { /* wmi_fw_status */ @@ -2484,6 +2895,81 @@ struct wmi_rs_cfg { __le32 mcs_en_vec; } __packed; +enum wmi_edmg_tx_mode { + WMI_TX_MODE_DMG = 0x0, + WMI_TX_MODE_EDMG_CB1 = 0x1, + WMI_TX_MODE_EDMG_CB2 = 0x2, + WMI_TX_MODE_EDMG_CB1_LONG_LDPC = 0x3, + WMI_TX_MODE_EDMG_CB2_LONG_LDPC = 0x4, + WMI_TX_MODE_MAX, +}; + +/* Rate search parameters common configuration */ +struct wmi_rs_cfg_ex_common { + /* enum wmi_edmg_tx_mode */ + u8 mode; + /* stop threshold [0-100] */ + u8 stop_th; + /* MCS1 stop threshold [0-100] */ + u8 mcs1_fail_th; + u8 max_back_failure_th; + /* Debug feature for disabling internal RS trigger (which is + * currently triggered by BF Done) + */ + u8 dbg_disable_internal_trigger; + u8 reserved[3]; + __le32 back_failure_mask; +} __packed; + +/* Rate search parameters configuration per MCS */ +struct wmi_rs_cfg_ex_mcs { + /* The maximal allowed PER for each MCS + * MCS will be considered as failed if PER during RS is higher + */ + u8 per_threshold; + /* Number of MPDUs for each MCS + * this is the minimal statistic required to make an educated + * decision + */ + u8 min_frame_cnt; + u8 reserved[2]; +} __packed; + +/* WMI_RS_CFG_EX_CMDID */ +struct wmi_rs_cfg_ex_cmd { + /* Configuration for all MCSs */ + struct wmi_rs_cfg_ex_common common_cfg; + u8 each_mcs_cfg_size; + u8 reserved[3]; + /* Configuration for each MCS */ + struct wmi_rs_cfg_ex_mcs each_mcs_cfg[0]; +} __packed; + +/* WMI_RS_CFG_EX_EVENTID */ +struct wmi_rs_cfg_ex_event { + /* enum wmi_edmg_tx_mode */ + u8 mode; + /* enum wmi_fw_status */ + u8 status; + u8 reserved[2]; +} __packed; + +/* WMI_RS_ENABLE_CMDID */ +struct wmi_rs_enable_cmd { + u8 cid; + /* enable or disable rate search */ + u8 rs_enable; + u8 reserved[2]; + __le32 mcs_en_vec; +} __packed; + +/* WMI_RS_ENABLE_EVENTID */ +struct wmi_rs_enable_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* Slot types */ enum wmi_sched_scheme_slot_type { WMI_SCHED_SLOT_SP = 0x0, @@ -2576,7 +3062,7 @@ struct wmi_scheduling_scheme_event { u8 reserved[1]; } __packed; -/* WMI_RS_CFG_CMDID */ +/* WMI_RS_CFG_CMDID - deprecated */ struct wmi_rs_cfg_cmd { /* connection id */ u8 cid; @@ -2586,7 +3072,7 @@ struct wmi_rs_cfg_cmd { struct wmi_rs_cfg rs_cfg; } __packed; -/* WMI_RS_CFG_DONE_EVENTID */ +/* WMI_RS_CFG_DONE_EVENTID - deprecated */ struct wmi_rs_cfg_done_event { u8 cid; /* enum wmi_fw_status */ @@ -2594,7 +3080,7 @@ struct wmi_rs_cfg_done_event { u8 reserved[2]; } __packed; -/* WMI_GET_DETAILED_RS_RES_CMDID */ +/* WMI_GET_DETAILED_RS_RES_CMDID - deprecated */ struct wmi_get_detailed_rs_res_cmd { /* connection id */ u8 cid; @@ -2619,7 +3105,7 @@ struct wmi_rs_results { u8 mcs; } __packed; -/* WMI_GET_DETAILED_RS_RES_EVENTID */ +/* WMI_GET_DETAILED_RS_RES_EVENTID - deprecated */ struct wmi_get_detailed_rs_res_event { u8 cid; /* enum wmi_rs_results_status */ @@ -2629,6 +3115,45 @@ struct wmi_get_detailed_rs_res_event { u8 reserved[3]; } __packed; +/* WMI_GET_DETAILED_RS_RES_EX_CMDID */ +struct wmi_get_detailed_rs_res_ex_cmd { + u8 cid; + u8 reserved[3]; +} __packed; + +/* Rate search results */ +struct wmi_rs_results_ex_common { + /* RS timestamp */ + __le32 tsf; + /* RS selected MCS */ + u8 mcs; + /* enum wmi_edmg_tx_mode */ + u8 mode; + u8 reserved[2]; +} __packed; + +/* Rate search results */ +struct wmi_rs_results_ex_mcs { + /* number of sent MPDUs */ + u8 num_of_tx_pkt; + /* number of non-acked MPDUs */ + u8 num_of_non_acked_pkt; + u8 reserved[2]; +} __packed; + +/* WMI_GET_DETAILED_RS_RES_EX_EVENTID */ +struct wmi_get_detailed_rs_res_ex_event { + u8 cid; + /* enum wmi_rs_results_status */ + u8 status; + u8 reserved0[2]; + struct wmi_rs_results_ex_common common_rs_results; + u8 each_mcs_results_size; + u8 reserved1[3]; + /* Results for each MCS */ + struct wmi_rs_results_ex_mcs each_mcs_results[0]; +} __packed; + /* BRP antenna limit mode */ enum wmi_brp_ant_limit_mode { /* Disable BRP force antenna limit */ @@ -3379,13 +3904,20 @@ struct wmi_get_assoc_list_res_event { u8 reserved[3]; } __packed; -/* WMI_BF_CONTROL_EVENTID */ +/* WMI_BF_CONTROL_EVENTID - deprecated */ struct wmi_bf_control_event { /* wmi_fw_status */ u8 status; u8 reserved[3]; } __packed; +/* WMI_BF_CONTROL_EX_EVENTID */ +struct wmi_bf_control_ex_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_COMMAND_NOT_SUPPORTED_EVENTID */ struct wmi_command_not_supported_event { /* device id */ @@ -3455,4 +3987,96 @@ struct wmi_internal_fw_set_channel_event { u8 reserved[3]; } __packed; +/* WMI_LINK_STATS_CONFIG_DONE_EVENTID */ +struct wmi_link_stats_config_done_event { + /* wmi_fw_status_e */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_LINK_STATS_EVENTID */ +struct wmi_link_stats_event { + __le64 tsf; + __le16 payload_size; + u8 has_next; + u8 reserved[5]; + /* a stream of wmi_link_stats_record_s */ + u8 payload[0]; +} __packed; + +/* WMI_LINK_STATS_EVENT */ +struct wmi_link_stats_record { + /* wmi_link_stats_record_type_e */ + u8 record_type_id; + u8 reserved; + __le16 record_size; + u8 record[0]; +} __packed; + +/* WMI_LINK_STATS_TYPE_BASIC */ +struct wmi_link_stats_basic { + u8 cid; + s8 rssi; + u8 sqi; + u8 bf_mcs; + u8 per_average; + u8 selected_rfc; + u8 rx_effective_ant_num; + u8 my_rx_sector; + u8 my_tx_sector; + u8 other_rx_sector; + u8 other_tx_sector; + u8 reserved[7]; + /* 1/4 Db units */ + __le16 snr; + __le32 tx_tpt; + __le32 tx_goodput; + __le32 rx_goodput; + __le32 bf_count; + __le32 rx_bcast_frames; +} __packed; + +/* WMI_LINK_STATS_TYPE_GLOBAL */ +struct wmi_link_stats_global { + /* all ack-able frames */ + __le32 rx_frames; + /* all ack-able frames */ + __le32 tx_frames; + __le32 rx_ba_frames; + __le32 tx_ba_frames; + __le32 tx_beacons; + __le32 rx_mic_errors; + __le32 rx_crc_errors; + __le32 tx_fail_no_ack; + u8 reserved[8]; +} __packed; + +/* WMI_SET_GRANT_MCS_EVENTID */ +struct wmi_set_grant_mcs_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_AP_SLOT_SIZE_EVENTID */ +struct wmi_set_ap_slot_size_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID */ +struct wmi_set_vring_priority_weight_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_VRING_PRIORITY_EVENTID */ +struct wmi_set_vring_priority_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + #endif /* __WILOCITY_WMI_H__ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index cd587325e2867915165d278e89174594d0b6b02b..dd6e27513cc1bb8395a7b79b9e391c10bcec79f2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1098,6 +1098,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 73da5e63a609296816414b9069bb6154cc55efe0..2c80c722fecad3f5b43b7f7ae8f26a037e4ee43a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -177,6 +177,17 @@ const struct iwl_cfg iwl9260_2ac_cfg = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwl9260_killer_2ac_cfg = { + .name = "Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW)", + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + const struct iwl_cfg iwl9270_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9270", .fw_name_pre = IWL9260A_FW_PRE, @@ -266,6 +277,34 @@ const struct iwl_cfg iwl9560_2ac_cfg_soc = { .soc_latency = 5000, }; +const struct iwl_cfg iwl9560_killer_2ac_cfg_soc = { + .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, +}; + +const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc = { + .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, +}; + const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = { .name = "Intel(R) Dual Band Wireless AC 9460", .fw_name_pre = IWL9000A_FW_PRE, @@ -326,6 +365,36 @@ const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = { .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK }; +const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk = { + .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9560_killer_s_2ac_cfg_shared_clk = { + .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 85fe1a928adc961b3ccfcf160ab209d4e2ad637c..70f3c327eb4abc3bc3ea03973aacb56d8ac19794 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -470,6 +470,7 @@ extern const struct iwl_cfg iwl8265_2ac_sdio_cfg; extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; extern const struct iwl_cfg iwl9160_2ac_cfg; extern const struct iwl_cfg iwl9260_2ac_cfg; +extern const struct iwl_cfg iwl9260_killer_2ac_cfg; extern const struct iwl_cfg iwl9270_2ac_cfg; extern const struct iwl_cfg iwl9460_2ac_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg; @@ -477,10 +478,14 @@ extern const struct iwl_cfg iwl9460_2ac_cfg_soc; extern const struct iwl_cfg iwl9461_2ac_cfg_soc; extern const struct iwl_cfg iwl9462_2ac_cfg_soc; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; +extern const struct iwl_cfg iwl9560_killer_2ac_cfg_soc; +extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc; extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_shared_clk; extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 9a8605abb00a99da41ed36638e32f4a16a363bba..4cbc6cb8bf89e979a5f00227c98c8e879d95aeb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -543,6 +543,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x1550, iwl9260_killer_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_cfg_soc)}, @@ -552,6 +555,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, @@ -576,6 +580,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2720, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)}, @@ -602,6 +608,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x30DC, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x30DC, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -628,6 +636,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x31DC, 0x1030, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x1551, iwl9560_killer_s_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x1552, iwl9560_killer_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)}, @@ -654,6 +664,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x34F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -680,6 +692,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x3DF0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -706,6 +720,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x43F0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x43F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -741,6 +757,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x9DF0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_cfg_soc)}, @@ -769,6 +787,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA0F0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -795,6 +815,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA370, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)}, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a06b6612b6583d6b5efa1d2396bc2060a2ffa37f..ca99c3cf41c21b8b400bae2e8874c45f29365bbd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -901,6 +901,8 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans) } def_rxq = trans_pcie->rxq; + cancel_work_sync(&rba->rx_alloc); + spin_lock(&rba->lock); atomic_set(&rba->req_pending, 0); atomic_set(&rba->req_ready, 0); diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index f4f2b9b27e3269a4c36f9ab462baad462ad330b2..50890cab8807bf81282ce817edde16a9ac969836 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -644,6 +644,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); mwifiex_dbg(adapter, FATAL, diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 0cd68ffc2c74dc1c849e8011b84208ebf74a6730..51ccf10f44132eeff9bdc9c347664b37f0e93a22 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -708,12 +708,14 @@ void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, s8 nflr) { struct mwifiex_histogram_data *phist_data = priv->hist_data; + s8 nf = -nflr; + s8 rssi = snr - nflr; atomic_inc(&phist_data->num_samples); atomic_inc(&phist_data->rx_rate[rx_rate]); - atomic_inc(&phist_data->snr[snr]); - atomic_inc(&phist_data->noise_flr[128 + nflr]); - atomic_inc(&phist_data->sig_str[nflr - snr]); + atomic_inc(&phist_data->snr[snr + 128]); + atomic_inc(&phist_data->noise_flr[nf + 128]); + atomic_inc(&phist_data->sig_str[rssi + 128]); } /* function to reset histogram data during init/reset */ diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 93256f8bc0b536627c6bde4ab499778bfc7c9c8b..ec82c1c3f12e419642ffddcb9ad06b60571d25cc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -483,18 +483,21 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) } -void rtl_deinit_deferred_work(struct ieee80211_hw *hw) +void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq) { struct rtl_priv *rtlpriv = rtl_priv(hw); del_timer_sync(&rtlpriv->works.watchdog_timer); - cancel_delayed_work(&rtlpriv->works.watchdog_wq); - cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); - cancel_delayed_work(&rtlpriv->works.ps_work); - cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); - cancel_delayed_work(&rtlpriv->works.fwevt_wq); - cancel_delayed_work(&rtlpriv->works.c2hcmd_wq); + cancel_delayed_work_sync(&rtlpriv->works.watchdog_wq); + if (ips_wq) + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + else + cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work_sync(&rtlpriv->works.ps_work); + cancel_delayed_work_sync(&rtlpriv->works.ps_rfon_wq); + cancel_delayed_work_sync(&rtlpriv->works.fwevt_wq); + cancel_delayed_work_sync(&rtlpriv->works.c2hcmd_wq); } EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work); diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index b56d1b7f556730c695ad9b665692936468655d6a..cbbb5be36a096bdb1b3655dedd111aa5ec5ef7d6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -121,7 +121,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw); void rtl_deinit_rfkill(struct ieee80211_hw *hw); void rtl_watch_dog_timer_callback(unsigned long data); -void rtl_deinit_deferred_work(struct ieee80211_hw *hw); +void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index c53cbf3d52bdd960a44f7be0d49a5f067ac80560..b01123138797dda5ad439d78a0c0a59445695d7d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -130,7 +130,6 @@ static void rtl_fw_do_work(const struct firmware *firmware, void *context, firmware->size); rtlpriv->rtlhal.wowlan_fwsize = firmware->size; } - rtlpriv->rtlhal.fwsize = firmware->size; release_firmware(firmware); } @@ -196,7 +195,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw) /* reset sec info */ rtl_cam_reset_sec_info(hw); - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, false); } rtlpriv->intf_ops->adapter_stop(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index d7331225c5f3df1d9a018cf796acb52d50fa47b6..457a0f725c8aa598c14ea80b38e6d4a6d4183c48 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2359,7 +2359,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev) ieee80211_unregister_hw(hw); rtlmac->mac80211_registered = 0; } else { - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, false); rtlpriv->intf_ops->adapter_stop(hw); } rtlpriv->cfg->ops->disable_interrupt(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 07ee3096f50e25f2a6cc264c9341982277f1017a..f6d00613c53d9f1a5bfcb332f82cb4b9a27c0cf5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -66,7 +66,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); /*<1> Stop all timer */ - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, true); /*<2> Disable Interrupt */ rtlpriv->cfg->ops->disable_interrupt(hw); @@ -287,7 +287,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); enum rf_pwrstate rtstate; - cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq); spin_lock(&rtlpriv->locks.ips_lock); if (ppsc->inactiveps) { diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 5590d07d0918bf7015874bd27b061c097509c068..820c42ff53841bb920e3ad43152997e353844600 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1150,7 +1150,7 @@ void rtl_usb_disconnect(struct usb_interface *intf) ieee80211_unregister_hw(hw); rtlmac->mac80211_registered = 0; } else { - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, false); rtlpriv->intf_ops->adapter_stop(hw); } /*deinit rfkill */ diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 070dfd68bb836281890e70a18ca9bed8f9cd7770..120b0ff545c176410998d13149b0616c9d928a5a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -557,28 +557,32 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, u32 content_size) { struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; - struct bl_header bl_hdr; + struct bl_header *bl_hdr; u32 write_addr, write_len; int status; - bl_hdr.flags = 0; - bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode); - bl_hdr.check_sum = cpu_to_le32( - *(u32 *)&flash_content[CHECK_SUM_OFFSET]); - bl_hdr.flash_start_address = cpu_to_le32( - *(u32 *)&flash_content[ADDR_OFFSET]); - bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); + bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL); + if (!bl_hdr) + return -ENOMEM; + + bl_hdr->flags = 0; + bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode); + bl_hdr->check_sum = + cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]); + bl_hdr->flash_start_address = + cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]); + bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); write_len = sizeof(struct bl_header); if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { write_addr = PING_BUFFER_ADDRESS; status = hif_ops->write_reg_multiple(adapter, write_addr, - (u8 *)&bl_hdr, write_len); + (u8 *)bl_hdr, write_len); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to load Version/CRC structure\n", __func__); - return status; + goto fail; } } else { write_addr = PING_BUFFER_ADDRESS >> 16; @@ -587,20 +591,23 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return status; + goto fail; } write_addr = RSI_SD_REQUEST_MASTER | (PING_BUFFER_ADDRESS & 0xFFFF); status = hif_ops->write_reg_multiple(adapter, write_addr, - (u8 *)&bl_hdr, write_len); + (u8 *)bl_hdr, write_len); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to load Version/CRC structure\n", __func__); - return status; + goto fail; } } - return 0; + status = 0; +fail: + kfree(bl_hdr); + return status; } static u32 read_flash_capacity(struct rsi_hw *adapter) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 370161ca2a1c34097cd8e1fd0f1b0502b2d842ee..0362967874aac45f19ff0cff9a68b9cf69d70d8e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -161,7 +161,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) int err; struct mmc_card *card = pfunction->card; struct mmc_host *host = card->host; - s32 bit = (fls(host->ocr_avail) - 1); u8 cmd52_resp; u32 clock, resp, i; u16 rca; @@ -181,7 +180,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) msleep(20); /* Initialize the SDIO card */ - host->ios.vdd = bit; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; @@ -970,17 +968,21 @@ static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, /*This function resets and re-initializes the chip.*/ static void rsi_reset_chip(struct rsi_hw *adapter) { - __le32 data; + u8 *data; u8 sdio_interrupt_status = 0; u8 request = 1; int ret; + data = kzalloc(sizeof(u32), GFP_KERNEL); + if (!data) + return; + rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n"); ret = rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request); if (ret < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to write SDIO wakeup register\n", __func__); - return; + goto err; } msleep(20); ret = rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER, @@ -988,7 +990,7 @@ static void rsi_reset_chip(struct rsi_hw *adapter) if (ret < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", __func__); - return; + goto err; } rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n", __func__, sdio_interrupt_status); @@ -998,17 +1000,17 @@ static void rsi_reset_chip(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return; + goto err; } - data = TA_HOLD_THREAD_VALUE; + put_unaligned_le32(TA_HOLD_THREAD_VALUE, data); if (rsi_sdio_write_register_multiple(adapter, TA_HOLD_THREAD_REG | RSI_SD_REQUEST_MASTER, - (u8 *)&data, 4)) { + data, 4)) { rsi_dbg(ERR_ZONE, "%s: Unable to hold Thread-Arch processor threads\n", __func__); - return; + goto err; } /* This msleep will ensure Thread-Arch processor to go to hold @@ -1029,6 +1031,9 @@ static void rsi_reset_chip(struct rsi_hw *adapter) * read write operations to complete for chip reset. */ msleep(500); +err: + kfree(data); + return; } /** diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 90339203920016dfc4fc90c8d8d2aa979ee18c27..6788fbbdd166e5aa77c8ff5597868ac81b0d6590 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -85,7 +85,7 @@ enum sdio_interrupt_type { #define TA_SOFT_RST_CLR 0 #define TA_SOFT_RST_SET BIT(0) #define TA_PC_ZERO 0 -#define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF) +#define TA_HOLD_THREAD_VALUE 0xF #define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) #define TA_BASE_ADDR 0x2200 #define MISC_CFG_BASE_ADDR 0x4105 diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index f8a1fea64e2567c6b368e2fc93a667b1a9bbb0ae..219d1a86b92ecb3f48491ab8034ef62e74790d38 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -406,6 +406,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f07b9c9bb5ba8155ec959d441e2c4af9ec40095f..dfc076f9ee4b582ada02f5a946fcef18ae91d2ad 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -87,6 +87,7 @@ struct netfront_cb { /* IRQ name is queue name with "-tx" or "-rx" appended */ #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3) +static DECLARE_WAIT_QUEUE_HEAD(module_load_q); static DECLARE_WAIT_QUEUE_HEAD(module_unload_q); struct netfront_stats { @@ -239,7 +240,7 @@ static void rx_refill_timeout(unsigned long data) static int netfront_tx_slot_available(struct netfront_queue *queue) { return (queue->tx.req_prod_pvt - queue->tx.rsp_cons) < - (NET_TX_RING_SIZE - MAX_SKB_FRAGS - 2); + (NET_TX_RING_SIZE - XEN_NETIF_NR_SLOTS_MIN - 1); } static void xennet_maybe_wake_tx(struct netfront_queue *queue) @@ -790,7 +791,7 @@ static int xennet_get_responses(struct netfront_queue *queue, RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *skb = xennet_get_rx_skb(queue, cons); grant_ref_t ref = xennet_get_rx_ref(queue, cons); - int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD); + int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD); int slots = 1; int err = 0; unsigned long ret; @@ -1330,6 +1331,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); xenbus_switch_state(dev, XenbusStateInitialising); + wait_event(module_load_q, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown); return netdev; exit: diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 4cac4755abefc48f9d04c640944455dfa136d160..a67d037165104db83dea64ab0bf99f05ee64e8db 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -77,7 +77,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown); * Represents an NVM Express device. Each nvme_dev is a PCI function. */ struct nvme_dev { - struct nvme_queue **queues; + struct nvme_queue *queues; struct blk_mq_tag_set tagset; struct blk_mq_tag_set admin_tagset; u32 __iomem *dbs; @@ -348,7 +348,7 @@ static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, unsigned int hctx_idx) { struct nvme_dev *dev = data; - struct nvme_queue *nvmeq = dev->queues[0]; + struct nvme_queue *nvmeq = &dev->queues[0]; WARN_ON(hctx_idx != 0); WARN_ON(dev->admin_tagset.tags[0] != hctx->tags); @@ -370,7 +370,7 @@ static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, unsigned int hctx_idx) { struct nvme_dev *dev = data; - struct nvme_queue *nvmeq = dev->queues[hctx_idx + 1]; + struct nvme_queue *nvmeq = &dev->queues[hctx_idx + 1]; if (!nvmeq->tags) nvmeq->tags = &dev->tagset.tags[hctx_idx]; @@ -386,7 +386,7 @@ static int nvme_init_request(struct blk_mq_tag_set *set, struct request *req, struct nvme_dev *dev = set->driver_data; struct nvme_iod *iod = blk_mq_rq_to_pdu(req); int queue_idx = (set == &dev->tagset) ? hctx_idx + 1 : 0; - struct nvme_queue *nvmeq = dev->queues[queue_idx]; + struct nvme_queue *nvmeq = &dev->queues[queue_idx]; BUG_ON(!nvmeq); iod->nvmeq = nvmeq; @@ -900,7 +900,7 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag) static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl, int aer_idx) { struct nvme_dev *dev = to_nvme_dev(ctrl); - struct nvme_queue *nvmeq = dev->queues[0]; + struct nvme_queue *nvmeq = &dev->queues[0]; struct nvme_command c; memset(&c, 0, sizeof(c)); @@ -1146,7 +1146,6 @@ static void nvme_free_queue(struct nvme_queue *nvmeq) if (nvmeq->sq_cmds) dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), nvmeq->sq_cmds, nvmeq->sq_dma_addr); - kfree(nvmeq); } static void nvme_free_queues(struct nvme_dev *dev, int lowest) @@ -1154,10 +1153,8 @@ static void nvme_free_queues(struct nvme_dev *dev, int lowest) int i; for (i = dev->ctrl.queue_count - 1; i >= lowest; i--) { - struct nvme_queue *nvmeq = dev->queues[i]; dev->ctrl.queue_count--; - dev->queues[i] = NULL; - nvme_free_queue(nvmeq); + nvme_free_queue(&dev->queues[i]); } } @@ -1189,10 +1186,8 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown) { - struct nvme_queue *nvmeq = dev->queues[0]; + struct nvme_queue *nvmeq = &dev->queues[0]; - if (!nvmeq) - return; if (nvme_suspend_queue(nvmeq)) return; @@ -1246,13 +1241,13 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, return 0; } -static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, - int depth, int node) +static int nvme_alloc_queue(struct nvme_dev *dev, int qid, + int depth, int node) { - struct nvme_queue *nvmeq = kzalloc_node(sizeof(*nvmeq), GFP_KERNEL, - node); - if (!nvmeq) - return NULL; + struct nvme_queue *nvmeq = &dev->queues[qid]; + + if (dev->ctrl.queue_count > qid) + return 0; nvmeq->cqes = dma_zalloc_coherent(dev->dev, CQ_SIZE(depth), &nvmeq->cq_dma_addr, GFP_KERNEL); @@ -1271,17 +1266,15 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, nvmeq->q_depth = depth; nvmeq->qid = qid; nvmeq->cq_vector = -1; - dev->queues[qid] = nvmeq; dev->ctrl.queue_count++; - return nvmeq; + return 0; free_cqdma: dma_free_coherent(dev->dev, CQ_SIZE(depth), (void *)nvmeq->cqes, nvmeq->cq_dma_addr); free_nvmeq: - kfree(nvmeq); - return NULL; + return -ENOMEM; } static int queue_request_irq(struct nvme_queue *nvmeq) @@ -1468,14 +1461,12 @@ static int nvme_pci_configure_admin_queue(struct nvme_dev *dev) if (result < 0) return result; - nvmeq = dev->queues[0]; - if (!nvmeq) { - nvmeq = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH, - dev_to_node(dev->dev)); - if (!nvmeq) - return -ENOMEM; - } + result = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH, + dev_to_node(dev->dev)); + if (result) + return result; + nvmeq = &dev->queues[0]; aqa = nvmeq->q_depth - 1; aqa |= aqa << 16; @@ -1505,7 +1496,7 @@ static int nvme_create_io_queues(struct nvme_dev *dev) for (i = dev->ctrl.queue_count; i <= dev->max_qid; i++) { /* vector == qid - 1, match nvme_create_queue */ - if (!nvme_alloc_queue(dev, i, dev->q_depth, + if (nvme_alloc_queue(dev, i, dev->q_depth, pci_irq_get_node(to_pci_dev(dev->dev), i - 1))) { ret = -ENOMEM; break; @@ -1514,7 +1505,7 @@ static int nvme_create_io_queues(struct nvme_dev *dev) max = min(dev->max_qid, dev->ctrl.queue_count - 1); for (i = dev->online_queues; i <= max; i++) { - ret = nvme_create_queue(dev->queues[i], i); + ret = nvme_create_queue(&dev->queues[i], i); if (ret) break; } @@ -1770,7 +1761,7 @@ static int nvme_setup_host_mem(struct nvme_dev *dev) static int nvme_setup_io_queues(struct nvme_dev *dev) { - struct nvme_queue *adminq = dev->queues[0]; + struct nvme_queue *adminq = &dev->queues[0]; struct pci_dev *pdev = to_pci_dev(dev->dev); int result, nr_io_queues; unsigned long size; @@ -1896,7 +1887,7 @@ static void nvme_disable_io_queues(struct nvme_dev *dev, int queues) retry: timeout = ADMIN_TIMEOUT; for (; i > 0; i--, sent++) - if (nvme_delete_queue(dev->queues[i], opcode)) + if (nvme_delete_queue(&dev->queues[i], opcode)) break; while (sent--) { @@ -2081,7 +2072,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) queues = dev->online_queues - 1; for (i = dev->ctrl.queue_count - 1; i > 0; i--) - nvme_suspend_queue(dev->queues[i]); + nvme_suspend_queue(&dev->queues[i]); if (dead) { /* A device might become IO incapable very soon during @@ -2089,7 +2080,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) * queue_count can be 0 here. */ if (dev->ctrl.queue_count) - nvme_suspend_queue(dev->queues[0]); + nvme_suspend_queue(&dev->queues[0]); } else { nvme_disable_io_queues(dev, queues); nvme_disable_admin_queue(dev, shutdown); @@ -2345,7 +2336,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node); if (!dev) return -ENOMEM; - dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(void *), + + dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(struct nvme_queue), GFP_KERNEL, node); if (!dev->queues) goto free; @@ -2519,6 +2511,9 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev) static void nvme_error_resume(struct pci_dev *pdev) { + struct nvme_dev *dev = pci_get_drvdata(pdev); + + flush_work(&dev->ctrl.reset_work); pci_cleanup_aer_uncorrect_error_status(pdev); } @@ -2562,6 +2557,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_LIGHTNVM, }, { PCI_DEVICE(0x1d1d, 0x2807), /* CNEX WL */ .driver_data = NVME_QUIRK_LIGHTNVM, }, + { PCI_DEVICE(0x1d1d, 0x2601), /* CNEX Granby */ + .driver_data = NVME_QUIRK_LIGHTNVM, }, { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 93a082e0bdd4e078c978c1db62c401780fc14e62..48a831d58e7aeab2f628bb43cc9c84339f6bb5a2 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -796,7 +796,7 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, if (error) { dev_err(ctrl->ctrl.device, "prop_get NVME_REG_CAP failed\n"); - goto out_cleanup_queue; + goto out_stop_queue; } ctrl->ctrl.sqsize = @@ -804,23 +804,25 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, error = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap); if (error) - goto out_cleanup_queue; + goto out_stop_queue; ctrl->ctrl.max_hw_sectors = (ctrl->max_fr_pages - 1) << (ilog2(SZ_4K) - 9); error = nvme_init_identify(&ctrl->ctrl); if (error) - goto out_cleanup_queue; + goto out_stop_queue; error = nvme_rdma_alloc_qe(ctrl->queues[0].device->dev, &ctrl->async_event_sqe, sizeof(struct nvme_command), DMA_TO_DEVICE); if (error) - goto out_cleanup_queue; + goto out_stop_queue; return 0; +out_stop_queue: + nvme_rdma_stop_queue(&ctrl->queues[0]); out_cleanup_queue: if (new) blk_cleanup_queue(ctrl->ctrl.admin_q); diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 8e21211b904b3291faebaf82d4b02c3e31fd3f3b..b7a5d1065378db75f48766c9d5caf003f99d1256 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -58,8 +58,8 @@ struct nvmet_fc_ls_iod { struct work_struct work; } __aligned(sizeof(unsigned long long)); +/* desired maximum for a single sequence - if sg list allows it */ #define NVMET_FC_MAX_SEQ_LENGTH (256 * 1024) -#define NVMET_FC_MAX_XFR_SGENTS (NVMET_FC_MAX_SEQ_LENGTH / PAGE_SIZE) enum nvmet_fcp_datadir { NVMET_FCP_NODATA, @@ -74,6 +74,7 @@ struct nvmet_fc_fcp_iod { struct nvme_fc_cmd_iu cmdiubuf; struct nvme_fc_ersp_iu rspiubuf; dma_addr_t rspdma; + struct scatterlist *next_sg; struct scatterlist *data_sg; int data_sg_cnt; u32 total_length; @@ -1000,8 +1001,7 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, INIT_LIST_HEAD(&newrec->assoc_list); kref_init(&newrec->ref); ida_init(&newrec->assoc_cnt); - newrec->max_sg_cnt = min_t(u32, NVMET_FC_MAX_XFR_SGENTS, - template->max_sgl_segments); + newrec->max_sg_cnt = template->max_sgl_segments; ret = nvmet_fc_alloc_ls_iodlist(newrec); if (ret) { @@ -1717,6 +1717,7 @@ nvmet_fc_alloc_tgt_pgs(struct nvmet_fc_fcp_iod *fod) ((fod->io_dir == NVMET_FCP_WRITE) ? DMA_FROM_DEVICE : DMA_TO_DEVICE)); /* note: write from initiator perspective */ + fod->next_sg = fod->data_sg; return 0; @@ -1874,24 +1875,49 @@ nvmet_fc_transfer_fcp_data(struct nvmet_fc_tgtport *tgtport, struct nvmet_fc_fcp_iod *fod, u8 op) { struct nvmefc_tgt_fcp_req *fcpreq = fod->fcpreq; + struct scatterlist *sg = fod->next_sg; unsigned long flags; - u32 tlen; + u32 remaininglen = fod->total_length - fod->offset; + u32 tlen = 0; int ret; fcpreq->op = op; fcpreq->offset = fod->offset; fcpreq->timeout = NVME_FC_TGTOP_TIMEOUT_SEC; - tlen = min_t(u32, tgtport->max_sg_cnt * PAGE_SIZE, - (fod->total_length - fod->offset)); + /* + * for next sequence: + * break at a sg element boundary + * attempt to keep sequence length capped at + * NVMET_FC_MAX_SEQ_LENGTH but allow sequence to + * be longer if a single sg element is larger + * than that amount. This is done to avoid creating + * a new sg list to use for the tgtport api. + */ + fcpreq->sg = sg; + fcpreq->sg_cnt = 0; + while (tlen < remaininglen && + fcpreq->sg_cnt < tgtport->max_sg_cnt && + tlen + sg_dma_len(sg) < NVMET_FC_MAX_SEQ_LENGTH) { + fcpreq->sg_cnt++; + tlen += sg_dma_len(sg); + sg = sg_next(sg); + } + if (tlen < remaininglen && fcpreq->sg_cnt == 0) { + fcpreq->sg_cnt++; + tlen += min_t(u32, sg_dma_len(sg), remaininglen); + sg = sg_next(sg); + } + if (tlen < remaininglen) + fod->next_sg = sg; + else + fod->next_sg = NULL; + fcpreq->transfer_length = tlen; fcpreq->transferred_length = 0; fcpreq->fcp_error = 0; fcpreq->rsplen = 0; - fcpreq->sg = &fod->data_sg[fod->offset / PAGE_SIZE]; - fcpreq->sg_cnt = DIV_ROUND_UP(tlen, PAGE_SIZE); - /* * If the last READDATA request: check if LLDD supports * combined xfr with response. diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index d12e5de78e700018dc58965157b21ff2639f34c5..2afafd5d8915088de1533881247fcb67b4a8aa4e 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1049,6 +1049,8 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, /* setup the first byte with lsb bits from nvmem */ rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); + if (rc) + goto err; *b++ |= GENMASK(bit_offset - 1, 0) & v; /* setup rest of the byte if any */ @@ -1067,11 +1069,16 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, /* setup the last byte with msb bits from nvmem */ rc = nvmem_reg_read(nvmem, cell->offset + cell->bytes - 1, &v, 1); + if (rc) + goto err; *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; } return buf; +err: + kfree(buf); + return ERR_PTR(rc); } /** diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c index 5596fdedbb9471c49b4bb73fbc57b5b03170521f..ea03f1ec12a47713f3633816cb6216a92965a629 100644 --- a/drivers/pci/dwc/pci-exynos.c +++ b/drivers/pci/dwc/pci-exynos.c @@ -695,7 +695,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) return ret; } - if (ep->ops && ep->ops->get_clk_resources) { + if (ep->ops && ep->ops->get_clk_resources && + ep->ops->init_clk_resources) { ret = ep->ops->get_clk_resources(ep); if (ret) return ret; diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index caea7c618207aae6b2e7c1822ddfa55a724103fa..4523d7e1bcb9c7d66528105306bf3b688c8a1e05 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -1091,6 +1091,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) struct pci_bus *pbus; struct pci_dev *pdev; struct cpumask *dest; + unsigned long flags; struct compose_comp_ctxt comp; struct tran_int_desc *int_desc; struct { @@ -1182,14 +1183,15 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) * the channel callback directly when channel->target_cpu is * the current CPU. When the higher level interrupt code * calls us with interrupt enabled, let's add the - * local_bh_disable()/enable() to avoid race. + * local_irq_save()/restore() to avoid race: + * hv_pci_onchannelcallback() can also run in tasklet. */ - local_bh_disable(); + local_irq_save(flags); if (hbus->hdev->channel->target_cpu == smp_processor_id()) hv_pci_onchannelcallback(hbus); - local_bh_enable(); + local_irq_restore(flags); if (hpdev->state == hv_pcichild_ejecting) { dev_err_once(&hbus->hdev->device, diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index 087645116ecb222bd44a3e90eb9bcbc5e3fc25a8..c78fd9c2cf8cf672021ea28789d869ac6ee629d6 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -686,7 +686,6 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) bus = bridge->bus; - pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 05832b597e536e3db9744bc4cff9e9661bc5ee80..46c2ee2caf281680aa280f1a386f4d059d110888 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -863,6 +863,13 @@ struct controller *pcie_init(struct pcie_device *dev) if (pdev->hotplug_user_indicators) slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP); + /* + * We assume no Thunderbolt controllers support Command Complete events, + * but some controllers falsely claim they do. + */ + if (pdev->is_thunderbolt) + slot_cap |= PCI_EXP_SLTCAP_NCCS; + ctrl->slot_cap = slot_cap; mutex_init(&ctrl->ctrl_lock); init_waitqueue_head(&ctrl->queue); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a8da543b3814b312a99af0ef1f3c3ef18e089478..4708eb9df71b0ebb7548b87e4cb4238a0b900b6a 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -624,7 +624,7 @@ void acpi_pci_add_bus(struct pci_bus *bus) union acpi_object *obj; struct pci_host_bridge *bridge; - if (acpi_pci_disabled || !bus->bridge) + if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge)) return; acpi_pci_slot_enumerate(bus); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 00fa4278c1f49c22d97451759ff0708016523830..c3f0473d1afa2aacaf4729bc8887bf137d299170 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -305,13 +305,16 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!val) { - if (pci_is_enabled(pdev)) - pci_disable_device(pdev); - else - result = -EIO; - } else + device_lock(dev); + if (dev->driver) + result = -EBUSY; + else if (val) result = pci_enable_device(pdev); + else if (pci_is_enabled(pdev)) + pci_disable_device(pdev); + else + result = -EIO; + device_unlock(dev); return result < 0 ? result : count; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f285cd74088ec47151b7852341884fd685ba1c83..4bccaf688aad7c7d5ed73b89b1b4f118c0a6690b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -516,12 +516,14 @@ static void devm_pci_release_host_bridge_dev(struct device *dev) if (bridge->release_fn) bridge->release_fn(bridge); + + pci_free_resource_list(&bridge->windows); } static void pci_release_host_bridge_dev(struct device *dev) { devm_pci_release_host_bridge_dev(dev); - pci_free_host_bridge(to_pci_host_bridge(dev)); + kfree(to_pci_host_bridge(dev)); } struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c index 7203405b19b73af2e7710d5d4473e06b24af99e4..12507a0af0f0cbe4d0d3ebaacec44105fbac42e0 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,7 @@ int ufs_qcom_phy_qmp_v3_660_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); tbl_B = phy_cal_table_rate_B; - if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) { + if ((major == 0x3) && (minor == 0x001) && (step >= 0x001)) { tbl_A = phy_cal_table_rate_A_3_1_1; tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1); } else { diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index b1ca838dd80a1c2843083b9c16d532be6ce5d40d..e61e2f8c91ce862c09123b9c0f391f51fb32bf6e 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -576,8 +576,10 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, for_each_child_of_node(np_config, np) { ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); - if (ret < 0) + if (ret < 0) { + of_node_put(np); break; + } } } diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index ed11b59348fb45a0ff88e78fb39623bdf6d3ac84..fef0970abaf24687ee60b252d61176ca14f38295 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1390,6 +1390,12 @@ static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl) static int msm_gpiochip_to_irq(struct gpio_chip *chip, unsigned int offset) { struct irq_fwspec fwspec; + struct irq_domain *domain = chip->irqdomain; + int virq; + + virq = irq_find_mapping(domain, offset); + if (virq) + return virq; fwspec.fwnode = of_node_to_fwnode(chip->of_node); fwspec.param[0] = offset; diff --git a/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c b/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c index 48e20ce254be176143add7198a5d936aa601ecd5..f6e6f8aa075fb2b4d1e3399c7e2c187bc64f7445 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c +++ b/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c @@ -1440,14 +1440,14 @@ static const struct msm_pingroup sdmmagpie_groups[] = { [116] = PINGROUP(116, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), [117] = PINGROUP(117, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), [118] = PINGROUP(118, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - [119] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9a000, 15, 0), - [120] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6), - [121] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3), - [122] = SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0), - [123] = SDC_QDSD_PINGROUP(sdc2_clk, 0x98000, 14, 6), - [124] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x98000, 11, 3), - [125] = SDC_QDSD_PINGROUP(sdc2_data, 0x98000, 9, 0), - [126] = UFS_RESET(ufs_reset, 0x9f000), + [119] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x19a000, 15, 0), + [120] = SDC_QDSD_PINGROUP(sdc1_clk, 0x19a000, 13, 6), + [121] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x19a000, 11, 3), + [122] = SDC_QDSD_PINGROUP(sdc1_data, 0x19a000, 9, 0), + [123] = SDC_QDSD_PINGROUP(sdc2_clk, 0x998000, 14, 6), + [124] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x998000, 11, 3), + [125] = SDC_QDSD_PINGROUP(sdc2_data, 0x998000, 9, 0), + [126] = UFS_RESET(ufs_reset, 0x19f000), }; static struct msm_dir_conn sdmmagpie_dir_conn[] = { diff --git a/drivers/pinctrl/qcom/pinctrl-sm6150.c b/drivers/pinctrl/qcom/pinctrl-sm6150.c index 937ffde559638af6946b070b5acd51116a759cab..39448b33c79fb83a1a9c581235c5cafcdc716657 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6150.c @@ -1548,14 +1548,14 @@ static const struct msm_pingroup sm6150_groups[] = { NA, NA, NA, NA), [121] = PINGROUP(121, SOUTH, mclk1, NA, NA, NA, NA, NA, NA, NA, NA), [122] = PINGROUP(122, SOUTH, mclk2, NA, NA, NA, NA, NA, NA, NA, NA), - [123] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9a000, 15, 0), - [124] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6), - [125] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3), - [126] = SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0), - [127] = SDC_QDSD_PINGROUP(sdc2_clk, 0x98000, 14, 6), - [128] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x98000, 11, 3), - [129] = SDC_QDSD_PINGROUP(sdc2_data, 0x98000, 9, 0), - [130] = UFS_RESET(ufs_reset, 0x9f000), + [123] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x59a000, 15, 0), + [124] = SDC_QDSD_PINGROUP(sdc1_clk, 0x59a000, 13, 6), + [125] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x59a000, 11, 3), + [126] = SDC_QDSD_PINGROUP(sdc1_data, 0x59a000, 9, 0), + [127] = SDC_QDSD_PINGROUP(sdc2_clk, 0xd98000, 14, 6), + [128] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xd98000, 11, 3), + [129] = SDC_QDSD_PINGROUP(sdc2_data, 0xd98000, 9, 0), + [130] = UFS_RESET(ufs_reset, 0x59f000), }; static struct msm_dir_conn sm6150_dir_conn[] = { diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 219112d04f12ad6a589f2653665abe40a1d01e4b..34ffbe2f626c49c1c6f6c53dd5ef18cb470f04d2 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -74,6 +74,15 @@ config GSI and CPUs over various types of interfaces such as MHI, xDCI, xHCI, GPI, WDI, Ethernet, etc. +config GSI_REGISTER_VERSION_2 + bool "GSI core Version 2 Registers SWI Support" + depends on GSI + help + GSI core registers Software interface version 2 has updated + registers interface to communicate with GSI. This includes + new registers offsets, new registers fields structure and + new registers. + config IPA3 tristate "IPA3 support" select GSI diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 19cd98f9c44e1e07d052d2da06206e63c913a2ed..a31fd5c35248d26b06219c71594e9647c9ec0b1e 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -116,8 +116,7 @@ static void __gsi_config_gen_irq(int ee, uint32_t mask, uint32_t val) static void gsi_channel_state_change_wait(unsigned long chan_hdl, struct gsi_chan_ctx *ctx, - uint32_t tm, - enum gsi_chan_state next_state) + uint32_t tm) { int poll_cnt; int gsi_pending_intr; @@ -166,9 +165,6 @@ static void gsi_channel_state_change_wait(unsigned long chan_hdl, ch, ctx->state, gsi_pending_intr); - - if (ctx->state == next_state) - break; } } @@ -937,6 +933,7 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) { int res; uint32_t val; + int needed_reg_ver; if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); @@ -968,6 +965,32 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) return -GSI_STATUS_UNSUPPORTED_OP; } + switch (props->ver) { + case GSI_VER_1_0: + case GSI_VER_1_2: + case GSI_VER_1_3: + case GSI_VER_2_0: + case GSI_VER_2_2: + needed_reg_ver = GSI_REGISTER_VER_1; + break; + case GSI_VER_2_5: + needed_reg_ver = GSI_REGISTER_VER_2; + break; + case GSI_VER_ERR: + case GSI_VER_MAX: + default: + GSIERR("GSI version is not supported %d\n", props->ver); + return -GSI_STATUS_INVALID_PARAMS; + } + + if (needed_reg_ver != GSI_REGISTER_VER_CURRENT) { + GSIERR("Invalid register version. current=%d, needed=%d\n", + GSI_REGISTER_VER_CURRENT, needed_reg_ver); + return -GSI_STATUS_UNSUPPORTED_OP; + } + GSIDBG("gsi ver %d register ver %d needed register ver %d\n", + props->ver, GSI_REGISTER_VER_CURRENT, needed_reg_ver); + spin_lock_init(&gsi_ctx->slock); if (props->intr == GSI_INTR_IRQ) { if (!props->irq) { @@ -2124,31 +2147,36 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, atomic_set(&ctx->poll_mode, GSI_CHAN_MODE_CALLBACK); ctx->props = *props; - mutex_lock(&gsi_ctx->mlock); - ee = gsi_ctx->per.ee; - gsi_ctx->ch_dbg[props->ch_id].ch_allocate++; - val = (((props->ch_id << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & - GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | - ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & - GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); - gsi_writel(val, gsi_ctx->base + - GSI_EE_n_GSI_CH_CMD_OFFS(ee)); - res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); - if (res == 0) { - GSIERR("chan_hdl=%u timed out\n", props->ch_id); + if (gsi_ctx->per.ver != GSI_VER_2_2) { + mutex_lock(&gsi_ctx->mlock); + ee = gsi_ctx->per.ee; + gsi_ctx->ch_dbg[props->ch_id].ch_allocate++; + val = (((props->ch_id << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & + GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | + ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_CH_CMD_OFFS(ee)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); + if (res == 0) { + GSIERR("chan_hdl=%u timed out\n", props->ch_id); + mutex_unlock(&gsi_ctx->mlock); + devm_kfree(gsi_ctx->dev, user_data); + return -GSI_STATUS_TIMED_OUT; + } + if (ctx->state != GSI_CHAN_STATE_ALLOCATED) { + GSIERR("chan_hdl=%u allocation failed state=%d\n", + props->ch_id, ctx->state); + mutex_unlock(&gsi_ctx->mlock); + devm_kfree(gsi_ctx->dev, user_data); + return -GSI_STATUS_RES_ALLOC_FAILURE; + } mutex_unlock(&gsi_ctx->mlock); - devm_kfree(gsi_ctx->dev, user_data); - return -GSI_STATUS_TIMED_OUT; - } - if (ctx->state != GSI_CHAN_STATE_ALLOCATED) { - GSIERR("chan_hdl=%u allocation failed state=%d\n", - props->ch_id, ctx->state); + } else { + mutex_lock(&gsi_ctx->mlock); + ctx->state = GSI_CHAN_STATE_ALLOCATED; mutex_unlock(&gsi_ctx->mlock); - devm_kfree(gsi_ctx->dev, user_data); - return -GSI_STATUS_RES_ALLOC_FAILURE; } - mutex_unlock(&gsi_ctx->mlock); - erindex = props->evt_ring_hdl != ~0 ? props->evt_ring_hdl : GSI_NO_EVT_ERINDEX; if (erindex != GSI_NO_EVT_ERINDEX) { @@ -2442,8 +2470,7 @@ int gsi_start_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Start, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, - GSI_START_CMD_TIMEOUT_MS, - GSI_CHAN_STATE_STARTED); + GSI_START_CMD_TIMEOUT_MS); if (ctx->state != GSI_CHAN_STATE_STARTED) { /* @@ -2516,8 +2543,7 @@ int gsi_stop_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Stop, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, - GSI_STOP_CMD_TIMEOUT_MS, - GSI_CHAN_STATE_STOPPED); + GSI_STOP_CMD_TIMEOUT_MS); if (ctx->state != GSI_CHAN_STATE_STOPPED && ctx->state != GSI_CHAN_STATE_STOP_IN_PROC) { @@ -2721,31 +2747,40 @@ int gsi_dealloc_channel(unsigned long chan_hdl) return -GSI_STATUS_UNSUPPORTED_OP; } - mutex_lock(&gsi_ctx->mlock); - reinit_completion(&ctx->compl); + /*In GSI_VER_2_2 version deallocation channel not supported*/ + if (gsi_ctx->per.ver != GSI_VER_2_2) { + mutex_lock(&gsi_ctx->mlock); + reinit_completion(&ctx->compl); + + gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++; + val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & + GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | + ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); + if (res == 0) { + GSIERR("chan_hdl=%lu timed out\n", chan_hdl); + mutex_unlock(&gsi_ctx->mlock); + return -GSI_STATUS_TIMED_OUT; + } + if (ctx->state != GSI_CHAN_STATE_NOT_ALLOCATED) { + GSIERR("chan_hdl=%lu unexpected state=%u\n", chan_hdl, + ctx->state); + /* Hardware returned incorrect value */ + BUG(); + } - gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++; - val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & - GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | - ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & - GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); - gsi_writel(val, gsi_ctx->base + - GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); - if (res == 0) { - GSIERR("chan_hdl=%lu timed out\n", chan_hdl); mutex_unlock(&gsi_ctx->mlock); - return -GSI_STATUS_TIMED_OUT; - } - if (ctx->state != GSI_CHAN_STATE_NOT_ALLOCATED) { - GSIERR("chan_hdl=%lu unexpected state=%u\n", chan_hdl, - ctx->state); - /* Hardware returned incorrect value */ - BUG(); + } else { + mutex_lock(&gsi_ctx->mlock); + GSIDBG("In GSI_VER_2_2 channel deallocation not supported\n"); + ctx->state = GSI_CHAN_STATE_NOT_ALLOCATED; + GSIDBG("chan_hdl=%lu Channel state = %u\n", chan_hdl, + ctx->state); + mutex_unlock(&gsi_ctx->mlock); } - - mutex_unlock(&gsi_ctx->mlock); - devm_kfree(gsi_ctx->dev, ctx->user_data); ctx->allocated = false; if (ctx->evtr) @@ -3555,6 +3590,72 @@ int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code) } EXPORT_SYMBOL(gsi_halt_channel_ee); +int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code) +{ + enum gsi_generic_ee_cmd_opcode op = GSI_GEN_EE_CMD_ALLOC_CHANNEL; + struct gsi_chan_ctx *ctx; + uint32_t val; + int res; + + if (chan_idx >= gsi_ctx->max_ch || !code) { + GSIERR("bad params chan_idx=%d\n", chan_idx); + return -GSI_STATUS_INVALID_PARAMS; + } + + mutex_lock(&gsi_ctx->mlock); + reinit_completion(&gsi_ctx->gen_ee_cmd_compl); + + /* invalidate the response */ + gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); + gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code = 0; + gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base + + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); + + val = (((op << GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK) | + ((chan_idx << GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT) & + GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK) | + ((ee << GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT) & + GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(gsi_ctx->per.ee)); + + res = wait_for_completion_timeout(&gsi_ctx->gen_ee_cmd_compl, + msecs_to_jiffies(GSI_CMD_TIMEOUT)); + if (res == 0) { + GSIERR("chan_idx=%u ee=%u timed out\n", chan_idx, ee); + res = -GSI_STATUS_TIMED_OUT; + goto free_lock; + } + + gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); + if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == + GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES) { + GSIDBG("chan_idx=%u ee=%u out of resources\n", chan_idx, ee); + *code = GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES; + res = -GSI_STATUS_RES_ALLOC_FAILURE; + goto free_lock; + } + if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == 0) { + GSIERR("No response received\n"); + res = -GSI_STATUS_ERROR; + goto free_lock; + } + if (ee == 0) { + ctx = &gsi_ctx->chan[chan_idx]; + gsi_ctx->ch_dbg[chan_idx].ch_allocate++; + } + res = GSI_STATUS_SUCCESS; + *code = gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code; +free_lock: + mutex_unlock(&gsi_ctx->mlock); + + return res; +} +EXPORT_SYMBOL(gsi_alloc_channel_ee); + int gsi_map_virtual_ch_to_per_ep(u32 ee, u32 chan_num, u32 per_ep_index) { if (!gsi_ctx) { diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 870d8d615ba39ffbf0b9dd4a8ecf8f70942c9134..dbf89418e2fcc74bdc8087786241d7990f71e106 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -295,6 +295,7 @@ enum gsi_evt_ch_cmd_opcode { enum gsi_generic_ee_cmd_opcode { GSI_GEN_EE_CMD_HALT_CHANNEL = 0x1, + GSI_GEN_EE_CMD_ALLOC_CHANNEL = 0x2, }; enum gsi_generic_ee_cmd_return_code { @@ -304,6 +305,7 @@ enum gsi_generic_ee_cmd_return_code { GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_TYPE = 0x4, GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_INDEX = 0x5, GSI_GEN_EE_CMD_RETURN_CODE_RETRY = 0x6, + GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES = 0x7, }; extern struct gsi_ctx *gsi_ctx; diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h index ec2e886fb2d709f1678f21c315327aa07f52f93e..8a5719282335b9ccad1ce6a612557ef4294e0bce 100644 --- a/drivers/platform/msm/gsi/gsi_reg.h +++ b/drivers/platform/msm/gsi/gsi_reg.h @@ -12,1052 +12,18 @@ #ifndef __GSI_REG_H__ #define __GSI_REG_H__ -#define GSI_GSI_REG_BASE_OFFS 0 - -#define GSI_GSI_CFG_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000000) -#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_BMSK 0xf00 -#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_SHFT 0x8 -#define GSI_GSI_CFG_BP_MTRIX_DISABLE_BMSK 0x20 -#define GSI_GSI_CFG_BP_MTRIX_DISABLE_SHFT 0x5 -#define GSI_GSI_CFG_GSI_PWR_CLPS_BMSK 0x10 -#define GSI_GSI_CFG_GSI_PWR_CLPS_SHFT 0x4 -#define GSI_GSI_CFG_UC_IS_MCS_BMSK 0x8 -#define GSI_GSI_CFG_UC_IS_MCS_SHFT 0x3 -#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_BMSK 0x4 -#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_SHFT 0x2 -#define GSI_GSI_CFG_MCS_ENABLE_BMSK 0x2 -#define GSI_GSI_CFG_MCS_ENABLE_SHFT 0x1 -#define GSI_GSI_CFG_GSI_ENABLE_BMSK 0x1 -#define GSI_GSI_CFG_GSI_ENABLE_SHFT 0x0 - -#define GSI_GSI_MCS_CFG_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000B000) -#define GSI_GSI_MCS_CFG_MCS_ENABLE_BMSK 0x1 -#define GSI_GSI_MCS_CFG_MCS_ENABLE_SHFT 0x0 - -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000018) -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_RMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_BMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_SHFT 0x0 - -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000001c) -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_RMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_BMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_SHFT 0x0 - -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000a0) -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000a4) -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000a8) -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000ac) -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_GEN_INT_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000b0) -#define GSI_IC_GEN_INT_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_GEN_INT_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000b4) -#define GSI_IC_GEN_INT_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000b8) -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000bc) -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000c0) -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000c4) -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000c8) -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000cc) -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000d0) -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000d4) -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000d8) -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000dc) -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_READ_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000e0) -#define GSI_IC_READ_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_READ_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000e4) -#define GSI_IC_READ_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_WRITE_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000e8) -#define GSI_IC_WRITE_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_WRITE_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000ec) -#define GSI_IC_WRITE_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000f0) -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000f4) -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_CMD_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000400) -#define GSI_GSI_IRAM_PTR_CH_CMD_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000404) -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_SHFT 0x0 - -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000408) -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_RMSK 0xfff -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_BMSK 0xfff -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_DB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000418) -#define GSI_GSI_IRAM_PTR_CH_DB_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_EV_DB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000041c) -#define GSI_GSI_IRAM_PTR_EV_DB_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_NEW_RE_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000420) -#define GSI_GSI_IRAM_PTR_NEW_RE_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000424) -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_EMPTY_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000428) -#define GSI_GSI_IRAM_PTR_CH_EMPTY_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000042c) -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000430) -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000434) -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000438) -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000043c) -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000440) -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000444) -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_UC_GP_INT_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000448) -#define GSI_GSI_IRAM_PTR_UC_GP_INT_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000044c) -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 -#define GSI_GSI_INST_RAM_n_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) -#define GSI_V2_5_GSI_INST_RAM_n_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001b000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) -#define GSI_GSI_INST_RAM_n_RMSK 0xffffffff -#define GSI_GSI_INST_RAM_n_MAXn 4095 -#define GSI_V2_0_GSI_INST_RAM_n_MAXn 6143 -#define GSI_V2_2_GSI_INST_RAM_n_MAXn 4095 -#define GSI_V2_5_GSI_INST_RAM_n_MAXn 8191 -#define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 -#define GSI_GSI_INST_RAM_n_INST_BYTE_3_SHFT 0x18 -#define GSI_GSI_INST_RAM_n_INST_BYTE_2_BMSK 0xff0000 -#define GSI_GSI_INST_RAM_n_INST_BYTE_2_SHFT 0x10 -#define GSI_GSI_INST_RAM_n_INST_BYTE_1_BMSK 0xff00 -#define GSI_GSI_INST_RAM_n_INST_BYTE_1_SHFT 0x8 -#define GSI_GSI_INST_RAM_n_INST_BYTE_0_BMSK 0xff -#define GSI_GSI_INST_RAM_n_INST_BYTE_0_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c000 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_BMSK 0x7c000 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_SHFT 0xe -#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_BMSK 0x2000 -#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_SHFT 0xd -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_BMSK 0x1f00 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_SHFT 0x8 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_BMSK 0xf0 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_SHFT 0x4 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_BMSK 0x8 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_SHFT 0x3 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_BMSK 0x7 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c004 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff -#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c008 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c00c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c010 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c014 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c018 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c01c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c054 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_RMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXk 30 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXn 3 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_BMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c058 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXk 30 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXn 3 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_BMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c05c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 -#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 -#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 -#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 -#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa -#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 -#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 -#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 -#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 -#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf -#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 - -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000f05c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_BMSK 0xff0000 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_SHFT 0x10 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_BMSK 0x3c00 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_SHFT 0xa -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 - - -#define GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c060 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c064 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c068 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c06c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d000 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 -#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 -#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_BMSK 0x10000 -#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_SHFT 0x10 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_BMSK 0xff00 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_SHFT 0x8 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_BMSK 0xf0 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_SHFT 0x4 -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK 0xf -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d004 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff -#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d008 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d00c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d010 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d014 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d018 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d01c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d020 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_BMSK 0xff000000 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_SHFT 0x18 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_BMSK 0xff0000 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_SHFT 0x10 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_BMSK 0xffff -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d024 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d028 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d02c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d030 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d034 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d048 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d04c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_DOORBELL_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e000 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_DOORBELL_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e004 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e100 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_DOORBELL_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e104 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_GSI_STATUS_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f000 + 0x4000 * (n)) -#define GSI_EE_n_GSI_STATUS_ENABLED_BMSK 0x1 -#define GSI_EE_n_GSI_STATUS_ENABLED_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_CMD_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f008 + 0x4000 * (n)) -#define GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK 0xff000000 -#define GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT 0x18 -#define GSI_EE_n_GSI_CH_CMD_CHID_BMSK 0xff -#define GSI_EE_n_GSI_CH_CMD_CHID_SHFT 0x0 - -#define GSI_EE_n_EV_CH_CMD_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f010 + 0x4000 * (n)) -#define GSI_EE_n_EV_CH_CMD_OPCODE_BMSK 0xff000000 -#define GSI_EE_n_EV_CH_CMD_OPCODE_SHFT 0x18 -#define GSI_EE_n_EV_CH_CMD_CHID_BMSK 0xff -#define GSI_EE_n_EV_CH_CMD_CHID_SHFT 0x0 - -#define GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f018 + 0x4000 * (n)) -#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f -#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa - -#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_BMSK 0x7c000000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_SHFT 0x1a -#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_BMSK 0x2000000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_SHFT 0x19 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_BMSK 0x1f00000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_SHFT 0x14 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_BMSK 0xf0000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_SHFT 0x10 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_BMSK 0xff00 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_SHFT 0x8 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_BMSK 0xff -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_SHFT 0x0 - -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f038 + 0x4000 * (n)) -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_BMSK 0x80000000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_SHFT 0x1f -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_BMSK 0x7c000000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_SHFT 0x1a -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_BMSK 0x3e00000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_SHFT 0x15 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_BMSK 0x1f0000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_SHFT 0x10 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_BMSK 0xff00 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_SHFT 0x8 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_BMSK 0xff -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_SHFT 0x0 - -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 - -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 - -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 - -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00012040 + 0x4000 * (n)) -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_N_HALF_KB_FVAL 0x4 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_FOUR_KB_FVAL 0x5 - -#define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f044 + 0x4000 * (n)) -#define GSI_EE_n_GSI_SW_VERSION_MAJOR_BMSK 0xf0000000 -#define GSI_EE_n_GSI_SW_VERSION_MAJOR_SHFT 0x1c -#define GSI_EE_n_GSI_SW_VERSION_MINOR_BMSK 0xfff0000 -#define GSI_EE_n_GSI_SW_VERSION_MINOR_SHFT 0x10 -#define GSI_EE_n_GSI_SW_VERSION_STEP_BMSK 0xffff -#define GSI_EE_n_GSI_SW_VERSION_STEP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f080 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK 0x40 -#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_SHFT 0x6 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_BMSK 0x20 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_SHFT 0x5 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_BMSK 0x10 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_SHFT 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_BMSK 0x8 -#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_SHFT 0x3 -#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_BMSK 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_SHFT 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_BMSK 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_SHFT 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_SHFT 0x0 - -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f088 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_BMSK 0x40 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_SHFT 0x6 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_BMSK 0x20 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_SHFT 0x5 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_BMSK 0x10 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_SHFT 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_BMSK 0x8 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT 0x3 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_BMSK 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_SHFT 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_BMSK 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_SHFT 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_BMSK 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f090 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f094 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f098 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x1ffff -#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x7fffff -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 -#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f09c + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff -#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 -#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0a0 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0a4 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0b0 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0b8 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff -#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 -#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0c0 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f100 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_BMSK 0x8 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_SHFT 0x3 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_BMSK 0x4 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_SHFT 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_BMSK 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_SHFT 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f108 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_BMSK 0x8 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_SHFT 0x3 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK 0x4 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_SHFT 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_SHFT 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f110 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_BMSK 0x8 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_SHFT 0x3 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_BMSK 0x4 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_SHFT 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_BMSK 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_SHFT 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f118 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_BMSK 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_SHFT 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f120 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_BMSK 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_SHFT 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f128 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_BMSK 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_SHFT 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_INTSET_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f180 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_INTSET_INTYPE_BMSK 0x1 -#define GSI_EE_n_CNTXT_INTSET_INTYPE_SHFT 0x0 - -#define GSI_EE_n_ERROR_LOG_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f200 + 0x4000 * (n)) -#define GSI_EE_n_ERROR_LOG_TODO_BMSK 0xffffffff -#define GSI_EE_n_ERROR_LOG_TODO_SHFT 0x0 - -#define GSI_EE_n_ERROR_LOG_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f210 + 0x4000 * (n)) -#define GSI_EE_n_ERROR_LOG_CLR_TODO_BMSK 0xffffffff -#define GSI_EE_n_ERROR_LOG_CLR_TODO_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SCRATCH_0_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f400 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c01c + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c028 + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c02c + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00003800 + 0x80 * (n) + 0x4 * (k)) -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_BMSK 0x20 -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_SHFT 0x5 -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 +enum gsi_register_ver { + GSI_REGISTER_VER_1 = 0, + GSI_REGISTER_VER_2 = 1, + GSI_REGISTER_MAX, +}; + +#ifdef CONFIG_GSI_REGISTER_VERSION_2 +#include "gsi_reg_v2.h" +#define GSI_REGISTER_VER_CURRENT GSI_REGISTER_VER_2 +#else +#include "gsi_reg_v1.h" +#define GSI_REGISTER_VER_CURRENT GSI_REGISTER_VER_1 +#endif #endif /* __GSI_REG_H__ */ diff --git a/drivers/platform/msm/gsi/gsi_reg_v1.h b/drivers/platform/msm/gsi/gsi_reg_v1.h new file mode 100644 index 0000000000000000000000000000000000000000..7dbe649cdb0a101a68f40ec1346495f4e5e58101 --- /dev/null +++ b/drivers/platform/msm/gsi/gsi_reg_v1.h @@ -0,0 +1,1063 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __GSI_REG_V1_H__ +#define __GSI_REG_V1_H__ + +#define GSI_GSI_REG_BASE_OFFS 0 + +#define GSI_GSI_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000000) +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_BMSK 0xf00 +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_SHFT 0x8 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_BMSK 0x20 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_SHFT 0x5 +#define GSI_GSI_CFG_GSI_PWR_CLPS_BMSK 0x10 +#define GSI_GSI_CFG_GSI_PWR_CLPS_SHFT 0x4 +#define GSI_GSI_CFG_UC_IS_MCS_BMSK 0x8 +#define GSI_GSI_CFG_UC_IS_MCS_SHFT 0x3 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_BMSK 0x4 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_SHFT 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_BMSK 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_SHFT 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_BMSK 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_SHFT 0x0 + +#define GSI_GSI_MCS_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000B000) +#define GSI_GSI_MCS_CFG_MCS_ENABLE_BMSK 0x1 +#define GSI_GSI_MCS_CFG_MCS_ENABLE_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000018) +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000001c) +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a0) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a4) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a8) +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ac) +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b0) +#define GSI_IC_GEN_INT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b4) +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b8) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000bc) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c0) +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c4) +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c8) +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000cc) +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d0) +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d4) +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d8) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000dc) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e0) +#define GSI_IC_READ_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e4) +#define GSI_IC_READ_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e8) +#define GSI_IC_WRITE_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ec) +#define GSI_IC_WRITE_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f0) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f4) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000400) +#define GSI_GSI_IRAM_PTR_CH_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000404) +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000408) +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_RMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_BMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000418) +#define GSI_GSI_IRAM_PTR_CH_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EV_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000041c) +#define GSI_GSI_IRAM_PTR_EV_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_NEW_RE_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000420) +#define GSI_GSI_IRAM_PTR_NEW_RE_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000424) +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_EMPTY_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000428) +#define GSI_GSI_IRAM_PTR_CH_EMPTY_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000042c) +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000430) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000434) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000438) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000043c) +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000440) +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000444) +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_UC_GP_INT_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000448) +#define GSI_GSI_IRAM_PTR_UC_GP_INT_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000044c) +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 +#define GSI_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_V2_5_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001b000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_GSI_INST_RAM_n_RMSK 0xffffffff +#define GSI_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_0_GSI_INST_RAM_n_MAXn 6143 +#define GSI_V2_2_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_5_GSI_INST_RAM_n_MAXn 8191 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_SHFT 0x18 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_BMSK 0xff0000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_SHFT 0x10 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_BMSK 0xff00 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_SHFT 0x8 +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_BMSK 0xff +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_BMSK 0x7c000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_SHFT 0xd +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_BMSK 0x1f00 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_BMSK 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_SHFT 0x3 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_BMSK 0x7 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c00c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c01c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c054 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c058 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 +#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 +#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_BMSK 0xff0000 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_BMSK 0x3c00 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_SHFT 0xa +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + + +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c060 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c064 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c068 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c06c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_BMSK 0x10000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_BMSK 0xff00 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_SHFT 0x8 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK 0xf +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d00c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d01c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d020 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_BMSK 0xff0000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d024 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d028 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d02c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d030 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d034 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d048 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d04c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e000 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e004 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e100 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e104 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_STATUS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f000 + 0x4000 * (n)) +#define GSI_EE_n_GSI_STATUS_ENABLED_BMSK 0x1 +#define GSI_EE_n_GSI_STATUS_ENABLED_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f008 + 0x4000 * (n)) +#define GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_GSI_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_EV_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f010 + 0x4000 * (n)) +#define GSI_EE_n_EV_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_EV_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_EV_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f018 + 0x4000 * (n)) +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa + +#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_BMSK 0x2000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_SHFT 0x19 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_BMSK 0x1f00000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_SHFT 0x14 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_BMSK 0xf0000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_SHFT 0x10 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f038 + 0x4000 * (n)) +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_BMSK 0x80000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_SHFT 0x1f +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_BMSK 0x3e00000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_SHFT 0x15 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_BMSK 0x1f0000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_SHFT 0x10 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 + +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012040 + 0x4000 * (n)) +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_N_HALF_KB_FVAL 0x4 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_FOUR_KB_FVAL 0x5 + +#define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f044 + 0x4000 * (n)) +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_BMSK 0xf0000000 +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_SHFT 0x1c +#define GSI_EE_n_GSI_SW_VERSION_MINOR_BMSK 0xfff0000 +#define GSI_EE_n_GSI_SW_VERSION_MINOR_SHFT 0x10 +#define GSI_EE_n_GSI_SW_VERSION_STEP_BMSK 0xffff +#define GSI_EE_n_GSI_SW_VERSION_STEP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f080 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f088 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f090 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f094 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f098 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x1ffff +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x7fffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f09c + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0a0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0a4 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0b0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0b8 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0c0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f100 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f108 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f110 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f118 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f120 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f128 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_INTSET_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f180 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_INTSET_INTYPE_BMSK 0x1 +#define GSI_EE_n_CNTXT_INTSET_INTYPE_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f200 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_TODO_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f210 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_CLR_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_CLR_TODO_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SCRATCH_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f400 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c01c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c028 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c02c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00003800 + 0x80 * (n) + 0x4 * (k)) +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_BMSK 0x20 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_SHFT 0x5 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 + +#endif /* __GSI_REG_V1_H__ */ diff --git a/drivers/platform/msm/gsi/gsi_reg_v2.h b/drivers/platform/msm/gsi/gsi_reg_v2.h new file mode 100644 index 0000000000000000000000000000000000000000..e31730d08b384c6d0d275d547c34c8df28eda3ac --- /dev/null +++ b/drivers/platform/msm/gsi/gsi_reg_v2.h @@ -0,0 +1,1063 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __GSI_REG_V2_H__ +#define __GSI_REG_V2_H__ + +#define GSI_GSI_REG_BASE_OFFS 0 + +#define GSI_GSI_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000000) +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_BMSK 0xf00 +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_SHFT 0x8 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_BMSK 0x20 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_SHFT 0x5 +#define GSI_GSI_CFG_GSI_PWR_CLPS_BMSK 0x10 +#define GSI_GSI_CFG_GSI_PWR_CLPS_SHFT 0x4 +#define GSI_GSI_CFG_UC_IS_MCS_BMSK 0x8 +#define GSI_GSI_CFG_UC_IS_MCS_SHFT 0x3 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_BMSK 0x4 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_SHFT 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_BMSK 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_SHFT 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_BMSK 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_SHFT 0x0 + +#define GSI_GSI_MCS_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000B000) +#define GSI_GSI_MCS_CFG_MCS_ENABLE_BMSK 0x1 +#define GSI_GSI_MCS_CFG_MCS_ENABLE_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000018) +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000001c) +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a0) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a4) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a8) +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ac) +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b0) +#define GSI_IC_GEN_INT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b4) +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b8) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000bc) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c0) +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c4) +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c8) +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000cc) +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d0) +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d4) +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d8) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000dc) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e0) +#define GSI_IC_READ_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e4) +#define GSI_IC_READ_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e8) +#define GSI_IC_WRITE_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ec) +#define GSI_IC_WRITE_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f0) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f4) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000400) +#define GSI_GSI_IRAM_PTR_CH_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000404) +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000408) +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_RMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_BMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000418) +#define GSI_GSI_IRAM_PTR_CH_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EV_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000041c) +#define GSI_GSI_IRAM_PTR_EV_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_NEW_RE_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000420) +#define GSI_GSI_IRAM_PTR_NEW_RE_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000424) +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_EMPTY_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000428) +#define GSI_GSI_IRAM_PTR_CH_EMPTY_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000042c) +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000430) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000434) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000438) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000043c) +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000440) +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000444) +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_UC_GP_INT_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000448) +#define GSI_GSI_IRAM_PTR_UC_GP_INT_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000044c) +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 +#define GSI_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_V2_5_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001b000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_GSI_INST_RAM_n_RMSK 0xffffffff +#define GSI_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_0_GSI_INST_RAM_n_MAXn 6143 +#define GSI_V2_2_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_5_GSI_INST_RAM_n_MAXn 8191 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_SHFT 0x18 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_BMSK 0xff0000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_SHFT 0x10 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_BMSK 0xff00 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_SHFT 0x8 +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_BMSK 0xff +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_BMSK 0x7c000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_SHFT 0xd +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_BMSK 0x1f00 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_BMSK 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_SHFT 0x3 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_BMSK 0x7 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f00c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f01c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f054 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f058 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 +#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 +#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_BMSK 0xff0000 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_BMSK 0x3c00 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_SHFT 0xa +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + + +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f060 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f064 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f068 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f06c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_BMSK 0x10000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_BMSK 0xff00 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_SHFT 0x8 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK 0xf +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001000c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001001c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010020 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_BMSK 0xff0000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010024 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010028 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001002c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010030 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010034 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010048 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001004c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011000 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011004 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011100 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011104 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_STATUS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012000 + 0x4000 * (n)) +#define GSI_EE_n_GSI_STATUS_ENABLED_BMSK 0x1 +#define GSI_EE_n_GSI_STATUS_ENABLED_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012008 + 0x4000 * (n)) +#define GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_GSI_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_EV_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012010 + 0x4000 * (n)) +#define GSI_EE_n_EV_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_EV_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_EV_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012018 + 0x4000 * (n)) +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa + +#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_BMSK 0x2000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_SHFT 0x19 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_BMSK 0x1f00000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_SHFT 0x14 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_BMSK 0xf0000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_SHFT 0x10 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f038 + 0x4000 * (n)) +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_BMSK 0x80000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_SHFT 0x1f +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_BMSK 0x3e00000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_SHFT 0x15 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_BMSK 0x1f0000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_SHFT 0x10 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 + +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012040 + 0x4000 * (n)) +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_N_HALF_KB_FVAL 0x4 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_FOUR_KB_FVAL 0x5 + +#define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012044 + 0x4000 * (n)) +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_BMSK 0xf0000000 +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_SHFT 0x1c +#define GSI_EE_n_GSI_SW_VERSION_MINOR_BMSK 0xfff0000 +#define GSI_EE_n_GSI_SW_VERSION_MINOR_SHFT 0x10 +#define GSI_EE_n_GSI_SW_VERSION_STEP_BMSK 0xffff +#define GSI_EE_n_GSI_SW_VERSION_STEP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012080 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012088 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012090 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012094 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012098 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x1ffff +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x7fffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001209c + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120a0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120a4 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120b0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120b8 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120c0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012100 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012108 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012110 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012118 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012120 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012128 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_INTSET_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012180 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_INTSET_INTYPE_BMSK 0x1 +#define GSI_EE_n_CNTXT_INTSET_INTYPE_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012200 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_TODO_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012210 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_CLR_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_CLR_TODO_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SCRATCH_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012400 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c01c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c028 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c02c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00003800 + 0x80 * (n) + 0x4 * (k)) +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_BMSK 0x20 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_SHFT 0x5 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 + +#endif /* __GSI_REG_V2_H__ */ diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 5379ef9d2cc6d74bb02876062a1bb9973a963a2d..221f06832a37a96c6ee01ff2abfcf82290dee533 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -194,6 +194,8 @@ const char *ipa_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_Q6_QBAP_STATUS_CONS), __stringify(RESERVERD_PROD_80), __stringify(IPA_CLIENT_MHI_DPL_CONS), + __stringify(RESERVERD_PROD_82), + __stringify(IPA_CLIENT_ODL_DPL_CONS), }; /** diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index 6cbfa4bcc12f832e76f69c37aeaa2f0f463acaa9..a4dceb6ca176a5f48cb7bfdda21e15af418b9278 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -2136,6 +2136,15 @@ int ipa_mhi_suspend(bool force) IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res); return res; } + + res = ipa_mhi_suspend_dl(force); + if (res) { + IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res); + goto fail_suspend_dl_channel; + } + + usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX); + res = ipa_mhi_suspend_ul(force, &empty, &force_clear); if (res) { IPA_MHI_ERR("ipa_mhi_suspend_ul failed %d\n", res); @@ -2176,12 +2185,6 @@ int ipa_mhi_suspend(bool force) } usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX); - res = ipa_mhi_suspend_dl(force); - if (res) { - IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res); - goto fail_suspend_dl_channel; - } - if (!empty) ipa_set_tag_process_before_gating(false); @@ -2195,7 +2198,6 @@ int ipa_mhi_suspend(bool force) IPA_MHI_FUNC_EXIT(); return 0; -fail_suspend_dl_channel: fail_release_cons: if (!ipa_pm_is_used()) ipa_mhi_request_prod(); @@ -2209,7 +2211,6 @@ int ipa_mhi_suspend(bool force) IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); fail_suspend_ul_channel: ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels); - ipa_mhi_set_state(IPA_MHI_STATE_STARTED); if (force_clear) { if ( ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id)) { @@ -2219,6 +2220,9 @@ int ipa_mhi_suspend(bool force) IPA_MHI_DBG("force clear datapath disabled\n"); ipa_mhi_client_ctx->qmi_req_id++; } +fail_suspend_dl_channel: + ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->dl_channels); + ipa_mhi_set_state(IPA_MHI_STATE_STARTED); return res; } diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index be0032ccb21c83868490a58893d0c5f90cb937b5..73369ed2fc639d902647381e51876227d0360d7b 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -1330,7 +1330,10 @@ static int ipa3_usb_request_xdci_channel( chan_params.chan_params.ring_base_addr = params->xfer_ring_base_addr_iova; chan_params.chan_params.ring_base_vaddr = NULL; - chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + chan_params.chan_params.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG; if (params->dir == GSI_CHAN_DIR_FROM_GSI) chan_params.chan_params.low_weight = diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c index fe916076e6c3e26de701a3889462aa9fd2b5d2c9..21bba6e8e9d025ca513c4253dca55c5891e74372 100644 --- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c @@ -454,6 +454,11 @@ struct rndis_pkt_hdr rndis_template_hdr = { .zeroes = {0}, }; +static void rndis_ipa_msg_free_cb(void *buff, u32 len, u32 type) +{ + kfree(buff); +} + /** * rndis_ipa_init() - create network device and initialize internal * data structures @@ -677,6 +682,8 @@ int rndis_ipa_pipe_connect_notify( int result; int ret; unsigned long flags; + struct ipa_ecm_msg *rndis_msg; + struct ipa_msg_meta msg_meta; RNDIS_IPA_LOG_ENTRY(); @@ -762,6 +769,26 @@ int rndis_ipa_pipe_connect_notify( } RNDIS_IPA_DEBUG("netif_carrier_on() was called\n"); + rndis_msg = kzalloc(sizeof(*rndis_msg), GFP_KERNEL); + if (!rndis_msg) { + result = -ENOMEM; + goto fail; + } + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = ECM_CONNECT; + msg_meta.msg_len = sizeof(struct ipa_ecm_msg); + strlcpy(rndis_msg->name, rndis_ipa_ctx->net->name, + IPA_RESOURCE_NAME_MAX); + rndis_msg->ifindex = rndis_ipa_ctx->net->ifindex; + + result = ipa_send_msg(&msg_meta, rndis_msg, rndis_ipa_msg_free_cb); + if (result) { + RNDIS_IPA_ERROR("fail to send ECM_CONNECT for rndis\n"); + kfree(rndis_msg); + goto fail; + } + spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags); next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_CONNECT); @@ -1222,6 +1249,8 @@ int rndis_ipa_pipe_disconnect_notify(void *private) int retval; int ret; unsigned long flags; + struct ipa_ecm_msg *rndis_msg; + struct ipa_msg_meta msg_meta; RNDIS_IPA_LOG_ENTRY(); @@ -1253,6 +1282,24 @@ int rndis_ipa_pipe_disconnect_notify(void *private) netif_carrier_off(rndis_ipa_ctx->net); RNDIS_IPA_DEBUG("carrier_off notification was sent\n"); + rndis_msg = kzalloc(sizeof(*rndis_msg), GFP_KERNEL); + if (!rndis_msg) + return -ENOMEM; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = ECM_DISCONNECT; + msg_meta.msg_len = sizeof(struct ipa_ecm_msg); + strlcpy(rndis_msg->name, rndis_ipa_ctx->net->name, + IPA_RESOURCE_NAME_MAX); + rndis_msg->ifindex = rndis_ipa_ctx->net->ifindex; + + retval = ipa_send_msg(&msg_meta, rndis_msg, rndis_ipa_msg_free_cb); + if (retval) { + RNDIS_IPA_ERROR("fail to send ECM_DISCONNECT for rndis\n"); + kfree(rndis_msg); + return -EPERM; + } + netif_stop_queue(rndis_ipa_ctx->net); RNDIS_IPA_DEBUG("queue stopped\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile index f6f08b1523935722976042da73dc97515f686685..275b33f8dabbbe005bbdefd7a62390e9bc41c6e9 100644 --- a/drivers/platform/msm/ipa/ipa_v3/Makefile +++ b/drivers/platform/msm/ipa/ipa_v3/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IPA3) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \ - ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o + ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o ipa_odl.o ipat-$(CONFIG_IPA_EMULATION) += ipa_dt_replacement.o diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 683906ae2993e21eb149a3d5dd2f62fa4acff1c2..d142de21ef071a82b1ed19929e48d125715c61ba 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -59,6 +59,7 @@ #define CREATE_TRACE_POINTS #include "ipa_trace.h" +#include "ipa_odl.h" /* * The following for adding code (ie. for EMULATION) not found on x86. @@ -2548,6 +2549,9 @@ void ipa3_q6_pre_shutdown_cleanup(void) ipa3_q6_pipe_delay(true); ipa3_q6_avoid_holb(); + if (ipa3_ctx->ipa_config_is_mhi) + ipa3_set_reset_client_cons_pipe_sus_holb(true, + IPA_CLIENT_MHI_CONS); if (ipa3_q6_clean_q6_tables()) { IPAERR("Failed to clean Q6 tables\n"); /* @@ -2568,8 +2572,11 @@ void ipa3_q6_pre_shutdown_cleanup(void) * on pipe reset procedure */ ipa3_q6_pipe_delay(false); - - ipa3_set_usb_prod_pipe_delay(); + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_USB_PROD); + if (ipa3_ctx->ipa_config_is_mhi) + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_MHI_PROD); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); @@ -3240,7 +3247,7 @@ static int ipa3_setup_apps_pipes(void) sys_in.ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = false; sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0; sys_in.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2; - sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL; + sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_DISABLE_CS_OFFLOAD; /** * ipa_lan_rx_cb() intended to notify the source EP about packet @@ -4437,6 +4444,38 @@ static int ipa3_gsi_pre_fw_load_init(void) return 0; } +static int ipa3_alloc_gsi_channel(void) +{ + const struct ipa_gsi_ep_config *gsi_ep_cfg; + enum ipa_client_type type; + int code = 0; + int ret = 0; + int i; + + for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) { + type = ipa3_get_client_by_pipe(i); + gsi_ep_cfg = ipa3_get_gsi_ep_info(type); + IPADBG("for ep %d client is %d\n", i, type); + if (!gsi_ep_cfg) + continue; + + ret = gsi_alloc_channel_ee(gsi_ep_cfg->ipa_gsi_chan_num, + gsi_ep_cfg->ee, &code); + if (ret == GSI_STATUS_SUCCESS) { + IPADBG("alloc gsi ch %d ee %d with code %d\n", + gsi_ep_cfg->ipa_gsi_chan_num, + gsi_ep_cfg->ee, + code); + } else { + IPAERR("failed to alloc ch %d ee %d code %d\n", + gsi_ep_cfg->ipa_gsi_chan_num, + gsi_ep_cfg->ee, + code); + return ret; + } + } + return ret; +} /** * ipa3_post_init() - Initialize the IPA Driver (Part II). * This part contains all initialization which requires interaction with @@ -4664,6 +4703,17 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, goto fail_register_device; } IPADBG("IPA gsi is registered\n"); + /* GSI 2.2 requires to allocate all EE GSI channel + * during device bootup. + */ + if (ipa3_get_gsi_ver(resource_p->ipa_hw_type) == GSI_VER_2_2) { + result = ipa3_alloc_gsi_channel(); + if (result) { + IPAERR("Failed to alloc the GSI channels\n"); + result = -ENODEV; + goto fail_alloc_gsi_channel; + } + } /* setup the AP-IPA pipes */ if (ipa3_setup_apps_pipes()) { @@ -4727,6 +4777,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, fail_teth_bridge_driver_init: ipa3_teardown_apps_pipes(); +fail_alloc_gsi_channel: fail_setup_apps_pipes: gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false); fail_register_device: @@ -5504,6 +5555,16 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, IPADBG("ipa cdev added successful. major:%d minor:%d\n", MAJOR(ipa3_ctx->cdev.dev_num), MINOR(ipa3_ctx->cdev.dev_num)); + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1) { + result = ipa_odl_init(); + if (result) { + IPADBG("Error: ODL init fialed\n"); + result = -ENODEV; + goto fail_cdev_add; + } + } + /* * for IPA 4.0 offline charge is not needed and we need to prevent * power collapse until IPA uC is loaded. @@ -5513,7 +5574,6 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0) ipa3_proxy_clk_unvote(); return 0; - fail_cdev_add: fail_gsi_pre_fw_load_init: ipa3_dma_shutdown(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 3aaf7f50e5a2a953874c95ff93a12e59d42ee6fc..7f0e29211efc1e8c95ee4a02bdce7491bd399e0c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1345,27 +1345,32 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id, } /* - * Set USB PROD pipe delay for MBIM/RMNET config + * Set reset ep_delay for CLIENT PROD pipe * Clocks, should be voted before calling this API * locks should be taken before calling this API */ -void ipa3_set_usb_prod_pipe_delay(void) +int ipa3_set_reset_client_prod_pipe_delay(bool set_reset, + enum ipa_client_type client) { - int result; + int result = 0; int pipe_idx; struct ipa3_ep_context *ep; struct ipa_ep_cfg_ctrl ep_ctrl; memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); - ep_ctrl.ipa_ep_delay = true; + ep_ctrl.ipa_ep_delay = set_reset; + if (IPA_CLIENT_IS_CONS(client)) { + IPAERR("client (%d) not PROD\n", client); + return -EINVAL; + } - pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD); + pipe_idx = ipa3_get_ep_mapping(client); if (pipe_idx == IPA_EP_NOT_ALLOCATED) { - IPAERR("client (%d) not valid\n", IPA_CLIENT_USB_PROD); - return; + IPAERR("client (%d) not valid\n", client); + return -EINVAL; } ep = &ipa3_ctx->ep[pipe_idx]; @@ -1382,6 +1387,59 @@ void ipa3_set_usb_prod_pipe_delay(void) IPADBG("client (ep: %d) success\n", pipe_idx); } client_lock_unlock_cb(pipe_idx, false); + return result; +} + +int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, + enum ipa_client_type client) +{ + int pipe_idx; + struct ipa3_ep_context *ep; + struct ipa_ep_cfg_ctrl ep_suspend; + struct ipa_ep_cfg_holb ep_holb; + + memset(&ep_suspend, 0, sizeof(ep_suspend)); + memset(&ep_holb, 0, sizeof(ep_holb)); + + ep_suspend.ipa_ep_suspend = set_reset; + ep_holb.tmr_val = 0; + ep_holb.en = set_reset; + + if (IPA_CLIENT_IS_PROD(client)) { + IPAERR("client (%d) not CONS\n", client); + return -EINVAL; + } + + pipe_idx = ipa3_get_ep_mapping(client); + + if (pipe_idx == IPA_EP_NOT_ALLOCATED) { + IPAERR("client (%d) not valid\n", client); + return -EINVAL; + } + + ep = &ipa3_ctx->ep[pipe_idx]; + /* Setting sus/holb on MHI_CONS with skip_ep_cfg */ + client_lock_unlock_cb(pipe_idx, true); + if (ep->valid && ep->skip_ep_cfg) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_n, + pipe_idx, &ep_suspend); + /* + * ipa3_cfg_ep_holb is not used here because we are + * setting HOLB on Q6 pipes, and from APPS perspective + * they are not valid, therefore, the above function + * will fail. + */ + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, + pipe_idx, &ep_holb); + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_EN_n, + pipe_idx, &ep_holb); + } + client_lock_unlock_cb(pipe_idx, false); + return 0; } void ipa3_xdci_ep_delay_rm(u32 clnt_hdl) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index e2be2bb72366f4266ff01be969b6a2ad052a9fec..206e53d67b36ac99740617cd0c1129249be78a24 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -18,6 +18,7 @@ #include "ipa_i.h" #include "../ipa_rm_i.h" #include "ipahal/ipahal_nat.h" +#include "ipa_odl.h" #define IPA_MAX_ENTRY_STRING_LEN 500 #define IPA_MAX_MSG_LEN 4096 @@ -75,6 +76,7 @@ const char *ipa3_event_name[] = { __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT), __stringify(ADD_BRIDGE_VLAN_MAPPING), __stringify(DEL_BRIDGE_VLAN_MAPPING), + __stringify(WLAN_FWR_SSR_BEFORE_SHUTDOWN), }; const char *ipa3_hdr_l2_type_name[] = { @@ -1136,6 +1138,27 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf, return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } +static ssize_t ipa3_read_odlstats(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + int nbytes; + int cnt = 0; + + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "ODL received pkt =%u\n" + "ODL processed pkt to DIAG=%u\n" + "ODL dropped pkt =%u\n" + "ODL packet in queue =%u\n", + ipa3_odl_ctx->stats.odl_rx_pkt, + ipa3_odl_ctx->stats.odl_tx_diag_pkt, + ipa3_odl_ctx->stats.odl_drop_pkt, + ipa3_odl_ctx->stats.numer_in_queue); + + cnt += nbytes; + + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); +} + static ssize_t ipa3_read_wstats(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { @@ -2180,6 +2203,10 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "wstats", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_wstats, } + }, { + "odlstats", IPA_READ_ONLY_MODE, NULL, { + .read = ipa3_read_odlstats, + } }, { "wdi", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_wdi, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index fb342ad4196174272be2a9e10f1353d6a726d714..f06fec9788a6539ecfa1576545f4bb5fd0319339 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -60,7 +60,8 @@ #define IPA_ODU_RX_BUFF_SZ 2048 #define IPA_ODU_RX_POOL_SZ 64 -#define IPA_SIZE_DL_CSUM_META_TRAILER 8 + +#define IPA_ODL_RX_BUFF_SZ (16 * 1024) #define IPA_GSI_MAX_CH_LOW_WEIGHT 15 #define IPA_GSI_EVT_RING_INT_MODT (16) /* 0.5ms under 32KHz clock */ @@ -2278,8 +2279,7 @@ static int ipa3_lan_rx_pyld_hdlr(struct sk_buff *skb, return rc; } memcpy(&comp, skb->data, sizeof(comp)); - skb_pull(skb, sizeof(comp) + - IPA_SIZE_DL_CSUM_META_TRAILER); + skb_pull(skb, sizeof(comp)); complete(&comp->comp); if (atomic_dec_return(&comp->cnt) == 0) kfree(comp); @@ -2325,8 +2325,7 @@ static int ipa3_lan_rx_pyld_hdlr(struct sk_buff *skb, pad_len_byte = ((status.pkt_len + 3) & ~3) - status.pkt_len; - len = status.pkt_len + pad_len_byte + - IPA_SIZE_DL_CSUM_META_TRAILER; + len = status.pkt_len + pad_len_byte; IPADBG_LOW("pad %d pkt_len %d len %d\n", pad_len_byte, status.pkt_len, len); @@ -2864,6 +2863,17 @@ static int ipa3_odu_rx_pyld_hdlr(struct sk_buff *rx_skb, return 0; } +static int ipa3_odl_dpl_rx_pyld_hdlr(struct sk_buff *rx_skb, + struct ipa3_sys_context *sys) +{ + if (WARN(!sys->ep->client_notify, "sys->ep->client_notify is NULL\n")) + dev_kfree_skb_any(rx_skb); + else + sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, + (unsigned long)(rx_skb)); + + return 0; +} static void ipa3_free_rx_wrapper(struct ipa3_rx_pkt_wrapper *rk_pkt) { kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rk_pkt); @@ -3054,6 +3064,26 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, in->client); sys->policy = IPA_POLICY_NOINTR_MODE; + } else if (in->client == IPA_CLIENT_ODL_DPL_CONS) { + IPADBG("assigning policy to ODL client:%d\n", + in->client); + sys->ep->status.status_en = true; + sys->policy = IPA_POLICY_INTR_POLL_MODE; + INIT_WORK(&sys->work, ipa3_wq_handle_rx); + INIT_DELAYED_WORK(&sys->switch_to_intr_work, + ipa3_switch_to_intr_rx_work_func); + INIT_DELAYED_WORK(&sys->replenish_rx_work, + ipa3_replenish_rx_work_func); + atomic_set(&sys->curr_polling_state, 0); + sys->rx_buff_sz = + IPA_GENERIC_RX_BUFF_SZ(IPA_ODL_RX_BUFF_SZ); + sys->pyld_hdlr = ipa3_odl_dpl_rx_pyld_hdlr; + sys->get_skb = ipa3_get_skb_ipa_rx; + sys->free_skb = ipa3_free_skb_rx; + sys->free_rx_wrapper = ipa3_recycle_rx_wrapper; + sys->repl_hdlr = ipa3_replenish_rx_cache_recycle; + sys->rx_pool_sz = in->desc_fifo_sz / + IPA_FIFO_ELEMENT_SIZE - 1; } else { WARN(1, "Need to install a RX pipe hdlr\n"); return -EINVAL; @@ -3523,8 +3553,10 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) IPADBG_LOW("event %d notified\n", notify->evt_id); sys = (struct ipa3_sys_context *)notify->chan_user_data; + spin_lock_bh(&sys->spinlock); rx_pkt_expected = list_first_entry(&sys->head_desc_list, struct ipa3_rx_pkt_wrapper, link); + spin_unlock_bh(&sys->spinlock); rx_pkt_rcvd = (struct ipa3_rx_pkt_wrapper *)notify->xfer_user_data; if (rx_pkt_expected != rx_pkt_rcvd) { @@ -3781,7 +3813,10 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, ep->gsi_mem_info.chan_ring_base_vaddr = gsi_channel_props.ring_base_vaddr; - gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; if (ep->client == IPA_CLIENT_APPS_CMD_PROD) gsi_channel_props.low_weight = IPA_GSI_MAX_CH_LOW_WEIGHT; @@ -4080,7 +4115,12 @@ int ipa_gsi_ch20_wa(void) dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, &dma_addr, 0); gsi_channel_props.ring_base_addr = dma_addr; - gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; gsi_channel_props.low_weight = 1; gsi_channel_props.err_cb = ipa_gsi_chan_err_cb; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 699e0bd0363c3cf88ac427618a33bfe29e522640..18ba305a555a514611941af034ffd1408b5af111 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1966,7 +1966,10 @@ int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); void ipa3_xdci_ep_delay_rm(u32 clnt_hdl); void ipa3_register_lock_unlock_callback(int (*client_cb)(bool), u32 ipa_ep_idx); void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx); -void ipa3_set_usb_prod_pipe_delay(void); +int ipa3_set_reset_client_prod_pipe_delay(bool set_reset, + enum ipa_client_type client); +int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, + enum ipa_client_type client); int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool should_force_clear, u32 qmi_req_id, bool is_dpl); @@ -2322,6 +2325,7 @@ void ipa3_proxy_clk_unvote(void); bool ipa3_is_client_handle_valid(u32 clnt_hdl); enum ipa_client_type ipa3_get_client_mapping(int pipe_idx); +enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx); void ipa_init_ep_flt_bitmap(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 35a0e61d46dfa31f7372b72a20eb2363997b89af..779047815adbbf147ee07a5e85ab5f529496948d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -198,6 +198,8 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, union __packed gsi_channel_scratch ch_scratch; struct ipa3_ep_context *ep; const struct ipa_gsi_ep_config *ep_cfg; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + bool burst_mode_enabled = false; IPA_MHI_FUNC_ENTRY(); @@ -280,7 +282,18 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, ch_props.ring_len = params->ch_ctx_host->rlen; ch_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND( params->ch_ctx_host->rbase); - ch_props.use_db_eng = GSI_CHAN_DB_MODE; + + if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT || + params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) { + burst_mode_enabled = true; + } + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0 && + !burst_mode_enabled) + ch_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + ch_props.use_db_eng = GSI_CHAN_DB_MODE; + ch_props.max_prefetch = GSI_ONE_PREFETCH_SEG; ch_props.low_weight = 1; ch_props.prefetch_mode = ep_cfg->prefetch_mode; @@ -314,9 +327,9 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, min(ep_cfg->ipa_if_tlv / 2, 8) * ch_props.re_size; } ch_scratch.mhi.oob_mod_threshold = 4; - if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT || - params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) { - ch_scratch.mhi.burst_mode_enabled = true; + + if (burst_mode_enabled) { + ch_scratch.mhi.burst_mode_enabled = burst_mode_enabled; ch_scratch.mhi.polling_configuration = ipa3_mhi_get_ch_poll_cfg(client, params->ch_ctx_host, (ch_props.ring_len / ch_props.re_size)); @@ -334,6 +347,20 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, *params->mhi = ch_scratch.mhi; + if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg) { + memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_delay = true; + ep->ep_delay_set = true; + res = ipa3_cfg_ep_ctrl(ipa_ep_idx, &ep_cfg_ctrl); + if (res) + IPA_MHI_ERR("client (ep: %d) failed result=%d\n", + ipa_ep_idx, res); + else + IPA_MHI_DBG("client (ep: %d) success\n", ipa_ep_idx); + } else { + ep->ep_delay_set = false; + } + IPA_MHI_DBG("Starting channel\n"); res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { @@ -517,6 +544,7 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) { struct ipa3_ep_context *ep; int res; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; IPA_MHI_FUNC_ENTRY(); @@ -531,6 +559,21 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) } ep = &ipa3_ctx->ep[clnt_hdl]; + if (ep->ep_delay_set == true) { + memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_delay = false; + res = ipa3_cfg_ep_ctrl(clnt_hdl, + &ep_cfg_ctrl); + if (res) { + IPAERR + ("client(ep:%d) failed to remove delay res=%d\n", + clnt_hdl, res); + } else { + IPADBG("client (ep: %d) delay removed\n", + clnt_hdl); + ep->ep_delay_set = false; + } + } res = gsi_dealloc_channel(ep->gsi_chan_hdl); if (res) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c index 86b235bf071fbd29258195298ce999f667551c07..9001b38cc5ec82c053e908e38eac8d7ec8d319c8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c @@ -923,9 +923,8 @@ static int imp_probe(struct platform_device *pdev) static int imp_remove(struct platform_device *pdev) { IMP_FUNC_ENTRY(); - mutex_lock(&imp_ctx->mutex); mhi_driver_unregister(&mhi_driver); - + mutex_lock(&imp_ctx->mutex); if (!imp_ctx->in_lpm) IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IMP"); imp_ctx->in_lpm = false; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h index 3a1d97d188c8964727f6d7dd4a17322f35051913..c0e5ef6b47e3f654629b268e3fb0c738a168ebc4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h @@ -24,6 +24,8 @@ struct ipa_mhi_alloc_channel_resp_msg_v01 *imp_handle_allocate_channel_req( int imp_handle_vote_req(bool vote); +void imp_handle_modem_shutdown(void); + #else /* CONFIG_IPA3_MHI_PROXY */ static inline void imp_handle_modem_ready(void) @@ -43,6 +45,11 @@ static inline int imp_handle_vote_req(bool vote) return -EPERM; } +static inline void imp_handle_modem_shutdown(void) +{ + +} + #endif /* CONFIG_IPA3_MHI_PROXY */ #endif /* __IMP_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c new file mode 100644 index 0000000000000000000000000000000000000000..87920f2818c56f24a4c17f4be1ca09f4b1135651 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c @@ -0,0 +1,681 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "ipa_i.h" +#include "ipa_odl.h" +#include +#include + +struct ipa_odl_context *ipa3_odl_ctx; + +static DECLARE_WAIT_QUEUE_HEAD(odl_ctl_msg_wq); + +static void print_ipa_odl_state_bit_mask(void) +{ + IPADBG("ipa3_odl_ctx->odl_state.odl_init --> %d\n", + ipa3_odl_ctx->odl_state.odl_init); + IPADBG("ipa3_odl_ctx->odl_state.odl_open --> %d\n", + ipa3_odl_ctx->odl_state.odl_open); + IPADBG("ipa3_odl_ctx->odl_state.adpl_open --> %d\n", + ipa3_odl_ctx->odl_state.adpl_open); + IPADBG("ipa3_odl_ctx->odl_state.aggr_byte_limit_sent --> %d\n", + ipa3_odl_ctx->odl_state.aggr_byte_limit_sent); + IPADBG("ipa3_odl_ctx->odl_state.odl_ep_setup --> %d\n", + ipa3_odl_ctx->odl_state.odl_ep_setup); + IPADBG("ipa3_odl_ctx->odl_state.odl_setup_done_sent --> %d\n", + ipa3_odl_ctx->odl_state.odl_setup_done_sent); + IPADBG("ipa3_odl_ctx->odl_state.odl_ep_info_sent --> %d\n", + ipa3_odl_ctx->odl_state.odl_ep_info_sent); + IPADBG("ipa3_odl_ctx->odl_state.odl_connected --> %d\n", + ipa3_odl_ctx->odl_state.odl_connected); + IPADBG("ipa3_odl_ctx->odl_state.odl_disconnected --> %d\n\n", + ipa3_odl_ctx->odl_state.odl_disconnected); +} + +static int ipa_odl_ctl_fops_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + if (ipa3_odl_ctx->odl_state.odl_init) { + ipa3_odl_ctx->odl_state.odl_open = true; + } else { + IPAERR("Before odl init trying to open odl ctl pipe\n"); + print_ipa_odl_state_bit_mask(); + ret = -ENODEV; + } + + return ret; +} + +static int ipa_odl_ctl_fops_release(struct inode *inode, struct file *filp) +{ + IPADBG("QTI closed ipa_odl_ctl node\n"); + ipa3_odl_ctx->odl_state.odl_open = false; + return 0; +} + +/** + * ipa_odl_ctl_fops_read() - read message from IPA ODL device + * @filp: [in] file pointer + * @buf: [out] buffer to read into + * @count: [in] size of above buffer + * @f_pos: [inout] file position + * + * Uer-space should continuously read from /dev/ipa_odl_ctl, + * read will block when there are no messages to read. + * Upon return, user-space should read the u32 data from the + * start of the buffer. + * + * 0 --> ODL disconnected. + * 1 --> ODL connected. + * + * Buffer supplied must be big enough to + * hold the message of size u32. + * + * Returns: how many bytes copied to buffer + * + * Note: Should not be called from atomic context + */ + +static ssize_t ipa_odl_ctl_fops_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + char __user *start; + u8 data; + int ret = 0; + static bool old_state; + bool new_state = false; + + start = buf; + while (1) { + wait_event_interruptible(odl_ctl_msg_wq, + ipa3_odl_ctx->odl_ctl_msg_wq_flag == true); + ipa3_odl_ctx->odl_ctl_msg_wq_flag = false; + if (!ipa3_odl_ctx->odl_state.adpl_open && + !ipa3_odl_ctx->odl_state.odl_disconnected) + break; + + if (ipa3_odl_ctx->odl_state.odl_ep_setup) + new_state = true; + else if (ipa3_odl_ctx->odl_state.odl_disconnected) + new_state = false; + else { + ret = -EAGAIN; + break; + } + + if (old_state != new_state) { + old_state = new_state; + + if (new_state == true) + data = 1; + else if (new_state == false) + data = 0; + + if (copy_to_user(buf, &data, + sizeof(data))) { + ret = -EFAULT; + break; + } + + buf += sizeof(data); + + if (data == 1) + ipa3_odl_ctx->odl_state.odl_setup_done_sent = + true; + } + + ret = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) + break; + + ret = -EINTR; + if (signal_pending(current)) + break; + + if (start != buf) + break; + } + + if (start != buf && ret != -EFAULT) + ret = buf - start; + + return ret; +} + +static long ipa_odl_ctl_fops_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ipa_odl_ep_info ep_info = {0}; + struct ipa_odl_modem_config status; + int retval = 0; + + IPADBG("Calling odl ioctl cmd = %d\n", cmd); + if (!ipa3_odl_ctx->odl_state.odl_setup_done_sent) { + IPAERR("Before complete the odl setup trying calling ioctl\n"); + print_ipa_odl_state_bit_mask(); + retval = -ENODEV; + goto fail; + } + + switch (cmd) { + case IPA_IOC_ODL_QUERY_ADAPL_EP_INFO: + /* Send ep_info to user APP */ + ep_info.ep_type = ODL_EP_TYPE_HSUSB; + ep_info.peripheral_iface_id = ODL_EP_PERIPHERAL_IFACE_ID; + ep_info.cons_pipe_num = -1; + ep_info.prod_pipe_num = + ipa3_odl_ctx->odl_client_hdl; + if (copy_to_user((void __user *)arg, &ep_info, + sizeof(ep_info))) { + retval = -EFAULT; + goto fail; + } + ipa3_odl_ctx->odl_state.odl_ep_info_sent = true; + break; + case IPA_IOC_ODL_QUERY_MODEM_CONFIG: + IPADBG("Received the IPA_IOC_ODL_QUERY_MODEM_CONFIG :\n"); + if (copy_from_user(&status, (const void __user *)arg, + sizeof(status))) { + retval = -EFAULT; + break; + } + if (status.config_status == CONFIG_SUCCESS) + ipa3_odl_ctx->odl_state.odl_connected = true; + IPADBG("status.config_status = %d odl_connected = %d\n", + status.config_status, ipa3_odl_ctx->odl_state.odl_connected); + break; + default: + retval = -ENOIOCTLCMD; + break; + } + +fail: + return retval; +} + +static void delete_first_node(void) +{ + struct ipa3_push_msg_odl *msg; + + if (!list_empty(&ipa3_odl_ctx->adpl_msg_list)) { + msg = list_first_entry(&ipa3_odl_ctx->adpl_msg_list, + struct ipa3_push_msg_odl, link); + if (msg) { + list_del(&msg->link); + kfree(msg->buff); + kfree(msg); + ipa3_odl_ctx->stats.odl_drop_pkt++; + IPA_STATS_DEC_CNT(ipa3_odl_ctx->stats.numer_in_queue); + } + } else { + IPADBG("List Empty\n"); + } +} + +int ipa3_send_adpl_msg(unsigned long skb_data) +{ + struct ipa3_push_msg_odl *msg; + struct sk_buff *skb = (struct sk_buff *)skb_data; + void *data; + + IPADBG_LOW("Processing DPL data\n"); + msg = kzalloc(sizeof(struct ipa3_push_msg_odl), GFP_KERNEL); + if (msg == NULL) { + IPADBG("Memory allocation failed\n"); + return -ENOMEM; + } + + data = kmalloc(skb->len, GFP_KERNEL); + if (data == NULL) { + kfree(msg); + return -ENOMEM; + } + memcpy(data, skb->data, skb->len); + msg->buff = data; + msg->len = skb->len; + mutex_lock(&ipa3_odl_ctx->adpl_msg_lock); + if (ipa3_odl_ctx->stats.numer_in_queue >= MAX_QUEUE_TO_ODL) + delete_first_node(); + list_add_tail(&msg->link, &ipa3_odl_ctx->adpl_msg_list); + IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.numer_in_queue); + mutex_unlock(&ipa3_odl_ctx->adpl_msg_lock); + IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.odl_rx_pkt); + + return 0; +} + +/** + * odl_ipa_packet_receive_notify() - Rx notify + * + * @priv: driver context + * @evt: event type + * @data: data provided with event + * + * IPA will pass a packet to the Linux network stack with skb->data + */ +static void odl_ipa_packet_receive_notify(void *priv, + enum ipa_dp_evt_type evt, + unsigned long data) +{ + IPADBG_LOW("Rx packet was received\n"); + if (evt == IPA_RECEIVE) + ipa3_send_adpl_msg(data); + else + IPAERR("Invalid evt %d received in wan_ipa_receive\n", evt); +} + +int ipa_setup_odl_pipe(void) +{ + struct ipa_sys_connect_params *ipa_odl_ep_cfg; + int ret; + + ipa_odl_ep_cfg = &ipa3_odl_ctx->odl_sys_param; + + IPADBG("Setting up the odl endpoint\n"); + ipa_odl_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL; + + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_hard_byte_limit_en = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr = IPA_GENERIC; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_byte_limit = + IPA_ODL_AGGR_BYTE_LIMIT; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_pkt_limit = 0; + + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2; + + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = 0; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = true; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_little_endian = 0; + ipa_odl_ep_cfg->ipa_ep_cfg.metadata_mask.metadata_mask = 0xFF000000; + + ipa_odl_ep_cfg->client = IPA_CLIENT_ODL_DPL_CONS; + ipa_odl_ep_cfg->notify = odl_ipa_packet_receive_notify; + + ipa_odl_ep_cfg->napi_enabled = false; + ipa_odl_ep_cfg->desc_fifo_sz = IPA_ODL_RX_RING_SIZE * + IPA_FIFO_ELEMENT_SIZE; + + ret = ipa3_setup_sys_pipe(ipa_odl_ep_cfg, + &ipa3_odl_ctx->odl_client_hdl); + return ret; + +} + +int ipa3_odl_pipe_open(void) +{ + int ret = 0; + struct ipa_ep_cfg_holb holb_cfg; + + if (!ipa3_odl_ctx->odl_state.adpl_open) { + IPAERR("adpl pipe not configured\n"); + return 0; + } + + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.tmr_val = 0; + holb_cfg.en = 1; + + ipa3_cfg_ep_holb_by_client(IPA_CLIENT_USB_DPL_CONS, &holb_cfg); + ret = ipa_setup_odl_pipe(); + if (ret) { + IPAERR(" Setup endpoint config failed\n"); + goto fail; + } + ipa3_cfg_ep_holb_by_client(IPA_CLIENT_ODL_DPL_CONS, &holb_cfg); + ipa3_odl_ctx->odl_state.odl_ep_setup = true; + IPADBG("Setup endpoint config success\n"); + + ipa3_odl_ctx->stats.odl_drop_pkt = 0; + ipa3_odl_ctx->stats.numer_in_queue = 0; + ipa3_odl_ctx->stats.odl_rx_pkt = 0; + ipa3_odl_ctx->stats.odl_tx_diag_pkt = 0; + /* + * Send signal to ipa_odl_ctl_fops_read, + * to send ODL ep open notification + */ + ipa3_odl_ctx->odl_ctl_msg_wq_flag = true; + IPADBG("Wake up odl ctl\n"); + wake_up_interruptible(&odl_ctl_msg_wq); + if (ipa3_odl_ctx->odl_state.odl_disconnected) + ipa3_odl_ctx->odl_state.odl_disconnected = false; +fail: + return ret; + +} +static int ipa_adpl_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + IPADBG("Called the function :\n"); + if (ipa3_odl_ctx->odl_state.odl_init) { + ipa3_odl_ctx->odl_state.adpl_open = true; + ret = ipa3_odl_pipe_open(); + } else { + IPAERR("Before odl init trying to open adpl pipe\n"); + print_ipa_odl_state_bit_mask(); + ret = -ENODEV; + } + + return ret; +} + +static int ipa_adpl_release(struct inode *inode, struct file *filp) +{ + ipa3_odl_pipe_cleanup(false); + return 0; +} + +void ipa3_odl_pipe_cleanup(bool is_ssr) +{ + bool ipa_odl_opened = false; + struct ipa_ep_cfg_holb holb_cfg; + + if (!ipa3_odl_ctx->odl_state.adpl_open) { + IPAERR("adpl pipe not configured\n"); + return; + } + if (ipa3_odl_ctx->odl_state.odl_open) + ipa_odl_opened = true; + + memset(&ipa3_odl_ctx->odl_state, 0, sizeof(ipa3_odl_ctx->odl_state)); + + /*Since init will not be done again*/ + ipa3_odl_ctx->odl_state.odl_init = true; + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.tmr_val = 0; + holb_cfg.en = 0; + + ipa3_cfg_ep_holb_by_client(IPA_CLIENT_USB_DPL_CONS, &holb_cfg); + + ipa3_teardown_sys_pipe(ipa3_odl_ctx->odl_client_hdl); + /*Assume QTI will never close this node once opened*/ + if (ipa_odl_opened) + ipa3_odl_ctx->odl_state.odl_open = true; + + /*Assume DIAG will not close this node in SSR case*/ + if (is_ssr) + ipa3_odl_ctx->odl_state.adpl_open = true; + + ipa3_odl_ctx->odl_state.odl_disconnected = true; + ipa3_odl_ctx->odl_state.odl_ep_setup = false; + ipa3_odl_ctx->odl_state.aggr_byte_limit_sent = false; + ipa3_odl_ctx->odl_state.odl_connected = false; + /* + * Send signal to ipa_odl_ctl_fops_read, + * to send ODL ep close notification + */ + ipa3_odl_ctx->odl_ctl_msg_wq_flag = true; + ipa3_odl_ctx->stats.odl_drop_pkt = 0; + ipa3_odl_ctx->stats.numer_in_queue = 0; + ipa3_odl_ctx->stats.odl_rx_pkt = 0; + ipa3_odl_ctx->stats.odl_tx_diag_pkt = 0; + IPADBG("Wake up odl ctl\n"); + wake_up_interruptible(&odl_ctl_msg_wq); + +} + +/** + * ipa_adpl_read() - read message from IPA device + * @filp: [in] file pointer + * @buf: [out] buffer to read into + * @count: [in] size of above buffer + * @f_pos: [inout] file position + * + * User-space should continually read from /dev/ipa_adpl, + * read will block when there are no messages to read. + * Upon return, user-space should read + * Buffer supplied must be big enough to + * hold the data. + * + * Returns: how many bytes copied to buffer + * + * Note: Should not be called from atomic context + */ +static ssize_t ipa_adpl_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + int ret = 0; + char __user *start = buf; + struct ipa3_push_msg_odl *msg; + + while (1) { + IPADBG_LOW("Writing message to adpl pipe\n"); + if (!ipa3_odl_ctx->odl_state.odl_open) + break; + + mutex_lock(&ipa3_odl_ctx->adpl_msg_lock); + msg = NULL; + if (!list_empty(&ipa3_odl_ctx->adpl_msg_list)) { + msg = list_first_entry(&ipa3_odl_ctx->adpl_msg_list, + struct ipa3_push_msg_odl, link); + list_del(&msg->link); + IPA_STATS_DEC_CNT(ipa3_odl_ctx->stats.numer_in_queue); + } + + mutex_unlock(&ipa3_odl_ctx->adpl_msg_lock); + + if (msg != NULL) { + if (msg->len > count) { + IPAERR("Message length greater than count\n"); + kfree(msg->buff); + kfree(msg); + msg = NULL; + ret = -EAGAIN; + break; + } + + if (msg->buff) { + if (copy_to_user(buf, msg->buff, + msg->len)) { + ret = -EFAULT; + kfree(msg->buff); + kfree(msg); + msg = NULL; + ret = -EAGAIN; + break; + } + buf += msg->len; + count -= msg->len; + kfree(msg->buff); + } + IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.odl_tx_diag_pkt); + kfree(msg); + msg = NULL; + } else { + ret = -EAGAIN; + break; + } + + ret = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) + break; + + ret = -EINTR; + if (signal_pending(current)) + break; + + if (start != buf) + break; + + } + + if (start != buf && ret != -EFAULT) + ret = buf - start; + + return ret; +} + +static long ipa_adpl_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct odl_agg_pipe_info odl_pipe_info; + int retval = 0; + + if (!ipa3_odl_ctx->odl_state.odl_connected) { + IPAERR("ODL config in progress not allowed ioctl\n"); + print_ipa_odl_state_bit_mask(); + retval = -ENODEV; + goto fail; + } + IPADBG("Calling adpl ioctl\n"); + + switch (cmd) { + case IPA_IOC_ODL_GET_AGG_BYTE_LIMIT: + odl_pipe_info.agg_byte_limit = + ipa3_odl_ctx->odl_sys_param.ipa_ep_cfg.aggr.aggr_byte_limit; + if (copy_to_user((void __user *)arg, &odl_pipe_info, + sizeof(odl_pipe_info))) { + retval = -EFAULT; + goto fail; + } + ipa3_odl_ctx->odl_state.aggr_byte_limit_sent = true; + break; + default: + retval = -ENOIOCTLCMD; + print_ipa_odl_state_bit_mask(); + break; + } + +fail: + return retval; +} + +static const struct file_operations ipa_odl_ctl_fops = { + .owner = THIS_MODULE, + .open = ipa_odl_ctl_fops_open, + .release = ipa_odl_ctl_fops_release, + .read = ipa_odl_ctl_fops_read, + .unlocked_ioctl = ipa_odl_ctl_fops_ioctl, +}; + +static const struct file_operations ipa_adpl_fops = { + .owner = THIS_MODULE, + .open = ipa_adpl_open, + .release = ipa_adpl_release, + .read = ipa_adpl_read, + .unlocked_ioctl = ipa_adpl_ioctl, +}; + +int ipa_odl_init(void) +{ + int result = 0; + struct cdev *cdev; + int loop = 0; + struct ipa3_odl_char_device_context *odl_cdev; + + ipa3_odl_ctx = kzalloc(sizeof(*ipa3_odl_ctx), GFP_KERNEL); + if (!ipa3_odl_ctx) { + result = -ENOMEM; + goto fail_mem_ctx; + } + + odl_cdev = ipa3_odl_ctx->odl_cdev; + INIT_LIST_HEAD(&ipa3_odl_ctx->adpl_msg_list); + mutex_init(&ipa3_odl_ctx->adpl_msg_lock); + + odl_cdev[loop].class = class_create(THIS_MODULE, "ipa_adpl"); + + if (IS_ERR(odl_cdev[loop].class)) { + IPAERR("Error: odl_cdev->class NULL\n"); + result = -ENODEV; + goto create_char_dev0_fail; + } + + result = alloc_chrdev_region(&odl_cdev[loop].dev_num, 0, 1, "ipa_adpl"); + if (result) { + IPAERR("alloc_chrdev_region error for ipa adpl pipe\n"); + result = -ENODEV; + goto alloc_chrdev0_region_fail; + } + + odl_cdev[loop].dev = device_create(odl_cdev[loop].class, NULL, + odl_cdev[loop].dev_num, ipa3_ctx, "ipa_adpl"); + if (IS_ERR(odl_cdev[loop].dev)) { + IPAERR("device_create err:%ld\n", PTR_ERR(odl_cdev[loop].dev)); + result = PTR_ERR(odl_cdev[loop].dev); + goto device0_create_fail; + } + + cdev = &odl_cdev[loop].cdev; + cdev_init(cdev, &ipa_adpl_fops); + cdev->owner = THIS_MODULE; + cdev->ops = &ipa_adpl_fops; + + result = cdev_add(cdev, odl_cdev[loop].dev_num, 1); + if (result) { + IPAERR("cdev_add err=%d\n", -result); + goto cdev0_add_fail; + } + + loop++; + + odl_cdev[loop].class = class_create(THIS_MODULE, "ipa_odl_ctl"); + + if (IS_ERR(odl_cdev[loop].class)) { + IPAERR("Error: odl_cdev->class NULL\n"); + result = -ENODEV; + goto create_char_dev1_fail; + } + + result = alloc_chrdev_region(&odl_cdev[loop].dev_num, 0, 1, + "ipa_odl_ctl"); + if (result) { + IPAERR("alloc_chrdev_region error for ipa odl ctl pipe\n"); + goto alloc_chrdev1_region_fail; + } + + odl_cdev[loop].dev = device_create(odl_cdev[loop].class, NULL, + odl_cdev[loop].dev_num, ipa3_ctx, "ipa_odl_ctl"); + if (IS_ERR(odl_cdev[loop].dev)) { + IPAERR("device_create err:%ld\n", PTR_ERR(odl_cdev[loop].dev)); + result = PTR_ERR(odl_cdev[loop].dev); + goto device1_create_fail; + } + + cdev = &odl_cdev[loop].cdev; + cdev_init(cdev, &ipa_odl_ctl_fops); + cdev->owner = THIS_MODULE; + cdev->ops = &ipa_odl_ctl_fops; + + result = cdev_add(cdev, odl_cdev[loop].dev_num, 1); + if (result) { + IPAERR(":cdev_add err=%d\n", -result); + goto cdev1_add_fail; + } + + ipa3_odl_ctx->odl_state.odl_init = true; + return 0; +cdev1_add_fail: + device_destroy(odl_cdev[1].class, odl_cdev[1].dev_num); +device1_create_fail: + unregister_chrdev_region(odl_cdev[1].dev_num, 1); +alloc_chrdev1_region_fail: + class_destroy(odl_cdev[1].class); +create_char_dev1_fail: +cdev0_add_fail: + device_destroy(odl_cdev[0].class, odl_cdev[0].dev_num); +device0_create_fail: + unregister_chrdev_region(odl_cdev[0].dev_num, 1); +alloc_chrdev0_region_fail: + class_destroy(odl_cdev[0].class); +create_char_dev0_fail: + kfree(ipa3_odl_ctx); +fail_mem_ctx: + return result; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h new file mode 100644 index 0000000000000000000000000000000000000000..5f522505aa1ed76cce8632d045ee752201c6fdb0 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _IPA3_ODL_H_ +#define _IPA3_ODL_H_ + +#define IPA_ODL_AGGR_BYTE_LIMIT (15 * 1024) +#define IPA_ODL_RX_RING_SIZE 192 +#define MAX_QUEUE_TO_ODL 1024 +#define CONFIG_SUCCESS 1 +#define ODL_EP_TYPE_HSUSB 2 +#define ODL_EP_PERIPHERAL_IFACE_ID 3 + +struct ipa3_odlstats { + u32 odl_rx_pkt; + u32 odl_tx_diag_pkt; + u32 odl_drop_pkt; + u32 numer_in_queue; +}; + +struct odl_state_bit_mask { + u32 odl_init:1; + u32 odl_open:1; + u32 adpl_open:1; + u32 aggr_byte_limit_sent:1; + u32 odl_ep_setup:1; + u32 odl_setup_done_sent:1; + u32 odl_ep_info_sent:1; + u32 odl_connected:1; + u32 odl_disconnected:1; + u32:0; +}; + +/** + * struct ipa3_odl_char_device_context - IPA ODL character device + * @class: pointer to the struct class + * @dev_num: device number + * @dev: the dev_t of the device + * @cdev: cdev of the device + */ +struct ipa3_odl_char_device_context { + struct class *class; + dev_t dev_num; + struct device *dev; + struct cdev cdev; +}; + +struct ipa_odl_context { + struct ipa3_odl_char_device_context odl_cdev[2]; + struct list_head adpl_msg_list; + struct mutex adpl_msg_lock; + struct ipa_sys_connect_params odl_sys_param; + u32 odl_client_hdl; + struct odl_state_bit_mask odl_state; + bool odl_ctl_msg_wq_flag; + struct ipa3_odlstats stats; +}; + +struct ipa3_push_msg_odl { + void *buff; + int len; + struct list_head link; +}; + +extern struct ipa_odl_context *ipa3_odl_ctx; + +int ipa_odl_init(void); +void ipa3_odl_pipe_cleanup(bool is_ssr); +int ipa3_odl_pipe_open(void); + +#endif /* _IPA3_ODL_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 1c59318cfefc857a01d0bbec2861007171da6d03..54640734157381d50d3f54f69b3d6b34d7e0873c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -476,26 +476,30 @@ static int ipa3_qmi_init_modem_send_sync_msg(void) IPA_MEM_PART(modem_comp_decomp_ofst) + IPA_MEM_PART(modem_comp_decomp_size) + smem_restr_bytes - 1; - req.v4_hash_route_tbl_info_valid = true; - req.v4_hash_route_tbl_info.route_tbl_start_addr = - IPA_MEM_PART(v4_rt_hash_ofst) + smem_restr_bytes; - req.v4_hash_route_tbl_info.num_indices = - IPA_MEM_PART(v4_modem_rt_index_hi); - - req.v6_hash_route_tbl_info_valid = true; - req.v6_hash_route_tbl_info.route_tbl_start_addr = - IPA_MEM_PART(v6_rt_hash_ofst) + smem_restr_bytes; - req.v6_hash_route_tbl_info.num_indices = - IPA_MEM_PART(v6_modem_rt_index_hi); - - req.v4_hash_filter_tbl_start_addr_valid = true; - req.v4_hash_filter_tbl_start_addr = - IPA_MEM_PART(v4_flt_hash_ofst) + smem_restr_bytes; - - req.v6_hash_filter_tbl_start_addr_valid = true; - req.v6_hash_filter_tbl_start_addr = - IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes; - + /* if hashing not supported, Modem filter/routing hash + * tables should not fill with valid data. + */ + if (!ipa3_ctx->ipa_fltrt_not_hashable) { + req.v4_hash_route_tbl_info_valid = true; + req.v4_hash_route_tbl_info.route_tbl_start_addr = + IPA_MEM_PART(v4_rt_hash_ofst) + smem_restr_bytes; + req.v4_hash_route_tbl_info.num_indices = + IPA_MEM_PART(v4_modem_rt_index_hi); + + req.v6_hash_route_tbl_info_valid = true; + req.v6_hash_route_tbl_info.route_tbl_start_addr = + IPA_MEM_PART(v6_rt_hash_ofst) + smem_restr_bytes; + req.v6_hash_route_tbl_info.num_indices = + IPA_MEM_PART(v6_modem_rt_index_hi); + + req.v4_hash_filter_tbl_start_addr_valid = true; + req.v4_hash_filter_tbl_start_addr = + IPA_MEM_PART(v4_flt_hash_ofst) + smem_restr_bytes; + + req.v6_hash_filter_tbl_start_addr_valid = true; + req.v6_hash_filter_tbl_start_addr = + IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes; + } req.hw_stats_quota_base_addr_valid = true; req.hw_stats_quota_base_addr = IPA_MEM_PART(stats_quota_ofst) + smem_restr_bytes; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index bca72e594910185cc02b25ca052626ba3a7f804d..4775351573a34b8072dc08abcb574fb7855aab86 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -923,6 +923,20 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) return 0; } +static int __ipa_rt_validate_rule_id(u16 rule_id) +{ + if (!rule_id) + return 0; + + if ((rule_id < ipahal_get_rule_id_hi_bit()) || + (rule_id >= ((ipahal_get_rule_id_hi_bit()<<1)-1))) { + IPAERR_RL("Invalid rule_id provided 0x%x\n", + rule_id); + return -EPERM; + } + + return 0; +} static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, struct ipa3_hdr_entry **hdr, struct ipa3_hdr_proc_ctx_entry **proc_ctx) @@ -1037,6 +1051,8 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; + if (__ipa_rt_validate_rule_id(rule_id)) + goto error; tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index e36e5fc8da0f6b117964007e0c9336198f3ff116..cd703e200915d4301c786016120feee96b1be3c7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -935,6 +935,7 @@ static int ipa3_wdi2_gsi_alloc_channel_ring( channel_props->use_db_eng = GSI_CHAN_DB_MODE; channel_props->max_prefetch = GSI_ONE_PREFETCH_SEG; + channel_props->prefetch_mode = ep_cfg->prefetch_mode; channel_props->low_weight = 1; channel_props->err_cb = ipa_gsi_chan_err_cb; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index c0fbeda0f678f1b8074e5a1141f4697a4e675aa4..357a4e5c3cb9a6cb32d1f1d51906f47a7f6a58e6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -70,6 +70,7 @@ #define IPA_EOT_COAL_GRAN_MIN (1) #define IPA_EOT_COAL_GRAN_MAX (16) +#define IPA_FILT_ROUT_HASH_REG_VAL_v4_2 (0x00000000) #define IPA_DMA_TASK_FOR_GSI_TIMEOUT_MSEC (15) #define IPA_AGGR_BYTE_LIMIT (\ @@ -1795,6 +1796,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, + [IPA_4_1][IPA_CLIENT_ODL_DPL_CONS] = { + true, IPA_v4_0_GROUP_UL_DL, + false, + IPA_DPS_HPS_SEQ_TYPE_INVALID, + QMB_MASTER_SELECT_DDR, + { 17, 1, 9, 9, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_ETHERNET_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, @@ -1865,80 +1872,80 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_DPS_HPS_REP_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 3, 7, 6, 7, IPA_EE_AP } }, + { 3, 7, 6, 7, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_USB_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 0, 5, 8, 9, IPA_EE_AP } }, + { 0, 5, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_LAN_PROD] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 2, 6, 8, 9, IPA_EE_AP } }, + { 2, 6, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_WAN_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 1, 0, 8, 12, IPA_EE_AP } }, + { 1, 0, 8, 12, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_CMD_PROD] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, - { 6, 1, 20, 20, IPA_EE_AP } }, + { 6, 1, 20, 20, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_Q6_WAN_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 4, 0, 8, 12, IPA_EE_Q6 } }, + { 4, 0, 8, 12, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_Q6_CMD_PROD] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 5, 1, 20, 20, IPA_EE_Q6 } }, + { 5, 1, 20, 20, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_ETHERNET_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 7, 0, 8, 10, IPA_EE_UC } }, + { 7, 0, 8, 10, IPA_EE_UC, GSI_USE_PREFETCH_BUFS} }, /* Only for test purpose */ [IPA_4_2][IPA_CLIENT_TEST_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - {0, 5, 8, 9, IPA_EE_AP } }, + {0, 5, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST1_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 0, 5, 8, 9, IPA_EE_AP } }, + { 0, 5, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST2_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 3, 7, 6, 7, IPA_EE_AP } }, + { 3, 7, 6, 7, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_TEST3_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - {1, 0, 8, 12, IPA_EE_AP } }, + {1, 0, 8, 12, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST4_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 7, 10, 8, 10, IPA_EE_AP } }, + { 7, 0, 8, 10, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_WLAN1_CONS] = { @@ -1946,55 +1953,55 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 14, 8, 6, 9, IPA_EE_AP } }, + { 14, 8, 6, 9, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_USB_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 9, 6, 6, IPA_EE_AP } }, + { 15, 9, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_USB_DPL_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 12, 4, 4, 4, IPA_EE_AP } }, + { 12, 4, 4, 4, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_LAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 8, 2, 6, 6, IPA_EE_AP } }, + { 8, 2, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_WAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 9, 3, 6, 6, IPA_EE_AP } }, + { 9, 3, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_Q6_LAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 11, 3, 6, 6, IPA_EE_Q6 } }, + { 11, 3, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_Q6_WAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 10, 2, 6, 6, IPA_EE_Q6 } }, + { 10, 2, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 13, 4, 6, 6, IPA_EE_Q6 } }, + { 13, 4, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_ETHERNET_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 16, 1, 6, 6, IPA_EE_UC } }, + { 16, 1, 6, 6, IPA_EE_UC, GSI_USE_PREFETCH_BUFS} }, /* Only for test purpose */ /* MBIM aggregation test pipes should have the same QMB as USB_CONS */ [IPA_4_2][IPA_CLIENT_TEST_CONS] = { @@ -2002,38 +2009,38 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 9, 6, 6, IPA_EE_AP } }, + { 15, 9, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 9, 6, 6, IPA_EE_AP } }, + { 15, 9, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST2_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 12, 4, 4, 4, IPA_EE_AP } }, + { 12, 4, 4, 4, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 14, 8, 6, 9, IPA_EE_AP } }, + { 14, 8, 6, 9, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_TEST4_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 9, 3, 6, 6, IPA_EE_AP } }, + { 9, 3, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_2][IPA_CLIENT_DUMMY_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 31, 31, 8, 8, IPA_EE_AP } }, + { 31, 31, 8, 8, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, /* IPA_4_5 */ [IPA_4_5][IPA_CLIENT_WLAN1_PROD] = { @@ -3121,6 +3128,21 @@ int ipa3_cfg_filter(u32 disable) return -EPERM; } +/** + * ipa_disable_hashing_rt_flt_v4_2() - Disable filer and route hashing. + * + * Return codes: 0 for success, negative value for failure + */ +static int ipa_disable_hashing_rt_flt_v4_2(void) +{ + + IPADBG("Disable hashing for filter and route table in IPA 4.2 HW\n"); + ipahal_write_reg(IPA_FILT_ROUT_HASH_EN, + IPA_FILT_ROUT_HASH_REG_VAL_v4_2); + return 0; +} + + /** * ipa_comp_cfg() - Configure QMB/Master port selection * @@ -3341,6 +3363,13 @@ int ipa3_init_hw(void) ipa_comp_cfg(); + /* + * In IPA 4.2 filter and routing hashing not supported + * disabling hash enable register. + */ + if (ipa3_ctx->ipa_fltrt_not_hashable) + ipa_disable_hashing_rt_flt_v4_2(); + return 0; } @@ -3578,7 +3607,7 @@ enum ipa_client_type ipa3_get_client_mapping(int pipe_idx) * * Return value: client type */ -static enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx) +enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx) { int j = 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 6772aecf399428d92792a8b73e5ab8dbd65a6e8a..c487e965640df0b267e271e7ddc7e3d4feaee881 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -88,6 +88,7 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_DEBUG_CNT_CTRL_n), __stringify(IPA_UC_MAILBOX_m_n), __stringify(IPA_FILT_ROUT_HASH_FLUSH), + __stringify(IPA_FILT_ROUT_HASH_EN), __stringify(IPA_SINGLE_NDP_MODE), __stringify(IPA_QCNCM), __stringify(IPA_SYS_PKT_PROC_CNTXT_BASE), @@ -1708,6 +1709,10 @@ static void ipareg_construct_endp_init_aggr_n(enum ipahal_reg_name reg, { struct ipa_ep_cfg_aggr *ep_aggr = (struct ipa_ep_cfg_aggr *)fields; + u32 byte_limit; + u32 pkt_limit; + u32 max_byte_limit; + u32 max_pkt_limit; IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_en, IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT, @@ -1717,7 +1722,12 @@ static void ipareg_construct_endp_init_aggr_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_BMSK); - IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_byte_limit, + /* make sure aggregation byte limit does not cross HW boundaries */ + max_byte_limit = IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK >> + IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT; + byte_limit = (ep_aggr->aggr_byte_limit > max_byte_limit) ? + max_byte_limit : ep_aggr->aggr_byte_limit; + IPA_SETFIELD_IN_REG(*val, byte_limit, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK); @@ -1726,7 +1736,12 @@ static void ipareg_construct_endp_init_aggr_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_BMSK); - IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_pkt_limit, + /* make sure aggregation pkt limit does not cross HW boundaries */ + max_pkt_limit = IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK >> + IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT; + pkt_limit = (ep_aggr->aggr_pkt_limit > max_pkt_limit) ? + max_pkt_limit : ep_aggr->aggr_pkt_limit; + IPA_SETFIELD_IN_REG(*val, pkt_limit, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK); @@ -1745,6 +1760,10 @@ static void ipareg_construct_endp_init_aggr_n_v4_5(enum ipahal_reg_name reg, { struct ipa_ep_cfg_aggr *ep_aggr = (struct ipa_ep_cfg_aggr *)fields; + u32 byte_limit; + u32 pkt_limit; + u32 max_byte_limit; + u32 max_pkt_limit; IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_en, IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT_V4_5, @@ -1754,7 +1773,12 @@ static void ipareg_construct_endp_init_aggr_n_v4_5(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_BMSK_V4_5); - IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_byte_limit, + /* make sure aggregation byte limit does not cross HW boundaries */ + max_byte_limit = IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK_V4_5 >> + IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT_V4_5; + byte_limit = (ep_aggr->aggr_byte_limit > max_byte_limit) ? + max_byte_limit : ep_aggr->aggr_byte_limit; + IPA_SETFIELD_IN_REG(*val, byte_limit, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK_V4_5); @@ -1762,6 +1786,11 @@ static void ipareg_construct_endp_init_aggr_n_v4_5(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_BMSK_V4_5); + /* make sure aggregation pkt limit does not cross HW boundaries */ + max_pkt_limit = IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK_V4_5 >> + IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT_V4_5; + pkt_limit = (ep_aggr->aggr_pkt_limit > max_pkt_limit) ? + max_pkt_limit : ep_aggr->aggr_pkt_limit; IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_pkt_limit, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK_V4_5); @@ -2747,6 +2776,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v4_2][IPA_HPS_FTCH_ARB_QUEUE_WEIGHT] = { ipareg_construct_dummy, ipareg_parse_dummy, -1, 0, 0, 0, 0}, + [IPA_HW_v4_2][IPA_FILT_ROUT_HASH_EN] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000148, 0, 0, 0, 0}, /* IPA4.5 */ [IPA_HW_v4_5][IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index 8b382898fd60f5ac0145347162325bbb05947bcc..68c82478b7f3d07a43c4bec4ef4f050f33edccef 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -89,6 +89,7 @@ enum ipahal_reg_name { IPA_DEBUG_CNT_CTRL_n, IPA_UC_MAILBOX_m_n, IPA_FILT_ROUT_HASH_FLUSH, + IPA_FILT_ROUT_HASH_EN, IPA_SINGLE_NDP_MODE, IPA_QCNCM, IPA_SYS_PKT_PROC_CNTXT_BASE, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 7aef668cc74bbf427ed13c7c24a4332abee1b27d..f8ae387a4c3ee1860388160b41f3cf40990ed65e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -39,6 +39,7 @@ #include "ipa_mhi_proxy.h" #include "ipa_trace.h" +#include "ipa_odl.h" #define OUTSTANDING_HIGH_DEFAULT 256 #define OUTSTANDING_HIGH_CTL_DEFAULT (OUTSTANDING_HIGH_DEFAULT + 32) @@ -67,6 +68,7 @@ MODULE_PARM_DESC(outstanding_low, "Outstanding low"); #define IPA_WWAN_DEV_NAME "rmnet_ipa%d" #define IPA_UPSTEAM_WLAN_IFACE_NAME "wlan0" +#define IPA_UPSTEAM_WLAN1_IFACE_NAME "wlan1" #define IPA_WWAN_RX_SOFTIRQ_THRESH 16 @@ -791,7 +793,8 @@ static enum ipa_upstream_type find_upstream_type(const char *upstreamIface) return IPA_UPSTEAM_MODEM; } - if (strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) + if ((strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) || + (strcmp(IPA_UPSTEAM_WLAN1_IFACE_NAME, upstreamIface) == 0)) return IPA_UPSTEAM_WLAN; else return MAX_NUM_OF_MUX_CHANNEL; @@ -2696,10 +2699,11 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, ipa_stop_polling_stats(); if (atomic_read(&rmnet_ipa3_ctx->is_initialized)) platform_driver_unregister(&rmnet_ipa_driver); - + imp_handle_modem_shutdown(); if (atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) ipa3_q6_post_shutdown_cleanup(); + ipa3_odl_pipe_cleanup(true); IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n"); break; case SUBSYS_AFTER_SHUTDOWN: @@ -2724,7 +2728,7 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); - + ipa3_odl_pipe_open(); IPAWANINFO("IPA AFTER_POWERUP handling is complete\n"); break; default: diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index 14c88122c80880f2bcfcbd0e57807d1f0663a2f1..9b0c3bda787fab3248620ab8bac859a405787def 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -780,7 +780,7 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx) static int msm_11ad_ssr_shutdown(const struct subsys_desc *subsys, bool force_stop) { - pr_info("%s(%p,%d)\n", __func__, subsys, force_stop); + pr_info("%s(%pK,%d)\n", __func__, subsys, force_stop); /* nothing is done in shutdown. We do full recovery in powerup */ return 0; } @@ -791,7 +791,7 @@ static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys) struct platform_device *pdev; struct msm11ad_ctx *ctx; - pr_info("%s(%p)\n", __func__, subsys); + pr_info("%s(%pK)\n", __func__, subsys); pdev = to_platform_device(subsys->dev); ctx = platform_get_drvdata(pdev); @@ -1185,12 +1185,12 @@ static int msm_11ad_probe(struct platform_device *pdev) msm_11ad_init_cpu_boost(ctx); /* report */ - dev_info(ctx->dev, "msm_11ad discovered. %p {\n" + dev_info(ctx->dev, "msm_11ad discovered. %pK {\n" " gpio_en = %d\n" " sleep_clk_en = %d\n" " rc_index = %d\n" " use_smmu = %d\n" - " pcidev = %p\n" + " pcidev = %pK\n" "}\n", ctx, ctx->gpio_en, ctx->sleep_clk_en, ctx->rc_index, ctx->use_smmu, ctx->pcidev); @@ -1227,7 +1227,7 @@ static int msm_11ad_remove(struct platform_device *pdev) msm_11ad_ssr_deinit(ctx); list_del(&ctx->list); - dev_info(ctx->dev, "%s: pdev %p pcidev %p\n", __func__, pdev, + dev_info(ctx->dev, "%s: pdev %pK pcidev %pK\n", __func__, pdev, ctx->pcidev); kfree(ctx->pristine_state); @@ -1490,7 +1490,7 @@ void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops, struct msm11ad_ctx *ctx = pcidev2ctx(pcidev); if (!ctx) { - pr_err("Context not found for pcidev %p\n", pcidev); + pr_err("Context not found for pcidev %pK\n", pcidev); return NULL; } diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 2fc420a64efad40fc895ca7e928e6132eee6e773..643f7412d42943185fb78809ef7c3a390b4cd929 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -176,6 +176,8 @@ static int sps_rm_assign(struct sps_pipe *pipe, struct sps_connection *map) { struct sps_connect *cfg = &pipe->connect; + unsigned long desc_iova; + unsigned long data_iova; /* Check ownership and BAM */ if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) || @@ -220,8 +222,24 @@ static int sps_rm_assign(struct sps_pipe *pipe, /* Copy parameters to client connect state */ pipe->connect.src_pipe_index = map->src.pipe_index; pipe->connect.dest_pipe_index = map->dest.pipe_index; + + /* + * The below assignment to connect.desc and connect.data will + * overwrite the previous values given by the first client + * in a BAM-to-BAM connection. Prevent that since the IOVAs + * may be different for the same physical buffers if the + * BAMs use different SMMUs. + */ + if (pipe->bam->props.options & SPS_BAM_SMMU_EN) { + desc_iova = pipe->connect.desc.iova; + data_iova = pipe->connect.data.iova; + } pipe->connect.desc = map->desc; pipe->connect.data = map->data; + if (pipe->bam->props.options & SPS_BAM_SMMU_EN) { + pipe->connect.desc.iova = desc_iova; + pipe->connect.data.iova = data_iova; + } pipe->client_state = SPS_STATE_ALLOCATE; diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 17dce361efb9e1e2c8a1e16249d8b247e0783163..2491252fdbfcf4b107b2fc46b93406a88eb3587f 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -381,6 +381,8 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(esr_actual), POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), + POWER_SUPPLY_ATTR(force_recharge), + POWER_SUPPLY_ATTR(fcc_stepper_enable), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index f72ade2f2ecea6caa1eed128ab8b4aea41feb820..88c8dc6e07768d2fd8429f1f961b2514fdf74078 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,9 +44,12 @@ #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" +#define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" struct pl_data { int pl_mode; + int pl_batfet_mode; + int pl_min_icl_ua; int slave_pct; int slave_fcc_ua; int restricted_current; @@ -70,10 +73,13 @@ struct pl_data { int charge_type; int total_settled_ua; int pl_settled_ua; + int pl_fcc_max; u32 wa_flags; struct class qcom_batt_class; struct wakeup_source *pl_ws; struct notifier_block nb; + bool pl_disable; + int taper_entry_fv; }; struct pl_data *the_chip; @@ -84,6 +90,7 @@ enum print_reason { enum { AICL_RERUN_WA_BIT = BIT(0), + FORCE_INOV_DISABLE_BIT = BIT(1), }; static int debug_mask; @@ -97,6 +104,8 @@ module_param_named(debug_mask, debug_mask, int, 0600); pr_debug(fmt, ##__VA_ARGS__); \ } while (0) +#define IS_USBIN(mode) ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ + || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) enum { VER = 0, SLAVE_PCT, @@ -107,19 +116,19 @@ enum { /******* * ICL * ********/ -static void split_settled(struct pl_data *chip) +static int get_settled_split(struct pl_data *chip, int *main_icl_ua, + int *slave_icl_ua, int *total_settled_icl_ua) { int slave_icl_pct, total_current_ua; int slave_ua = 0, main_settled_ua = 0; union power_supply_propval pval = {0, }; int rc, total_settled_ua = 0; - if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN) - && (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT)) - return; + if (!IS_USBIN(chip->pl_mode)) + return -EINVAL; if (!chip->main_psy) - return; + return -EINVAL; if (!get_effective_result_locked(chip->pl_disable_votable)) { /* read the aicl settled value */ @@ -127,11 +136,10 @@ static void split_settled(struct pl_data *chip) POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) { pr_err("Couldn't get aicl settled value rc=%d\n", rc); - return; + return rc; } main_settled_ua = pval.intval; - /* slave gets 10 percent points less for ICL */ - slave_icl_pct = max(0, chip->slave_pct - 10); + slave_icl_pct = max(0, chip->slave_pct); slave_ua = ((main_settled_ua + chip->pl_settled_ua) * slave_icl_pct) / 100; total_settled_ua = main_settled_ua + chip->pl_settled_ua; @@ -143,42 +151,114 @@ static void split_settled(struct pl_data *chip) chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) { pr_err("Couldn't get usbpsy while splitting settled\n"); - return; + return -ENOENT; } /* no client is voting, so get the total current from charger */ rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't get max current rc=%d\n", rc); - return; + return rc; } total_current_ua = pval.intval; } - pval.intval = total_current_ua - slave_ua; - /* Set ICL on main charger */ - rc = power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + *main_icl_ua = total_current_ua - slave_ua; + *slave_icl_ua = slave_ua; + *total_settled_icl_ua = total_settled_ua; + + pl_dbg(chip, PR_PARALLEL, + "Split total_current_ua=%d total_settled_ua=%d main_settled_ua=%d slave_ua=%d\n", + total_current_ua, total_settled_ua, main_settled_ua, slave_ua); + + return 0; +} + +static int validate_parallel_icl(struct pl_data *chip, bool *disable) +{ + int rc = 0; + int main_ua = 0, slave_ua = 0, total_settled_ua = 0; + + if (!IS_USBIN(chip->pl_mode) + || get_effective_result_locked(chip->pl_disable_votable)) + return 0; + + rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); if (rc < 0) { - pr_err("Couldn't change slave suspend state rc=%d\n", rc); - return; + pr_err("Couldn't get split current rc=%d\n", rc); + return rc; } - /* set parallel's ICL could be 0mA when pl is disabled */ - pval.intval = slave_ua; - rc = power_supply_set_property(chip->pl_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (slave_ua < chip->pl_min_icl_ua) + *disable = true; + else + *disable = false; + + return 0; +} + +static void split_settled(struct pl_data *chip) +{ + union power_supply_propval pval = {0, }; + int rc, main_ua, slave_ua, total_settled_ua; + + rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); if (rc < 0) { - pr_err("Couldn't set parallel icl, rc=%d\n", rc); + pr_err("Couldn't get split current rc=%d\n", rc); return; } + /* + * If there is an increase in slave share + * (Also handles parallel enable case) + * Set Main ICL then slave ICL + * else + * (Also handles parallel disable case) + * Set slave ICL then main ICL. + */ + if (slave_ua > chip->pl_settled_ua) { + pval.intval = main_ua; + /* Set ICL on main charger */ + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't change slave suspend state rc=%d\n", + rc); + return; + } + + /* set parallel's ICL could be 0mA when pl is disabled */ + pval.intval = slave_ua; + rc = power_supply_set_property(chip->pl_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't set parallel icl, rc=%d\n", rc); + return; + } + } else { + /* set parallel's ICL could be 0mA when pl is disabled */ + pval.intval = slave_ua; + rc = power_supply_set_property(chip->pl_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't set parallel icl, rc=%d\n", rc); + return; + } + + pval.intval = main_ua; + /* Set ICL on main charger */ + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't change slave suspend state rc=%d\n", + rc); + return; + } + } + chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; - pl_dbg(chip, PR_PARALLEL, - "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n", - total_current_ua, main_settled_ua, slave_ua); } static ssize_t version_show(struct class *c, struct class_attribute *attr, @@ -204,14 +284,21 @@ static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr, static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr, const char *ubuf, size_t count) { - struct pl_data *chip = container_of(c, struct pl_data, - qcom_batt_class); + struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); + int rc; unsigned long val; + bool disable = false; if (kstrtoul(ubuf, 10, &val)) return -EINVAL; chip->slave_pct = val; + + rc = validate_parallel_icl(chip, &disable); + if (rc < 0) + return rc; + + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0); rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); split_settled(chip); @@ -225,7 +312,7 @@ static struct class_attribute class_attr_slave_pct = * RESTRICTED CHARGIGNG * ************************/ static ssize_t restrict_chg_show(struct class *c, struct class_attribute *attr, - char *ubuf) + char *ubuf) { struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); @@ -343,13 +430,14 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, effective_total_ua = max(0, total_ua + hw_cc_delta_ua); slave_limited_ua = min(effective_total_ua, bcl_ua); *slave_ua = (slave_limited_ua * chip->slave_pct) / 100; + *slave_ua = min(*slave_ua, chip->pl_fcc_max); /* - * In USBIN_USBIN configuration with internal rsense parallel - * charger's current goes through main charger's BATFET, keep - * the main charger's FCC to the votable result. + * In stacked BATFET configuration charger's current goes + * through main charger's BATFET, keep the main charger's FCC + * to the votable result. */ - if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if (chip->pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) *master_ua = max(0, total_ua); else *master_ua = max(0, total_ua - *slave_ua); @@ -368,6 +456,7 @@ static void pl_taper_work(struct work_struct *work) int eff_fcc_ua; int total_fcc_ua, master_fcc_ua, slave_fcc_ua = 0; + chip->taper_entry_fv = get_effective_result(chip->fv_votable); chip->taper_work_running = true; while (true) { if (get_effective_result(chip->pl_disable_votable)) { @@ -414,7 +503,25 @@ static void pl_taper_work(struct work_struct *work) vote(chip->fcc_votable, TAPER_STEPPER_VOTER, true, eff_fcc_ua); } else { - pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n"); + /* + * Due to reduction of float voltage in JEITA condition + * taper charging can be initiated at a lower FV. On + * removal of JEITA condition, FV readjusts itself. + * However, once taper charging is initiated, it doesn't + * exits until parallel chaging is disabled due to which + * FCC doesn't scale back to its original value, leading + * to slow charging thereafter. + * Check if FV increases in comparison to FV at which + * taper charging was initiated, and if yes, exit taper + * charging. + */ + if (get_effective_result(chip->fv_votable) > + chip->taper_entry_fv) { + pl_dbg(chip, PR_PARALLEL, "Float voltage increased. Exiting taper\n"); + goto done; + } else { + pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n"); + } } /* wait for the charger state to deglitch after FCC change */ msleep(PL_TAPER_WORK_DELAY_MS); @@ -442,11 +549,9 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, &slave_fcc_ua); if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { - chip->slave_fcc_ua = slave_fcc_ua; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0); } else { - chip->slave_fcc_ua = 0; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, true, 0); } @@ -600,11 +705,9 @@ static int pl_disable_vote_callback(struct votable *votable, { struct pl_data *chip = data; union power_supply_propval pval = {0, }; - int master_fcc_ua, total_fcc_ua, slave_fcc_ua; - int rc; - - chip->total_settled_ua = 0; - chip->pl_settled_ua = 0; + int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0; + int rc = 0; + bool disable = false; if (!is_main_available(chip)) return -ENODEV; @@ -616,6 +719,16 @@ static int pl_disable_vote_callback(struct votable *votable, cancel_delayed_work_sync(&chip->pl_awake_work); vote(chip->pl_awake_votable, PL_VOTER, true, 0); + rc = validate_parallel_icl(chip, &disable); + if (rc < 0) + return rc; + + if (disable) { + pr_info("Parallel ICL is less than min ICL(%d), skipping parallel enable\n", + chip->pl_min_icl_ua); + return 0; + } + /* enable parallel charging */ rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); @@ -634,24 +747,56 @@ static int pl_disable_vote_callback(struct votable *votable, get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); - chip->slave_fcc_ua = slave_fcc_ua; + /* + * If there is an increase in slave share + * (Also handles parallel enable case) + * Set Main ICL then slave FCC + * else + * (Also handles parallel disable case) + * Set slave ICL then main FCC. + */ + if (slave_fcc_ua > chip->slave_fcc_ua) { + pval.intval = master_fcc_ua; + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + &pval); + if (rc < 0) { + pr_err("Could not set main fcc, rc=%d\n", rc); + return rc; + } - pval.intval = master_fcc_ua; - rc = power_supply_set_property(chip->main_psy, + pval.intval = slave_fcc_ua; + rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Could not set main fcc, rc=%d\n", rc); - return rc; - } + if (rc < 0) { + pr_err("Couldn't set parallel fcc, rc=%d\n", + rc); + return rc; + } - pval.intval = slave_fcc_ua; - rc = power_supply_set_property(chip->pl_psy, + chip->slave_fcc_ua = slave_fcc_ua; + } else { + pval.intval = slave_fcc_ua; + rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't set parallel fcc, rc=%d\n", rc); - return rc; + if (rc < 0) { + pr_err("Couldn't set parallel fcc, rc=%d\n", + rc); + return rc; + } + + chip->slave_fcc_ua = slave_fcc_ua; + + pval.intval = master_fcc_ua; + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + &pval); + if (rc < 0) { + pr_err("Could not set main fcc, rc=%d\n", rc); + return rc; + } } /* @@ -666,8 +811,7 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", rc); - if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + if (IS_USBIN(chip->pl_mode)) split_settled(chip); /* * we could have been enabled while in taper mode, @@ -694,8 +838,7 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); } else { - if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + if (IS_USBIN(chip->pl_mode)) split_settled(chip); /* pl_psy may be NULL while in the disable branch */ @@ -718,11 +861,22 @@ static int pl_disable_vote_callback(struct votable *votable, return rc; } + /* reset parallel FCC */ + chip->slave_fcc_ua = 0; rerun_election(chip->fv_votable); cancel_delayed_work_sync(&chip->pl_awake_work); schedule_delayed_work(&chip->pl_awake_work, msecs_to_jiffies(5000)); + + chip->total_settled_ua = 0; + chip->pl_settled_ua = 0; + } + + /* notify parallel state change */ + if (chip->pl_psy && (chip->pl_disable != pl_disable)) { + power_supply_changed(chip->pl_psy); + chip->pl_disable = (bool)pl_disable; } pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", @@ -793,8 +947,8 @@ static bool is_parallel_available(struct pl_data *chip) chip->pl_mode = pval.intval; /* Disable autonomous votage increments for USBIN-USBIN */ - if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { + if (IS_USBIN(chip->pl_mode) + && (chip->wa_flags & FORCE_INOV_DISABLE_BIT)) { if (!chip->hvdcp_hw_inov_dis_votable) chip->hvdcp_hw_inov_dis_votable = find_votable("HVDCP_HW_INOV_DIS"); @@ -806,6 +960,26 @@ static bool is_parallel_available(struct pl_data *chip) return false; } + rc = power_supply_get_property(chip->pl_psy, + POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, &pval); + if (rc < 0) { + pr_err("Couldn't get parallel batfet mode rc=%d\n", + rc); + return false; + } + chip->pl_batfet_mode = pval.intval; + + pval.intval = 0; + power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_MIN_ICL, + &pval); + chip->pl_min_icl_ua = pval.intval; + + chip->pl_fcc_max = INT_MAX; + rc = power_supply_get_property(chip->pl_psy, + POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval); + if (!rc) + chip->pl_fcc_max = pval.intval; + vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; @@ -827,9 +1001,6 @@ static void handle_main_charge_type(struct pl_data *chip) if ((pval.intval != POWER_SUPPLY_CHARGE_TYPE_FAST) && (pval.intval != POWER_SUPPLY_CHARGE_TYPE_TAPER)) { vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0); - vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); - vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, - false, 0); chip->charge_type = pval.intval; return; } @@ -849,6 +1020,16 @@ static void handle_main_charge_type(struct pl_data *chip) /* handle fast/taper charge entry */ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER || pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST) { + /* + * Undo parallel charging termination if entered taper in + * reduced float voltage condition due to jeita mitigation. + */ + if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST && + (chip->taper_entry_fv < + get_effective_result(chip->fv_votable))) { + vote(chip->pl_disable_votable, TAPER_END_VOTER, + false, 0); + } pl_dbg(chip, PR_PARALLEL, "chg_state enabling parallel\n"); vote(chip->pl_disable_votable, CHG_STATE_VOTER, false, 0); chip->charge_type = pval.intval; @@ -868,6 +1049,7 @@ static void handle_settled_icl_change(struct pl_data *chip) int main_settled_ua; int main_limited; int total_current_ua; + bool disable = false; total_current_ua = get_effective_result_locked(chip->usb_icl_votable); @@ -901,13 +1083,8 @@ static void handle_settled_icl_change(struct pl_data *chip) else vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0); - rerun_election(chip->fcc_votable); - - if (get_effective_result(chip->pl_disable_votable)) - return; - if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN - || chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) { + if (IS_USBIN(chip->pl_mode)) { /* * call aicl split only when USBIN_USBIN and enabled * and if settled current has changed by more than 300mA @@ -921,8 +1098,17 @@ static void handle_settled_icl_change(struct pl_data *chip) /* If ICL change is small skip splitting */ if (abs(new_total_settled_ua - chip->total_settled_ua) - > MIN_ICL_CHANGE_DELTA_UA) - split_settled(chip); + > MIN_ICL_CHANGE_DELTA_UA) { + rc = validate_parallel_icl(chip, &disable); + if (rc < 0) + return; + + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, + disable, 0); + if (!get_effective_result_locked( + chip->pl_disable_votable)) + split_settled(chip); + } } } @@ -955,6 +1141,34 @@ static void handle_parallel_in_taper(struct pl_data *chip) } } +static void handle_usb_change(struct pl_data *chip) +{ + int rc; + union power_supply_propval pval = {0, }; + + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) { + pr_err("Couldn't get usbpsy\n"); + return; + } + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + if (rc < 0) { + pr_err("Couldn't get present from USB rc=%d\n", rc); + return; + } + + if (!pval.intval) { + /* USB removed: remove all stale votes */ + vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); + vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, + false, 0); + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0); + } +} + static void status_change_work(struct work_struct *work) { struct pl_data *chip = container_of(work, @@ -979,6 +1193,7 @@ static void status_change_work(struct work_struct *work) is_parallel_available(chip); + handle_usb_change(chip); handle_main_charge_type(chip); handle_settled_icl_change(chip); handle_parallel_in_taper(chip); @@ -1026,7 +1241,9 @@ static void pl_config_init(struct pl_data *chip, int smb_version) switch (smb_version) { case PMI8998_SUBTYPE: case PM660_SUBTYPE: - chip->wa_flags = AICL_RERUN_WA_BIT; + chip->wa_flags = AICL_RERUN_WA_BIT | FORCE_INOV_DISABLE_BIT; + break; + case PMI632_SUBTYPE: break; default: break; @@ -1127,6 +1344,7 @@ int qcom_batt_init(int smb_version) goto unreg_notifier; } + chip->pl_disable = true; chip->qcom_batt_class.name = "qcom-battery", chip->qcom_batt_class.owner = THIS_MODULE, chip->qcom_batt_class.class_groups = batt_class_groups; diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h index 931af0b2ed8fe64507e988a10b748ad79b169030..267bb08e7a2ba851bc7f4cc41bf3f261fdfab25e 100644 --- a/drivers/power/supply/qcom/fg-reg.h +++ b/drivers/power/supply/qcom/fg-reg.h @@ -176,6 +176,7 @@ /* GEN4 bit definitions */ #define GEN4_ESR_FAST_CRG_IVAL_MASK GENMASK(7, 4) +#define GEN4_ESR_FAST_CRG_IVAL_SHIFT 4 #define GEN4_ESR_FCC_300MA 0x0 #define GEN4_ESR_FCC_600MA 0x1 #define GEN4_ESR_FCC_1A 0x2 @@ -267,6 +268,9 @@ #define BATT_INFO_IADC_MSB(chip) (chip->batt_info_base + 0xAF) #define IADC_MSB_MASK GENMASK(6, 0) +#define BATT_INFO_FG_CNV_CHAR_CFG(chip) (chip->batt_info_base + 0xB7) +#define SMB_MEASURE_EN_BIT BIT(2) + #define BATT_INFO_TM_MISC(chip) (chip->batt_info_base + 0xE5) #define FORCE_SEQ_RESP_TOGGLE_BIT BIT(6) #define ALG_DIRECT_VALID_DATA_BIT BIT(5) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 70aa40c1134d514cb8dcf8e39a63e12dde0ae5c3..575b77aa3d01c7b212549ff01f035fa765b75bbf 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -96,6 +96,7 @@ struct qpnp_qg { struct votable *fifo_irq_disable_votable; struct votable *good_ocv_irq_disable_votable; u32 qg_base; + u8 qg_subtype; /* local data variables */ u32 batt_id_ohm; @@ -206,6 +207,7 @@ enum qg_irq { enum qg_wa_flags { QG_VBAT_LOW_WA = BIT(0), QG_RECHARGE_SOC_WA = BIT(1), + QG_CLK_ADJUST_WA = BIT(2), }; diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index 997ff701c77d671760f9e11b83c8b2f2c8953335..c398c697e0144b50edbcc476b6ba335c3c43ec89 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -37,7 +37,6 @@ #define TTF_AWAKE_VOTER "TTF_AWAKE_VOTER" #define V_RAW_TO_UV(V_RAW) div_u64(194637ULL * (u64)V_RAW, 1000) -#define I_RAW_TO_UA(I_RAW) div_s64(152588LL * (s64)I_RAW, 1000) #define FIFO_V_RESET_VAL 0x8000 #define FIFO_I_RESET_VAL 0x8000 diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index 894e0764301c9cd78de231a280ef18ae72748e32..4048fd4d63a59425f378f846de8863de53057d71 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -14,6 +14,11 @@ #define __QG_REG_H__ #define PERPH_TYPE_REG 0x04 + +#define PERPH_SUBTYPE_REG 0x05 +#define QG_ADC_IBAT_5A 0x3 +#define QG_ADC_IBAT_10A 0x4 + #define QG_TYPE 0x0D #define QG_STATUS1_REG 0x08 diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index 69eb4e9a848b10b1e184ad4e80182011476a559d..bd998c9652a555665b9dd73db7671b7b2f50d66d 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -127,6 +127,14 @@ int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data) return rc; } +s64 qg_iraw_to_ua(struct qpnp_qg *chip, int iraw) +{ + if (chip->qg_subtype == QG_ADC_IBAT_5A) + return div_s64(152588LL * (s64)iraw, 1000); + else + return div_s64(305176LL * (s64)iraw, 1000); +} + int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt) { int rc; @@ -167,6 +175,8 @@ int get_sample_count(struct qpnp_qg *chip, u32 *sample_count) return rc; } +#define QG_CLK_RATE 32000 +#define QG_ACTUAL_CLK_RATE 32764 int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval) { int rc; @@ -181,6 +191,11 @@ int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval) *sample_interval = reg * 10; + if (chip->wa_flags & QG_CLK_ADJUST_WA) { + *sample_interval = DIV_ROUND_CLOSEST( + *sample_interval * QG_CLK_RATE, QG_ACTUAL_CLK_RATE); + } + return rc; } @@ -354,7 +369,7 @@ int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua) } last_ibat = sign_extend32(last_ibat, 15); - *ibat_ua = I_RAW_TO_UA(last_ibat); + *ibat_ua = qg_iraw_to_ua(chip, last_ibat); release: /* release */ diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h index 5dd6c85728f833f66422dd37dc3e4b4a9cdd2789..307b2ae54546cb7b66e5e1c2e4e63d11b4385716 100644 --- a/drivers/power/supply/qcom/qg-util.h +++ b/drivers/power/supply/qcom/qg-util.h @@ -27,5 +27,6 @@ int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc); int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp); int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua); int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv); +s64 qg_iraw_to_ua(struct qpnp_qg *chip, int iraw); #endif diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 76f4897fe7c66d9626e721aa2b9ec2e87b39fbe4..2cc7d5d1f12596b625b28b23a56102c37354d099 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -176,6 +176,7 @@ struct fg_dt_props { bool force_load_profile; bool hold_soc_while_full; bool linearize_soc; + bool rapid_soc_dec_en; int cutoff_volt_mv; int empty_volt_mv; int cutoff_curr_ma; @@ -215,9 +216,13 @@ struct fg_gen4_chip { struct cap_learning *cl; struct ttf *ttf; struct votable *delta_esr_irq_en_votable; + struct votable *pl_disable_votable; + struct votable *cp_disable_votable; struct work_struct esr_calib_work; struct alarm esr_fast_cal_timer; + struct delayed_work pl_enable_work; char batt_profile[PROFILE_LEN]; + enum slope_limit_status slope_limit_sts; int delta_esr_count; int recharge_soc_thr; int esr_actual; @@ -228,7 +233,9 @@ struct fg_gen4_chip { bool esr_fast_calib; bool esr_fast_calib_done; bool esr_fast_cal_timer_expired; + bool esr_fcc_ctrl_en; bool rslow_low; + bool rapid_soc_dec_en; }; struct bias_config { @@ -1071,6 +1078,93 @@ static int fg_gen4_adjust_ki_coeff_dischg(struct fg_dev *fg) return 0; } +static int fg_gen4_slope_limit_config(struct fg_gen4_chip *chip, int batt_temp) +{ + struct fg_dev *fg = &chip->fg; + enum slope_limit_status status; + int rc; + u8 buf; + + if (!chip->slope_limit_en || chip->rapid_soc_dec_en) + return 0; + + if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING || + fg->charge_status == POWER_SUPPLY_STATUS_FULL) { + if (batt_temp < chip->dt.slope_limit_temp) + status = LOW_TEMP_CHARGE; + else + status = HIGH_TEMP_CHARGE; + } else { + if (batt_temp < chip->dt.slope_limit_temp) + status = LOW_TEMP_DISCHARGE; + else + status = HIGH_TEMP_DISCHARGE; + } + + if (chip->slope_limit_sts == status) + return 0; + + fg_encode(fg->sp, FG_SRAM_SLOPE_LIMIT, + chip->dt.slope_limit_coeffs[status], &buf); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_SLOPE_LIMIT].addr_word, + fg->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf, + fg->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in configuring slope_limit coefficient, rc=%d\n", + rc); + return rc; + } + + chip->slope_limit_sts = status; + fg_dbg(fg, FG_STATUS, "Slope limit status: %d value: %x\n", status, + buf); + return 0; +} + +static int fg_gen4_configure_cutoff_current(struct fg_dev *fg, int current_ma) +{ + int rc; + u8 buf[2]; + + fg_encode(fg->sp, FG_SRAM_CUTOFF_CURR, current_ma, buf); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_CUTOFF_CURR].addr_word, + fg->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf, + fg->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT); + if (rc < 0) + pr_err("Error in writing cutoff_curr, rc=%d\n", rc); + + return rc; +} + +#define SLOPE_LIMIT_DEFAULT 5738 +#define CUTOFF_CURRENT_MAX 15999 +static int fg_gen4_rapid_soc_config(struct fg_gen4_chip *chip, bool en) +{ + struct fg_dev *fg = &chip->fg; + int rc, slope_limit_coeff, cutoff_curr_ma; + u8 buf; + + slope_limit_coeff = en ? SLOPE_LIMIT_COEFF_MAX : SLOPE_LIMIT_DEFAULT; + fg_encode(fg->sp, FG_SRAM_SLOPE_LIMIT, slope_limit_coeff, &buf); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_SLOPE_LIMIT].addr_word, + fg->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf, + fg->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in configuring slope_limit coefficient, rc=%d\n", + rc); + return rc; + } + + cutoff_curr_ma = en ? CUTOFF_CURRENT_MAX : chip->dt.cutoff_curr_ma; + rc = fg_gen4_configure_cutoff_current(fg, cutoff_curr_ma); + if (rc < 0) + return rc; + + fg_dbg(fg, FG_STATUS, "Configured slope limit coeff %d cutoff current %d mA\n", + slope_limit_coeff, cutoff_curr_ma); + return 0; +} + static int fg_gen4_get_batt_profile(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); @@ -1598,10 +1692,12 @@ static void profile_load_work(struct work_struct *work) batt_psy_initialized(fg); fg_notify_charger(fg); - schedule_delayed_work(&chip->ttf->ttf_work, 10000); + schedule_delayed_work(&chip->ttf->ttf_work, msecs_to_jiffies(10000)); fg_dbg(fg, FG_STATUS, "profile loaded successfully"); out: fg->soc_reporting_ready = true; + vote(fg->awake_votable, ESR_FCC_VOTER, true, 0); + schedule_delayed_work(&chip->pl_enable_work, msecs_to_jiffies(5000)); vote(fg->awake_votable, PROFILE_LOAD, false, 0); if (!work_pending(&fg->status_change_work)) { pm_stay_awake(fg->dev); @@ -1974,6 +2070,87 @@ static int fg_gen4_charge_full_update(struct fg_dev *fg) return rc; } +static int fg_gen4_esr_fcc_config(struct fg_gen4_chip *chip) +{ + struct fg_dev *fg = &chip->fg; + union power_supply_propval prop = {0, }; + int rc; + bool parallel_en = false, cp_en = false, qnovo_en, esr_fcc_ctrl_en; + u8 val, mask; + + if (is_parallel_charger_available(fg)) { + rc = power_supply_get_property(fg->parallel_psy, + POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop); + if (rc < 0) + pr_err_ratelimited("Error in reading charging_enabled from parallel_psy, rc=%d\n", + rc); + else + parallel_en = prop.intval; + } + + if (usb_psy_initialized(fg)) { + rc = power_supply_get_property(fg->usb_psy, + POWER_SUPPLY_PROP_SMB_EN_MODE, &prop); + if (rc < 0) { + pr_err("Couldn't read usb SMB_EN_MODE rc=%d\n", rc); + return rc; + } + + /* + * If SMB_EN_MODE is 1, then charge pump can get enabled for + * the charger inserted. However, whether the charge pump + * switching happens only if the conditions are met. + */ + cp_en = (prop.intval == 1); + } + + qnovo_en = is_qnovo_en(fg); + + fg_dbg(fg, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d cp_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n", + fg->charge_status, parallel_en, cp_en, qnovo_en, + chip->esr_fcc_ctrl_en); + + if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING && + (parallel_en || qnovo_en || cp_en)) { + if (chip->esr_fcc_ctrl_en) + return 0; + + /* + * When parallel charging or Qnovo or Charge pump is enabled, + * configure ESR FCC to 300mA to trigger an ESR pulse. Without + * this, FG can request the main charger to increase FCC when it + * is supposed to decrease it. + */ + val = GEN4_ESR_FCC_300MA << GEN4_ESR_FAST_CRG_IVAL_SHIFT | + ESR_FAST_CRG_CTL_EN_BIT; + esr_fcc_ctrl_en = true; + } else { + if (!chip->esr_fcc_ctrl_en) + return 0; + + /* + * If we're here, then it means either the device is not in + * charging state or parallel charging / Qnovo / Charge pump is + * disabled. Disable ESR fast charge current control in SW. + */ + val = GEN4_ESR_FCC_1A << GEN4_ESR_FAST_CRG_IVAL_SHIFT; + esr_fcc_ctrl_en = false; + } + + mask = GEN4_ESR_FAST_CRG_IVAL_MASK | ESR_FAST_CRG_CTL_EN_BIT; + rc = fg_masked_write(fg, BATT_INFO_ESR_FAST_CRG_CFG(fg), mask, val); + if (rc < 0) { + pr_err("Error in writing to %04x, rc=%d\n", + BATT_INFO_ESR_FAST_CRG_CFG(fg), rc); + return rc; + } + + chip->esr_fcc_ctrl_en = esr_fcc_ctrl_en; + fg_dbg(fg, FG_STATUS, "esr_fcc_ctrl_en set to %d\n", + chip->esr_fcc_ctrl_en); + return 0; +} + /* All irq handlers below this */ static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) @@ -2029,13 +2206,34 @@ static irqreturn_t fg_delta_esr_irq_handler(int irq, void *data) static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) { struct fg_dev *fg = data; - int rc, vbatt_mv; + struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); + int rc, vbatt_mv, msoc_raw; rc = fg_get_battery_voltage(fg, &vbatt_mv); if (rc < 0) return IRQ_HANDLED; - fg_dbg(fg, FG_IRQ, "irq %d triggered vbatt_mv: %d\n", irq, vbatt_mv); + vbatt_mv /= 1000; + rc = fg_get_msoc_raw(fg, &msoc_raw); + if (rc < 0) + return IRQ_HANDLED; + + fg_dbg(fg, FG_IRQ, "irq %d triggered vbatt_mv: %d msoc_raw:%d\n", irq, + vbatt_mv, msoc_raw); + + if (chip->dt.rapid_soc_dec_en && vbatt_mv < chip->dt.cutoff_volt_mv) { + /* + * Set this flag so that slope limiter coefficient cannot be + * configured during rapid SOC decrease. + */ + chip->rapid_soc_dec_en = true; + + rc = fg_gen4_rapid_soc_config(chip, true); + if (rc < 0) + pr_err("Error in configuring for rapid SOC reduction rc:%d\n", + rc); + } + if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); @@ -2073,6 +2271,12 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data) kfree(chip->ttf->step_chg_data); chip->ttf->step_chg_data = NULL; mutex_unlock(&chip->ttf->lock); + cancel_delayed_work_sync(&chip->pl_enable_work); + vote(fg->awake_votable, ESR_FCC_VOTER, false, 0); + if (chip->pl_disable_votable) + vote(chip->pl_disable_votable, ESR_FCC_VOTER, true, 0); + if (chip->cp_disable_votable) + vote(chip->cp_disable_votable, ESR_FCC_VOTER, true, 0); return IRQ_HANDLED; } @@ -2096,6 +2300,7 @@ static irqreturn_t fg_batt_temp_irq_handler(int irq, void *data) static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) { struct fg_dev *fg = data; + struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, batt_temp; rc = fg_gen4_get_battery_temp(fg, &batt_temp); @@ -2106,6 +2311,10 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) fg_dbg(fg, FG_IRQ, "irq %d triggered batt_temp:%d\n", irq, batt_temp); + rc = fg_gen4_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", rc); + if (abs(fg->last_batt_temp - batt_temp) > 30) pr_warn("Battery temperature last:%d current: %d\n", fg->last_batt_temp, batt_temp); @@ -2171,12 +2380,19 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) fg->charge_status, fg->charge_done, input_present); rc = fg_gen4_get_battery_temp(fg, &batt_temp); - if (rc < 0) + if (rc < 0) { pr_err("Failed to read battery temp rc: %d\n", rc); - else if (chip->cl->active) - cap_learning_update(chip->cl, batt_temp, batt_soc, - fg->charge_status, fg->charge_done, input_present, - is_qnovo_en(fg)); + } else { + if (chip->cl->active) + cap_learning_update(chip->cl, batt_temp, batt_soc, + fg->charge_status, fg->charge_done, + input_present, is_qnovo_en(fg)); + + rc = fg_gen4_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", + rc); + } rc = fg_gen4_charge_full_update(fg); if (rc < 0) @@ -2645,6 +2861,20 @@ static void esr_calib_work(struct work_struct *work) vote(fg->awake_votable, ESR_CALIB, false, 0); } +static void pl_enable_work(struct work_struct *work) +{ + struct fg_gen4_chip *chip = container_of(work, + struct fg_gen4_chip, + pl_enable_work.work); + struct fg_dev *fg = &chip->fg; + + if (chip->pl_disable_votable) + vote(chip->pl_disable_votable, ESR_FCC_VOTER, false, 0); + if (chip->cp_disable_votable) + vote(chip->cp_disable_votable, ESR_FCC_VOTER, false, 0); + vote(fg->awake_votable, ESR_FCC_VOTER, false, 0); +} + static void status_change_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, @@ -2653,6 +2883,12 @@ static void status_change_work(struct work_struct *work) int rc, batt_soc, batt_temp; bool input_present, qnovo_en; + if (!chip->pl_disable_votable) + chip->pl_disable_votable = find_votable("PL_DISABLE"); + + if (!chip->cp_disable_votable) + chip->cp_disable_votable = find_votable("CP_DISABLE"); + if (!batt_psy_initialized(fg)) { fg_dbg(fg, FG_STATUS, "Charger not available?!\n"); goto out; @@ -2691,6 +2927,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); + rc = fg_gen4_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", rc); + rc = fg_gen4_adjust_ki_coeff_dischg(fg); if (rc < 0) pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); @@ -2699,6 +2939,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in adjusting recharge SOC, rc=%d\n", rc); + rc = fg_gen4_esr_fcc_config(chip); + if (rc < 0) + pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); + ttf_update(chip->ttf, input_present); fg->prev_charge_status = fg->charge_status; out: @@ -3281,6 +3525,15 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) int rc; u8 buf[4], val, mask; + /* Enable measurement of parallel charging current */ + val = mask = SMB_MEASURE_EN_BIT; + rc = fg_masked_write(fg, BATT_INFO_FG_CNV_CHAR_CFG(fg), mask, val); + if (rc < 0) { + pr_err("Error in writing to 0x%04x, rc=%d\n", + BATT_INFO_FG_CNV_CHAR_CFG(fg), rc); + return rc; + } + fg_encode(fg->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_CUTOFF_VOLT].addr_word, fg->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf, @@ -3290,14 +3543,9 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) return rc; } - fg_encode(fg->sp, FG_SRAM_CUTOFF_CURR, chip->dt.cutoff_curr_ma, buf); - rc = fg_sram_write(fg, fg->sp[FG_SRAM_CUTOFF_CURR].addr_word, - fg->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf, - fg->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in writing cutoff_curr, rc=%d\n", rc); + rc = fg_gen4_configure_cutoff_current(fg, chip->dt.cutoff_curr_ma); + if (rc < 0) return rc; - } fg_encode(fg->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma, buf); @@ -3535,6 +3783,19 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) return rc; } } + + /* + * Disable ESR discharging timer and ESR pulsing during + * discharging when ESR fast calibration is disabled. + */ + val = 0; + mask = BIT(6) | BIT(7); + rc = fg_sram_masked_write(fg, SYS_CONFIG_WORD, + SYS_CONFIG_OFFSET, mask, val, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing SYS_CONFIG_WORD, rc=%d\n", rc); + return rc; + } } /* @@ -3869,35 +4130,35 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) else chip->dt.delta_soc_thr = temp; + chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-chg-fast", chip->dt.esr_timer_chg_fast, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; + chip->dt.esr_timer_dischg_fast[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_dischg_fast[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-dischg-fast", chip->dt.esr_timer_dischg_fast, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_dischg_fast[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_dischg_fast[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; + chip->dt.esr_timer_chg_slow[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_chg_slow[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-chg-slow", chip->dt.esr_timer_chg_slow, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_chg_slow[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_chg_slow[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; + chip->dt.esr_timer_dischg_slow[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_dischg_slow[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-dischg-slow", chip->dt.esr_timer_dischg_slow, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_dischg_slow[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_dischg_slow[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); @@ -4005,6 +4266,8 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) if (rc < 0) return rc; + chip->dt.rapid_soc_dec_en = of_property_read_bool(node, + "qcom,rapid-soc-dec-en"); return 0; } @@ -4058,6 +4321,17 @@ static int fg_gen4_probe(struct platform_device *pdev) return -ENXIO; } + mutex_init(&fg->bus_lock); + mutex_init(&fg->sram_rw_lock); + mutex_init(&fg->charge_full_lock); + init_completion(&fg->soc_update); + init_completion(&fg->soc_ready); + INIT_WORK(&fg->status_change_work, status_change_work); + INIT_WORK(&chip->esr_calib_work, esr_calib_work); + INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); + INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); + INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); + fg->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, fg); if (IS_ERR(fg->awake_votable)) { @@ -4110,16 +4384,6 @@ static int fg_gen4_probe(struct platform_device *pdev) } } - mutex_init(&fg->bus_lock); - mutex_init(&fg->sram_rw_lock); - mutex_init(&fg->charge_full_lock); - init_completion(&fg->soc_update); - init_completion(&fg->soc_ready); - INIT_WORK(&fg->status_change_work, status_change_work); - INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); - INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); - INIT_WORK(&chip->esr_calib_work, esr_calib_work); - rc = fg_memif_init(fg); if (rc < 0) { dev_err(fg->dev, "Error in initializing FG_MEMIF, rc:%d\n", @@ -4178,7 +4442,7 @@ static int fg_gen4_probe(struct platform_device *pdev) rc = fg_get_battery_voltage(fg, &volt_uv); if (!rc) - rc = fg_gen4_get_prop_capacity(fg, &msoc); + rc = fg_get_msoc(fg, &msoc); if (!rc) rc = fg_gen4_get_battery_temp(fg, &batt_temp); @@ -4186,9 +4450,11 @@ static int fg_gen4_probe(struct platform_device *pdev) if (!rc) rc = fg_gen4_get_batt_id(chip); - if (!rc) + if (!rc) { + fg->last_batt_temp = batt_temp; pr_info("battery SOC:%d voltage: %duV temp: %d id: %d ohms\n", msoc, volt_uv, batt_temp, fg->batt_id_ohms); + } device_init_wakeup(fg->dev, true); schedule_delayed_work(&fg->profile_load_work, 0); @@ -4214,6 +4480,15 @@ static void fg_gen4_shutdown(struct platform_device *pdev) struct fg_dev *fg = &chip->fg; int rc, bsoc; + fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); + + if (chip->rapid_soc_dec_en) { + rc = fg_gen4_rapid_soc_config(chip, false); + if (rc < 0) + pr_err("Error in reverting rapid SOC decrease config rc:%d\n", + rc); + } + rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &bsoc); if (rc < 0) { pr_err("Error in getting BATT_SOC, rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 09a109761f329a64341756e2903ffe26469f9af7..47818ca011feb994d2b0942cb75b32fe808ec165 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -347,7 +347,7 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length) temp = sign_extend32(fifo_i, 15); chip->kdata.fifo[j].v = V_RAW_TO_UV(fifo_v); - chip->kdata.fifo[j].i = I_RAW_TO_UA(temp); + chip->kdata.fifo[j].i = qg_iraw_to_ua(chip, temp); chip->kdata.fifo[j].interval = sample_interval; chip->kdata.fifo[j].count = sample_count; @@ -408,7 +408,7 @@ static int qg_process_accumulator(struct qpnp_qg *chip) temp = sign_extend64(acc_i, 23); chip->kdata.fifo[index].v = V_RAW_TO_UV(div_u64(acc_v, count)); - chip->kdata.fifo[index].i = I_RAW_TO_UA(div_s64(temp, count)); + chip->kdata.fifo[index].i = qg_iraw_to_ua(chip, div_s64(temp, count)); chip->kdata.fifo[index].interval = sample_interval; chip->kdata.fifo[index].count = count; chip->kdata.fifo_length++; @@ -966,11 +966,12 @@ static int qg_esr_estimate(struct qpnp_qg *chip) chip->esr_data[i].pre_esr_v = V_RAW_TO_UV(chip->esr_data[i].pre_esr_v); ibat = sign_extend32(chip->esr_data[i].pre_esr_i, 15); - chip->esr_data[i].pre_esr_i = I_RAW_TO_UA(ibat); + chip->esr_data[i].pre_esr_i = qg_iraw_to_ua(chip, ibat); chip->esr_data[i].post_esr_v = V_RAW_TO_UV(chip->esr_data[i].post_esr_v); ibat = sign_extend32(chip->esr_data[i].post_esr_i, 15); - chip->esr_data[i].post_esr_i = I_RAW_TO_UA(ibat); + chip->esr_data[i].post_esr_i = + qg_iraw_to_ua(chip, ibat); chip->esr_data[i].valid = true; @@ -1889,7 +1890,7 @@ static int qg_charge_full_update(struct qpnp_qg *chip) /* Force recharge */ prop.intval = 0; rc = power_supply_set_property(chip->batt_psy, - POWER_SUPPLY_PROP_RECHARGE_SOC, &prop); + POWER_SUPPLY_PROP_FORCE_RECHARGE, &prop); if (rc < 0) pr_err("Failed to force recharge rc=%d\n", rc); else @@ -2393,7 +2394,7 @@ static int get_batt_id_ohm(struct qpnp_qg *chip, u32 *batt_id_ohm) /* Read battery-id */ rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); - if (rc) { + if (rc < 0) { pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); return rc; } @@ -2572,7 +2573,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) use_pon_ocv: if (use_pon_ocv == true) { rc = qg_get_battery_temp(chip, &batt_temp); - if (rc) { + if (rc < 0) { pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); goto done; } @@ -2664,6 +2665,10 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) if (chip->pmic_rev_id->rev4 == PMI632_V1P0_REV4) chip->wa_flags |= QG_VBAT_LOW_WA; break; + case PM6150_SUBTYPE: + chip->wa_flags |= QG_CLK_ADJUST_WA | + QG_RECHARGE_SOC_WA; + break; default: pr_err("Unsupported PMIC subtype %d\n", chip->pmic_rev_id->pmic_subtype); @@ -2681,6 +2686,14 @@ static int qg_hw_init(struct qpnp_qg *chip) int rc, temp; u8 reg; + /* read the QG perph_subtype */ + rc = qg_read(chip, chip->qg_base + PERPH_SUBTYPE_REG, + &chip->qg_subtype, 1); + if (rc < 0) { + pr_err("Failed to read QG subtype rc=%d", rc); + return rc; + } + rc = qg_set_wa_flags(chip); if (rc < 0) { pr_err("Failed to update PMIC type flags, rc=%d\n", rc); @@ -3589,21 +3602,19 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->batt_id_chan = iio_channel_get(&pdev->dev, "batt-id"); if (IS_ERR(chip->batt_id_chan)) { rc = PTR_ERR(chip->batt_id_chan); - if (rc != -EPROBE_DEFER) { + if (rc != -EPROBE_DEFER) pr_err("batt-id channel unavailable, rc=%d\n", rc); - chip->batt_id_chan = NULL; - return rc; - } + chip->batt_id_chan = NULL; + return rc; } chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm"); if (IS_ERR(chip->batt_therm_chan)) { rc = PTR_ERR(chip->batt_therm_chan); - if (rc != -EPROBE_DEFER) { + if (rc != -EPROBE_DEFER) pr_err("batt-therm channel unavailable, rc=%d\n", rc); - chip->batt_therm_chan = NULL; - return rc; - } + chip->batt_therm_chan = NULL; + return rc; } chip->dev = &pdev->dev; @@ -3750,8 +3761,8 @@ static int qpnp_qg_probe(struct platform_device *pdev) } qg_get_battery_capacity(chip, &soc); - pr_info("QG initialized! battery_profile=%s SOC=%d\n", - qg_get_battery_type(chip), soc); + pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d\n", + qg_get_battery_type(chip), soc, chip->qg_subtype); return rc; diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 39e4ec07f1bd7df5a82cc57e84ce1f1ad0dc0ec6..4df9147d49845be198b623f5247c69cf48e90c64 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1024,7 +1024,10 @@ static enum power_supply_property smb5_dc_props[] = { POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, POWER_SUPPLY_PROP_REAL_TYPE, }; @@ -1046,9 +1049,14 @@ static int smb5_dc_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: rc = smblib_get_prop_dc_online(chg, val); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + rc = smblib_get_prop_dc_voltage_now(chg, val); + break; case POWER_SUPPLY_PROP_CURRENT_MAX: - rc = smblib_get_charge_param(chg, &chg->param.dc_icl, - &val->intval); + rc = smblib_get_prop_dc_current_max(chg, val); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + rc = smblib_get_prop_dc_voltage_max(chg, val); break; case POWER_SUPPLY_PROP_REAL_TYPE: val->intval = POWER_SUPPLY_TYPE_WIPOWER; @@ -1077,8 +1085,10 @@ static int smb5_dc_set_prop(struct power_supply *psy, (bool)val->intval, 0); break; case POWER_SUPPLY_PROP_CURRENT_MAX: - rc = smblib_set_charge_param(chg, &chg->param.dc_icl, - val->intval); + rc = smblib_set_prop_dc_current_max(chg, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + rc = smblib_set_prop_voltage_wls_output(chg, val); break; default: return -EINVAL; @@ -1162,6 +1172,8 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_RECHARGE_SOC, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_FORCE_RECHARGE, }; static int smb5_batt_get_prop(struct power_supply *psy, @@ -1212,14 +1224,16 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = chg->sw_jeita_enabled; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - rc = smblib_get_prop_batt_voltage_now(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, val); break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: val->intval = get_client_vote(chg->fv_votable, BATT_PROFILE_VOTER); break; case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = smblib_get_prop_batt_current_now(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CURRENT_NOW, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: val->intval = get_client_vote(chg->fcc_votable, @@ -1229,7 +1243,7 @@ static int smb5_batt_get_prop(struct power_supply *psy, rc = smblib_get_prop_batt_iterm(chg, val); break; case POWER_SUPPLY_PROP_TEMP: - rc = smblib_get_prop_batt_temp(chg, val); + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -1258,10 +1272,12 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = 0; break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: - rc = smblib_get_prop_batt_charge_counter(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_COUNTER, val); break; case POWER_SUPPLY_PROP_CYCLE_COUNT: - rc = smblib_get_prop_batt_cycle_count(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CYCLE_COUNT, val); break; case POWER_SUPPLY_PROP_RECHARGE_SOC: val->intval = chg->auto_recharge_soc; @@ -1269,6 +1285,13 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE: val->intval = 0; break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_FULL, val); + break; + case POWER_SUPPLY_PROP_FORCE_RECHARGE: + val->intval = 0; + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; @@ -1348,6 +1371,15 @@ static int smb5_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_RECHARGE_SOC: rc = smblib_set_prop_rechg_soc_thresh(chg, val); break; + case POWER_SUPPLY_PROP_FORCE_RECHARGE: + /* toggle charging to force recharge */ + vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, + true, 0); + /* charge disable delay */ + msleep(50); + vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, + false, 0); + break; default: rc = -EINVAL; } @@ -1531,6 +1563,8 @@ static int smb5_configure_typec(struct smb_charger *chg) dev_err(chg->dev, "Couldn't enable try.snk rc=%d\n", rc); return rc; + } else { + chg->typec_try_mode |= EN_TRY_SNK_BIT; } /* configure VCONN for software control */ @@ -1543,6 +1577,13 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, + USBIN_IN_COLLAPSE_GF_SEL_MASK | USBIN_AICL_STEP_TIMING_SEL_MASK, + 0); + if (rc < 0) + dev_err(chg->dev, + "Couldn't set USBIN_LOAD_CFG_REG rc=%d\n", rc); + return rc; } @@ -1550,6 +1591,8 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) { int rc; + chg->pd_not_supported = true; + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, MICRO_USB_STATE_CHANGE_INT_EN_BIT, MICRO_USB_STATE_CHANGE_INT_EN_BIT); @@ -1559,6 +1602,16 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } + /* Enable HVDCP and BC 1.2 source detection */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't enable HVDCP detection rc=%d\n", rc); + return rc; + } + return rc; } @@ -2602,12 +2655,17 @@ static int smb5_probe(struct platform_device *pdev) goto cleanup; } - if (chg->smb_version == PM8150B_SUBTYPE) { + switch (chg->smb_version) { + case PM8150B_SUBTYPE: + case PM6150_SUBTYPE: rc = smb5_init_dc_psy(chip); if (rc < 0) { pr_err("Couldn't initialize dc psy rc=%d\n", rc); goto cleanup; } + break; + default: + break; } rc = smb5_init_usb_psy(chip); diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 2dbba634f6c3cf3ef81e08f996b4739ab11b1308..39a8ea5b8f3cc00faa00cacebd2a3a9086fecf70 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,18 +26,23 @@ #include #include #include +#include #include - -#define SMB1355_DEFAULT_FCC_UA 1000000 +#include /* SMB1355 registers, different than mentioned in smb-reg.h */ +#define REVID_BASE 0x0100 #define I2C_SS_DIG_BASE 0x0E00 #define CHGR_BASE 0x1000 +#define ANA2_BASE 0x1100 #define BATIF_BASE 0x1200 #define USBIN_BASE 0x1300 +#define ANA1_BASE 0x1400 #define MISC_BASE 0x1600 +#define REVID_MFG_ID_SPARE_REG (REVID_BASE + 0xFF) + #define I2C_SS_DIG_PMIC_SID_REG (I2C_SS_DIG_BASE + 0x45) #define PMIC_SID_MASK GENMASK(3, 0) #define PMIC_SID0_BIT BIT(0) @@ -70,6 +75,9 @@ #define CHGR_PRE_TO_FAST_THRESHOLD_CFG_REG (CHGR_BASE + 0x74) #define PRE_TO_FAST_CHARGE_THRESHOLD_MASK GENMASK(2, 0) +#define ANA2_TR_SBQ_ICL_1X_REF_OFFSET_REG (ANA2_BASE + 0xF5) +#define TR_SBQ_ICL_1X_REF_OFFSET GENMASK(4, 0) + #define POWER_MODE_HICCUP_CFG (BATIF_BASE + 0x72) #define MAX_HICCUP_DUETO_BATDIS_MASK GENMASK(5, 2) #define HICCUP_TIMEOUT_CFG_MASK GENMASK(1, 0) @@ -77,21 +85,38 @@ #define BATIF_CFG_SMISC_BATID_REG (BATIF_BASE + 0x73) #define CFG_SMISC_RBIAS_EXT_CTRL_BIT BIT(2) +#define SMB2CHG_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) +#define TDIE_COMPARATOR_THRESHOLD GENMASK(5, 0) +#define DIE_LOW_RANGE_BASE_DEGC 34 +#define DIE_LOW_RANGE_DELTA 16 +#define DIE_LOW_RANGE_MAX_DEGC 97 +#define DIE_LOW_RANGE_SHIFT 4 + #define BATIF_ENG_SCMISC_SPARE1_REG (BATIF_BASE + 0xC2) #define EXT_BIAS_PIN_BIT BIT(2) +#define DIE_TEMP_COMP_HYST_BIT BIT(1) + +#define ANA1_ENG_SREFGEN_CFG2_REG (ANA1_BASE + 0xC1) +#define VALLEY_COMPARATOR_EN_BIT BIT(0) #define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) -#define SKIN_TEMP_RST_HOT_BIT BIT(6) -#define SKIN_TEMP_UB_HOT_BIT BIT(5) -#define SKIN_TEMP_LB_HOT_BIT BIT(4) -#define DIE_TEMP_TSD_HOT_BIT BIT(3) -#define DIE_TEMP_RST_HOT_BIT BIT(2) -#define DIE_TEMP_UB_HOT_BIT BIT(1) -#define DIE_TEMP_LB_HOT_BIT BIT(0) +#define TEMP_RST_HOT_BIT BIT(2) +#define TEMP_UB_HOT_BIT BIT(1) +#define TEMP_LB_HOT_BIT BIT(0) +#define SKIN_TEMP_SHIFT 4 + +#define MISC_RT_STS_REG (MISC_BASE + 0x10) +#define HARD_ILIMIT_RT_STS_BIT BIT(5) + +#define BANDGAP_ENABLE_REG (MISC_BASE + 0x42) +#define BANDGAP_ENABLE_CMD_BIT BIT(0) #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) +#define CLOCK_REQUEST_REG (MISC_BASE + 0x44) +#define CLOCK_REQUEST_CMD_BIT BIT(0) + #define WD_CFG_REG (MISC_BASE + 0x51) #define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7) #define BARK_WDOG_INT_EN_BIT BIT(6) @@ -100,6 +125,13 @@ #define WDOG_TIMER_EN_ON_PLUGIN_BIT BIT(1) #define WDOG_TIMER_EN_BIT BIT(0) +#define MISC_CUST_SDCDC_CLK_CFG_REG (MISC_BASE + 0xA0) +#define SWITCHER_CLK_FREQ_MASK GENMASK(3, 0) + +#define MISC_CUST_SDCDC_ILIMIT_CFG_REG (MISC_BASE + 0xA1) +#define LS_VALLEY_THRESH_PCT_BIT BIT(3) +#define PCL_LIMIT_MASK GENMASK(1, 0) + #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) #define SNARL_WDOG_TIMEOUT_MASK GENMASK(6, 4) @@ -114,6 +146,36 @@ #define MISC_CHGR_TRIM_OPTIONS_REG (MISC_BASE + 0x55) #define CMD_RBIAS_EN_BIT BIT(2) +#define MISC_ENG_SDCDC_INPUT_CURRENT_CFG1_REG (MISC_BASE + 0xC8) +#define PROLONG_ISENSE_MASK GENMASK(7, 6) +#define PROLONG_ISENSEM_SHIFT 6 +#define SAMPLE_HOLD_DELAY_MASK GENMASK(5, 2) +#define SAMPLE_HOLD_DELAY_SHIFT 2 +#define DISABLE_ILIMIT_BIT BIT(0) + +#define MISC_ENG_SDCDC_INPUT_CURRENT_CFG2_REG (MISC_BASE + 0xC9) +#define INPUT_CURRENT_LIMIT_SOURCE_BIT BIT(7) +#define TC_ISENSE_AMPLIFIER_MASK GENMASK(6, 4) +#define TC_ISENSE_AMPLIFIER_SHIFT 4 +#define HS_II_CORRECTION_MASK GENMASK(3, 0) + +#define MISC_ENG_SDCDC_RESERVE3_REG (MISC_BASE + 0xCB) +#define VDDCAP_SHORT_DISABLE_TRISTATE_BIT BIT(7) +#define PCL_SHUTDOWN_BUCK_BIT BIT(6) +#define ISENSE_TC_CORRECTION_BIT BIT(5) +#define II_SOURCE_BIT BIT(4) +#define SCALE_SLOPE_COMP_MASK GENMASK(3, 0) + +#define USBIN_CURRENT_LIMIT_CFG_REG (USBIN_BASE + 0x70) +#define USB_TR_SCPATH_ICL_1X_GAIN_REG (USBIN_BASE + 0xF2) +#define TR_SCPATH_ICL_1X_GAIN_MASK GENMASK(5, 0) + +#define IS_USBIN(mode) \ + ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ + || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + +#define PARALLEL_ENABLE_VOTER "PARALLEL_ENABLE_VOTER" + struct smb_chg_param { const char *name; u16 reg; @@ -125,6 +187,7 @@ struct smb_chg_param { struct smb_params { struct smb_chg_param fcc; struct smb_chg_param ov; + struct smb_chg_param usb_icl; }; static struct smb_params v1_params = { @@ -142,6 +205,13 @@ static struct smb_params v1_params = { .max_u = 5000000, .step_u = 10000, }, + .usb_icl = { + .name = "usb input current limit", + .reg = USBIN_CURRENT_LIMIT_CFG_REG, + .min_u = 100000, + .max_u = 5000000, + .step_u = 30000, + }, }; struct smb_irq_info { @@ -151,13 +221,12 @@ struct smb_irq_info { int irq; }; -struct smb_iio { - struct iio_channel *temp_chan; - struct iio_channel *temp_max_chan; -}; - struct smb_dt_props { bool disable_ctm; + int pl_mode; + int pl_batfet_mode; + bool hw_die_temp_mitigation; + u32 die_temp_threshold; }; struct smb1355 { @@ -165,9 +234,10 @@ struct smb1355 { char *name; struct regmap *regmap; + int max_fcc; + struct smb_dt_props dt; struct smb_params param; - struct smb_iio iio; struct mutex write_lock; @@ -176,10 +246,24 @@ struct smb1355 { int c_health; int c_charger_temp_max; + int die_temp_deciDegC; + bool exit_die_temp; + struct delayed_work die_temp_work; + bool disabled; + + struct votable *irq_disable_votable; +}; + +enum { + CONNECTOR_TEMP = 0, + DIE_TEMP, }; static bool is_secure(struct smb1355 *chip, int addr) { + if (addr == CLOCK_REQUEST_REG) + return true; + /* assume everything above 0xA0 is secure */ return (addr & 0xFF) >= 0xA0; } @@ -196,6 +280,25 @@ static int smb1355_read(struct smb1355 *chip, u16 addr, u8 *val) return rc; } +static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask, + u8 val) +{ + int rc; + + mutex_lock(&chip->write_lock); + if (is_secure(chip, addr)) { + rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5); + if (rc < 0) + goto unlock; + } + + rc = regmap_write_bits(chip->regmap, addr, mask, val); + +unlock: + mutex_unlock(&chip->write_lock); + return rc; +} + static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; @@ -275,6 +378,62 @@ static int smb1355_get_charge_param(struct smb1355 *chip, return rc; } +#define UB_COMP_OFFSET_DEGC 34 +#define DIE_TEMP_MEAS_PERIOD_MS 10000 +static void die_temp_work(struct work_struct *work) +{ + struct smb1355 *chip = container_of(work, struct smb1355, + die_temp_work.work); + int rc, i; + u8 temp_stat; + + for (i = 0; i < BIT(5); i++) { + rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, + TDIE_COMPARATOR_THRESHOLD, i); + if (rc < 0) { + pr_err("Couldn't set temp comp threshold rc=%d\n", rc); + continue; + } + + if (chip->exit_die_temp) + return; + + /* wait for the comparator output to deglitch */ + msleep(100); + + rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp_stat); + if (rc < 0) { + pr_err("Couldn't read temp comp status rc=%d\n", rc); + continue; + } + + if (!(temp_stat & TEMP_UB_HOT_BIT)) { + /* found the temp */ + break; + } + } + + chip->die_temp_deciDegC = 10 * (i + UB_COMP_OFFSET_DEGC); + + schedule_delayed_work(&chip->die_temp_work, + msecs_to_jiffies(DIE_TEMP_MEAS_PERIOD_MS)); +} + +static int smb1355_get_prop_input_current_limited(struct smb1355 *chip, + union power_supply_propval *pval) +{ + int rc; + u8 stat = 0; + + rc = smb1355_read(chip, MISC_RT_STS_REG, &stat); + if (rc < 0) + pr_err("Couldn't read SMB1355_BATTERY_STATUS_3 rc=%d\n", rc); + + pval->intval = !!(stat & HARD_ILIMIT_RT_STS_BIT); + + return 0; +} + static irqreturn_t smb1355_handle_chg_state_change(int irq, void *data) { struct smb1355 *chip = data; @@ -314,6 +473,7 @@ static int smb1355_determine_initial_status(struct smb1355 *chip) return 0; } +#define DEFAULT_DIE_TEMP_LOW_THRESHOLD 90 static int smb1355_parse_dt(struct smb1355 *chip) { struct device_node *node = chip->dev->of_node; @@ -327,7 +487,33 @@ static int smb1355_parse_dt(struct smb1355 *chip) chip->dt.disable_ctm = of_property_read_bool(node, "qcom,disable-ctm"); - return rc; + /* + * If parallel-mode property is not present default + * parallel configuration is USBMID-USBMID. + */ + rc = of_property_read_u32(node, + "qcom,parallel-mode", &chip->dt.pl_mode); + if (rc < 0) + chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID; + + /* + * If stacked-batfet property is not present default + * configuration is NON-STACKED-BATFET. + */ + chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_NON_STACKED_BATFET; + if (of_property_read_bool(node, "qcom,stacked-batfet")) + chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_STACKED_BATFET; + + chip->dt.hw_die_temp_mitigation = of_property_read_bool(node, + "qcom,hw-die-temp-mitigation"); + + chip->dt.die_temp_threshold = DEFAULT_DIE_TEMP_LOW_THRESHOLD; + of_property_read_u32(node, "qcom,die-temp-threshold-degc", + &chip->dt.die_temp_threshold); + if (chip->dt.die_temp_threshold > DIE_LOW_RANGE_MAX_DEGC) + chip->dt.die_temp_threshold = DIE_LOW_RANGE_MAX_DEGC; + + return 0; } /***************************** @@ -346,6 +532,13 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, + POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, + POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, + POWER_SUPPLY_PROP_MIN_ICL, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_SET_SHIP_MODE, + POWER_SUPPLY_PROP_DIE_HEALTH, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, @@ -372,29 +565,13 @@ static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, return rc; } -static int smb1355_get_parallel_charging(struct smb1355 *chip, int *disabled) -{ - int rc; - u8 cfg2; - - rc = smb1355_read(chip, CHGR_CFG2_REG, &cfg2); - if (rc < 0) { - pr_err("Couldn't read en_cmg_reg rc=%d\n", rc); - return rc; - } - - if (cfg2 & CHG_EN_SRC_BIT) - *disabled = 0; - else - *disabled = 1; - - return 0; -} - -static int smb1355_get_prop_connector_health(struct smb1355 *chip) +static int smb1355_get_prop_health(struct smb1355 *chip, int type) { u8 temp; - int rc; + int rc, shift; + + /* Connector-temp uses skin-temp configuration */ + shift = (type == CONNECTOR_TEMP) ? SKIN_TEMP_SHIFT : 0; rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp); if (rc < 0) { @@ -402,37 +579,19 @@ static int smb1355_get_prop_connector_health(struct smb1355 *chip) return POWER_SUPPLY_HEALTH_UNKNOWN; } - if (temp & SKIN_TEMP_RST_HOT_BIT) + if (temp & (TEMP_RST_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_OVERHEAT; - if (temp & SKIN_TEMP_UB_HOT_BIT) + if (temp & (TEMP_UB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_HOT; - if (temp & SKIN_TEMP_LB_HOT_BIT) + if (temp & (TEMP_LB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_WARM; return POWER_SUPPLY_HEALTH_COOL; } - -static int smb1355_get_prop_charger_temp(struct smb1355 *chip, - union power_supply_propval *val) -{ - int rc; - - if (!chip->iio.temp_chan || - PTR_ERR(chip->iio.temp_chan) == -EPROBE_DEFER) - chip->iio.temp_chan = devm_iio_channel_get(chip->dev, - "charger_temp"); - - if (IS_ERR(chip->iio.temp_chan)) - return PTR_ERR(chip->iio.temp_chan); - - rc = iio_read_channel_processed(chip->iio.temp_chan, &val->intval); - val->intval /= 100; - return rc; -} - +#define MIN_PARALLEL_ICL_UA 250000 static int smb1355_parallel_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) @@ -456,13 +615,23 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->intval = !(stat & DISABLE_CHARGING_BIT); break; case POWER_SUPPLY_PROP_CHARGER_TEMP: - rc = smb1355_get_prop_charger_temp(chip, val); + val->intval = chip->die_temp_deciDegC; break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: - val->intval = chip->c_charger_temp_max; + /* + * In case of h/w controlled die_temp mitigation, + * die_temp/die_temp_max can not be reported as this + * requires run time manipulation of DIE_TEMP low + * threshold which will interfere with h/w mitigation + * scheme. + */ + if (chip->dt.hw_die_temp_mitigation) + val->intval = -EINVAL; + else + val->intval = chip->c_charger_temp_max; break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: - rc = smb1355_get_parallel_charging(chip, &val->intval); + val->intval = chip->disabled; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smb1355_get_charge_param(chip, &chip->param.ov, @@ -476,14 +645,44 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->strval = chip->name; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: - val->intval = POWER_SUPPLY_PL_USBMID_USBMID; + val->intval = chip->dt.pl_mode; break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: if (chip->c_health == -EINVAL) - val->intval = smb1355_get_prop_connector_health(chip); + val->intval = smb1355_get_prop_health(chip, + CONNECTOR_TEMP); else val->intval = chip->c_health; break; + case POWER_SUPPLY_PROP_DIE_HEALTH: + val->intval = smb1355_get_prop_health(chip, DIE_TEMP); + break; + case POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE: + val->intval = chip->dt.pl_batfet_mode; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: + if (IS_USBIN(chip->dt.pl_mode)) + rc = smb1355_get_prop_input_current_limited(chip, val); + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + if (IS_USBIN(chip->dt.pl_mode)) + rc = smb1355_get_charge_param(chip, + &chip->param.usb_icl, &val->intval); + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_MIN_ICL: + val->intval = MIN_PARALLEL_ICL_UA; + break; + case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX: + val->intval = chip->max_fcc; + break; + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + /* Not in ship mode as long as device is active */ + val->intval = 0; + break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); @@ -502,6 +701,9 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) { int rc; + if (chip->disabled == disable) + return 0; + rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT, disable ? 0 : WDOG_TIMER_EN_BIT); if (rc < 0) { @@ -520,12 +722,75 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) disable ? 0 : CHG_EN_SRC_BIT); if (rc < 0) { pr_err("Couldn't configure charge enable source rc=%d\n", rc); + disable = true; + } + + chip->die_temp_deciDegC = -EINVAL; + /* Only enable temperature measurement for s/w based mitigation */ + if (!chip->dt.hw_die_temp_mitigation) { + if (disable) { + chip->exit_die_temp = true; + cancel_delayed_work_sync(&chip->die_temp_work); + } else { + /* start the work to measure temperature */ + chip->exit_die_temp = false; + schedule_delayed_work(&chip->die_temp_work, 0); + } + } + + if (chip->irq_disable_votable) + vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, + disable, 0); + + rc = smb1355_masked_write(chip, BANDGAP_ENABLE_REG, + BANDGAP_ENABLE_CMD_BIT, + disable ? 0 : BANDGAP_ENABLE_CMD_BIT); + if (rc < 0) { + pr_err("Couldn't configure bandgap enable rc=%d\n", rc); return rc; } + chip->disabled = disable; + return 0; } +static int smb1355_set_current_max(struct smb1355 *chip, int curr) +{ + int rc = 0; + + if (!IS_USBIN(chip->dt.pl_mode)) + return 0; + + if ((curr / 1000) < 100) { + /* disable parallel path (ICL < 100mA) */ + rc = smb1355_set_parallel_charging(chip, true); + } else { + rc = smb1355_set_parallel_charging(chip, false); + if (rc < 0) + return rc; + + rc = smb1355_set_charge_param(chip, + &chip->param.usb_icl, curr); + } + + return rc; +} + +static int smb1355_clk_request(struct smb1355 *chip, bool enable) +{ + int rc; + + rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG, + CLOCK_REQUEST_CMD_BIT, + enable ? CLOCK_REQUEST_CMD_BIT : 0); + if (rc < 0) + pr_err("Couldn't %s clock rc=%d\n", + enable ? "enable" : "disable", rc); + + return rc; +} + static int smb1355_parallel_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) @@ -537,6 +802,9 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_SUSPEND: rc = smb1355_set_parallel_charging(chip, (bool)val->intval); break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + rc = smb1355_set_current_max(chip, val->intval); + break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smb1355_set_charge_param(chip, &chip->param.ov, val->intval); @@ -551,6 +819,10 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: chip->c_charger_temp_max = val->intval; + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + if (!val->intval) + break; + rc = smb1355_clk_request(chip, false); break; default: pr_debug("parallel power supply set prop %d not supported\n", @@ -609,6 +881,38 @@ static int smb1355_init_parallel_psy(struct smb1355 *chip) * HARDWARE INITIALIZATION * ***************************/ +#define MFG_ID_SMB1354 0x01 +#define MFG_ID_SMB1355 0xFF +#define SMB1354_MAX_PARALLEL_FCC_UA 2500000 +#define SMB1355_MAX_PARALLEL_FCC_UA 6000000 +static int smb1355_detect_version(struct smb1355 *chip) +{ + int rc; + u8 val; + + rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val); + if (rc < 0) { + pr_err("Unable to read REVID rc=%d\n", rc); + return rc; + } + + switch (val) { + case MFG_ID_SMB1354: + chip->name = "smb1354"; + chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA; + break; + case MFG_ID_SMB1355: + chip->name = "smb1355"; + chip->max_fcc = SMB1355_MAX_PARALLEL_FCC_UA; + break; + default: + pr_err("Invalid value of REVID val=%d", val); + return -EINVAL; + } + + return rc; +} + static int smb1355_tskin_sensor_config(struct smb1355 *chip) { int rc; @@ -698,6 +1002,12 @@ static int smb1355_tskin_sensor_config(struct smb1355 *chip) static int smb1355_init_hw(struct smb1355 *chip) { int rc; + u8 val, range; + + /* request clock always on */ + rc = smb1355_clk_request(chip, true); + if (rc < 0) + return rc; /* Change to let SMB1355 only respond to address 0x0C */ rc = smb1355_masked_write(chip, I2C_SS_DIG_PMIC_SID_REG, @@ -769,25 +1079,152 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } + /* Configure DIE temp Low threshold */ + if (chip->dt.hw_die_temp_mitigation) { + range = (chip->dt.die_temp_threshold - DIE_LOW_RANGE_BASE_DEGC) + / (DIE_LOW_RANGE_DELTA); + val = (chip->dt.die_temp_threshold + - ((range * DIE_LOW_RANGE_DELTA) + + DIE_LOW_RANGE_BASE_DEGC)) + % DIE_LOW_RANGE_DELTA; + + rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, + TDIE_COMPARATOR_THRESHOLD, + (range << DIE_LOW_RANGE_SHIFT) | val); + if (rc < 0) { + pr_err("Couldn't set temp comp threshold rc=%d\n", rc); + return rc; + } + } + /* - * Disable thermal Die temperature comparator source and hw mitigation - * for skin/die + * Enable thermal Die temperature comparator source and + * enable hardware controlled current adjustment for die temp + * if charger is configured in h/w controlled die temp mitigation. */ + val = THERMREG_DIE_CMP_SRC_EN_BIT; + if (!chip->dt.hw_die_temp_mitigation) + val |= BYP_THERM_CHG_CURR_ADJUST_BIT; rc = smb1355_masked_write(chip, MISC_THERMREG_SRC_CFG_REG, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT, - BYP_THERM_CHG_CURR_ADJUST_BIT); + val); if (rc < 0) { pr_err("Couldn't set Skin temperature comparator src rc=%d\n", rc); return rc; } + /* + * Disable hysterisis for die temperature. This is so that sw can run + * stepping scheme quickly + */ + val = chip->dt.hw_die_temp_mitigation ? DIE_TEMP_COMP_HYST_BIT : 0; + rc = smb1355_masked_write(chip, BATIF_ENG_SCMISC_SPARE1_REG, + DIE_TEMP_COMP_HYST_BIT, val); + if (rc < 0) { + pr_err("Couldn't disable hyst. for die rc=%d\n", rc); + return rc; + } + + /* Enable valley current comparator all the time */ + rc = smb1355_masked_write(chip, ANA1_ENG_SREFGEN_CFG2_REG, + VALLEY_COMPARATOR_EN_BIT, VALLEY_COMPARATOR_EN_BIT); + if (rc < 0) { + pr_err("Couldn't enable valley current comparator rc=%d\n", rc); + return rc; + } + + /* Set LS_VALLEY threshold to 85% */ + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, + LS_VALLEY_THRESH_PCT_BIT, LS_VALLEY_THRESH_PCT_BIT); + if (rc < 0) { + pr_err("Couldn't set LS valley threshold to 85pc rc=%d\n", rc); + return rc; + } + + /* For SMB1354, set PCL to 8.6 A */ + if (!strcmp(chip->name, "smb1354")) { + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, + PCL_LIMIT_MASK, PCL_LIMIT_MASK); + if (rc < 0) { + pr_err("Couldn't set PCL limit to 8.6A rc=%d\n", rc); + return rc; + } + } + rc = smb1355_tskin_sensor_config(chip); if (rc < 0) { pr_err("Couldn't configure tskin regs rc=%d\n", rc); return rc; } + /* USBIN-USBIN configuration */ + if (IS_USBIN(chip->dt.pl_mode)) { + /* set swicther clock frequency to 700kHz */ + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_CLK_CFG_REG, + SWITCHER_CLK_FREQ_MASK, 0x03); + if (rc < 0) { + pr_err("Couldn't set MISC_CUST_SDCDC_CLK_CFG rc=%d\n", + rc); + return rc; + } + + /* + * configure compensation for input current limit (ICL) loop + * accuracy, scale slope compensation using 30k resistor. + */ + rc = smb1355_masked_write(chip, MISC_ENG_SDCDC_RESERVE3_REG, + II_SOURCE_BIT | SCALE_SLOPE_COMP_MASK, + II_SOURCE_BIT); + if (rc < 0) { + pr_err("Couldn't set MISC_ENG_SDCDC_RESERVE3_REG rc=%d\n", + rc); + return rc; + } + + /* configuration to improve ICL accuracy */ + rc = smb1355_masked_write(chip, + MISC_ENG_SDCDC_INPUT_CURRENT_CFG1_REG, + PROLONG_ISENSE_MASK | SAMPLE_HOLD_DELAY_MASK, + ((uint8_t)0x0C << SAMPLE_HOLD_DELAY_SHIFT)); + if (rc < 0) { + pr_err("Couldn't set MISC_ENG_SDCDC_INPUT_CURRENT_CFG1_REG rc=%d\n", + rc); + return rc; + } + + rc = smb1355_masked_write(chip, + MISC_ENG_SDCDC_INPUT_CURRENT_CFG2_REG, + INPUT_CURRENT_LIMIT_SOURCE_BIT + | HS_II_CORRECTION_MASK, + INPUT_CURRENT_LIMIT_SOURCE_BIT | 0xC); + + if (rc < 0) { + pr_err("Couldn't set MISC_ENG_SDCDC_INPUT_CURRENT_CFG2_REG rc=%d\n", + rc); + return rc; + } + + /* configure DAC offset */ + rc = smb1355_masked_write(chip, + ANA2_TR_SBQ_ICL_1X_REF_OFFSET_REG, + TR_SBQ_ICL_1X_REF_OFFSET, 0x00); + if (rc < 0) { + pr_err("Couldn't set ANA2_TR_SBQ_ICL_1X_REF_OFFSET_REG rc=%d\n", + rc); + return rc; + } + + /* configure DAC gain */ + rc = smb1355_masked_write(chip, USB_TR_SCPATH_ICL_1X_GAIN_REG, + TR_SCPATH_ICL_1X_GAIN_MASK, 0x22); + if (rc < 0) { + pr_err("Couldn't set USB_TR_SCPATH_ICL_1X_GAIN_REG rc=%d\n", + rc); + return rc; + } + } + return 0; } @@ -852,6 +1289,7 @@ static int smb1355_request_interrupt(struct smb1355 *chip, return rc; } + smb1355_irqs[irq_index].irq = irq; if (smb1355_irqs[irq_index].wake) enable_irq_wake(irq); @@ -880,6 +1318,23 @@ static int smb1355_request_interrupts(struct smb1355 *chip) return rc; } +static int smb1355_irq_disable_callback(struct votable *votable, void *data, + int disable, const char *client) + +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smb1355_irqs); i++) { + if (smb1355_irqs[i].irq) { + if (disable) + disable_irq(smb1355_irqs[i].irq); + else + enable_irq(smb1355_irqs[i].irq); + } + } + + return 0; +} /********* * PROBE * @@ -905,8 +1360,10 @@ static int smb1355_probe(struct platform_device *pdev) chip->param = v1_params; chip->c_health = -EINVAL; chip->c_charger_temp_max = -EINVAL; - chip->name = "smb1355"; mutex_init(&chip->write_lock); + INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work); + chip->disabled = true; + chip->die_temp_deciDegC = -EINVAL; chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { @@ -920,6 +1377,12 @@ static int smb1355_probe(struct platform_device *pdev) return -ENODEV; } + rc = smb1355_detect_version(chip); + if (rc < 0) { + pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc); + goto cleanup; + } + platform_set_drvdata(pdev, chip); rc = smb1355_parse_dt(chip); @@ -953,7 +1416,20 @@ static int smb1355_probe(struct platform_device *pdev) goto cleanup; } - pr_info("%s probed successfully\n", chip->name); + chip->irq_disable_votable = create_votable("SMB1355_IRQ_DISABLE", + VOTE_SET_ANY, smb1355_irq_disable_callback, chip); + if (IS_ERR(chip->irq_disable_votable)) { + rc = PTR_ERR(chip->irq_disable_votable); + goto cleanup; + } + /* keep IRQ's disabled until parallel is enabled */ + vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, true, 0); + + pr_info("%s probed successfully pl_mode=%s batfet_mode=%s\n", + chip->name, + IS_USBIN(chip->dt.pl_mode) ? "USBIN-USBIN" : "USBMID-USBMID", + (chip->dt.pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) + ? "STACKED_BATFET" : "NON-STACKED_BATFET"); return rc; cleanup: @@ -976,6 +1452,8 @@ static void smb1355_shutdown(struct platform_device *pdev) rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) pr_err("Couldn't disable parallel path rc=%d\n", rc); + + smb1355_clk_request(chip, false); } static struct platform_driver smb1355_driver = { diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 1d5771cd72db13d5eeee8940a527e093cb2e349a..92e7fa6ec35036e757fd9cb2e3eeb895e7acc61f 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -86,7 +86,8 @@ #define ILIM_VOTER "ILIM_VOTER" #define FCC_VOTER "FCC_VOTER" #define ICL_VOTER "ICL_VOTER" -#define USB_VOTER "USB_VOTER" +#define WIRELESS_VOTER "WIRELESS_VOTER" +#define SRC_VOTER "SRC_VOTER" enum { SWITCHER_OFF_WINDOW_IRQ = 0, @@ -126,6 +127,7 @@ struct smb1390 { /* power supplies */ struct power_supply *usb_psy; struct power_supply *batt_psy; + struct power_supply *dc_psy; int irqs[NUM_IRQS]; bool status_change_running; @@ -184,6 +186,14 @@ static bool is_psy_voter_available(struct smb1390 *chip) } } + if (!chip->dc_psy) { + chip->dc_psy = power_supply_get_by_name("dc"); + if (!chip->dc_psy) { + pr_debug("Couldn't find dc psy\n"); + return false; + } + } + if (!chip->fcc_votable) { chip->fcc_votable = find_votable("FCC"); if (!chip->fcc_votable) { @@ -479,19 +489,39 @@ static void smb1390_status_change_work(struct work_struct *work) } if (pval.intval == POWER_SUPPLY_CHARGER_SEC_CP) { - vote(chip->disable_votable, USB_VOTER, false, 0); + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_SMB_EN_REASON, &pval); + if (rc < 0) { + pr_err("Couldn't get cp reason rc=%d\n", rc); + goto out; + } + + vote(chip->disable_votable, SRC_VOTER, false, 0); /* * ILIM is set based on the primary chargers AICL result. This * ensures VBUS does not collapse due to the current drawn via * MID. */ - rc = power_supply_get_property(chip->usb_psy, + if (pval.intval == POWER_SUPPLY_CP_WIRELESS) { + vote(chip->ilim_votable, ICL_VOTER, false, 0); + rc = power_supply_get_property(chip->dc_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) + pr_err("Couldn't get dc icl rc=%d\n", rc); + else + vote(chip->ilim_votable, WIRELESS_VOTER, true, + pval.intval); + } else { /* QC3 or PPS */ + vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); + rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); - if (rc < 0) - pr_err("Couldn't get usb icl rc=%d\n", rc); - else - vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); + if (rc < 0) + pr_err("Couldn't get usb icl rc=%d\n", rc); + else + vote(chip->ilim_votable, ICL_VOTER, true, + pval.intval); + } /* input current is always half the charge current */ vote(chip->ilim_votable, FCC_VOTER, true, @@ -522,7 +552,7 @@ static void smb1390_status_change_work(struct work_struct *work) } } } else { - vote(chip->disable_votable, USB_VOTER, true, 0); + vote(chip->disable_votable, SRC_VOTER, true, 0); vote(chip->fcc_votable, CP_VOTER, false, 0); } diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index a03d0c9f07a13d031a4b0ef09dc55c82ee8c0f6c..4382b83dd6faa14282d324c368d6c1c7cbf2c611 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -629,6 +629,21 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, /******************** * HELPER FUNCTIONS * ********************/ + +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, psp, val); + + return rc; +} + int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable) { int rc; @@ -801,6 +816,14 @@ static void smblib_uusb_removal(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; + chg->cp_reason = POWER_SUPPLY_CP_NONE; + rc = smblib_select_sec_charger(chg, + chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE); + if (rc < 0) + dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", + rc); + cancel_delayed_work_sync(&chg->pl_enable_work); if (chg->wa_flags & BOOST_BACK_WA) { @@ -859,7 +882,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg) int rc; union power_supply_propval val; - rc = power_supply_get_property(chg->bms_psy, + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_DEBUG_BATTERY, &val); if (rc < 0) { smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc); @@ -1328,9 +1351,8 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg, return 0; } - if (chg->bms_psy) - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CAPACITY, val); + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CAPACITY, val); + return rc; } @@ -1473,7 +1495,8 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - rc = smblib_get_prop_batt_voltage_now(chg, &pval); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); if (!rc) { /* * If Vbatt is within 40mV above Vfloat, then don't @@ -1544,32 +1567,6 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_VOLTAGE_NOW, val); - return rc; -} - -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CURRENT_NOW, val); - return rc; -} - int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val) { @@ -1609,19 +1606,6 @@ int smblib_get_prop_batt_iterm(struct smb_charger *chg, return rc; } -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_TEMP, val); - return rc; -} - int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) { @@ -1640,32 +1624,6 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CHARGE_COUNTER, val); - return rc; -} - -int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CYCLE_COUNT, val); - return rc; -} - /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -1893,11 +1851,21 @@ int smblib_dp_dm(struct smb_charger *chg, int val) pr_err("Failed to force 5V\n"); break; case POWER_SUPPLY_DP_DM_FORCE_9V: + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_9V) { + smblib_err(chg, "Couldn't set 9V: unsupported\n"); + return -EINVAL; + } + rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT); if (rc < 0) pr_err("Failed to force 9V\n"); break; case POWER_SUPPLY_DP_DM_FORCE_12V: + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_12V) { + smblib_err(chg, "Couldn't set 12V: unsupported\n"); + return -EINVAL; + } + rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT); if (rc < 0) pr_err("Failed to force 12V\n"); @@ -1978,6 +1946,72 @@ int smblib_get_prop_dc_online(struct smb_charger *chg, return rc; } +int smblib_get_prop_dc_current_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + return smblib_get_charge_param(chg, &chg->param.dc_icl, &val->intval); +} + +int smblib_get_prop_dc_voltage_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = MICRO_12V; + return 0; +} + +int smblib_get_prop_dc_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->wls_psy) { + chg->wls_psy = power_supply_get_by_name("wireless"); + if (!chg->wls_psy) + return -ENODEV; + } + + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + val); + if (rc < 0) + dev_err(chg->dev, "Couldn't get POWER_SUPPLY_PROP_VOLTAGE_MAX, rc=%d\n", + rc); + return rc; +} + +/******************* + * DC PSY SETTERS * + *******************/ + +int smblib_set_prop_dc_current_max(struct smb_charger *chg, + const union power_supply_propval *val) +{ + return smblib_set_charge_param(chg, &chg->param.dc_icl, val->intval); +} + +int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc; + + if (!chg->wls_psy) { + chg->wls_psy = power_supply_get_by_name("wireless"); + if (!chg->wls_psy) + return -ENODEV; + } + + rc = power_supply_set_property(chg->wls_psy, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, + val); + if (rc < 0) + dev_err(chg->dev, "Couldn't set POWER_SUPPLY_PROP_VOLTAGE_REGULATION, rc=%d\n", + rc); + + smblib_dbg(chg, PR_WLS, "Set WLS output voltage %d\n", val->intval); + + return rc; +} + /******************* * USB PSY GETTERS * *******************/ @@ -2028,6 +2062,15 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, { switch (chg->real_charger_type) { case POWER_SUPPLY_TYPE_USB_HVDCP: + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_9V) { + val->intval = MICRO_5V; + break; + } else if (chg->qc2_unsupported_voltage == + QC2_NON_COMPLIANT_12V) { + val->intval = MICRO_9V; + break; + } + /* else, fallthrough */ case POWER_SUPPLY_TYPE_USB_HVDCP_3: case POWER_SUPPLY_TYPE_USB_PD: if (chg->smb_version == PMI632_SUBTYPE) @@ -2083,6 +2126,73 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, return ret; } +bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) +{ + int r_sbu1, r_sbu2; + bool ret = false; + int rc; + + if (!chg->iio.sbux_chan) + return false; + + /* disable crude sensors */ + rc = smblib_masked_write(chg, TYPE_C_CRUDE_SENSOR_CFG_REG, + EN_SRC_CRUDE_SENSOR_BIT | EN_SNK_CRUDE_SENSOR_BIT, + 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable crude sensor rc=%d\n", rc); + return false; + } + + /* select SBU1 as current source */ + rc = smblib_write(chg, TYPE_C_SBU_CFG_REG, SEL_SBU1_ISRC_VAL); + if (rc < 0) { + smblib_err(chg, "Couldn't select SBU1 rc=%d\n", rc); + goto cleanup; + } + + rc = iio_read_channel_processed(chg->iio.sbux_chan, &r_sbu1); + if (rc < 0) { + smblib_err(chg, "Couldn't read SBU1 rc=%d\n", rc); + goto cleanup; + } + + if (r_sbu1 < r_thr) { + ret = true; + goto cleanup; + } + + /* select SBU2 as current source */ + rc = smblib_write(chg, TYPE_C_SBU_CFG_REG, SEL_SBU2_ISRC_VAL); + if (rc < 0) { + smblib_err(chg, "Couldn't select SBU1 rc=%d\n", rc); + goto cleanup; + } + + rc = iio_read_channel_processed(chg->iio.sbux_chan, &r_sbu2); + if (rc < 0) { + smblib_err(chg, "Couldn't read SBU1 rc=%d\n", rc); + goto cleanup; + } + + if (r_sbu2 < r_thr) + ret = true; +cleanup: + /* enable crude sensors */ + rc = smblib_masked_write(chg, TYPE_C_CRUDE_SENSOR_CFG_REG, + EN_SRC_CRUDE_SENSOR_BIT | EN_SNK_CRUDE_SENSOR_BIT, + EN_SRC_CRUDE_SENSOR_BIT | EN_SNK_CRUDE_SENSOR_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't enable crude sensor rc=%d\n", rc); + + /* disable current source */ + rc = smblib_write(chg, TYPE_C_SBU_CFG_REG, 0); + if (rc < 0) + smblib_err(chg, "Couldn't select SBU1 rc=%d\n", rc); + + return ret; +} + int smblib_get_prop_charger_temp(struct smb_charger *chg, union power_supply_propval *val) { @@ -2627,7 +2737,7 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, power_role = TYPEC_DISABLE_CMD_BIT; break; case POWER_SUPPLY_TYPEC_PR_DUAL: - power_role = 0; + power_role = chg->typec_try_mode; break; case POWER_SUPPLY_TYPEC_PR_SINK: power_role = EN_SNK_ONLY_BIT; @@ -2641,7 +2751,8 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, } rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, - TYPEC_POWER_ROLE_CMD_MASK, power_role); + TYPEC_POWER_ROLE_CMD_MASK | TYPEC_TRY_MODE_MASK, + power_role); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", power_role, rc); @@ -3052,7 +3163,8 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data; reset_storm_count(wdata); - if (!chg->non_compliant_chg_detected && + /* Workaround for non-QC2.0-compliant chargers follows */ + if (!chg->qc2_unsupported_voltage && apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); if (rc < 0) @@ -3067,11 +3179,11 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) smblib_err(chg, "Couldn't read QC2 max pulses rc=%d\n", rc); - chg->non_compliant_chg_detected = true; chg->qc2_max_pulses = (max_pulses & HVDCP_PULSE_COUNT_MAX_QC2_MASK); if (stat & QC_12V_BIT) { + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_12V; rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, HVDCP_PULSE_COUNT_MAX_QC2_MASK, HVDCP_PULSE_COUNT_MAX_QC2_9V); @@ -3080,6 +3192,7 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) rc); } else if (stat & QC_9V_BIT) { + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_9V; rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, HVDCP_PULSE_COUNT_MAX_QC2_MASK, HVDCP_PULSE_COUNT_MAX_QC2_5V); @@ -3679,7 +3792,7 @@ static void typec_src_removal(struct smb_charger *chg) * if non-compliant charger caused UV, restore original max pulses * and turn SUSPEND_ON_COLLAPSE_USBIN_BIT back on. */ - if (chg->non_compliant_chg_detected) { + if (chg->qc2_unsupported_voltage) { rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, HVDCP_PULSE_COUNT_MAX_QC2_MASK, chg->qc2_max_pulses); @@ -3694,7 +3807,7 @@ static void typec_src_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", rc); - chg->non_compliant_chg_detected = false; + chg->qc2_unsupported_voltage = QC2_COMPLIANT; } if (chg->use_extcon) @@ -3832,8 +3945,65 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + union power_supply_propval pval; + bool dcin_present, vbus_present; + int rc, wireless_vout = 0; + + rc = iio_read_channel_processed(chg->iio.vph_v_chan, + &wireless_vout); + if (rc < 0) + return IRQ_HANDLED; + + wireless_vout *= 2; + wireless_vout /= 100000; + wireless_vout *= 100000; + + rc = smblib_get_prop_dc_present(chg, &pval); + if (rc < 0) + return IRQ_HANDLED; + + dcin_present = pval.intval; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", + rc); + return IRQ_HANDLED; + } + + vbus_present = pval.intval; + + if (dcin_present) { + if (!vbus_present && chg->sec_cp_present) { + pval.intval = wireless_vout; + rc = smblib_set_prop_voltage_wls_output(chg, &pval); + if (rc < 0) + dev_err(chg->dev, "Couldn't set dc voltage to 2*vph rc=%d\n", + rc); + + chg->cp_reason = POWER_SUPPLY_CP_WIRELESS; + rc = smblib_select_sec_charger(chg, + POWER_SUPPLY_CHARGER_SEC_CP); + if (rc < 0) + dev_err(chg->dev, "Couldn't enable secondary chargers rc=%d\n", + rc); + } + } else if (chg->cp_reason == POWER_SUPPLY_CP_WIRELESS) { + chg->cp_reason = POWER_SUPPLY_CP_NONE; + rc = smblib_select_sec_charger(chg, + chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE); + if (rc < 0) + dev_err(chg->dev, + "Couldn't disable secondary charger rc=%d\n", + rc); + } power_supply_changed(chg->dc_psy); + + smblib_dbg(chg, PR_WLS, "dcin_present= %d, usbin_present= %d, cp_reason = %d\n", + dcin_present, vbus_present, chg->cp_reason); + return IRQ_HANDLED; } @@ -4189,7 +4359,7 @@ static void jeita_update_work(struct work_struct *work) if (!chg->bms_psy) return; - rc = power_supply_get_property(chg->bms_psy, + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_RESISTANCE_ID, &val); if (rc < 0) { smblib_err(chg, "Failed to get batt-id rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 26a0fa1f950838360c1c0a318b7f6f2c1b0b861f..62781c76f9d9920da97d72e0c456270689d0d8e6 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -26,6 +26,7 @@ enum print_reason { PR_MISC = BIT(2), PR_PARALLEL = BIT(3), PR_OTG = BIT(4), + PR_WLS = BIT(5), }; #define DEFAULT_VOTER "DEFAULT_VOTER" @@ -58,6 +59,7 @@ enum print_reason { #define WBC_VOTER "WBC_VOTER" #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER" +#define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 @@ -78,6 +80,12 @@ enum sink_src_mode { UNATTACHED_MODE, }; +enum qc2_non_comp_voltage { + QC2_COMPLIANT, + QC2_NON_COMPLIANT_9V, + QC2_NON_COMPLIANT_12V +}; + enum { BOOST_BACK_WA = BIT(0), }; @@ -282,6 +290,7 @@ struct smb_charger { struct power_supply *bms_psy; struct power_supply *usb_main_psy; struct power_supply *usb_port_psy; + struct power_supply *wls_psy; enum power_supply_type real_charger_type; /* notifiers */ @@ -366,12 +375,13 @@ struct smb_charger { bool jeita_configured; int charger_temp_max; int smb_temp_max; + u8 typec_try_mode; /* workaround flag */ u32 wa_flags; int boost_current_ua; int qc2_max_pulses; - bool non_compliant_chg_detected; + enum qc2_non_comp_voltage qc2_unsupported_voltage; /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; @@ -392,6 +402,9 @@ struct smb_charger { u32 headroom_mode; bool flash_init_done; bool flash_active; + + /* wireless */ + int wireless_vout; }; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); @@ -464,18 +477,8 @@ int smblib_get_prop_system_temp_level_max(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val); int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, - union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -495,6 +498,12 @@ int smblib_get_prop_dc_current_max(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_dc_current_max(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_get_prop_dc_voltage_now(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_dc_voltage_max(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_get_prop_usb_present(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_usb_online(struct smb_charger *chg, @@ -561,6 +570,9 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val); int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); int smblib_icl_override(struct smb_charger *chg, bool override); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 902396d14c33ba26182ab14626ee45908555dbbb..8218b9ec40172c3f9e80fc6beba12b6a6fc71488 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -258,6 +258,8 @@ enum { #define USBIN_LOAD_CFG_REG (USBIN_BASE + 0x65) #define ICL_OVERRIDE_AFTER_APSD_BIT BIT(4) +#define USBIN_AICL_STEP_TIMING_SEL_MASK GENMASK(3, 2) +#define USBIN_IN_COLLAPSE_GF_SEL_MASK GENMASK(1, 0) #define USBIN_ICL_OPTIONS_REG (USBIN_BASE + 0x66) #define CFG_USB3P0_SEL_BIT BIT(2) @@ -320,8 +322,10 @@ enum { #define U_USB_GROUND_BIT BIT(4) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) -#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 1) +#define TYPEC_TRY_MODE_MASK GENMASK(4, 3) #define EN_TRY_SNK_BIT BIT(4) +#define EN_TRY_SRC_BIT BIT(3) +#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) #define EN_SRC_ONLY_BIT BIT(2) #define EN_SNK_ONLY_BIT BIT(1) #define TYPEC_DISABLE_CMD_BIT BIT(0) @@ -336,6 +340,10 @@ enum { #define TYPEC_CCOUT_VALUE_BIT BIT(1) #define TYPEC_CCOUT_SRC_BIT BIT(0) +#define TYPE_C_CRUDE_SENSOR_CFG_REG (TYPEC_BASE + 0x4e) +#define EN_SRC_CRUDE_SENSOR_BIT BIT(1) +#define EN_SNK_CRUDE_SENSOR_BIT BIT(0) + #define TYPE_C_EXIT_STATE_CFG_REG (TYPEC_BASE + 0x50) #define BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT BIT(3) #define EXIT_SNK_BASED_ON_CC_BIT BIT(0) @@ -372,6 +380,10 @@ enum { #define TYPE_C_DEBOUNCE_OPTION_REG (TYPEC_BASE + 0x62) #define REDUCE_TCCDEBOUNCE_TO_2MS_BIT BIT(2) +#define TYPE_C_SBU_CFG_REG (TYPEC_BASE + 0x6A) +#define SEL_SBU1_ISRC_VAL 0x04 +#define SEL_SBU2_ISRC_VAL 0x01 + #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) #define EN_MICRO_USB_MODE_BIT BIT(0) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 58a97d4205723fff7e25f454480169b6f658b0a4..51364621f77ce737a65b8fd7e1c8479c76324f3d 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -89,6 +89,7 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, case PTP_PF_PHYSYNC: if (chan != 0) return -EINVAL; + break; default: return -EINVAL; } diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index aca41a8d5b9c9cca1538b15705179f764a53b158..784fc8bb3ae226d5d648dcb1ee5a3ec0afd4a268 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -165,6 +165,7 @@ struct qpnp_lpg_chip { struct qpnp_lpg_channel *lpgs; struct qpnp_lpg_lut *lut; struct mutex bus_lock; + u32 *lpg_group; u32 num_lpgs; }; @@ -659,8 +660,9 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) { struct qpnp_lpg_chip *chip = lpg->chip; struct qpnp_lpg_lut *lut = chip->lut; + struct pwm_device *pwm; u8 mask, val; - int rc; + int i, lpg_idx, rc; mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT | LPG_EN_RAMP_GEN_MASK; @@ -680,8 +682,31 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) } if (lpg->src_sel == LUT_PATTERN && en) { - mutex_lock(&lut->lock); val = 1 << lpg->lpg_idx; + for (i = 0; i < chip->num_lpgs; i++) { + if (chip->lpg_group == NULL) + break; + if (chip->lpg_group[i] == 0) + break; + lpg_idx = chip->lpg_group[i] - 1; + pwm = &chip->pwm_chip.pwms[lpg_idx]; + if ((pwm_get_output_type(pwm) == PWM_OUTPUT_MODULATED) + && pwm_is_enabled(pwm)) { + rc = qpnp_lpg_masked_write(&chip->lpgs[lpg_idx], + REG_LPG_ENABLE_CONTROL, + LPG_EN_LPG_OUT_BIT, 0); + if (rc < 0) + break; + rc = qpnp_lpg_masked_write(&chip->lpgs[lpg_idx], + REG_LPG_ENABLE_CONTROL, + LPG_EN_LPG_OUT_BIT, + LPG_EN_LPG_OUT_BIT); + if (rc < 0) + break; + val |= 1 << lpg_idx; + } + } + mutex_lock(&lut->lock); rc = qpnp_lut_write(lut, REG_LPG_LUT_RAMP_CONTROL, val); if (rc < 0) dev_err(chip->dev, "Write LPG_LUT_RAMP_CONTROL failed, rc=%d\n", @@ -1146,6 +1171,53 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) "qcom,ramp-toggle"); } + rc = of_property_count_elems_of_size(chip->dev->of_node, + "qcom,sync-channel-ids", sizeof(u32)); + if (rc < 0) + return 0; + + length = rc; + if (length > chip->num_lpgs) { + dev_err(chip->dev, "qcom,sync-channel-ids has too many channels: %d\n", + length); + return -EINVAL; + } + + chip->lpg_group = devm_kcalloc(chip->dev, chip->num_lpgs, + sizeof(u32), GFP_KERNEL); + if (!chip->lpg_group) + return -ENOMEM; + + rc = of_property_read_u32_array(chip->dev->of_node, + "qcom,sync-channel-ids", chip->lpg_group, length); + if (rc < 0) { + dev_err(chip->dev, "Get qcom,sync-channel-ids failed, rc=%d\n", + rc); + return rc; + } + + for (i = 0; i < length; i++) { + if (chip->lpg_group[i] <= 0 || + chip->lpg_group[i] > chip->num_lpgs) { + dev_err(chip->dev, "lpg_group[%d]: %d is not a valid channel\n", + i, chip->lpg_group[i]); + return -EINVAL; + } + } + + /* + * The LPG channel in the same group should have the same ramping + * configuration, so force to use the ramping configuration of the + * 1st LPG channel in the group for sychronization. + */ + lpg = &chip->lpgs[chip->lpg_group[0] - 1]; + ramp = &lpg->ramp_config; + + for (i = 1; i < length; i++) { + lpg = &chip->lpgs[chip->lpg_group[i] - 1]; + memcpy(&lpg->ramp_config, ramp, sizeof(struct lpg_ramp_config)); + } + return 0; } diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index f541b80f1b540ae12d47ece8de124b74839b1acf..bd910fe123d98e65794990a14d7c26986369b6cb 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -222,7 +222,7 @@ static unsigned int cpcap_map_mode(unsigned int mode) case CPCAP_BIT_AUDIO_LOW_PWR: return REGULATOR_MODE_STANDBY; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index a3bc8037153e5d1a490f93618646e0cf6fe2ede5..bb768cc4428526d787c610406cca2d399102c550 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -55,6 +55,7 @@ enum fan53555_vendor { FAN53555_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_SILERGY, + HALO_HL7509, }; /* IC Type */ @@ -98,6 +99,8 @@ struct fan53555_device_info { unsigned int slew_rate; /* Sleep voltage cache */ unsigned int sleep_vol_cache; + /* Disable suspend */ + bool disable_suspend; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -105,6 +108,8 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) struct fan53555_device_info *di = rdev_get_drvdata(rdev); int ret; + if (di->disable_suspend) + return 0; if (di->sleep_vol_cache == uV) return 0; ret = regulator_map_voltage_linear(rdev, uV, uV); @@ -309,6 +314,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case FAN53555_VENDOR_SILERGY: ret = fan53555_voltages_setup_silergy(di); break; + case HALO_HL7509: + ret = fan53555_voltages_setup_fairchild(di); + break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; @@ -344,26 +352,29 @@ static const struct regmap_config fan53555_regmap_config = { .val_bits = 8, }; -static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, - struct device_node *np, - const struct regulator_desc *desc) +static int fan53555_parse_dt(struct fan53555_device_info *di, + struct fan53555_platform_data *pdata, + const struct regulator_desc *desc) { - struct fan53555_platform_data *pdata; + struct device *dev = di->dev; + struct device_node *np = dev->of_node; int ret; u32 tmp; - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - pdata->regulator = of_get_regulator_init_data(dev, np, desc); + if (!pdata->regulator) { + dev_err(dev, "regulator init data is missing\n"); + return -ENODEV; + } ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", &tmp); if (!ret) pdata->sleep_vsel_id = tmp; - return pdata; + di->disable_suspend = of_property_read_bool(np, "fcs,disable-suspend"); + + return ret; } static const struct of_device_id fan53555_dt_ids[] = { @@ -376,6 +387,9 @@ static const struct of_device_id fan53555_dt_ids[] = { }, { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY, + }, { + .compatible = "halo,hl7509", + .data = (void *)HALO_HL7509, }, { } }; @@ -384,7 +398,6 @@ MODULE_DEVICE_TABLE(of, fan53555_dt_ids); static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct device_node *np = client->dev.of_node; struct fan53555_device_info *di; struct fan53555_platform_data *pdata; struct regulator_config config = { }; @@ -397,14 +410,17 @@ static int fan53555_regulator_probe(struct i2c_client *client, return -ENOMEM; pdata = dev_get_platdata(&client->dev); - if (!pdata) - pdata = fan53555_parse_dt(&client->dev, np, &di->desc); - - if (!pdata || !pdata->regulator) { - dev_err(&client->dev, "Platform data not found!\n"); - return -ENODEV; + if (!pdata) { + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; } + di->dev = &client->dev; + ret = fan53555_parse_dt(di, pdata, &di->desc); + if (ret) + return ret; + di->regulator = pdata->regulator; if (client->dev.of_node) { di->vendor = @@ -427,7 +443,6 @@ static int fan53555_regulator_probe(struct i2c_client *client, dev_err(&client->dev, "Failed to allocate regmap!\n"); return PTR_ERR(di->regmap); } - di->dev = &client->dev; i2c_set_clientdata(client, di); /* Get chip ID */ ret = regmap_read(di->regmap, FAN53555_ID1, &val); @@ -456,7 +471,7 @@ static int fan53555_regulator_probe(struct i2c_client *client, config.init_data = di->regulator; config.regmap = di->regmap; config.driver_data = di; - config.of_node = np; + config.of_node = client->dev.of_node; ret = fan53555_regulator_register(di, &config); if (ret < 0) @@ -475,6 +490,9 @@ static const struct i2c_device_id fan53555_id[] = { }, { .name = "syr828", .driver_data = FAN53555_VENDOR_SILERGY + }, { + .name = "hl7509", + .driver_data = HALO_HL7509 }, { }, }; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index c9875355905d159827ea565affd0b26b7bc18b01..a3bf7c993723acdaab9160b22be58a7e5d52b37a 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -31,6 +31,7 @@ static void of_get_regulation_constraints(struct device_node *np, struct regulation_constraints *constraints = &(*init_data)->constraints; struct regulator_state *suspend_state; struct device_node *suspend_np; + unsigned int mode; int ret, i; u32 pval; @@ -124,11 +125,11 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) { if (desc && desc->of_map_mode) { - ret = desc->of_map_mode(pval); - if (ret == -EINVAL) + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) pr_err("%s: invalid mode %u\n", np->name, pval); else - constraints->initial_mode = ret; + constraints->initial_mode = mode; } else { pr_warn("%s: mapping for mode %d not defined\n", np->name, pval); @@ -163,12 +164,12 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(suspend_np, "regulator-mode", &pval)) { if (desc && desc->of_map_mode) { - ret = desc->of_map_mode(pval); - if (ret == -EINVAL) + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) pr_err("%s: invalid mode %u\n", np->name, pval); else - suspend_state->mode = ret; + suspend_state->mode = mode; } else { pr_warn("%s: mapping for mode %d not defined\n", np->name, pval); diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 63922a2167e55a75fb5e3c3f2526bc9f06bcabf2..659e516455bee1f14f50a1f60ad13b590375e5a7 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -158,6 +158,7 @@ static const struct regulator_ops pfuze100_sw_regulator_ops = { static const struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index a4456db5849d06282b7eb2884d20e8da29093753..884c7505ed91c493b127e680b7406773952fc1d7 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -274,7 +274,7 @@ static inline unsigned int twl4030reg_map_mode(unsigned int mode) case RES_STATE_SLEEP: return REGULATOR_MODE_STANDBY; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index a7e74f9204d1f52149bf8717b1207dbb39d61c12..f432d62a8e6fd108a4e9b567e29eb0e76181e7f0 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -114,6 +115,8 @@ struct glink_core_rx_intent { * @rx_pipe: pipe object for receive FIFO * @tx_pipe: pipe object for transmit FIFO * @irq: IRQ for signaling incoming events + * @kworker: kworker to handle rx_done work + * @task: kthread running @kworker * @rx_work: worker for handling received control messages * @rx_lock: protects the @rx_queue * @rx_queue: queue of received control messages to be processed in @rx_work @@ -136,6 +139,9 @@ struct qcom_glink { int irq; + struct kthread_worker kworker; + struct task_struct *task; + struct work_struct rx_work; spinlock_t rx_lock; struct list_head rx_queue; @@ -200,7 +206,7 @@ struct glink_channel { spinlock_t intent_lock; struct idr liids; struct idr riids; - struct work_struct intent_work; + struct kthread_work intent_work; struct list_head done_intents; struct glink_core_rx_intent *buf; @@ -240,7 +246,7 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops; #define GLINK_FEATURE_INTENTLESS BIT(1) -static void qcom_glink_rx_done_work(struct work_struct *work); +static void qcom_glink_rx_done_work(struct kthread_work *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, const char *name) @@ -264,7 +270,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(&channel->intent_req_comp); INIT_LIST_HEAD(&channel->done_intents); - INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work); + kthread_init_work(&channel->intent_work, qcom_glink_rx_done_work); idr_init(&channel->liids); idr_init(&channel->riids); @@ -280,6 +286,8 @@ static void qcom_glink_channel_release(struct kref *ref) unsigned long flags; CH_INFO(channel, "\n"); + kthread_cancel_work_sync(&channel->intent_work); + spin_lock_irqsave(&channel->intent_lock, flags); idr_destroy(&channel->liids); idr_destroy(&channel->riids); @@ -504,7 +512,7 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink, qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true); } -static void qcom_glink_rx_done_work(struct work_struct *work) +static void qcom_glink_rx_done_work(struct kthread_work *work) { struct glink_channel *channel = container_of(work, struct glink_channel, intent_work); @@ -566,7 +574,7 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, list_add_tail(&intent->node, &channel->done_intents); spin_unlock(&channel->intent_lock); - schedule_work(&channel->intent_work); + kthread_queue_work(&glink->kworker, &channel->intent_work); } /** @@ -1610,7 +1618,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) CH_INFO(channel, "\n"); /* cancel pending rx_done work */ - cancel_work_sync(&channel->intent_work); + kthread_cancel_work_sync(&channel->intent_work); if (channel->rpdev) { strlcpy(chinfo.name, channel->name, sizeof(chinfo.name)); @@ -1800,6 +1808,15 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, return ERR_CAST(glink->mbox_chan); } + kthread_init_worker(&glink->kworker); + glink->task = kthread_run(kthread_worker_fn, &glink->kworker, + "glink_%s", glink->name); + if (IS_ERR(glink->task)) { + dev_err(dev, "failed to spawn intent kthread %d\n", + PTR_ERR(glink->task)); + return ERR_CAST(glink->task); + } + irq = of_irq_get(dev->of_node, 0); ret = devm_request_irq(dev, irq, qcom_glink_native_intr, @@ -1864,6 +1881,8 @@ void qcom_glink_native_remove(struct qcom_glink *glink) idr_destroy(&glink->rcids); spin_unlock_irqrestore(&glink->idr_lock, flags); + kthread_flush_worker(&glink->kworker); + kthread_stop(glink->task); qcom_glink_pipe_reset(glink); mbox_free_channel(glink->mbox_chan); } diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index c0c75731adc16ead6ababbd96ae6f80af4b6c724..bef6d430559e679704bd949cc4455a73800a8690 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -359,6 +359,11 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; + if (!rtc->ops) + return -ENODEV; + else if (!rtc->ops->set_alarm) + return -EINVAL; + err = rtc_valid_tm(&alarm->time); if (err != 0) return err; diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index a3418a8a37965a909fc4a86cb1cd513d2c9f8c9a..97fdc99bfeefbf1eda692be0a7b464c773102060 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -276,14 +276,15 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, rtc); - rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev), - &tps6586x_rtc_ops, THIS_MODULE); + rtc->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc)) { ret = PTR_ERR(rtc->rtc); - dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); + dev_err(&pdev->dev, "RTC allocate device: ret %d\n", ret); goto fail_rtc_register; } + rtc->rtc->ops = &tps6586x_rtc_ops; + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, tps6586x_rtc_irq, IRQF_ONESHOT, @@ -294,6 +295,13 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) goto fail_rtc_register; } disable_irq(rtc->irq); + + ret = rtc_register_device(rtc->rtc); + if (ret) { + dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); + goto fail_rtc_register; + } + return 0; fail_rtc_register: diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index d0244d7979fcb8913bfaf6093334b6f3f5938bf4..a56b526db89a415771930f06539878c95a4a3f0d 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -380,6 +380,10 @@ static int tps65910_rtc_probe(struct platform_device *pdev) if (!tps_rtc) return -ENOMEM; + tps_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(tps_rtc->rtc)) + return PTR_ERR(tps_rtc->rtc); + /* Clear pending interrupts */ ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg); if (ret < 0) @@ -421,10 +425,10 @@ static int tps65910_rtc_probe(struct platform_device *pdev) tps_rtc->irq = irq; device_set_wakeup_capable(&pdev->dev, 1); - tps_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &tps65910_rtc_ops, THIS_MODULE); - if (IS_ERR(tps_rtc->rtc)) { - ret = PTR_ERR(tps_rtc->rtc); + tps_rtc->rtc->ops = &tps65910_rtc_ops; + + ret = rtc_register_device(tps_rtc->rtc); + if (ret) { dev_err(&pdev->dev, "RTC device register: err %d\n", ret); return ret; } diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 7ce22967fd167d53717f86cb54895a8f4e810b2a..7ed010714f2968a243031e780fcad208b4da05d4 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -292,13 +292,14 @@ static int rtc_probe(struct platform_device *pdev) goto err_rtc1_iounmap; } - rtc = devm_rtc_device_register(&pdev->dev, rtc_name, &vr41xx_rtc_ops, - THIS_MODULE); + rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc)) { retval = PTR_ERR(rtc); goto err_iounmap_all; } + rtc->ops = &vr41xx_rtc_ops; + rtc->max_user_freq = MAX_PERIODIC_RATE; spin_lock_irq(&rtc_lock); @@ -340,6 +341,10 @@ static int rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n"); + retval = rtc_register_device(rtc); + if (retval) + goto err_iounmap_all; + return 0; err_iounmap_all: diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index b415ba42ca73a7430d387d75f578cbac00761563..599447032e50af8d594c051879d9ea2297780459 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -285,6 +285,8 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, struct list_head *entry; unsigned long flags; + lockdep_assert_held(&adapter->erp_lock); + if (unlikely(!debug_level_enabled(dbf->rec, level))) return; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 00e7968a1d70f6b120aa0309087d196f77f5f145..a1388842e17e561e901726ccb61bc44163332c24 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -886,6 +886,11 @@ static int twa_chrdev_open(struct inode *inode, struct file *file) unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; + if (!capable(CAP_SYS_ADMIN)) { + retval = -EACCES; + goto out; + } + minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 33261b690774a8deeb8ec20835d0b24100a926b0..f6179e3d695397e368cdd57e913d8863e829fa31 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1033,6 +1033,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + minor_number = iminor(inode); if (minor_number >= tw_device_extension_count) return -ENODEV; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 0b6467206f8ea7834bfe14ae68a6bae4e6f1fb7c..737314cac8d84fa5640b036503fae866b06c64d6 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -946,9 +946,9 @@ static void cxlflash_remove(struct pci_dev *pdev) return; } - /* If a Task Management Function is active, wait for it to complete - * before continuing with remove. - */ + /* Yield to running recovery threads before continuing with remove */ + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && + cfg->state != STATE_PROBING); spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) wait_event_interruptible_lock_irq(cfg->tmf_waitq, @@ -1303,7 +1303,10 @@ static void afu_err_intr_init(struct afu *afu) for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); - writeq_be(SISL_MSI_SYNC_ERROR, &hwq->host_map->ctx_ctrl); + reg = readq_be(&hwq->host_map->ctx_ctrl); + WARN_ON((reg & SISL_CTX_CTRL_LISN_MASK) != 0); + reg |= SISL_MSI_SYNC_ERROR; + writeq_be(reg, &hwq->host_map->ctx_ctrl); writeq_be(SISL_ISTATUS_MASK, &hwq->host_map->intr_mask); } } diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 09daa86670fcbb412ddb8f4ea01aefd707798c9e..0892fb1f0a1ee35afc4d452e130d1a42f2ad9f77 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -284,6 +284,7 @@ struct sisl_host_map { __be64 cmd_room; __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ #define SISL_CTX_CTRL_UNMAP_SECTOR 0x8000000000000000ULL /* b0 */ +#define SISL_CTX_CTRL_LISN_MASK (0xFFULL) __be64 mbox_w; /* restricted use */ __be64 sq_start; /* Submission Queue (R/W): write sequence and */ __be64 sq_end; /* inclusion semantics are the same as RRQ */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 2e5fa9717be89acdcc3b1565c0b1c85a5ab089c1..871962b2e2f64df1ae436a5b2ea8b32ca843d925 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -328,10 +328,11 @@ enum { #define DIR_TO_DEVICE 2 #define DIR_RESERVED 3 -#define CMD_IS_UNCONSTRAINT(cmd) \ - ((cmd == ATA_CMD_READ_LOG_EXT) || \ - (cmd == ATA_CMD_READ_LOG_DMA_EXT) || \ - (cmd == ATA_CMD_DEV_RESET)) +#define FIS_CMD_IS_UNCONSTRAINED(fis) \ + ((fis.command == ATA_CMD_READ_LOG_EXT) || \ + (fis.command == ATA_CMD_READ_LOG_DMA_EXT) || \ + ((fis.command == ATA_CMD_DEV_RESET) && \ + ((fis.control & ATA_SRST) != 0))) static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { @@ -1044,7 +1045,7 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba, << CMD_HDR_FRAME_TYPE_OFF; dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; - if (CMD_IS_UNCONSTRAINT(task->ata_task.fis.command)) + if (FIS_CMD_IS_UNCONSTRAINED(task->ata_task.fis)) dw1 |= 1 << CMD_HDR_UNCON_CMD_OFF; hdr->dw1 = cpu_to_le32(dw1); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 7195cff51d4c4181f60ab3330796818771590798..9b6f5d024dbae8df9af3625e3d2b35c4a5543462 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4199,6 +4199,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) int irq, i, j; int error = -ENODEV; + if (hba_count >= MAX_CONTROLLERS) + goto out; + if (pci_enable_device(pdev)) goto out; pci_set_master(pdev); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index d8f626567f590723e4e6f626e33c302b2101f100..06a2e3d9fc5b2e15849bfb91a027e44f3e245713 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2677,6 +2677,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value); pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); } else { + if (os_timeout_value) + os_timeout_value++; + /* system pd Fast Path */ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; timeout_limit = (scmd->device->type == TYPE_DISK) ? diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 7c0064500cc528a9d8c29e3ecd4ff66f005717d6..382edb79a0de99f4bda0551cf999ec3a20a3ad56 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -1649,6 +1649,15 @@ static int qedf_vport_destroy(struct fc_vport *vport) struct Scsi_Host *shost = vport_to_shost(vport); struct fc_lport *n_port = shost_priv(shost); struct fc_lport *vn_port = vport->dd_data; + struct qedf_ctx *qedf = lport_priv(vn_port); + + if (!qedf) { + QEDF_ERR(NULL, "qedf is NULL.\n"); + goto out; + } + + /* Set unloading bit on vport qedf_ctx to prevent more I/O */ + set_bit(QEDF_UNLOADING, &qedf->flags); mutex_lock(&n_port->lp_mutex); list_del(&vn_port->list); @@ -1675,6 +1684,7 @@ static int qedf_vport_destroy(struct fc_vport *vport) if (vn_port->host) scsi_host_put(vn_port->host); +out: return 0; } diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 9ce28c4f9812b6a4890fd909ae3fec8f6b39bd0c..b09d29931393265ce4989cd5b35b30a98326aa2d 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2142,6 +2142,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) msleep(1000); qla24xx_disable_vp(vha); + qla2x00_wait_for_sess_deletion(vha); vha->flags.delete_progress = 1; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f852ca60c49fd182192efaeb6853bf5c379f015c..89706341514e29b57ef94f8b96c27fcd6e556bd9 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -200,6 +200,7 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, uint16_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_abort_cmd(srb_t *); +void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); /* * Global Functions in qla_mid.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 59ecc4eda6cdec096d53927b3a994262141f9cd3..2a19ec0660cbbb031c28b9b382cb4563466ea6ef 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3368,6 +3368,10 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) return rval; done_free_sp: + spin_lock_irqsave(&vha->hw->vport_slock, flags); + list_del(&sp->elem); + spin_unlock_irqrestore(&vha->hw->vport_slock, flags); + if (sp->u.iocb_cmd.u.ctarg.req) { dma_free_coherent(&vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bcde6130f12149026b29314b68a811af94905810..1d42d38f5a45a48c9755ec29a280ceb60b385d7f 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1326,11 +1326,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, wait_for_completion(&tm_iocb->u.tmf.comp); - rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ? - QLA_SUCCESS : QLA_FUNCTION_FAILED; + rval = tm_iocb->u.tmf.data; - if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) { - ql_dbg(ql_dbg_taskm, vha, 0x8030, + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x8030, "TM IOCB failed (%x).\n", rval); } diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 9a2c86eacf44add92137dc94d5bf2846987e89e0..3f5a0f0f8b62824c90f3e155611f6e51a2e3b49b 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -221,6 +221,8 @@ qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) sp->fcport = fcport; sp->iocbs = 1; sp->vha = qpair->vha; + INIT_LIST_HEAD(&sp->elem); + done: if (!sp) QLA_QPAIR_MARK_NOT_BUSY(qpair); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index d77dde89118e3ff0e1a6e1e0b18a02743a98d5dd..375a88e18afe6a0c910822bc233b02265e60dc83 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -152,10 +152,15 @@ qla24xx_disable_vp(scsi_qla_host_t *vha) { unsigned long flags; int ret; + fc_port_t *fcport; ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); atomic_set(&vha->loop_state, LOOP_DOWN); atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); + list_for_each_entry(fcport, &vha->vp_fcports, list) + fcport->logout_on_delete = 0; + + qla2x00_mark_all_devices_lost(vha, 0); /* Remove port id from vp target map */ spin_lock_irqsave(&vha->hw->vport_slock, flags); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1be76695e6924331e7e16b57137de694eef3caae..7d7fb5bbb600791de6e4b88bbcfbc115ab03c105 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1136,7 +1136,7 @@ static inline int test_fcport_count(scsi_qla_host_t *vha) * qla2x00_wait_for_sess_deletion can only be called from remove_one. * it has dependency on UNLOADING flag to stop device discovery */ -static void +void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha) { qla2x00_mark_all_devices_lost(vha, 0); @@ -5794,8 +5794,9 @@ qla2x00_do_dpc(void *data) set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); } - if (test_and_clear_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags)) { + if (test_and_clear_bit + (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && + !test_bit(UNLOADING, &base_vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, base_vha, 0x4007, "ISP abort scheduled.\n"); diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index a5e30e9449efed76883e62cc2cd2a77b38feeb3d..375cede0c534bb364940a2f0aba077f923c247a4 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -58,7 +58,10 @@ static const struct scsi_dh_blist scsi_dh_blist[] = { {"IBM", "3526", "rdac", }, {"IBM", "3542", "rdac", }, {"IBM", "3552", "rdac", }, - {"SGI", "TP9", "rdac", }, + {"SGI", "TP9300", "rdac", }, + {"SGI", "TP9400", "rdac", }, + {"SGI", "TP9500", "rdac", }, + {"SGI", "TP9700", "rdac", }, {"SGI", "IS", "rdac", }, {"STK", "OPENstorage", "rdac", }, {"STK", "FLEXLINE 380", "rdac", }, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 60345cb4e414a469b4ca45288a1d0193b8e9ca67..11ff33c1e5c4ad9b58024be134fc63edddff9751 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2159,6 +2159,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) if (!shost->use_clustering) q->limits.cluster = 0; + if (shost->inlinecrypt_support) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); /* * Set a reasonable default alignment: The larger of 32-byte (dword), * which is a common minimum for HBAs, and the minimum DMA alignment, diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index ea9e1e0ed5b8502be262940459d3cad7d4ec0392..f4944dde6c8e8e1696fe22ba6cab34e44e61aa95 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -430,7 +430,8 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, * Check that all zones of the device are equal. The last zone can however * be smaller. The zone size must also be a power of two number of LBAs. * - * Returns the zone size in bytes upon success or an error code upon failure. + * Returns the zone size in number of blocks upon success or an error code + * upon failure. */ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) { @@ -440,7 +441,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) unsigned char *rec; unsigned int buf_len; unsigned int list_length; - int ret; + s64 ret; u8 same; /* Get a buffer */ diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0576fe79bd1fbb7406ef9fcea7535db9334aa5fd..6dc7f6150c131c00778920e020a3852e0cfc77f2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2190,6 +2190,7 @@ sg_add_sfp(Sg_device * sdp) write_lock_irqsave(&sdp->sfd_lock, iflags); if (atomic_read(&sdp->detaching)) { write_unlock_irqrestore(&sdp->sfd_lock, iflags); + kfree(sfp); return ERR_PTR(-ENODEV); } list_add_tail(&sfp->sfd_siblings, &sdp->sfds); diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index fb42b567a1b791a2f2cf34f9e2c49338a3a22e23..7b1a958b2bbf702320b40abfba32f18d67e81e3e 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -937,11 +937,18 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, req = lrbp->cmd->request; else return 0; - - /* Use request LBA as the DUN value */ - if (req->bio) - *dun = (req->bio->bi_iter.bi_sector) >> - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + /* + * Right now ICE do not support variable dun but can be + * taken as future enhancement + * if (bio_dun(req->bio)) { + * dun @bio can be split, so we have to adjust offset + * *dun = bio_dun(req->bio); + * } else + */ + if (req->bio) { + *dun = req->bio->bi_iter.bi_sector; + *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + } ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable); @@ -2093,6 +2100,7 @@ static int ufs_qcom_parse_reg_info(struct ufs_qcom_host *host, char *name, dev_dbg(dev, "%s: unable to find %s err %d, using default\n", __func__, prop_name, ret); vreg->min_uV = VDDP_REF_CLK_MIN_UV; + ret = 0; } snprintf(prop_name, MAX_PROP_SIZE, "%s-max-uV", name); @@ -2101,6 +2109,7 @@ static int ufs_qcom_parse_reg_info(struct ufs_qcom_host *host, char *name, dev_dbg(dev, "%s: unable to find %s err %d, using default\n", __func__, prop_name, ret); vreg->max_uV = VDDP_REF_CLK_MAX_UV; + ret = 0; } out: @@ -2180,6 +2189,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_err(dev, "%s: ufs_qcom_ice_get_dev failed %d\n", __func__, err); goto out_variant_clear; + } else { + hba->host->inlinecrypt_support = 1; } host->generic_phy = devm_phy_get(dev, "ufsphy"); diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index afc7ecc3c1876158d33e45933458fc035593c39f..f4e3bd40c72e60c0448c98456f7b53f6be7936bd 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -155,7 +155,7 @@ static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false); } -static struct imx7_pgc_domain imx7_pgc_domains[] = { +static const struct imx7_pgc_domain imx7_pgc_domains[] = { [IMX7_POWER_DOMAIN_MIPI_PHY] = { .genpd = { .name = "mipi-phy", @@ -321,11 +321,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) continue; } - domain = &imx7_pgc_domains[domain_index]; - domain->regmap = regmap; - domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; - domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; - pd_pdev = platform_device_alloc("imx7-pgc-domain", domain_index); if (!pd_pdev) { @@ -334,7 +329,20 @@ static int imx_gpcv2_probe(struct platform_device *pdev) return -ENOMEM; } - pd_pdev->dev.platform_data = domain; + ret = platform_device_add_data(pd_pdev, + &imx7_pgc_domains[domain_index], + sizeof(imx7_pgc_domains[domain_index])); + if (ret) { + platform_device_put(pd_pdev); + of_node_put(np); + return ret; + } + + domain = pd_pdev->dev.platform_data; + domain->regmap = regmap; + domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; + domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; + pd_pdev->dev.parent = dev; pd_pdev->dev.of_node = np; diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index 9cfa7f71a0088c651c1657d49b2f3bf6b8495521..b2ad30d7756a79d97ca6f4b12c349651b359ca4b 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -24,6 +24,33 @@ #define DFC_MAX_BEARERS_V01 16 #define DFC_MAX_QOS_ID_V01 2 +#define DFC_ACK_TYPE_DISABLE 1 +#define DFC_ACK_TYPE_THRESHOLD 2 + +struct dfc_qmap_header { + u8 pad_len:6; + u8 reserved_bit:1; + u8 cd_bit:1; + u8 mux_id; + __be16 pkt_len; +} __aligned(1); + +struct dfc_ack_cmd { + struct dfc_qmap_header header; + u8 command_name; + u8 cmd_type:2; + u8 reserved:6; + u16 reserved2; + u32 transaction_id; + u8 ver:2; + u8 reserved3:6; + u8 type:2; + u8 reserved4:6; + u16 dfc_seq; + u8 reserved5[3]; + u8 bearer_id; +} __aligned(1); + struct dfc_qmi_data { void *rmnet_port; struct workqueue_struct *dfc_wq; @@ -40,6 +67,14 @@ struct dfc_svc_ind { void *dfc_info; }; +struct dfc_burst_ind { + struct work_struct work; + struct net_device *dev; + struct qos_info *qos; + struct rmnet_bearer_map *bearer; + struct dfc_qmi_data *data; +}; + static void dfc_svc_init(struct work_struct *work); static void dfc_do_burst_flow_control(struct work_struct *work); @@ -506,25 +541,75 @@ static int dfc_init_service(struct dfc_qmi_data *data, struct qmi_info *qmi) return dfc_indication_register_req(&data->handle, &data->ssctl, 1); } -static int dfc_bearer_flow_ctl(struct net_device *dev, struct qos_info *qos, - u8 bearer_id, u32 grant_size, int enable) +static void +dfc_send_ack(struct net_device *dev, u8 bearer_id, u16 seq, u8 mux_id, u8 type) +{ + struct qos_info *qos = rmnet_get_qos_pt(dev); + struct sk_buff *skb; + struct dfc_ack_cmd *msg; + int data_size = sizeof(struct dfc_ack_cmd); + int header_size = sizeof(struct dfc_qmap_header); + + if (!qos) + return; + + skb = alloc_skb(data_size, GFP_ATOMIC); + if (!skb) + return; + + msg = (struct dfc_ack_cmd *)skb_put(skb, data_size); + memset(msg, 0, data_size); + + msg->header.cd_bit = 1; + msg->header.mux_id = mux_id; + msg->header.pkt_len = htons(data_size - header_size); + + msg->bearer_id = bearer_id; + msg->command_name = 4; + msg->cmd_type = 0; + msg->dfc_seq = htons(seq); + msg->type = type; + msg->ver = 2; + msg->transaction_id = htonl(qos->tran_num); + + skb->dev = qos->real_dev; + skb->protocol = htons(ETH_P_MAP); + + trace_dfc_qmap_cmd(mux_id, bearer_id, seq, type, qos->tran_num); + qos->tran_num++; + + rmnet_map_tx_qmap_cmd(skb); +} + +static int dfc_bearer_flow_ctl(struct net_device *dev, + struct rmnet_bearer_map *bearer, + struct qos_info *qos) { struct list_head *p; struct rmnet_flow_map *itm; int rc = 0, qlen; + int enable; + + enable = bearer->grant_size ? 1 : 0; list_for_each(p, &qos->flow_head) { itm = list_entry(p, struct rmnet_flow_map, list); - if (itm->bearer_id == bearer_id) { + if (itm->bearer_id == bearer->bearer_id) { qlen = tc_qdisc_flow_control(dev, itm->tcm_handle, enable); trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id, - grant_size, qlen, itm->tcm_handle, - enable); + bearer->grant_size, qlen, + itm->tcm_handle, enable); rc++; } } + + if (enable == 0 && bearer->ack_req) + dfc_send_ack(dev, bearer->bearer_id, + bearer->seq, qos->mux_id, + DFC_ACK_TYPE_DISABLE); + return rc; } @@ -542,6 +627,8 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, bearer_itm = list_entry(p, struct rmnet_bearer_map, list); bearer_itm->grant_size = fc_info->num_bytes; + bearer_itm->grant_thresh = + qmi_rmnet_grant_per(bearer_itm->grant_size); bearer_itm->seq = fc_info->seq_num; bearer_itm->ack_req = ack_req; } @@ -557,6 +644,12 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, flow_itm->tcm_handle, enable); rc++; } + + if (enable == 0 && ack_req) + dfc_send_ack(dev, fc_info->bearer_id, + fc_info->seq_num, fc_info->mux_id, + DFC_ACK_TYPE_DISABLE); + return rc; } @@ -576,12 +669,12 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, action = 0; itm->grant_size = fc_info->num_bytes; + itm->grant_thresh = qmi_rmnet_grant_per(itm->grant_size); itm->seq = fc_info->seq_num; itm->ack_req = ack_req; if (action != -1) - rc = dfc_bearer_flow_ctl(dev, qos, fc_info->bearer_id, - itm->grant_size, action); + rc = dfc_bearer_flow_ctl(dev, itm, qos); } else { pr_debug("grant %u before flow activate", fc_info->num_bytes); qos->default_grant = fc_info->num_bytes; @@ -606,22 +699,12 @@ static void dfc_do_burst_flow_control(struct work_struct *work) return; } -get_lock: - local_bh_disable(); - /* This will drop some messages but that is - * unavoidable for now since the notifier callback is - * protected by rtnl_lock() and destroy_workqueue() - * will dead lock with this. - */ - if (!rtnl_trylock()) { + while (!rtnl_trylock()) { if (!svc_ind->data->restart_state) { - local_bh_enable(); - msleep(20); - goto get_lock; + cond_resched(); } else { kfree(ind); kfree(svc_ind); - local_bh_enable(); return; } } @@ -657,7 +740,56 @@ static void dfc_do_burst_flow_control(struct work_struct *work) kfree(ind); kfree(svc_ind); rtnl_unlock(); - local_bh_enable(); +} + +static void dfc_bearer_limit_work(struct work_struct *work) +{ + struct dfc_burst_ind *dfc_ind = (struct dfc_burst_ind *)work; + struct rmnet_flow_map *itm; + struct list_head *p; + int qlen, fc; + + /* enable transmit on device so that the other + * flows which transmit proceed normally. + */ + netif_start_queue(dfc_ind->dev); + + while (!rtnl_trylock()) { + if (!dfc_ind->data->restart_state) { + cond_resched(); + } else { + kfree(dfc_ind); + return; + } + } + + fc = dfc_ind->bearer->grant_size ? 1 : 0; + /* if grant size is non zero here, we must have already + * got an updated grant. do nothing in that case + */ + if (fc) + goto done; + + list_for_each(p, &dfc_ind->qos->flow_head) { + itm = list_entry(p, struct rmnet_flow_map, list); + + if (itm->bearer_id == dfc_ind->bearer->bearer_id) { + qlen = tc_qdisc_flow_control(dfc_ind->dev, + itm->tcm_handle, fc); + trace_dfc_qmi_tc_limit(itm->bearer_id, itm->flow_id, + dfc_ind->bearer->grant_size, + qlen, itm->tcm_handle, fc); + } + } + + if (dfc_ind->bearer->ack_req) + dfc_send_ack(dfc_ind->dev, dfc_ind->bearer->bearer_id, + dfc_ind->bearer->seq, dfc_ind->qos->mux_id, + DFC_ACK_TYPE_DISABLE); + +done: + kfree(dfc_ind); + rtnl_unlock(); } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, @@ -833,39 +965,64 @@ void dfc_qmi_client_exit(void *dfc_data) } void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, - struct sk_buff *skb) + struct sk_buff *skb, struct qmi_info *qmi) { struct rmnet_bearer_map *bearer; + struct dfc_burst_ind *dfc_ind; struct rmnet_flow_map *itm; + struct dfc_qmi_data *data; int ip_type; + u32 start_grant; - if (!qos) - return; + ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; - if (!rtnl_trylock()) + itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); + if (unlikely(!itm)) return; - ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; + bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); + if (unlikely(!bearer)) + return; - itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); - if (itm) { - bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); - if (unlikely(!bearer)) { - rtnl_unlock(); - return; - } + trace_dfc_flow_check(bearer->bearer_id, skb->len, bearer->grant_size); - trace_dfc_flow_check(bearer->bearer_id, - skb->len, bearer->grant_size); + if (!bearer->grant_size) + return; - if (skb->len >= bearer->grant_size) { - bearer->grant_size = 0; - dfc_bearer_flow_ctl(dev, qos, bearer->bearer_id, - bearer->grant_size, 0); - } else { - bearer->grant_size -= skb->len; - } + start_grant = bearer->grant_size; + if (skb->len >= bearer->grant_size) + bearer->grant_size = 0; + else + bearer->grant_size -= skb->len; + + if (start_grant > bearer->grant_thresh && + bearer->grant_size <= bearer->grant_thresh) { + dfc_send_ack(dev, bearer->bearer_id, + bearer->seq, qos->mux_id, + DFC_ACK_TYPE_THRESHOLD); } - rtnl_unlock(); + if (bearer->grant_size) + return; + + data = (struct dfc_qmi_data *)qmi_rmnet_has_dfc_client(qmi); + if (!data) + return; + + dfc_ind = kzalloc(sizeof(*dfc_ind), GFP_ATOMIC); + if (!dfc_ind) + return; + + INIT_WORK((struct work_struct *)dfc_ind, dfc_bearer_limit_work); + + dfc_ind->dev = dev; + dfc_ind->qos = qos; + dfc_ind->bearer = bearer; + dfc_ind->data = data; + + /* stop the flow in hope that the worker thread is + * immediately scheduled beyond this point of time + */ + netif_stop_queue(dev); + queue_work(data->dfc_wq, (struct work_struct *)dfc_ind); } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 9a68853ffd6c0ef209207743cdef995a21383cab..5c354fdb0df1b3b65b5cbd0f942eef250a37d29a 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -800,6 +800,7 @@ static int icnss_driver_event_server_arrive(void *data) err_setup_msa: icnss_assign_msa_perm_all(penv, ICNSS_MSA_PERM_HLOS_ALL); + clear_bit(ICNSS_MSA0_ASSIGNED, &penv->state); err_power_on: icnss_hw_power_off(penv); clear_server: @@ -2004,7 +2005,6 @@ int icnss_trigger_recovery(struct device *dev) goto out; } - WARN_ON(1); icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n", priv->state); diff --git a/drivers/soc/qcom/mem-offline.c b/drivers/soc/qcom/mem-offline.c index 8a4eaeae684c2e72a7f36a973cdd5f086f3d5388..dbd16078134237ca2c3f53a8a90c150697c207be 100644 --- a/drivers/soc/qcom/mem-offline.c +++ b/drivers/soc/qcom/mem-offline.c @@ -324,10 +324,14 @@ static int mem_parse_dt(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; val = of_get_property(node, "granule", NULL); - if (!val && !*val) { + if (!val) { pr_err("mem-offine: granule property not found in DT\n"); return -EINVAL; } + if (!*val) { + pr_err("mem-offine: invalid granule property\n"); + return -EINVAL; + } offline_granule = be32_to_cpup(val); if (!offline_granule && !(offline_granule & (offline_granule - 1)) && offline_granule * SZ_1M < MIN_MEMORY_BLOCK_SIZE) { diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c index 79921d2259d366fb9e32cf2c29607fb680366a58..bb67e8296ed431228b35b8c65922315578c3a39e 100644 --- a/drivers/soc/qcom/qdss_bridge.c +++ b/drivers/soc/qcom/qdss_bridge.c @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include #include @@ -39,6 +41,28 @@ module_param(poolsize, int, 0644); static int itemsize = QDSS_BUF_SIZE; module_param(itemsize, int, 0644); +static struct class *mhi_class; + +static const char * const str_mhi_transfer_mode[] = { + [MHI_TRANSFER_TYPE_USB] = "usb", + [MHI_TRANSFER_TYPE_UCI] = "uci", +}; + +static int qdss_destroy_mhi_buf_tbl(struct qdss_bridge_drvdata *drvdata) +{ + struct list_head *start, *temp; + struct qdss_mhi_buf_tbl_t *entry = NULL; + + list_for_each_safe(start, temp, &drvdata->mhi_buf_tbl) { + entry = list_entry(start, struct qdss_mhi_buf_tbl_t, link); + list_del(&entry->link); + kfree(entry->buf); + kfree(entry); + } + + return 0; +} + static int qdss_destroy_buf_tbl(struct qdss_bridge_drvdata *drvdata) { struct list_head *start, *temp; @@ -67,7 +91,7 @@ static int qdss_create_buf_tbl(struct qdss_bridge_drvdata *drvdata) if (!entry) goto err; - buf = kzalloc(QDSS_BUF_SIZE, GFP_KERNEL); + buf = kzalloc(drvdata->mtu, GFP_KERNEL); usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL); entry->buf = buf; @@ -129,11 +153,99 @@ static void qdss_buf_tbl_remove(struct qdss_bridge_drvdata *drvdata, static void mhi_ch_close(struct qdss_bridge_drvdata *drvdata) { - flush_workqueue(drvdata->mhi_wq); - qdss_destroy_buf_tbl(drvdata); - mhi_unprepare_from_transfer(drvdata->mhi_dev); + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) { + flush_workqueue(drvdata->mhi_wq); + qdss_destroy_buf_tbl(drvdata); + } else if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + qdss_destroy_mhi_buf_tbl(drvdata); + if (drvdata->cur_buf) + kfree(drvdata->cur_buf->buf); + + drvdata->cur_buf = NULL; + } +} + +static ssize_t mhi_show_transfer_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qdss_bridge_drvdata *drvdata = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + str_mhi_transfer_mode[drvdata->mode]); +} + +static ssize_t mhi_store_transfer_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct qdss_bridge_drvdata *drvdata = dev_get_drvdata(dev); + char str[10] = ""; + int ret; + + if (strlen(buf) >= 10) + return -EINVAL; + if (sscanf(buf, "%3s", str) != 1) + return -EINVAL; + + spin_lock_bh(&drvdata->lock); + if (!strcmp(str, str_mhi_transfer_mode[MHI_TRANSFER_TYPE_UCI])) { + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) { + if (drvdata->opened == ENABLE) { + drvdata->opened = DISABLE; + drvdata->mode = MHI_TRANSFER_TYPE_UCI; + spin_unlock_bh(&drvdata->lock); + usb_qdss_close(drvdata->usb_ch); + mhi_unprepare_from_transfer(drvdata->mhi_dev); + mhi_ch_close(drvdata); + } else if (drvdata->opened == DISABLE) { + drvdata->mode = MHI_TRANSFER_TYPE_UCI; + spin_unlock_bh(&drvdata->lock); + } else { + ret = -ERESTARTSYS; + goto out; + } + } else + spin_unlock_bh(&drvdata->lock); + + } else if (!strcmp(str, str_mhi_transfer_mode[MHI_TRANSFER_TYPE_USB])) { + if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + if (drvdata->opened == ENABLE) { + drvdata->opened = DISABLE; + spin_unlock_bh(&drvdata->lock); + wake_up(&drvdata->uci_wq); + mhi_unprepare_from_transfer(drvdata->mhi_dev); + mhi_ch_close(drvdata); + drvdata->mode = MHI_TRANSFER_TYPE_USB; + queue_work(drvdata->mhi_wq, + &drvdata->open_work); + } else if (drvdata->opened == DISABLE) { + drvdata->mode = MHI_TRANSFER_TYPE_USB; + spin_unlock_bh(&drvdata->lock); + queue_work(drvdata->mhi_wq, + &drvdata->open_work); + } else { + ret = -ERESTARTSYS; + goto out; + } + } else + spin_unlock_bh(&drvdata->lock); + + } else { + ret = -EINVAL; + goto out; + } + + ret = size; + return ret; +out: + spin_unlock_bh(&drvdata->lock); + return ret; } +static DEVICE_ATTR(mode, 0644, + mhi_show_transfer_mode, mhi_store_transfer_mode); + + static void mhi_read_work_fn(struct work_struct *work) { int err = 0; @@ -146,14 +258,14 @@ static void mhi_read_work_fn(struct work_struct *work) read_work); do { - if (!drvdata->opened) + if (drvdata->opened != ENABLE) break; entry = qdss_get_entry(drvdata); if (!entry) break; err = mhi_queue_transfer(drvdata->mhi_dev, DMA_FROM_DEVICE, - entry->buf, QDSS_BUF_SIZE, mhi_flags); + entry->buf, drvdata->mtu, mhi_flags); if (err) { pr_err_ratelimited("Unable to read from MHI buffer err:%d", err); @@ -203,7 +315,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) LIST_HEAD(head); do { - if (!(drvdata->opened)) + if (drvdata->opened != ENABLE) break; spin_lock_bh(&drvdata->lock); if (list_empty(&drvdata->read_done_list)) { @@ -227,7 +339,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) * read, discard the buffers here and do not forward * them to the mux layer. */ - if (drvdata->opened) { + if (drvdata->opened == ENABLE) { err = usb_write(drvdata, buf, len); if (err) qdss_buf_tbl_remove(drvdata, buf); @@ -282,18 +394,26 @@ static int mhi_ch_open(struct qdss_bridge_drvdata *drvdata) { int ret; - if (drvdata->opened) + spin_lock_bh(&drvdata->lock); + if (drvdata->opened == ENABLE) return 0; + if (drvdata->opened == SSR) + return -ERESTARTSYS; + drvdata->opened = ENABLE; + spin_unlock_bh(&drvdata->lock); + ret = mhi_prepare_for_transfer(drvdata->mhi_dev); if (ret) { pr_err("Unable to open MHI channel\n"); - return ret; + goto err; } + return 0; +err: spin_lock_bh(&drvdata->lock); - drvdata->opened = 1; + drvdata->opened = DISABLE; spin_unlock_bh(&drvdata->lock); - return 0; + return ret; } static void qdss_bridge_open_work_fn(struct work_struct *work) @@ -320,6 +440,7 @@ static void qdss_bridge_open_work_fn(struct work_struct *work) return; err: + mhi_unprepare_from_transfer(drvdata->mhi_dev); mhi_ch_close(drvdata); err_open: pr_err("Open work failed with err:%d\n", ret); @@ -342,8 +463,10 @@ static void qdss_mhi_read_cb(struct mhi_device *mhi_dev, return; buf = result->buf_addr; - if (drvdata->opened && + spin_lock_bh(&drvdata->lock); + if (drvdata->opened == ENABLE && result->transaction_status != -ENOTCONN) { + spin_unlock_bh(&drvdata->lock); tp = kmalloc(sizeof(*tp), GFP_ATOMIC); if (!tp) return; @@ -352,12 +475,243 @@ static void qdss_mhi_read_cb(struct mhi_device *mhi_dev, spin_lock_bh(&drvdata->lock); list_add_tail(&tp->link, &drvdata->read_done_list); spin_unlock_bh(&drvdata->lock); - queue_work(drvdata->mhi_wq, &drvdata->read_done_work); + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) + queue_work(drvdata->mhi_wq, &drvdata->read_done_work); + else + wake_up(&drvdata->uci_wq); } else { - qdss_buf_tbl_remove(drvdata, buf); + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) { + spin_unlock_bh(&drvdata->lock); + qdss_buf_tbl_remove(drvdata, buf); + } else { + spin_unlock_bh(&drvdata->lock); + return; + } } + } +static int mhi_uci_release(struct inode *inode, struct file *file) +{ + struct qdss_bridge_drvdata *drvdata = file->private_data; + + spin_lock_bh(&drvdata->lock); + if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + if (drvdata->opened == ENABLE) { + drvdata->opened = DISABLE; + spin_unlock_bh(&drvdata->lock); + wake_up(&drvdata->uci_wq); + mhi_unprepare_from_transfer(drvdata->mhi_dev); + mhi_ch_close(drvdata); + } else if (drvdata->opened == SSR) { + spin_unlock_bh(&drvdata->lock); + complete(&drvdata->completion); + } else + spin_unlock_bh(&drvdata->lock); + } else + spin_unlock_bh(&drvdata->lock); + + return 0; +} + +static ssize_t mhi_uci_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + struct qdss_bridge_drvdata *drvdata = file->private_data; + struct mhi_device *mhi_dev = drvdata->mhi_dev; + struct qdss_mhi_buf_tbl_t *uci_buf; + char *ptr; + size_t to_copy; + int ret = 0; + + if (!buf) + return -EINVAL; + + pr_debug("Client provided buf len:%lu\n", count); + + /* confirm channel is active */ + spin_lock_bh(&drvdata->lock); + if (drvdata->opened != ENABLE || + drvdata->mode != MHI_TRANSFER_TYPE_UCI) { + spin_unlock_bh(&drvdata->lock); + return -ERESTARTSYS; + } + + /* No data available to read, wait */ + if (!drvdata->cur_buf && list_empty(&drvdata->read_done_list)) { + spin_unlock_bh(&drvdata->lock); + + pr_debug("No data available to read waiting\n"); + ret = wait_event_interruptible(drvdata->uci_wq, + ((drvdata->opened != ENABLE + || !list_empty(&drvdata->read_done_list)))); + if (ret == -ERESTARTSYS) { + pr_debug("Exit signal caught for node\n"); + return -ERESTARTSYS; + } + + spin_lock_bh(&drvdata->lock); + if (drvdata->opened != ENABLE) { + spin_unlock_bh(&drvdata->lock); + pr_debug("node was disabled or SSR occurred.\n"); + ret = -ERESTARTSYS; + return ret; + } + } + + /* new read, get the next descriptor from the list */ + if (!drvdata->cur_buf) { + uci_buf = list_first_entry_or_null(&drvdata->read_done_list, + struct qdss_mhi_buf_tbl_t, link); + if (unlikely(!uci_buf)) { + ret = -EIO; + goto read_error; + } + + list_del(&uci_buf->link); + drvdata->cur_buf = uci_buf; + drvdata->rx_size = uci_buf->len; + pr_debug("Got pkt of size:%zu\n", drvdata->rx_size); + } + + uci_buf = drvdata->cur_buf; + spin_unlock_bh(&drvdata->lock); + + /* Copy the buffer to user space */ + to_copy = min_t(size_t, count, drvdata->rx_size); + ptr = uci_buf->buf + (uci_buf->len - drvdata->rx_size); + ret = copy_to_user(buf, ptr, to_copy); + if (ret) + return ret; + + pr_debug("Copied %lu of %lu bytes\n", to_copy, drvdata->rx_size); + drvdata->rx_size -= to_copy; + + /* we finished with this buffer, queue it back to hardware */ + if (!drvdata->rx_size) { + spin_lock_bh(&drvdata->lock); + drvdata->cur_buf = NULL; + + if (drvdata->opened == ENABLE) + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, + uci_buf->buf, drvdata->mtu, + MHI_EOT); + else + ret = -ERESTARTSYS; + + if (ret) { + pr_err("Failed to recycle element, ret: %d\n", ret); + kfree(uci_buf->buf); + kfree(uci_buf); + uci_buf->buf = NULL; + uci_buf = NULL; + goto read_error; + } + + spin_unlock_bh(&drvdata->lock); + } + + pr_debug("Returning %lu bytes\n", to_copy); + return to_copy; + +read_error: + spin_unlock_bh(&drvdata->lock); + return ret; +} + +static int mhi_queue_inbound(struct qdss_bridge_drvdata *drvdata) +{ + struct mhi_device *mhi_dev = drvdata->mhi_dev; + int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE); + void *buf; + struct qdss_mhi_buf_tbl_t *entry; + int ret = -EIO, i; + + for (i = 0; i < nr_trbs; i++) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto err; + + buf = kzalloc(drvdata->mtu, GFP_KERNEL); + if (!buf) { + kfree(entry); + goto err; + } + + entry->buf = buf; + + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, + drvdata->mtu, + MHI_EOT); + if (ret) { + kfree(buf); + kfree(entry); + pr_err("Failed to queue buffer %d\n", i); + return ret; + } + list_add_tail(&entry->link, &drvdata->mhi_buf_tbl); + } + + return ret; +err: + return -ENOMEM; + +} + +static int mhi_uci_open(struct inode *inode, struct file *filp) +{ + int ret = -EIO; + struct qdss_mhi_buf_tbl_t *buf_itr, *tmp; + struct qdss_bridge_drvdata *drvdata = container_of(inode->i_cdev, + struct qdss_bridge_drvdata, + cdev); + + spin_lock_bh(&drvdata->lock); + if (drvdata->opened) { + pr_err("Node was opened or SSR occurred\n"); + spin_unlock_bh(&drvdata->lock); + return ret; + } + drvdata->opened = ENABLE; + spin_unlock_bh(&drvdata->lock); + + ret = mhi_prepare_for_transfer(drvdata->mhi_dev); + if (ret) { + pr_err("Error starting transfer channels\n"); + goto error_open_chan; + } + + ret = mhi_queue_inbound(drvdata); + if (ret) + goto error_rx_queue; + + filp->private_data = drvdata; + return ret; + +error_rx_queue: + mhi_unprepare_from_transfer(drvdata->mhi_dev); + list_for_each_entry_safe(buf_itr, tmp, &drvdata->read_done_list, link) { + list_del(&buf_itr->link); + kfree(buf_itr->buf); + } + +error_open_chan: + spin_lock_bh(&drvdata->lock); + drvdata->opened = DISABLE; + spin_unlock_bh(&drvdata->lock); + return ret; +} + + + +static const struct file_operations mhidev_fops = { + .open = mhi_uci_open, + .release = mhi_uci_release, + .read = mhi_uci_read, +}; + static void qdss_mhi_remove(struct mhi_device *mhi_dev) { struct qdss_bridge_drvdata *drvdata = NULL; @@ -367,14 +721,26 @@ static void qdss_mhi_remove(struct mhi_device *mhi_dev) drvdata = mhi_dev->priv_data; if (!drvdata) return; - if (!drvdata->opened) - return; spin_lock_bh(&drvdata->lock); - drvdata->opened = 0; - spin_unlock_bh(&drvdata->lock); - usb_qdss_close(drvdata->usb_ch); - flush_workqueue(drvdata->mhi_wq); - qdss_destroy_buf_tbl(drvdata); + if (drvdata->opened == ENABLE) { + drvdata->opened = SSR; + if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + spin_unlock_bh(&drvdata->lock); + wake_up(&drvdata->uci_wq); + wait_for_completion(&drvdata->completion); + } else { + spin_unlock_bh(&drvdata->lock); + usb_qdss_close(drvdata->usb_ch); + } + mhi_ch_close(drvdata); + + } else + spin_unlock_bh(&drvdata->lock); + + device_remove_file(drvdata->dev, &dev_attr_mode); + device_destroy(mhi_class, drvdata->cdev.dev); + cdev_del(&drvdata->cdev); + unregister_chrdev_region(drvdata->cdev.dev, 1); } int qdss_mhi_init(struct qdss_bridge_drvdata *drvdata) @@ -388,8 +754,11 @@ int qdss_mhi_init(struct qdss_bridge_drvdata *drvdata) INIT_WORK(&(drvdata->read_done_work), mhi_read_done_work_fn); INIT_WORK(&(drvdata->open_work), qdss_bridge_open_work_fn); INIT_LIST_HEAD(&drvdata->buf_tbl); + INIT_LIST_HEAD(&drvdata->mhi_buf_tbl); + init_waitqueue_head(&drvdata->uci_wq); + init_completion(&drvdata->completion); INIT_LIST_HEAD(&drvdata->read_done_list); - drvdata->opened = 0; + drvdata->opened = DISABLE; return 0; } @@ -398,7 +767,10 @@ static int qdss_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) { int ret; + unsigned int baseminor = 0; + unsigned int count = 1; struct qdss_bridge_drvdata *drvdata; + dev_t dev; drvdata = devm_kzalloc(&mhi_dev->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { @@ -406,21 +778,63 @@ static int qdss_mhi_probe(struct mhi_device *mhi_dev, return ret; } + ret = alloc_chrdev_region(&dev, baseminor, count, "mhi_qdss"); + if (ret < 0) { + pr_err("alloc_chrdev_region failed %d\n", ret); + return ret; + } + cdev_init(&drvdata->cdev, &mhidev_fops); + + drvdata->cdev.owner = THIS_MODULE; + drvdata->cdev.ops = &mhidev_fops; + + ret = cdev_add(&drvdata->cdev, dev, 1); + if (ret) + goto exit_unreg_chrdev_region; + + drvdata->dev = device_create(mhi_class, NULL, + drvdata->cdev.dev, drvdata, + "mhi_qdss"); + if (IS_ERR(drvdata->dev)) { + pr_err("class_device_create failed %d\n", ret); + ret = -ENOMEM; + goto exit_cdev_add; + } + + drvdata->mode = MHI_TRANSFER_TYPE_USB; + drvdata->mtu = min_t(size_t, id->driver_data, mhi_dev->mtu); drvdata->mhi_dev = mhi_dev; mhi_device_set_devdata(mhi_dev, drvdata); + dev_set_drvdata(drvdata->dev, drvdata); + + ret = device_create_file(drvdata->dev, &dev_attr_mode); + if (ret) { + pr_err("sysfs node create failed error:%d\n", ret); + goto exit_destroy_device; + } ret = qdss_mhi_init(drvdata); - if (ret) - goto err; + if (ret) { + pr_err("Device probe failed err:%d\n", ret); + goto remove_sysfs_exit; + } queue_work(drvdata->mhi_wq, &drvdata->open_work); return 0; -err: - pr_err("Device probe failed err:%d\n", ret); + +remove_sysfs_exit: + device_remove_file(drvdata->dev, &dev_attr_mode); +exit_destroy_device: + device_destroy(mhi_class, drvdata->cdev.dev); +exit_cdev_add: + cdev_del(&drvdata->cdev); +exit_unreg_chrdev_region: + unregister_chrdev_region(drvdata->cdev.dev, 1); return ret; + } static const struct mhi_device_id qdss_mhi_match_table[] = { - { .chan = "QDSS" }, + { .chan = "QDSS", .driver_data = 0x4000 }, {}, }; @@ -438,7 +852,17 @@ static struct mhi_driver qdss_mhi_driver = { static int __init qdss_bridge_init(void) { - return mhi_driver_register(&qdss_mhi_driver); + int ret; + + mhi_class = class_create(THIS_MODULE, MODULE_NAME); + if (IS_ERR(mhi_class)) + return -ENODEV; + + ret = mhi_driver_register(&qdss_mhi_driver); + if (ret) + class_destroy(mhi_class); + + return ret; } static void __exit qdss_bridge_exit(void) diff --git a/drivers/soc/qcom/qdss_bridge.h b/drivers/soc/qcom/qdss_bridge.h index 60c8b4c63cd2d168736fde27bdd48aea18f98bb5..f5e119b0ce844db2ea140afbcb9126517eea6a31 100644 --- a/drivers/soc/qcom/qdss_bridge.h +++ b/drivers/soc/qcom/qdss_bridge.h @@ -26,10 +26,26 @@ struct qdss_mhi_buf_tbl_t { size_t len; }; +enum mhi_transfer_mode { + MHI_TRANSFER_TYPE_USB, + MHI_TRANSFER_TYPE_UCI, +}; + +enum open_status { + DISABLE, + ENABLE, + SSR, +}; + struct qdss_bridge_drvdata { int alias; - bool opened; + enum open_status opened; + struct completion completion; + size_t mtu; + enum mhi_transfer_mode mode; spinlock_t lock; + struct device *dev; + struct cdev cdev; struct mhi_device *mhi_dev; struct work_struct read_work; struct work_struct read_done_work; @@ -39,8 +55,12 @@ struct qdss_bridge_drvdata { struct mhi_client_handle *hdl; struct mhi_client_info_t *client_info; struct list_head buf_tbl; + struct list_head mhi_buf_tbl; struct list_head read_done_list; struct usb_qdss_ch *usb_ch; + struct qdss_mhi_buf_tbl_t *cur_buf; + wait_queue_head_t uci_wq; + size_t rx_size; }; #endif diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 2fa51bf85ed1c4f4228c83ebbed1b4f6985c2115..812fc01a2150bf7d96c00c15c7c54d11ae518a84 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -19,6 +19,7 @@ #include #include "qmi_rmnet_i.h" #include +#include #define NLMSG_FLOW_ACTIVATE 1 #define NLMSG_FLOW_DEACTIVATE 2 @@ -31,6 +32,10 @@ #define PS_INTERVAL (0x0004 * HZ) #define NO_DELAY (0x0000 * HZ) +#ifdef CONFIG_QCOM_QMI_DFC +static unsigned int qmi_rmnet_scale_factor = 5; +#endif + struct qmi_elem_info data_ep_id_type_v01_ei[] = { { .data_type = QMI_SIGNED_4_BYTE_ENUM, @@ -75,20 +80,19 @@ static struct qmi_info *qmi_rmnet_qmi_init(void) return qmi_info; } -static inline int -qmi_rmnet_has_dfc_client(struct qmi_info *qmi) +void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) { int i; if (!qmi || !(qmi->flag & FLAG_DFC_MASK)) - return 0; + return NULL; for (i = 0; i < MAX_CLIENT_NUM; i++) { if (qmi->fc_info[i].dfc_client) - return 1; + return qmi->fc_info[i].dfc_client; } - return 0; + return NULL; } static inline int @@ -97,7 +101,7 @@ qmi_rmnet_has_client(struct qmi_info *qmi) if (qmi->wda_client) return 1; - return qmi_rmnet_has_dfc_client(qmi); + return qmi_rmnet_has_dfc_client(qmi) ? 1 : 0; } #ifdef CONFIG_QCOM_QMI_DFC @@ -229,20 +233,26 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, qmi_rmnet_update_flow_link(qmi, dev, itm, 1); qmi_rmnet_update_flow_map(itm, &new_map); list_add(&itm->list, &qos_info->flow_head); - } - bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); - if (bearer) { - bearer->flow_ref++; - } else { - bearer = kzalloc(sizeof(*bearer), GFP_KERNEL); - if (!bearer) - return -ENOMEM; + bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); + if (bearer) { + bearer->flow_ref++; + } else { + bearer = kzalloc(sizeof(*bearer), GFP_KERNEL); + if (!bearer) + return -ENOMEM; + + bearer->bearer_id = new_map.bearer_id; + bearer->flow_ref = 1; + bearer->grant_size = qos_info->default_grant; + bearer->grant_thresh = + qmi_rmnet_grant_per(bearer->grant_size); + qos_info->default_grant = DEFAULT_GRANT; + list_add(&bearer->list, &qos_info->bearer_head); + } - bearer->bearer_id = new_map.bearer_id; - bearer->flow_ref = 1; - bearer->grant_size = qos_info->default_grant; - list_add(&bearer->list, &qos_info->bearer_head); + tc_qdisc_flow_control(dev, itm->tcm_handle, + bearer->grant_size > 0 ? 1 : 0); } return 0; @@ -277,18 +287,19 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, new_map.ip_type, itm->tcm_handle, 0); qmi_rmnet_update_flow_link(qmi, dev, itm, 0); list_del(&itm->list); - } - /*clear bearer map*/ - bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); - if (bearer && --bearer->flow_ref == 0) { - list_del(&bearer->list); - bearer_removed = 1; + /*clear bearer map*/ + bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); + if (bearer && --bearer->flow_ref == 0) { + list_del(&bearer->list); + bearer_removed = 1; + } + + kfree(itm); + if (bearer_removed) + kfree(bearer); } - kfree(itm); - if (bearer_removed) - kfree(bearer); return 0; } @@ -312,7 +323,9 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) if (bearer) { if (bearer->grant_size == 0) need_enable = 1; - bearer->grant_size = qos->default_grant; + bearer->grant_size = DEFAULT_GRANT; + bearer->grant_thresh = + qmi_rmnet_grant_per(DEFAULT_GRANT); if (need_enable) { qlen = tc_qdisc_flow_control(qmi->flow[i].dev, m->tcm_handle, 1); @@ -325,6 +338,27 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) return 0; } + +static int qmi_rmnet_set_scale_factor(const char *val, + const struct kernel_param *kp) +{ + int ret; + unsigned int num = 0; + + ret = kstrtouint(val, 10, &num); + if (ret != 0 || num == 0) + return -EINVAL; + + return param_set_uint(val, kp); +} + +static const struct kernel_param_ops qmi_rmnet_scale_ops = { + .set = qmi_rmnet_set_scale_factor, + .get = param_get_uint, +}; + +module_param_cb(qmi_rmnet_scale_factor, &qmi_rmnet_scale_ops, + &qmi_rmnet_scale_factor, 0664); #else static inline void qmi_rmnet_update_flow_link(struct qmi_info *qmi, struct net_device *dev, @@ -528,10 +562,16 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev, struct sk_buff *skb) if (!qmi || !qos) return; - dfc_qmi_burst_check(dev, qos, skb); + dfc_qmi_burst_check(dev, qos, skb, qmi); } EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); +inline unsigned int qmi_rmnet_grant_per(unsigned int grant) +{ + return grant / qmi_rmnet_scale_factor; +} +EXPORT_SYMBOL(qmi_rmnet_grant_per); + void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) { struct qos_info *qos; diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index 17b1e6802f4a8f115b89fd8d811077ff58d70e5b..a2c4ce1e48975c4934c212a900c6028e4f40b208 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -37,6 +37,7 @@ struct rmnet_bearer_map { u8 bearer_id; int flow_ref; u32 grant_size; + u32 grant_thresh; u16 seq; u8 ack_req; }; @@ -93,6 +94,8 @@ struct data_ep_id_type_v01 { extern struct qmi_elem_info data_ep_id_type_v01_ei[]; +void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi); + #ifdef CONFIG_QCOM_QMI_DFC struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -101,12 +104,15 @@ qmi_rmnet_get_flow_map(struct qos_info *qos_info, struct rmnet_bearer_map * qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id); +unsigned int qmi_rmnet_grant_per(unsigned int grant); + int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi); void dfc_qmi_client_exit(void *dfc_data); void dfc_qmi_burst_check(struct net_device *dev, - struct qos_info *qos, struct sk_buff *skb); + struct qos_info *qos, struct sk_buff *skb, + struct qmi_info *qmi); #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -131,9 +137,9 @@ static inline void dfc_qmi_client_exit(void *dfc_data) { } -static inline void dfc_qmi_burst_check(struct net_device *dev, - struct qos_info *qos, - struct sk_buff *skb) +static inline void +dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, + struct sk_buff *skb, struct qmi_info *qmi) { } #endif diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c index 2259a1a0195f73a02a04c48cfaf35181d37937df..3918a840a01d6b83fb7fbcfa1dc518f9f944a4f3 100644 --- a/drivers/soc/qcom/secure_buffer.c +++ b/drivers/soc/qcom/secure_buffer.c @@ -56,7 +56,7 @@ struct dest_vm_and_perm_info { }; static void *qcom_secure_mem; -#define QCOM_SECURE_MEM_SIZE (512*1024) +#define QCOM_SECURE_MEM_SIZE (2048*1024) static int secure_buffer_change_chunk(u32 chunks, u32 nchunks, diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index ecd53bd54ea91d8425bfc9b93ee20b20a4f30c79..faf3a22188368cf6da0763cadad3a97c08782278 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -267,7 +267,7 @@ static int init_service_locator(void) service_locator.connected = false; rc = qmi_handle_init(&service_locator.clnt_handle, - QMI_SERVREG_LOC_GET_DOMAIN_LIST_REQ_MSG_V01_MAX_MSG_LEN, + QMI_SERVREG_LOC_GET_DOMAIN_LIST_RESP_MSG_V01_MAX_MSG_LEN, &server_ops, NULL); if (rc < 0) { pr_err("Service locator QMI handle init failed rc:%d\n", rc); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 88ef903c211c3e206a22b0641b2eb559724eadf3..e752ad57a83a9887681379fb8e2359cee128d598 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -68,6 +68,7 @@ enum { HW_PLATFORM_SBC = 24, HW_PLATFORM_ADP = 25, HW_PLATFORM_IOT = 32, + HW_PLATFORM_IDP = 34, HW_PLATFORM_INVALID }; @@ -89,7 +90,8 @@ const char *hw_platform[] = { [HW_PLATFORM_STP] = "STP", [HW_PLATFORM_SBC] = "SBC", [HW_PLATFORM_ADP] = "ADP", - [HW_PLATFORM_IOT] = "IOT" + [HW_PLATFORM_IOT] = "IOT", + [HW_PLATFORM_IDP] = "IDP" }; enum { diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 7f84296355025d9f95d660c14587609fd6921975..a5b0df7e6131e56d9eb63abf995dab6d9b89d13b 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -574,10 +574,15 @@ static int meson_spicc_probe(struct platform_device *pdev) master->max_speed_hz = rate >> 2; ret = devm_spi_register_master(&pdev->dev, master); - if (!ret) - return 0; + if (ret) { + dev_err(&pdev->dev, "spi master registration failed\n"); + goto out_clk; + } - dev_err(&pdev->dev, "spi master registration failed\n"); + return 0; + +out_clk: + clk_disable_unprepare(spicc->core); out_master: spi_master_put(master); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index b392cca8fa4f5ba3c1c499ea8b1bc228fcabdbee..1a6ec226d6e46b36bc36051d3229b49e6441cb03 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1273,8 +1273,6 @@ static int s3c64xx_spi_resume(struct device *dev) if (ret < 0) return ret; - s3c64xx_spi_hwinit(sdd, sdd->port_id); - return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ @@ -1312,6 +1310,8 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) if (ret != 0) goto err_disable_src_clk; + s3c64xx_spi_hwinit(sdd, sdd->port_id); + return 0; err_disable_src_clk: diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 52056535f54e07fc882e94e97bbcf12595ea3a62..0fea18ab970e30424d0799f0b265d24f6d26dfc2 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -555,14 +555,16 @@ static int sh_msiof_spi_setup(struct spi_device *spi) /* Configure native chip select mode/polarity early */ clr = MDR1_SYNCMD_MASK; - set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI; + set = MDR1_SYNCMD_SPI; if (spi->mode & SPI_CS_HIGH) clr |= BIT(MDR1_SYNCAC_SHIFT); else set |= BIT(MDR1_SYNCAC_SHIFT); pm_runtime_get_sync(&p->pdev->dev); tmp = sh_msiof_read(p, TMDR1) & ~clr; - sh_msiof_write(p, TMDR1, tmp | set); + sh_msiof_write(p, TMDR1, tmp | set | MDR1_TRMD | TMDR1_PCON); + tmp = sh_msiof_read(p, RMDR1) & ~clr; + sh_msiof_write(p, RMDR1, tmp | set); pm_runtime_put(&p->pdev->dev); p->native_cs_high = spi->mode & SPI_CS_HIGH; p->native_cs_inited = true; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 84dfef4bd6ae6b20090581b9a42fe5d59b62bedd..f85d30dc91878dbb8472b3bc8fec69ff2244fb6a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1222,6 +1222,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) if (!was_busy && ctlr->auto_runtime_pm) { ret = pm_runtime_get_sync(ctlr->dev.parent); if (ret < 0) { + pm_runtime_put_noidle(ctlr->dev.parent); dev_err(&ctlr->dev, "Failed to power device: %d\n", ret); mutex_unlock(&ctlr->io_mutex); diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 69df278e9aa471e9cd9d4b68d939ac8f8bc4cbef..9dc534f677d1b434c504948a1e652416e95ff28f 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -294,9 +294,19 @@ static int ashmem_release(struct inode *ignored, struct file *file) return 0; } -static ssize_t ashmem_read_iter(struct kiocb *iocb, struct iov_iter *iter) +/** + * ashmem_read() - Reads a set of bytes from an Ashmem-enabled file + * @file: The associated backing file. + * @buf: The buffer of data being written to + * @len: The number of bytes being read + * @pos: The position of the first byte to read. + * + * Return: 0 if successful, or another return code if not. + */ +static ssize_t ashmem_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) { - struct ashmem_area *asma = iocb->ki_filp->private_data; + struct ashmem_area *asma = file->private_data; int ret = 0; mutex_lock(&ashmem_mutex); @@ -310,17 +320,20 @@ static ssize_t ashmem_read_iter(struct kiocb *iocb, struct iov_iter *iter) goto out_unlock; } + mutex_unlock(&ashmem_mutex); + /* * asma and asma->file are used outside the lock here. We assume * once asma->file is set it will never be changed, and will not * be destroyed until all references to the file are dropped and * ashmem_release is called. */ - mutex_unlock(&ashmem_mutex); - ret = vfs_iter_read(asma->file, iter, &iocb->ki_pos, 0); - mutex_lock(&ashmem_mutex); - if (ret > 0) - asma->file->f_pos = iocb->ki_pos; + ret = __vfs_read(asma->file, buf, len, pos); + if (ret >= 0) + /** Update backing file pos, since f_ops->read() doesn't */ + asma->file->f_pos = *pos; + return ret; + out_unlock: mutex_unlock(&ashmem_mutex); return ret; @@ -815,7 +828,7 @@ static const struct file_operations ashmem_fops = { .owner = THIS_MODULE, .open = ashmem_open, .release = ashmem_release, - .read_iter = ashmem_read_iter, + .read = ashmem_read, .llseek = ashmem_llseek, .mmap = ashmem_mmap, .unlocked_ioctl = ashmem_ioctl, diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 5275759becc1f776714569b369085fffaed201b9..d7f56b29eb90084f8acd6f90a83a6d9d00cbbf33 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -264,13 +264,8 @@ static DEFINE_MUTEX(scan_mutex); static int can_use_cma_pages(gfp_t gfp_mask) { - int mtype = gfpflags_to_migratetype(gfp_mask); - - /* - * Assumes that all types of movable pages can be - * served by cma. Fix this if that changes. - */ - if (mtype == MIGRATE_MOVABLE) + if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE && + (gfp_mask & __GFP_CMA)) return 1; return 0; diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 284cdd44a2ee39f88f8b98db184826bc97337ed9..8b92cf06d06355ab0698bcdb7afb9ff674f42f19 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1710,7 +1710,7 @@ int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, return 0; } spin_unlock(&fps->fps_lock); - rc = -EBUSY; + rc = -EAGAIN; } spin_lock(&fps->fps_lock); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 29e10021b906b22acfeec08b3cb672d9f5640b77..4b4a2014989488d2286b6020dc316c70135f3e4b 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -47,7 +47,7 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, __u64 dstcookie); static void kiblnd_queue_tx_locked(struct kib_tx *tx, struct kib_conn *conn); static void kiblnd_queue_tx(struct kib_tx *tx, struct kib_conn *conn); -static void kiblnd_unmap_tx(struct lnet_ni *ni, struct kib_tx *tx); +static void kiblnd_unmap_tx(struct kib_tx *tx); static void kiblnd_check_sends_locked(struct kib_conn *conn); static void @@ -65,7 +65,7 @@ kiblnd_tx_done(struct lnet_ni *ni, struct kib_tx *tx) LASSERT(!tx->tx_waiting); /* mustn't be awaiting peer response */ LASSERT(tx->tx_pool); - kiblnd_unmap_tx(ni, tx); + kiblnd_unmap_tx(tx); /* tx may have up to 2 lnet msgs to finalise */ lntmsg[0] = tx->tx_lntmsg[0]; tx->tx_lntmsg[0] = NULL; @@ -590,13 +590,9 @@ kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx, struct kib_rdma_desc * return 0; } -static void kiblnd_unmap_tx(struct lnet_ni *ni, struct kib_tx *tx) +static void kiblnd_unmap_tx(struct kib_tx *tx) { - struct kib_net *net = ni->ni_data; - - LASSERT(net); - - if (net->ibn_fmr_ps) + if (tx->fmr.fmr_pfmr || tx->fmr.fmr_frd) kiblnd_fmr_pool_unmap(&tx->fmr, tx->tx_status); if (tx->tx_nfrags) { @@ -1289,11 +1285,6 @@ kiblnd_connect_peer(struct kib_peer *peer) goto failed2; } - LASSERT(cmid->device); - CDEBUG(D_NET, "%s: connection bound to %s:%pI4h:%s\n", - libcfs_nid2str(peer->ibp_nid), dev->ibd_ifname, - &dev->ibd_ifip, cmid->device->name); - return; failed2: @@ -2995,8 +2986,19 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) } else { rc = rdma_resolve_route( cmid, *kiblnd_tunables.kib_timeout * 1000); - if (!rc) + if (!rc) { + struct kib_net *net = peer->ibp_ni->ni_data; + struct kib_dev *dev = net->ibn_dev; + + CDEBUG(D_NET, "%s: connection bound to "\ + "%s:%pI4h:%s\n", + libcfs_nid2str(peer->ibp_nid), + dev->ibd_ifname, + &dev->ibd_ifip, cmid->device->name); + return 0; + } + /* Can't initiate route resolution */ CERROR("Can't resolve route for %s: %d\n", libcfs_nid2str(peer->ibp_nid), rc); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index b5d84f3f6071913572606a2e8306e0772804b388..11e01c48f51ac59073e5ad090c9562daff5358e7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -1571,8 +1571,10 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns, return ERR_CAST(res); lock = ldlm_lock_new(res); - if (!lock) + if (!lock) { + ldlm_resource_putref(res); return ERR_PTR(-ENOMEM); + } lock->l_req_mode = mode; lock->l_ast_data = data; @@ -1615,6 +1617,8 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns, return ERR_PTR(rc); } + + /** * Enqueue (request) a lock. * On the client this is called from ldlm_cli_enqueue_fini diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index 0be55623bac4b0d9141f4e00760c7188dece302f..364d697b26906664db2ae166844c8d81c3509a36 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -93,7 +93,11 @@ ll_xattr_set_common(const struct xattr_handler *handler, __u64 valid; int rc; - if (flags == XATTR_REPLACE) { + /* When setxattr() is called with a size of 0 the value is + * unconditionally replaced by "". When removexattr() is + * called we get a NULL value and XATTR_REPLACE for flags. + */ + if (!value && flags == XATTR_REPLACE) { ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1); valid = OBD_MD_FLXATTRRM; } else { diff --git a/drivers/staging/media/atomisp/i2c/ov2680.c b/drivers/staging/media/atomisp/i2c/ov2680.c index 51b7d61df0f5513173d98f6bc6f2d3e5d40be9ef..17957622431901d729a03f9e715d855d36e9d80d 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.c +++ b/drivers/staging/media/atomisp/i2c/ov2680.c @@ -396,12 +396,11 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts,hts; + u16 vts; int ret,exp_val; dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); - hts = ov2680_res[dev->fmt_idx].pixels_per_line; vts = ov2680_res[dev->fmt_idx].lines_per_frame; /* group hold */ @@ -1190,7 +1189,8 @@ static int ov2680_detect(struct i2c_client *client) OV2680_SC_CMMN_SUB_ID, &high); revision = (u8) high & 0x0f; - dev_info(&client->dev, "sensor_revision id = 0x%x\n", id); + dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n", + id, revision); return 0; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c index 0592ac1f2832eedd947dcc3c1d39dad917454751..cfe6bb61001455e44cc274b6b4d972e7b1f680d9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c @@ -81,7 +81,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, get_user(kp->flags, &up->flags)) return -EFAULT; - kp->base = compat_ptr(tmp); + kp->base = (void __force *)compat_ptr(tmp); get_v4l2_pix_format((struct v4l2_pix_format *)&kp->fmt, &up->fmt); return 0; } @@ -232,10 +232,10 @@ static int get_atomisp_dvs_6axis_config32(struct atomisp_dvs_6axis_config *kp, get_user(ycoords_uv, &up->ycoords_uv)) return -EFAULT; - kp->xcoords_y = compat_ptr(xcoords_y); - kp->ycoords_y = compat_ptr(ycoords_y); - kp->xcoords_uv = compat_ptr(xcoords_uv); - kp->ycoords_uv = compat_ptr(ycoords_uv); + kp->xcoords_y = (void __force *)compat_ptr(xcoords_y); + kp->ycoords_y = (void __force *)compat_ptr(ycoords_y); + kp->xcoords_uv = (void __force *)compat_ptr(xcoords_uv); + kp->ycoords_uv = (void __force *)compat_ptr(ycoords_uv); return 0; } @@ -296,7 +296,7 @@ static int get_atomisp_metadata_stat32(struct atomisp_metadata *kp, return -EFAULT; kp->data = compat_ptr(data); - kp->effective_width = compat_ptr(effective_width); + kp->effective_width = (void __force *)compat_ptr(effective_width); return 0; } @@ -360,7 +360,7 @@ static int get_atomisp_metadata_by_type_stat32( return -EFAULT; kp->data = compat_ptr(data); - kp->effective_width = compat_ptr(effective_width); + kp->effective_width = (void __force *)compat_ptr(effective_width); return 0; } @@ -437,7 +437,7 @@ static int get_atomisp_overlay32(struct atomisp_overlay *kp, get_user(kp->overlay_start_x, &up->overlay_start_y)) return -EFAULT; - kp->frame = compat_ptr(frame); + kp->frame = (void __force *)compat_ptr(frame); return 0; } @@ -481,7 +481,7 @@ static int get_atomisp_calibration_group32( get_user(calb_grp_values, &up->calb_grp_values)) return -EFAULT; - kp->calb_grp_values = compat_ptr(calb_grp_values); + kp->calb_grp_values = (void __force *)compat_ptr(calb_grp_values); return 0; } @@ -703,8 +703,8 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, return -EFAULT; while (n >= 0) { - compat_uptr_t *src = (compat_uptr_t *)up + n; - uintptr_t *dst = (uintptr_t *)kp + n; + compat_uptr_t __user *src = ((compat_uptr_t __user *)up) + n; + uintptr_t *dst = ((uintptr_t *)kp) + n; if (get_user((*dst), src)) return -EFAULT; @@ -751,12 +751,12 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->shading_table = user_ptr + offset; + kp->shading_table = (void __force *)user_ptr + offset; offset = sizeof(struct atomisp_shading_table); if (!kp->shading_table) return -EFAULT; - if (copy_to_user(kp->shading_table, + if (copy_to_user((void __user *)kp->shading_table, &karg.shading_table, sizeof(struct atomisp_shading_table))) return -EFAULT; @@ -777,13 +777,14 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->morph_table = user_ptr + offset; + kp->morph_table = (void __force *)user_ptr + offset; offset += sizeof(struct atomisp_morph_table); if (!kp->morph_table) return -EFAULT; - if (copy_to_user(kp->morph_table, &karg.morph_table, - sizeof(struct atomisp_morph_table))) + if (copy_to_user((void __user *)kp->morph_table, + &karg.morph_table, + sizeof(struct atomisp_morph_table))) return -EFAULT; } @@ -802,13 +803,14 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->dvs2_coefs = user_ptr + offset; + kp->dvs2_coefs = (void __force *)user_ptr + offset; offset += sizeof(struct atomisp_dis_coefficients); if (!kp->dvs2_coefs) return -EFAULT; - if (copy_to_user(kp->dvs2_coefs, &karg.dvs2_coefs, - sizeof(struct atomisp_dis_coefficients))) + if (copy_to_user((void __user *)kp->dvs2_coefs, + &karg.dvs2_coefs, + sizeof(struct atomisp_dis_coefficients))) return -EFAULT; } /* handle dvs 6axis configuration */ @@ -826,13 +828,14 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->dvs_6axis_config = user_ptr + offset; + kp->dvs_6axis_config = (void __force *)user_ptr + offset; offset += sizeof(struct atomisp_dvs_6axis_config); if (!kp->dvs_6axis_config) return -EFAULT; - if (copy_to_user(kp->dvs_6axis_config, &karg.dvs_6axis_config, - sizeof(struct atomisp_dvs_6axis_config))) + if (copy_to_user((void __user *)kp->dvs_6axis_config, + &karg.dvs_6axis_config, + sizeof(struct atomisp_dvs_6axis_config))) return -EFAULT; } } @@ -891,7 +894,7 @@ static int get_atomisp_sensor_ae_bracketing_lut( get_user(lut, &up->lut)) return -EFAULT; - kp->lut = compat_ptr(lut); + kp->lut = (void __force *)compat_ptr(lut); return 0; } diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c index d99daf69e501bf88e3274cb41a5420a20a481ae5..fe229d63deec166cfe892c6b97160122c673a835 100644 --- a/drivers/staging/speakup/speakup_soft.c +++ b/drivers/staging/speakup/speakup_soft.c @@ -207,11 +207,15 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count, int chars_sent = 0; char __user *cp; char *init; + size_t bytes_per_ch = unicode ? 3 : 1; u16 ch; int empty; unsigned long flags; DEFINE_WAIT(wait); + if (count < bytes_per_ch) + return -EINVAL; + spin_lock_irqsave(&speakup_info.spinlock, flags); while (1) { prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); @@ -237,7 +241,7 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count, init = get_initstring(); /* Keep 3 bytes available for a 16bit UTF-8-encoded character */ - while (chars_sent <= count - 3) { + while (chars_sent <= count - bytes_per_ch) { if (speakup_info.flushing) { speakup_info.flushing = 0; ch = '\x18'; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 486be990d7fc7b6ac96053d2b2246beaf6d3a7af..a457034818c33b9a1d99932bef73b627d59dde3f 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -601,6 +601,7 @@ reserve_space(VCHIQ_STATE_T *state, size_t space, int is_blocking) } if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE)) { + up(&state->slot_available_event); pr_warn("%s: invalid tx_pos: %d\n", __func__, tx_pos); return NULL; } diff --git a/drivers/thermal/qcom/bcl_pmic5.c b/drivers/thermal/qcom/bcl_pmic5.c index 42d5817e3c12cf756ec4c0f2e5eb70e0f8940065..7a5124e11f26816aed636600706fe4d1dbc832c0 100644 --- a/drivers/thermal/qcom/bcl_pmic5.c +++ b/drivers/thermal/qcom/bcl_pmic5.c @@ -496,7 +496,7 @@ static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type, data->irq_num = 0; data->irq_enabled = false; irq_num = platform_get_irq_byname(pdev, int_name); - if (irq_num && handle) { + if (irq_num > 0 && handle) { ret = devm_request_threaded_irq(&pdev->dev, irq_num, NULL, handle, IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -510,7 +510,7 @@ static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type, } disable_irq_nosync(irq_num); data->irq_num = irq_num; - } else if (irq_num && !handle) { + } else if (irq_num > 0 && !handle) { disable_irq_nosync(irq_num); data->irq_num = irq_num; } @@ -559,6 +559,9 @@ static void bcl_ibat_init(struct platform_device *pdev, ibat->type = type; ibat->dev = bcl_perph; bcl_fetch_trip(pdev, type, ibat, NULL); + if (ibat->irq_num <= 0) + return; + ibat->ops.get_temp = bcl_read_ibat; ibat->ops.set_trips = bcl_set_ibat; diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ac83f721db24d78cff24d9349ecf75edafe9f2d4..d60069b5dc98dee7bb4ccf82f11c057fc9519a11 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -598,6 +598,7 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev) threshold_code = temp_to_code(data, temp); rising_threshold = readl(data->base + rising_reg_offset); + rising_threshold &= ~(0xff << j * 8); rising_threshold |= (threshold_code << j * 8); writel(rising_threshold, data->base + rising_reg_offset); diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 16331a90c1e89f3430e6c5e5909a05e7e8914aed..9da8474fe50afce9f30ff4426e7b053bf3700370 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -332,7 +332,6 @@ static void udbg_init_opal_common(void) udbg_putc = udbg_opal_putc; udbg_getc = udbg_opal_getc; udbg_getc_poll = udbg_opal_getc_poll; - tb_ticks_per_usec = 0x200; /* Make udelay not suck */ } void __init hvc_opal_init_early(void) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 64338442050ef9d4e47e48edc72676159952090c..899e8fe5e00f512a75fe82c25b42f341eb9a338e 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -110,16 +110,19 @@ static void pty_unthrottle(struct tty_struct *tty) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; + unsigned long flags; if (tty->stopped) return 0; if (c > 0) { + spin_lock_irqsave(&to->port->lock, flags); /* Stuff the data into the input queue of the other end */ c = tty_insert_flip_string(to->port, buf, c); /* And shovel */ if (c) tty_flip_buffer_push(to->port); + spin_unlock_irqrestore(&to->port->lock, flags); } return c; } diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 0b98669a09ca4f218349dbe699c7b83e803eaa3e..837ef891ec2327681d1e62cfb4967bba679e532b 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -112,6 +112,7 @@ #define DEF_TX_WM (2) #define DEF_FIFO_WIDTH_BITS (32) #define UART_CORE2X_VOTE (10000) +#define UART_CONSOLE_CORE2X_VOTE (960) #define WAKEBYTE_TIMEOUT_MSEC (2000) #define WAIT_XFER_MAX_ITER (50) @@ -2386,8 +2387,16 @@ static int msm_geni_serial_probe(struct platform_device *pdev) } dev_port->wrapper_dev = &wrapper_pdev->dev; dev_port->serial_rsc.wrapper_dev = &wrapper_pdev->dev; - ret = geni_se_resources_init(&dev_port->serial_rsc, UART_CORE2X_VOTE, - (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + + if (is_console) + ret = geni_se_resources_init(&dev_port->serial_rsc, + UART_CONSOLE_CORE2X_VOTE, + (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + else + ret = geni_se_resources_init(&dev_port->serial_rsc, + UART_CORE2X_VOTE, + (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + if (ret) goto exit_geni_serial_probe; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3b9aadd007f5b60e5741283a4dcff0a7da4e07d7..f2f31fc16f2909720bd1fdf2b53d77a405098a9e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1844,6 +1844,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */ }, + { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */ .driver_info = CLEAR_HALT_CONDITIONS, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6d94d96dc2e5c3e9c74c113b4da5b69fa03cc25d..01dde0450b55b7d39354406c612833812a69daa1 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1152,10 +1152,14 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) if (!udev || udev->state == USB_STATE_NOTATTACHED) { /* Tell hub_wq to disconnect the device or - * check for a new connection + * check for a new connection or over current condition. + * Based on USB2.0 Spec Section 11.12.5, + * C_PORT_OVER_CURRENT could be set while + * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || - (portstatus & USB_PORT_STAT_OVERCURRENT)) + (portstatus & USB_PORT_STAT_OVERCURRENT) || + (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits); } else if (portstatus & USB_PORT_STAT_ENABLE) { @@ -3368,6 +3372,10 @@ static int wait_for_connected(struct usb_device *udev, while (delay_ms < 2000) { if (status || *portstatus & USB_PORT_STAT_CONNECTION) break; + if (!port_is_power_on(hub, *portstatus)) { + status = -ENODEV; + break; + } msleep(20); delay_ms += 20; status = hub_port_status(hub, *port1, portstatus, portchange); @@ -4368,6 +4376,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, const char *speed; int devnum = udev->devnum; const char *driver_name; + char *error_event[] = { + "USB_DEVICE_ERROR=Device_No_Response", NULL }; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -4555,6 +4565,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, if (r != -ENODEV) dev_err(&udev->dev, "device descriptor read/64, error %d\n", r); + kobject_uevent_env(&udev->parent->dev.kobj, + KOBJ_CHANGE, error_event); retval = -EMSGSIZE; continue; } @@ -4607,6 +4619,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, dev_err(&udev->dev, "device descriptor read/8, error %d\n", retval); + kobject_uevent_env(&udev->parent->dev.kobj, + KOBJ_CHANGE, error_event); if (retval >= 0) retval = -EMSGSIZE; } else { diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 87484f71b2abbb29f446ee4aec57c4545a0d8f66..46d3b0fc00c5c6dadc91d61d3bcfeb3571697449 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2606,34 +2606,29 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, #define DWC2_USB_DMA_ALIGN 4 -struct dma_aligned_buffer { - void *kmalloc_ptr; - void *old_xfer_buffer; - u8 data[0]; -}; - static void dwc2_free_dma_aligned_buffer(struct urb *urb) { - struct dma_aligned_buffer *temp; + void *stored_xfer_buffer; if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) return; - temp = container_of(urb->transfer_buffer, - struct dma_aligned_buffer, data); + /* Restore urb->transfer_buffer from the end of the allocated area */ + memcpy(&stored_xfer_buffer, urb->transfer_buffer + + urb->transfer_buffer_length, sizeof(urb->transfer_buffer)); if (usb_urb_dir_in(urb)) - memcpy(temp->old_xfer_buffer, temp->data, + memcpy(stored_xfer_buffer, urb->transfer_buffer, urb->transfer_buffer_length); - urb->transfer_buffer = temp->old_xfer_buffer; - kfree(temp->kmalloc_ptr); + kfree(urb->transfer_buffer); + urb->transfer_buffer = stored_xfer_buffer; urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; } static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) { - struct dma_aligned_buffer *temp, *kmalloc_ptr; + void *kmalloc_ptr; size_t kmalloc_size; if (urb->num_sgs || urb->sg || @@ -2641,22 +2636,29 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1))) return 0; - /* Allocate a buffer with enough padding for alignment */ + /* + * Allocate a buffer with enough padding for original transfer_buffer + * pointer. This allocation is guaranteed to be aligned properly for + * DMA + */ kmalloc_size = urb->transfer_buffer_length + - sizeof(struct dma_aligned_buffer) + DWC2_USB_DMA_ALIGN - 1; + sizeof(urb->transfer_buffer); kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); if (!kmalloc_ptr) return -ENOMEM; - /* Position our struct dma_aligned_buffer such that data is aligned */ - temp = PTR_ALIGN(kmalloc_ptr + 1, DWC2_USB_DMA_ALIGN) - 1; - temp->kmalloc_ptr = kmalloc_ptr; - temp->old_xfer_buffer = urb->transfer_buffer; + /* + * Position value of original urb->transfer_buffer pointer to the end + * of allocation for later referencing + */ + memcpy(kmalloc_ptr + urb->transfer_buffer_length, + &urb->transfer_buffer, sizeof(urb->transfer_buffer)); + if (usb_urb_dir_out(urb)) - memcpy(temp->data, urb->transfer_buffer, + memcpy(kmalloc_ptr, urb->transfer_buffer, urb->transfer_buffer_length); - urb->transfer_buffer = temp->data; + urb->transfer_buffer = kmalloc_ptr; urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index f471fe93e9b990337d3a0260bf5cd21b193b9cd6..e2575c3e3711e026d07eab281778339cced53ac7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -83,6 +83,7 @@ #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) #define PWR_EVNT_LPM_IN_L2_MASK BIT(4) #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) +#define PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK BIT(12) #define PWR_EVNT_LPM_OUT_L1_MASK BIT(13) /* QSCRATCH_GENERAL_CFG register bit offset */ @@ -245,6 +246,7 @@ struct dwc3_msm { bool suspend; bool use_pdc_interrupts; enum dwc3_id_state id_state; + bool use_pwr_event_for_wakeup; unsigned long lpm_flags; #define MDWC3_SS_PHY_SUSPEND BIT(0) #define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1) @@ -2189,6 +2191,27 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } +static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on) +{ + u32 irq_mask, irq_stat; + + irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); + + /* clear pending interrupts */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_stat); + + irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG); + + if (on) + irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK | + PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + else + irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK | + PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask); +} + static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) { int ret = 0; @@ -2228,6 +2251,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); struct dwc3_event_buffer *evt; struct usb_irq *uirq; + bool can_suspend_ssphy, no_active_ss; mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { @@ -2303,13 +2327,28 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); + /* + * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect + * any wakeup events in host mode PHY cannot be suspended. + * This Superspeed PHY can be suspended only in the following cases: + * 1. The core is not in host mode + * 2. A Highspeed device is connected but not a Superspeed device + */ + no_active_ss = (!mdwc->in_host_mode) || (mdwc->in_host_mode && + ((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) && + !dwc3_msm_is_superspeed(mdwc))); + can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER && + (!mdwc->use_pwr_event_for_wakeup || no_active_ss); /* Suspend SS PHY */ - if (dwc->maximum_speed >= USB_SPEED_SUPER) { + if (can_suspend_ssphy) { /* indicate phy about SS mode */ if (dwc3_msm_is_superspeed(mdwc)) mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; usb_phy_set_suspend(mdwc->ss_phy, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; + } else if (mdwc->use_pwr_event_for_wakeup) { + dwc3_msm_set_ss_pwr_events(mdwc, true); + enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); } /* make sure above writes are completed before turning off clocks */ @@ -2465,6 +2504,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) if (mdwc->bus_aggr_clk) clk_prepare_enable(mdwc->bus_aggr_clk); + /* + * Disable any wakeup events that were enabled if pwr_event_irq + * is used as wakeup interrupt. + */ + if (mdwc->use_pwr_event_for_wakeup && + !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) { + disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); + dwc3_msm_set_ss_pwr_events(mdwc, false); + } + /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { @@ -2974,17 +3023,6 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) struct extcon_dev *edev; int idx, extcon_cnt, ret = 0; bool check_vbus_state, check_id_state, phandle_found = false; - struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - - if (!of_property_read_bool(node, "extcon")) { - if (dwc->dr_mode == USB_DR_MODE_OTG) { - dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", - __func__); - mdwc->vbus_active = true; - queue_work(mdwc->dwc3_wq, &mdwc->resume_work); - } - return 0; - } extcon_cnt = of_count_phandle_with_args(node, "extcon", NULL); if (extcon_cnt < 0) { @@ -3278,7 +3316,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; - bool host_mode; int ret = 0, i; u32 val; unsigned long irq_type; @@ -3499,6 +3536,14 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } + /* + * On platforms with SS PHY that do not support ss_phy_irq for wakeup + * events, use pwr_event_irq for wakeup events in superspeed mode. + */ + mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER + && !mdwc->wakeup_irq[SS_PHY_IRQ].irq; + + /* IOMMU will be reattached upon each resume/connect */ if (mdwc->iommu_map) arm_iommu_detach_device(mdwc->dev); @@ -3526,24 +3571,29 @@ static int dwc3_msm_probe(struct platform_device *pdev) mutex_init(&mdwc->suspend_resume_mutex); - ret = dwc3_msm_extcon_register(mdwc); - if (ret) - goto put_dwc3; + if (of_property_read_bool(node, "extcon")) { + ret = dwc3_msm_extcon_register(mdwc); + if (ret) + goto put_dwc3; + } else { + if (dwc->dr_mode == USB_DR_MODE_OTG || + dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { + dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", + __func__); + mdwc->vbus_active = true; + } else if (dwc->dr_mode == USB_DR_MODE_HOST) { + dev_dbg(mdwc->dev, "DWC3 in host only mode\n"); + mdwc->id_state = DWC3_ID_GROUND; + } - schedule_delayed_work(&mdwc->sm_work, 0); + dwc3_ext_event_notify(mdwc); + } device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode); device_create_file(&pdev->dev, &dev_attr_bus_vote); - host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; - if (host_mode) { - dev_dbg(&pdev->dev, "DWC3 in host only mode\n"); - mdwc->id_state = DWC3_ID_GROUND; - dwc3_ext_event_notify(mdwc); - } - return 0; put_dwc3: @@ -3659,6 +3709,14 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, udev->dev.parent->parent == &dwc->xhci->dev) { if (event == USB_DEVICE_ADD && udev->actconfig) { if (!dwc3_msm_is_ss_rhport_connected(mdwc)) { + /* + * controller may wakeup ss phy during hs data + * transfers or doorbell rings. Power down the + * ss phy to avoid turning on pipe clock during + * these wake-ups. + */ + usb_phy_powerdown(mdwc->ss_phy); + /* * Core clock rate can be reduced only if root * hub SS port is not enabled/connected. @@ -3674,6 +3732,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, mdwc->max_rh_port_speed = USB_SPEED_SUPER; } } else { + usb_phy_powerup(mdwc->ss_phy); /* set rate back to default core clk rate */ clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); dev_dbg(mdwc->dev, "set core clk rate %ld\n", diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3518ab3908e9977194d526fc13d933684225bad5..772c5b4e75fa3f542726bdd40f7a6214849ac36b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -43,6 +43,8 @@ MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes"); static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -332,12 +334,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) { } + /* * ch 9.4.5 */ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { + int ret; struct dwc3_ep *dep; u32 recip; u32 value; @@ -377,7 +381,8 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + ret = dwc3_ep0_delegate_req(dwc, ctrl); + return ret; case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -538,6 +543,9 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, * For now, we're not doing anything, just making sure we return * 0 so USB Command Verifier tests pass without any errors. */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); + if (ret) + return ret; break; default: ret = -EINVAL; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f2c06bb61cb84fbf33f47ce91b5463426038cf4c..f54d8346a1626a52328326564c7558035dee091b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3017,43 +3017,55 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, static void dwc3_disconnect_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (dwc->gadget_driver && dwc->gadget_driver->disconnect) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "DISCONNECT", 0); - dwc->gadget_driver->disconnect(&dwc->gadget); + gadget_driver->disconnect(&dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_suspend_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (dwc->gadget_driver && dwc->gadget_driver->suspend) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "SUSPEND", 0); - dwc->gadget_driver->suspend(&dwc->gadget); + gadget_driver->suspend(&dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_resume_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (dwc->gadget_driver && dwc->gadget_driver->resume) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "RESUME", 0); - dwc->gadget_driver->resume(&dwc->gadget); + gadget_driver->resume(&dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_reset_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (!dwc->gadget_driver) return; if (dwc->gadget.speed != USB_SPEED_UNKNOWN) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "UDC RESET", 0); - usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver); + usb_gadget_udc_reset(&dwc->gadget, gadget_driver); spin_lock(&dwc->lock); } } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 5bbf99dc3208d01bbe9010db3e633d6bb7c366cd..1d86cb6f05b29b638175190b9cd797aa50b7f869 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3537,7 +3537,7 @@ static int ffs_func_setup(struct usb_function *f, ffs_log("exit"); - return USB_GADGET_DELAYED_STATUS; + return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0; } static bool ffs_func_req_match(struct usb_function *f, diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 88bc5a574f539e3650b0c4a249677201cf844cd4..d40fb9a2fa750f433097b8b915b95774ccf98f05 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2342,6 +2342,14 @@ static void gsi_resume(struct usb_function *f) log_event_dbg("%s: completed", __func__); } +static int gsi_get_status(struct usb_function *f) +{ + unsigned int remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; + + return (remote_wakeup_en_status << FUNC_WAKEUP_ENABLE_SHIFT) | + (1 << FUNC_WAKEUP_CAPABLE_SHIFT); +} + static int gsi_func_suspend(struct usb_function *f, u8 options) { bool func_wakeup_allowed; @@ -3002,6 +3010,7 @@ static int gsi_bind_config(struct f_gsi *gsi) gsi->function.disable = gsi_disable; gsi->function.free_func = gsi_free_func; gsi->function.suspend = gsi_suspend; + gsi->function.get_status = gsi_get_status; gsi->function.func_suspend = gsi_func_suspend; gsi->function.resume = gsi_resume; diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index e9ff9341fdbdf31fefdb12b09fac5fbcc379663e..06b1bb4845314783d71947e6d08c8997d8dbd0fa 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -49,7 +49,7 @@ #define GSI_ECM_AGGR_SIZE 2048 #define GSI_OUT_MBIM_BUF_LEN 16384 -#define GSI_OUT_RMNET_BUF_LEN 16384 +#define GSI_OUT_RMNET_BUF_LEN 31744 #define GSI_OUT_ECM_BUF_LEN 2048 #define GSI_IPA_READY_TIMEOUT 5000 diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 4cfa72cb0a91443ffe3ca1d9446b8f8dda380c1b..c12a1a6554bad90bd36d805e3805453f433c5121 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -334,6 +334,7 @@ struct renesas_usb3 { struct usb_gadget_driver *driver; struct extcon_dev *extcon; struct work_struct extcon_work; + struct dentry *dentry; struct renesas_usb3_ep *usb3_ep; int num_usb3_eps; @@ -2397,8 +2398,12 @@ static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, file = debugfs_create_file("b_device", 0644, root, usb3, &renesas_usb3_b_device_fops); - if (!file) + if (!file) { dev_info(dev, "%s: Can't create debugfs mode\n", __func__); + debugfs_remove_recursive(root); + } else { + usb3->dentry = root; + } } /*------- platform_driver ------------------------------------------------*/ @@ -2406,6 +2411,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) { struct renesas_usb3 *usb3 = platform_get_drvdata(pdev); + debugfs_remove_recursive(usb3->dentry); device_remove_file(&pdev->dev, &dev_attr_role); usb_del_gadget_udc(&usb3->gadget); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index b540f00c85df020226fe8fb90e20632ed5f12f87..02b9054e9a41b60af96d40acb8de5c61308cc30d 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,7 +20,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +#include #include #include @@ -1029,6 +1029,151 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, return status; } +static void xhci_single_step_completion(struct urb *urb) +{ + struct completion *done = urb->context; + + complete(done); +} + +/* + * Allocate a URB and initialize the various fields of it. + * This API is used by the single_step_set_feature test of + * EHSET where IN packet of the GetDescriptor request is + * sent 15secs after the SETUP packet. + * Return NULL if failed. + */ +static struct urb *xhci_request_single_step_set_feature_urb( + struct usb_device *udev, + void *dr, + void *buf, + struct completion *done) +{ + struct urb *urb; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_host_endpoint *ep; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return NULL; + + urb->pipe = usb_rcvctrlpipe(udev, 0); + ep = udev->ep_in[usb_pipeendpoint(urb->pipe)]; + if (!ep) { + usb_free_urb(urb); + return NULL; + } + + /* + * Initialize the various URB fields as these are used by the HCD + * driver to queue it and as well as when completion happens. + */ + urb->ep = ep; + urb->dev = udev; + urb->setup_packet = dr; + urb->transfer_buffer = buf; + urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; + urb->complete = xhci_single_step_completion; + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->transfer_flags = URB_DIR_IN; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + usb_hcd_map_urb_for_dma(hcd, urb, GFP_KERNEL); + urb->context = done; + return urb; +} + +/* + * This function implements the USB_PORT_FEAT_TEST handling of the + * SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded + * High-Speed Electrical Test (EHSET) specification. This simply + * issues a GetDescriptor control transfer, with an inserted 15-second + * delay after the end of the SETUP stage and before the IN token of + * the DATA stage is set. The idea is that this gives the test operator + * enough time to configure the oscilloscope to perform a measurement + * of the response time between the DATA and ACK packets that follow. + */ +static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port) +{ + int retval; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct usb_device *udev; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct usb_device_descriptor *buf; + unsigned long flags; + DECLARE_COMPLETION_ONSTACK(done); + + /* Obtain udev of the rhub's child port */ + udev = usb_hub_find_child(hcd->self.root_hub, port); + if (!udev) { + xhci_err(xhci, "No device attached to the RootHub\n"); + return -ENODEV; + } + buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) { + kfree(buf); + return -ENOMEM; + } + + /* Fill Setup packet for GetDescriptor */ + dr->bRequestType = USB_DIR_IN; + dr->bRequest = USB_REQ_GET_DESCRIPTOR; + dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); + dr->wIndex = 0; + dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); + urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done); + if (!urb) { + retval = -ENOMEM; + goto cleanup; + } + + /* Now complete just the SETUP stage */ + spin_lock_irqsave(&xhci->lock, flags); + retval = xhci_submit_single_step_set_feature(hcd, urb, 1); + spin_unlock_irqrestore(&xhci->lock, flags); + if (retval) + goto out1; + + if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__); + goto out1; + } + + /* Sleep for 15 seconds; HC will send SOFs during this period */ + msleep(15 * 1000); + + /* Complete remaining DATA and status stages. Re-use same URB */ + urb->status = -EINPROGRESS; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + + spin_lock_irqsave(&xhci->lock, flags); + retval = xhci_submit_single_step_set_feature(hcd, urb, 0); + spin_unlock_irqrestore(&xhci->lock, flags); + if (!retval && !wait_for_completion_timeout(&done, + msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__); + } +out1: + usb_free_urb(urb); +cleanup: + kfree(dr); + kfree(buf); + return retval; +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -1321,6 +1466,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* 4.19.6 Port Test Modes (USB2 Test Mode) */ if (hcd->speed != HCD_USB2) goto error; + if (test_mode == 6) { /* TEST_SINGLE_STEP_SET_FEATURE */ + spin_unlock_irqrestore(&xhci->lock, flags); + retval = xhci_ehset_single_step_set_feature(hcd, + wIndex); + spin_lock_irqsave(&xhci->lock, flags); + break; + } if (test_mode > TEST_FORCE_EN || test_mode < TEST_J) goto error; retval = xhci_enter_test_mode(xhci, test_mode, wIndex, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 08b464b03ddca3ca74a79f2622e103ce5625e1df..5d76b81bdcbe01e1e01d8ad5eff7b3e183fdcd4d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3477,6 +3477,150 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return 0; } +/* + * Variant of xhci_queue_ctrl_tx() used to implement EHSET + * SINGLE_STEP_SET_FEATURE test mode. It differs in that the control + * transfer is broken up so that the SETUP stage can happen and call + * the URB's completion handler before the DATA/STATUS stages are + * executed by the xHC hardware. This assumes the control transfer is a + * GetDescriptor, with a DATA stage in the IN direction, and an OUT + * STATUS stage. + * + * This function is called twice, usually with a 15-second delay in between. + * - with is_setup==true, the SETUP stage for the control request + * (GetDescriptor) is queued in the TRB ring and sent to HW immediately + * - with is_setup==false, the DATA and STATUS TRBs are queued and exceuted + * + * Caller must have locked xhci->lock + */ +int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb, + int is_setup) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_ring *ep_ring; + int num_trbs; + int ret; + unsigned int slot_id, ep_index; + struct usb_ctrlrequest *setup; + struct xhci_generic_trb *start_trb; + int start_cycle; + u32 field, length_field, remainder; + struct urb_priv *urb_priv; + struct xhci_td *td; + + ep_ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ep_ring) + return -EINVAL; + + /* Need buffer for data stage */ + if (urb->transfer_buffer_length <= 0) + return -EINVAL; + + /* + * Need to copy setup packet into setup TRB, so we can't use the setup + * DMA address. + */ + if (!urb->setup_packet) + return -EINVAL; + setup = (struct usb_ctrlrequest *) urb->setup_packet; + + slot_id = urb->dev->slot_id; + ep_index = xhci_get_endpoint_index(&urb->ep->desc); + + urb_priv = kzalloc(sizeof(struct urb_priv) + + sizeof(struct xhci_td *), GFP_ATOMIC); + if (!urb_priv) + return -ENOMEM; + + td = &urb_priv->td[0]; + urb_priv->num_tds = 1; + urb_priv->num_tds_done = 0; + urb->hcpriv = urb_priv; + + num_trbs = is_setup ? 1 : 2; + + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + num_trbs, urb, 0, GFP_ATOMIC); + if (ret < 0) { + kfree(urb_priv); + return ret; + } + + /* + * Don't give the first TRB to the hardware (by toggling the cycle bit) + * until we've finished creating all the other TRBs. The ring's cycle + * state may change as we enqueue the other TRBs, so save it too. + */ + start_trb = &ep_ring->enqueue->generic; + start_cycle = ep_ring->cycle_state; + + if (is_setup) { + /* Queue only the setup TRB */ + field = TRB_IDT | TRB_IOC | TRB_TYPE(TRB_SETUP); + if (start_cycle == 0) + field |= 0x1; + + /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */ + if (xhci->hci_version >= 0x100) { + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_TX_TYPE(TRB_DATA_IN); + else + field |= TRB_TX_TYPE(TRB_DATA_OUT); + } + + /* Save the DMA address of the last TRB in the TD */ + td->last_trb = ep_ring->enqueue; + + queue_trb(xhci, ep_ring, false, + setup->bRequestType | setup->bRequest << 8 | + le16_to_cpu(setup->wValue) << 16, + le16_to_cpu(setup->wIndex) | + le16_to_cpu(setup->wLength) << 16, + TRB_LEN(8) | TRB_INTR_TARGET(0), + field); + } else { + /* Queue data TRB */ + field = TRB_ISP | TRB_TYPE(TRB_DATA); + if (start_cycle == 0) + field |= 0x1; + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_DIR_IN; + + remainder = xhci_td_remainder(xhci, 0, + urb->transfer_buffer_length, + urb->transfer_buffer_length, + urb, 1); + + length_field = TRB_LEN(urb->transfer_buffer_length) | + TRB_TD_SIZE(remainder) | + TRB_INTR_TARGET(0); + + queue_trb(xhci, ep_ring, true, + lower_32_bits(urb->transfer_dma), + upper_32_bits(urb->transfer_dma), + length_field, + field); + + /* Save the DMA address of the last TRB in the TD */ + td->last_trb = ep_ring->enqueue; + + /* Queue status TRB */ + field = TRB_IOC | TRB_TYPE(TRB_STATUS); + if (!(setup->bRequestType & USB_DIR_IN)) + field |= TRB_DIR_IN; + + queue_trb(xhci, ep_ring, false, + 0, + 0, + TRB_INTR_TARGET(0), + field | ep_ring->cycle_state); + } + + giveback_first_trb(xhci, slot_id, ep_index, 0, start_cycle, start_trb); + return 0; +} + /* * The transfer burst count field of the isochronous TRB defines the number of * bursts that are required to move all packets in this TD. Only SuperSpeed diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8ce6979af0ad7757c66938996b2b54946c13fa9e..27d267a54e68da860e55c61c1a82459cf14f29cc 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -864,6 +864,41 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) spin_unlock_irqrestore(&xhci->lock, flags); } +static bool xhci_pending_portevent(struct xhci_hcd *xhci) +{ + __le32 __iomem **port_array; + int port_index; + u32 status; + u32 portsc; + + status = readl(&xhci->op_regs->status); + if (status & STS_EINT) + return true; + /* + * Checking STS_EINT is not enough as there is a lag between a change + * bit being set and the Port Status Change Event that it generated + * being written to the Event Ring. See note in xhci 1.1 section 4.19.2. + */ + + port_index = xhci->num_usb2_ports; + port_array = xhci->usb2_ports; + while (port_index--) { + portsc = readl(port_array[port_index]); + if (portsc & PORT_CHANGE_MASK || + (portsc & PORT_PLS_MASK) == XDEV_RESUME) + return true; + } + port_index = xhci->num_usb3_ports; + port_array = xhci->usb3_ports; + while (port_index--) { + portsc = readl(port_array[port_index]); + if (portsc & PORT_CHANGE_MASK || + (portsc & PORT_PLS_MASK) == XDEV_RESUME) + return true; + } + return false; +} + /* * Stop HC (not bus-specific) * @@ -963,7 +998,7 @@ EXPORT_SYMBOL_GPL(xhci_suspend); */ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { - u32 command, temp = 0, status; + u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; @@ -1085,8 +1120,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) done: if (retval == 0) { /* Resume root hubs only when have pending events. */ - status = readl(&xhci->op_regs->status); - if (status & STS_EINT) { + if (xhci_pending_portevent(xhci)) { usb_hcd_resume_root_hub(xhci->shared_hcd); usb_hcd_resume_root_hub(hcd); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f4e046001a268b48dfe24e376e8095b97141effe..955bfad5ab188754c4c123859ab4146caa2c68ce 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -392,6 +392,10 @@ struct xhci_op_regs { #define PORT_PLC (1 << 22) /* port configure error change - port failed to configure its link partner */ #define PORT_CEC (1 << 23) +#define PORT_CHANGE_MASK (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ + PORT_RC | PORT_PLC | PORT_CEC) + + /* Cold Attach Status - xHC can set this bit to report device attached during * Sx state. Warm port reset should be perfomed to clear this bit and move port * to connected state. @@ -2589,4 +2593,8 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq, return str; } +/* EHSET */ +int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb, + int is_setup); + #endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c index c31b4a33e6bb0a61e5d9253dc6a2679cbb6b94ef..0efcd485c02aa36d5d7325c920111f2cd0dd67fe 100644 --- a/drivers/usb/misc/ehset.c +++ b/drivers/usb/misc/ehset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2013, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,69 +26,89 @@ #define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107 #define TEST_SINGLE_STEP_SET_FEATURE 0x0108 -static int ehset_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static u8 numPorts; + +static int ehset_get_port_num(struct device *dev, const char *buf, + unsigned long *val) +{ + int ret; + + ret = kstrtoul(buf, 10, val); + if (ret < 0) { + dev_err(dev, "couldn't parse string %d\n", ret); + return ret; + } + + if (!*val || *val > numPorts) { + dev_err(dev, "Invalid port num entered\n"); + return -EINVAL; + } + + return 0; +} + +static int ehset_clear_port_feature(struct usb_device *udev, int feature, + int port1) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, 1000); +} + +static int ehset_set_port_feature(struct usb_device *udev, int feature, + int port1, int timeout) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, timeout); +} + +static int ehset_set_testmode(struct device *dev, struct usb_device *child_udev, + struct usb_device *hub_udev, int test_id, int port) { - int ret = -EINVAL; - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_device *hub_udev = dev->parent; struct usb_device_descriptor *buf; - u8 portnum = dev->portnum; - u16 test_pid = le16_to_cpu(dev->descriptor.idProduct); + int ret = -EINVAL; - switch (test_pid) { + switch (test_id) { case TEST_SE0_NAK_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_SE0_NAK << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_SE0_NAK << 8) | port, 1000); break; case TEST_J_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_J << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_J << 8) | port, 1000); break; case TEST_K_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_K << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_K << 8) | port, 1000); break; case TEST_PACKET_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_PACKET << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_PACKET << 8) | port, 1000); break; case TEST_HS_HOST_PORT_SUSPEND_RESUME: /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */ msleep(15 * 1000); - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_SUSPEND, portnum, - NULL, 0, 1000); - if (ret < 0) + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_SUSPEND, + port, 1000); + if (ret) break; msleep(15 * 1000); - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_SUSPEND, portnum, - NULL, 0, 1000); + ret = ehset_clear_port_feature(hub_udev, USB_PORT_FEAT_SUSPEND, + port); break; case TEST_SINGLE_STEP_GET_DEV_DESC: /* Test: wait for 15secs -> GetDescriptor request */ msleep(15 * 1000); buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + ret = -ENOMEM; + break; + } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(child_udev, + usb_rcvctrlpipe(child_udev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, 0, buf, USB_DT_DEVICE_SIZE, @@ -103,28 +123,212 @@ static int ehset_probe(struct usb_interface *intf, * SetPortFeature handling can only be done inside the HCD's * hub_control callback function. */ - if (hub_udev != dev->bus->root_hub) { - dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n"); + if (hub_udev != child_udev->bus->root_hub) { + dev_err(dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n"); break; } - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (6 << 8) | portnum, - NULL, 0, 60 * 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (6 << 8) | port, 60 * 1000); break; default: - dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n", - __func__, test_pid); + dev_err(dev, "%s: unsupported test ID: 0x%x\n", + __func__, test_id); + } + + return ret; +} + +static ssize_t test_se0_nak_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_SE0_NAK_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while SE0_NAK test\n", ret); + return ret; } + return count; +} +static DEVICE_ATTR_WO(test_se0_nak_portnum); + +static ssize_t test_j_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_J_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while J state test\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_j_portnum); + +static ssize_t test_k_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_K_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while K state test\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_k_portnum); + +static ssize_t test_packet_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_PACKET_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while sending test packets\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_packet_portnum); + +static ssize_t test_port_susp_resume_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, + TEST_HS_HOST_PORT_SUSPEND_RESUME, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while port suspend resume test\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_port_susp_resume_portnum); + +static struct attribute *ehset_attributes[] = { + &dev_attr_test_se0_nak_portnum.attr, + &dev_attr_test_j_portnum.attr, + &dev_attr_test_k_portnum.attr, + &dev_attr_test_packet_portnum.attr, + &dev_attr_test_port_susp_resume_portnum.attr, + NULL +}; + +static const struct attribute_group ehset_attr_group = { + .attrs = ehset_attributes, +}; + +static int ehset_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = -EINVAL; + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_device *hub_udev = dev->parent; + u8 portnum = dev->portnum; + u16 test_pid = le16_to_cpu(dev->descriptor.idProduct); + + /* + * If an external hub does not support the EHSET test fixture, then user + * can forcefully unbind the external hub from the hub driver (to which + * an external hub gets bound by default) and bind it to this driver, so + * as to send test signals on any downstream port of the hub. + */ + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) { + struct usb_hub_descriptor *descriptor; + + descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL); + if (!descriptor) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_HUB << 8, 0, descriptor, + USB_DT_HUB_NONVAR_SIZE, USB_CTRL_GET_TIMEOUT); + if (ret < 0) { + dev_err(&intf->dev, "%s: Failed to get hub desc %d\n", + __func__, ret); + kfree(descriptor); + return ret; + } + + numPorts = descriptor->bNbrPorts; + ret = sysfs_create_group(&intf->dev.kobj, &ehset_attr_group); + if (ret < 0) + dev_err(&intf->dev, "%s: Failed to create sysfs nodes %d\n", + __func__, ret); + + kfree(descriptor); + return ret; + } + + ret = ehset_set_testmode(&intf->dev, dev, hub_udev, test_pid, portnum); + return (ret < 0) ? ret : 0; } static void ehset_disconnect(struct usb_interface *intf) { + struct usb_device *dev = interface_to_usbdev(intf); + + numPorts = 0; + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) + sysfs_remove_group(&intf->dev.kobj, &ehset_attr_group); } static const struct usb_device_id ehset_id_table[] = { diff --git a/drivers/usb/phy/class-dual-role.c b/drivers/usb/phy/class-dual-role.c index 9ef889593ef52ad5dc5e768f02a4472c84f37927..51fcb545a9d578589da728c488643d6887f75008 100644 --- a/drivers/usb/phy/class-dual-role.c +++ b/drivers/usb/phy/class-dual-role.c @@ -70,7 +70,15 @@ static char *kstrdupcase(const char *str, gfp_t gfp, bool to_upper) return ret; } -static void dual_role_changed_work(struct work_struct *work); +static void dual_role_changed_work(struct work_struct *work) +{ + struct dual_role_phy_instance *dual_role = + container_of(work, struct dual_role_phy_instance, + changed_work); + + dev_dbg(&dual_role->dev, "%s\n", __func__); + kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE); +} void dual_role_instance_changed(struct dual_role_phy_instance *dual_role) { @@ -497,17 +505,6 @@ int dual_role_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } -static void dual_role_changed_work(struct work_struct *work) -{ - struct dual_role_phy_instance *dual_role = - container_of(work, struct dual_role_phy_instance, - changed_work); - - dev_dbg(&dual_role->dev, "%s\n", __func__); - sysfs_update_group(&dual_role->dev.kobj, &dual_role_attr_group); - kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE); -} - /******************* Module Init ***********************************/ static int __init dual_role_class_init(void) diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index b57ad1e25f1c2377d6f858cdcbed601b69ec5b0f..4dfd786506ee184d377836c2b4b574709ee06200 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -79,6 +79,7 @@ enum core_ldo_levels { /* USB3_DP_COM_PHY_MODE_CTRL bits */ #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ +#define USB3_DP_COMBO_MODE (USB3_MODE | DP_MODE) /*enables combo mode */ /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) @@ -91,6 +92,9 @@ enum qmp_phy_rev_reg { USB3_PHY_SW_RESET, USB3_PHY_START, + /* TypeC port select configuration (optional) */ + USB3_PHY_PCS_MISC_TYPEC_CTRL, + /* USB DP Combo PHY related */ USB3_DP_DP_PHY_PD_CTL, USB3_DP_COM_POWER_DOWN_CTRL, @@ -103,8 +107,6 @@ enum qmp_phy_rev_reg { USB3_DP_PCS_PCS_STATUS2, USB3_DP_PCS_INSIG_SW_CTRL3, USB3_DP_PCS_INSIG_MX_CTRL3, - /* TypeC port select configuration (optional) */ - USB3_PHY_PCS_MISC_TYPEC_CTRL, USB3_PHY_REG_MAX, }; @@ -344,6 +346,18 @@ static int configure_phy_regs(struct usb_phy *uphy, return 0; } +static void msm_ssphy_qmp_setmode(struct msm_ssphy_qmp *phy, u32 mode) +{ + mode = mode & USB3_DP_COMBO_MODE; + + writel_relaxed(mode, + phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); + + /* flush the write by reading it */ + readl_relaxed(phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); +} + + static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) { int val; @@ -373,14 +387,14 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]); } - writel_relaxed(USB3_MODE | DP_MODE, - phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); + msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE); /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); break; case USB_PHY_TYPE_USB3_OR_DP: + case USB_PHY_TYPE_USB3: if (val > 0) { dev_err(phy->phy.dev, "USB QMP PHY: Update TYPEC CTRL(%d)\n", val); @@ -636,8 +650,14 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { - if (phy->cable_connected) + if (phy->cable_connected) { msm_ssusb_qmp_enable_autonomous(phy, 1); + } else { + if (uphy->type == USB_PHY_TYPE_USB3_AND_DP) + msm_ssphy_qmp_setmode(phy, USB3_MODE); + writel_relaxed(0x00, + phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + } /* Make sure above write completed with PHY */ wmb(); @@ -764,6 +784,23 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, return 0; } +static int msm_ssphy_qmp_powerup(struct usb_phy *uphy, bool powerup) +{ + struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, + phy); + u8 reg = powerup ? 1 : 0; + u8 temp; + + writel_relaxed(reg, + phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + temp = readl_relaxed(phy->base + + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + + dev_dbg(uphy->dev, "P3 powerup:%x\n", temp); + + return 0; +} + static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev) { int ret = 0; @@ -1065,6 +1102,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.set_suspend = msm_ssphy_qmp_set_suspend; phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; + phy->phy.powerup = msm_ssphy_qmp_powerup; if (of_property_read_bool(dev->of_node, "qcom,link-training-reset")) phy->phy.link_training = msm_ssphy_qmp_link_training; diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 126991046eb739f331d66e33bb56cd9bfb91c986..0212f0ee8aea7577246c01c99821e0ba12cf9373 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -66,34 +66,6 @@ uuid_le mdev_uuid(struct mdev_device *mdev) } EXPORT_SYMBOL(mdev_uuid); -static int _find_mdev_device(struct device *dev, void *data) -{ - struct mdev_device *mdev; - - if (!dev_is_mdev(dev)) - return 0; - - mdev = to_mdev_device(dev); - - if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0) - return 1; - - return 0; -} - -static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid) -{ - struct device *dev; - - dev = device_find_child(parent->dev, &uuid, _find_mdev_device); - if (dev) { - put_device(dev); - return true; - } - - return false; -} - /* Should be called holding parent_list_lock */ static struct mdev_parent *__find_parent_device(struct device *dev) { @@ -221,7 +193,6 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) } kref_init(&parent->ref); - mutex_init(&parent->lock); parent->dev = dev; parent->ops = ops; @@ -297,6 +268,10 @@ static void mdev_device_release(struct device *dev) { struct mdev_device *mdev = to_mdev_device(dev); + mutex_lock(&mdev_list_lock); + list_del(&mdev->next); + mutex_unlock(&mdev_list_lock); + dev_dbg(&mdev->dev, "MDEV: destroying\n"); kfree(mdev); } @@ -304,7 +279,7 @@ static void mdev_device_release(struct device *dev) int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) { int ret; - struct mdev_device *mdev; + struct mdev_device *mdev, *tmp; struct mdev_parent *parent; struct mdev_type *type = to_mdev_type(kobj); @@ -312,21 +287,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) if (!parent) return -EINVAL; - mutex_lock(&parent->lock); + mutex_lock(&mdev_list_lock); /* Check for duplicate */ - if (mdev_device_exist(parent, uuid)) { - ret = -EEXIST; - goto create_err; + list_for_each_entry(tmp, &mdev_list, next) { + if (!uuid_le_cmp(tmp->uuid, uuid)) { + mutex_unlock(&mdev_list_lock); + ret = -EEXIST; + goto mdev_fail; + } } mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) { + mutex_unlock(&mdev_list_lock); ret = -ENOMEM; - goto create_err; + goto mdev_fail; } memcpy(&mdev->uuid, &uuid, sizeof(uuid_le)); + list_add(&mdev->next, &mdev_list); + mutex_unlock(&mdev_list_lock); + mdev->parent = parent; kref_init(&mdev->ref); @@ -338,35 +320,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) ret = device_register(&mdev->dev); if (ret) { put_device(&mdev->dev); - goto create_err; + goto mdev_fail; } ret = mdev_device_create_ops(kobj, mdev); if (ret) - goto create_failed; + goto create_fail; ret = mdev_create_sysfs_files(&mdev->dev, type); if (ret) { mdev_device_remove_ops(mdev, true); - goto create_failed; + goto create_fail; } mdev->type_kobj = kobj; + mdev->active = true; dev_dbg(&mdev->dev, "MDEV: created\n"); - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - - return ret; + return 0; -create_failed: +create_fail: device_unregister(&mdev->dev); - -create_err: - mutex_unlock(&parent->lock); +mdev_fail: mdev_put_parent(parent); return ret; } @@ -377,44 +352,39 @@ int mdev_device_remove(struct device *dev, bool force_remove) struct mdev_parent *parent; struct mdev_type *type; int ret; - bool found = false; mdev = to_mdev_device(dev); mutex_lock(&mdev_list_lock); list_for_each_entry(tmp, &mdev_list, next) { - if (tmp == mdev) { - found = true; + if (tmp == mdev) break; - } } - if (found) - list_del(&mdev->next); + if (tmp != mdev) { + mutex_unlock(&mdev_list_lock); + return -ENODEV; + } - mutex_unlock(&mdev_list_lock); + if (!mdev->active) { + mutex_unlock(&mdev_list_lock); + return -EAGAIN; + } - if (!found) - return -ENODEV; + mdev->active = false; + mutex_unlock(&mdev_list_lock); type = to_mdev_type(mdev->type_kobj); parent = mdev->parent; - mutex_lock(&parent->lock); ret = mdev_device_remove_ops(mdev, force_remove); if (ret) { - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - + mdev->active = true; return ret; } mdev_remove_sysfs_files(dev, type); device_unregister(dev); - mutex_unlock(&parent->lock); mdev_put_parent(parent); return 0; diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index a9cefd70a7050a45d88b77dfd17efeffd5d3e95f..b5819b7d7ef7016f2467f07b57495be54ce33940 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -20,7 +20,6 @@ struct mdev_parent { struct device *dev; const struct mdev_parent_ops *ops; struct kref ref; - struct mutex lock; struct list_head next; struct kset *mdev_types_kset; struct list_head type_list; @@ -34,6 +33,7 @@ struct mdev_device { struct kref ref; struct list_head next; struct kobject *type_kobj; + bool active; }; #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index f041b1a6cf665e6410917d3608de5fe0ac557476..695b9d1a1aae235efd3e03ca4402513c4e33dcf4 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "vfio_pci_private.h" @@ -746,6 +747,9 @@ static long vfio_pci_ioctl(void *device_data, if (info.index >= VFIO_PCI_NUM_REGIONS + vdev->num_regions) return -EINVAL; + info.index = array_index_nospec(info.index, + VFIO_PCI_NUM_REGIONS + + vdev->num_regions); i = info.index - VFIO_PCI_NUM_REGIONS; diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index 4c27f4be3c3d038598304729dbb1af90c6b2395a..aa9e792110e381d00177f95c2525debc1a4f118d 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -681,18 +681,23 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, group = vfio_iommu_group_get(dev); if (!group) { pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); - return -EINVAL; + ret = -EINVAL; + goto put_reset; } ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev); - if (ret) { - vfio_iommu_group_put(group, dev); - return ret; - } + if (ret) + goto put_iommu; mutex_init(&vdev->igate); return 0; + +put_iommu: + vfio_iommu_group_put(group, dev); +put_reset: + vfio_platform_put_reset(vdev); + return ret; } EXPORT_SYMBOL_GPL(vfio_platform_probe_common); diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 63112c36ab2de129e41b70e2c9db77e17399a781..b4c68f3b82be9187f0a4fcb58d9b45c08c217082 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -457,17 +457,17 @@ static void tce_iommu_unuse_page(struct tce_container *container, } static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container, - unsigned long tce, unsigned long size, + unsigned long tce, unsigned long shift, unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem) { long ret = 0; struct mm_iommu_table_group_mem_t *mem; - mem = mm_iommu_lookup(container->mm, tce, size); + mem = mm_iommu_lookup(container->mm, tce, 1ULL << shift); if (!mem) return -EINVAL; - ret = mm_iommu_ua_to_hpa(mem, tce, phpa); + ret = mm_iommu_ua_to_hpa(mem, tce, shift, phpa); if (ret) return -EINVAL; @@ -487,7 +487,7 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container, if (!pua) return; - ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl), + ret = tce_iommu_prereg_ua_to_hpa(container, *pua, tbl->it_page_shift, &hpa, &mem); if (ret) pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n", @@ -609,7 +609,7 @@ static long tce_iommu_build_v2(struct tce_container *container, entry + i); ret = tce_iommu_prereg_ua_to_hpa(container, - tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem); + tce, tbl->it_page_shift, &hpa, &mem); if (ret) break; diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index d639378e36acc8634258c2d29a8b4057866d2c82..50eeb74ddc0aa71b07b911a393e21c93c9886e3a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -83,6 +83,7 @@ struct vfio_dma { size_t size; /* Map size (bytes) */ int prot; /* IOMMU_READ/WRITE */ bool iommu_mapped; + bool lock_cap; /* capable(CAP_IPC_LOCK) */ struct task_struct *task; struct rb_root pfn_list; /* Ex-user pinned pfn list */ }; @@ -246,29 +247,25 @@ static int vfio_iova_put_vfio_pfn(struct vfio_dma *dma, struct vfio_pfn *vpfn) return ret; } -static int vfio_lock_acct(struct task_struct *task, long npage, bool *lock_cap) +static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async) { struct mm_struct *mm; - bool is_current; int ret; if (!npage) return 0; - is_current = (task->mm == current->mm); - - mm = is_current ? task->mm : get_task_mm(task); + mm = async ? get_task_mm(dma->task) : dma->task->mm; if (!mm) return -ESRCH; /* process exited */ ret = down_write_killable(&mm->mmap_sem); if (!ret) { if (npage > 0) { - if (lock_cap ? !*lock_cap : - !has_capability(task, CAP_IPC_LOCK)) { + if (!dma->lock_cap) { unsigned long limit; - limit = task_rlimit(task, + limit = task_rlimit(dma->task, RLIMIT_MEMLOCK) >> PAGE_SHIFT; if (mm->locked_vm + npage > limit) @@ -282,7 +279,7 @@ static int vfio_lock_acct(struct task_struct *task, long npage, bool *lock_cap) up_write(&mm->mmap_sem); } - if (!is_current) + if (async) mmput(mm); return ret; @@ -391,7 +388,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, */ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, long npage, unsigned long *pfn_base, - bool lock_cap, unsigned long limit) + unsigned long limit) { unsigned long pfn = 0; long ret, pinned = 0, lock_acct = 0; @@ -414,7 +411,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, * pages are already counted against the user. */ if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && current->mm->locked_vm + 1 > limit) { + if (!dma->lock_cap && current->mm->locked_vm + 1 > limit) { put_pfn(*pfn_base, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, limit << PAGE_SHIFT); @@ -440,7 +437,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, } if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && + if (!dma->lock_cap && current->mm->locked_vm + lock_acct + 1 > limit) { put_pfn(pfn, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", @@ -453,7 +450,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, } out: - ret = vfio_lock_acct(current, lock_acct, &lock_cap); + ret = vfio_lock_acct(dma, lock_acct, false); unpin_out: if (ret) { @@ -484,7 +481,7 @@ static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, } if (do_accounting) - vfio_lock_acct(dma->task, locked - unlocked, NULL); + vfio_lock_acct(dma, locked - unlocked, true); return unlocked; } @@ -501,7 +498,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr, ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); if (!ret && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) { - ret = vfio_lock_acct(dma->task, 1, NULL); + ret = vfio_lock_acct(dma, 1, true); if (ret) { put_pfn(*pfn_base, dma->prot); if (ret == -ENOMEM) @@ -528,7 +525,7 @@ static int vfio_unpin_page_external(struct vfio_dma *dma, dma_addr_t iova, unlocked = vfio_iova_put_vfio_pfn(dma, vpfn); if (do_accounting) - vfio_lock_acct(dma->task, -unlocked, NULL); + vfio_lock_acct(dma, -unlocked, true); return unlocked; } @@ -723,7 +720,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma, dma->iommu_mapped = false; if (do_accounting) { - vfio_lock_acct(dma->task, -unlocked, NULL); + vfio_lock_acct(dma, -unlocked, true); return 0; } return unlocked; @@ -935,14 +932,12 @@ static int vfio_pin_map_dma(struct vfio_iommu *iommu, struct vfio_dma *dma, size_t size = map_size; long npage; unsigned long pfn, limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - bool lock_cap = capable(CAP_IPC_LOCK); int ret = 0; while (size) { /* Pin a contiguous chunk of memory */ npage = vfio_pin_pages_remote(dma, vaddr + dma->size, - size >> PAGE_SHIFT, &pfn, - lock_cap, limit); + size >> PAGE_SHIFT, &pfn, limit); if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; @@ -1017,8 +1012,36 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, dma->iova = iova; dma->vaddr = vaddr; dma->prot = prot; - get_task_struct(current); - dma->task = current; + + /* + * We need to be able to both add to a task's locked memory and test + * against the locked memory limit and we need to be able to do both + * outside of this call path as pinning can be asynchronous via the + * external interfaces for mdev devices. RLIMIT_MEMLOCK requires a + * task_struct and VM locked pages requires an mm_struct, however + * holding an indefinite mm reference is not recommended, therefore we + * only hold a reference to a task. We could hold a reference to + * current, however QEMU uses this call path through vCPU threads, + * which can be killed resulting in a NULL mm and failure in the unmap + * path when called via a different thread. Avoid this problem by + * using the group_leader as threads within the same group require + * both CLONE_THREAD and CLONE_VM and will therefore use the same + * mm_struct. + * + * Previously we also used the task for testing CAP_IPC_LOCK at the + * time of pinning and accounting, however has_capability() makes use + * of real_cred, a copy-on-write field, so we can't guarantee that it + * matches group_leader, or in fact that it might not change by the + * time it's evaluated. If a process were to call MAP_DMA with + * CAP_IPC_LOCK but later drop it, it doesn't make sense that they + * possibly see different results for an iommu_mapped vfio_dma vs + * externally mapped. Therefore track CAP_IPC_LOCK in vfio_dma at the + * time of calling MAP_DMA. + */ + get_task_struct(current->group_leader); + dma->task = current->group_leader; + dma->lock_cap = capable(CAP_IPC_LOCK); + dma->pfn_list = RB_ROOT; /* Insert zero-sized and grow as we map chunks of it */ @@ -1053,7 +1076,6 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, struct vfio_domain *d; struct rb_node *n; unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - bool lock_cap = capable(CAP_IPC_LOCK); int ret; /* Arbitrarily pick the first domain in the list for lookups */ @@ -1100,8 +1122,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, npage = vfio_pin_pages_remote(dma, vaddr, n >> PAGE_SHIFT, - &pfn, lock_cap, - limit); + &pfn, limit); if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; @@ -1378,7 +1399,7 @@ static void vfio_iommu_unmap_unpin_reaccount(struct vfio_iommu *iommu) if (!is_invalid_reserved_pfn(vpfn->pfn)) locked++; } - vfio_lock_acct(dma->task, locked - unlocked, NULL); + vfio_lock_acct(dma, locked - unlocked, true); } } diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index b0d606b2d06c34e8df9f4d78914ec995ec6a2d95..6123b4dd86381cf2c69b693bb60de730921b6116 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1186,7 +1186,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) if (ubufs) vhost_net_ubuf_put_wait_and_free(ubufs); err_ubufs: - sockfd_put(sock); + if (sock) + sockfd_put(sock); err_vq: mutex_unlock(&vq->mutex); err: diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 1c2289ddd555a64a418f29edeaf8e4b5643430b9..0fa7d2bd0e4811c6c404663451c67f6ecea6afee 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -301,14 +301,14 @@ static int pwm_backlight_probe(struct platform_device *pdev) /* * If the GPIO is not known to be already configured as output, that - * is, if gpiod_get_direction returns either GPIOF_DIR_IN or -EINVAL, - * change the direction to output and set the GPIO as active. + * is, if gpiod_get_direction returns either 1 or -EINVAL, change the + * direction to output and set the GPIO as active. * Do not force the GPIO to active when it was already output as it * could cause backlight flickering or we would enable the backlight too * early. Leave the decision of the initial backlight state for later. */ if (pb->enable_gpio && - gpiod_get_direction(pb->enable_gpio) != GPIOF_DIR_OUT) + gpiod_get_direction(pb->enable_gpio) != 0) gpiod_direction_output(pb->enable_gpio, 1); pb->power_supply = devm_regulator_get(&pdev->dev, "power"); diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index b5123b7c7c32825da82e5d98af3cb95abb330924..de6c31564f929023e88fa7dfc86b104e7b4647ca 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -1330,7 +1330,7 @@ static const struct wled_config wled4_config_defaults = { static const struct wled_config wled5_config_defaults = { .boost_i_limit = 5, - .fs_current = 12, + .fs_current = 10, /* 25 mA */ .ovp = 4, .switch_freq = -EINVAL, .string_cfg = 0xf, diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f0b3a0b9d42f8b8b3ea9c6943a4010c3d7e15f18..36c9fbf70d44badd229661d65546d10e067d8728 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -490,7 +490,9 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, tell_host(vb, vb->inflate_vq); /* balloon's page migration 2nd step -- deflate "page" */ + spin_lock_irqsave(&vb_dev_info->pages_lock, flags); balloon_page_delete(page); + spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags); vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; set_page_pfns(vb, vb->pfns, page); tell_host(vb, vb->deflate_vq); diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 2a20fc163ed0b50b1d078b4179dcced844ad2159..4c62ad74aec0c135bc01175785eb14d32a580bfb 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -102,10 +102,23 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd, { struct da9063 *da9063 = watchdog_get_drvdata(wdd); unsigned int selector; - int ret; + int ret = 0; selector = da9063_wdt_timeout_to_sel(timeout); - ret = _da9063_wdt_set_timeout(da9063, selector); + + /* + * There are two cases when a set_timeout() will be called: + * 1. The watchdog is off and someone wants to set the timeout for the + * further use. + * 2. The watchdog is already running and a new timeout value should be + * set. + * + * The watchdog can't store a timeout value not equal zero without + * enabling the watchdog, so the timeout must be buffered by the driver. + */ + if (watchdog_active(wdd)) + ret = _da9063_wdt_set_timeout(da9063, selector); + if (ret) dev_err(da9063->dev, "Failed to set watchdog timeout (err = %d)\n", ret); diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index b7c816f3940402f21002cb6e6cbc391b35cb32b9..6dd63981787a2f7f2b15e87c6f955ad36fb3510e 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -148,6 +148,15 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) cmd); goto out; } + } else { + unsigned int inr = _IOC_NR(cmd); + + if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD || + inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD || + inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) { + err = -EINVAL; + goto out; + } } err = 0; @@ -284,7 +293,8 @@ static int autofs_dev_ioctl_openmount(struct file *fp, dev_t devid; int err, fd; - /* param->path has already been checked */ + /* param->path has been checked in validate_dev_ioctl() */ + if (!param->openmount.devid) return -EINVAL; @@ -446,10 +456,7 @@ static int autofs_dev_ioctl_requester(struct file *fp, dev_t devid; int err = -ENOENT; - if (param->size <= AUTOFS_DEV_IOCTL_SIZE) { - err = -EINVAL; - goto out; - } + /* param->path has been checked in validate_dev_ioctl() */ devid = sbi->sb->s_dev; @@ -534,10 +541,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, unsigned int devid, magic; int err = -ENOENT; - if (param->size <= AUTOFS_DEV_IOCTL_SIZE) { - err = -EINVAL; - goto out; - } + /* param->path has been checked in validate_dev_ioctl() */ name = param->path; type = param->ismountpoint.in.type; diff --git a/fs/block_dev.c b/fs/block_dev.c index 789f55e851aeffb6b1212403188638d12a1d2540..3323eec5c164991e45228ec53c68f8ec1958e313 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -231,7 +231,7 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter, ret = bio_iov_iter_get_pages(&bio, iter); if (unlikely(ret)) - return ret; + goto out; ret = bio.bi_iter.bi_size; if (iov_iter_rw(iter) == READ) { @@ -260,12 +260,13 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter, put_page(bvec->bv_page); } - if (vecs != inline_vecs) - kfree(vecs); - if (unlikely(bio.bi_status)) ret = blk_status_to_errno(bio.bi_status); +out: + if (vecs != inline_vecs) + kfree(vecs); + bio_uninit(&bio); return ret; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7fa50e12f18e7371032438689e46ea158684862e..5b62e06567a379bf3003c57c01083ee68e325764 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4280,6 +4280,7 @@ int try_release_extent_mapping(struct extent_map_tree *map, struct extent_map *em; u64 start = page_offset(page); u64 end = start + PAGE_SIZE - 1; + struct btrfs_inode *btrfs_inode = BTRFS_I(page->mapping->host); if (gfpflags_allow_blocking(mask) && page->mapping->host->i_size > SZ_16M) { @@ -4302,6 +4303,8 @@ int try_release_extent_mapping(struct extent_map_tree *map, extent_map_end(em) - 1, EXTENT_LOCKED | EXTENT_WRITEBACK, 0, NULL)) { + set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, + &btrfs_inode->runtime_flags); remove_extent_mapping(map, em); /* once for the rb tree */ free_extent_map(em); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f5b90dc137ec5c80fdb54258db9faae38554f5e6..28a58f40f3a4746b2586f8155840ed7c692bea2e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3162,6 +3162,9 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) /* once for the tree */ btrfs_put_ordered_extent(ordered_extent); + /* Try to release some metadata so we don't get an OOM but don't wait */ + btrfs_btree_balance_dirty_nodelay(fs_info); + return ret; } @@ -4737,7 +4740,10 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, extent_num_bytes, 0, btrfs_header_owner(leaf), ino, extent_offset); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, ret); + break; + } if (btrfs_should_throttle_delayed_refs(trans, fs_info)) btrfs_async_run_delayed_refs(fs_info, trans->delayed_ref_updates * 2, @@ -5496,13 +5502,18 @@ void btrfs_evict_inode(struct inode *inode) trans->block_rsv = rsv; ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0); - if (ret != -ENOSPC && ret != -EAGAIN) + if (ret) { + trans->block_rsv = &fs_info->trans_block_rsv; + btrfs_end_transaction(trans); + btrfs_btree_balance_dirty(fs_info); + if (ret != -ENOSPC && ret != -EAGAIN) { + btrfs_orphan_del(NULL, BTRFS_I(inode)); + btrfs_free_block_rsv(fs_info, rsv); + goto no_delete; + } + } else { break; - - trans->block_rsv = &fs_info->trans_block_rsv; - btrfs_end_transaction(trans); - trans = NULL; - btrfs_btree_balance_dirty(fs_info); + } } btrfs_free_block_rsv(fs_info, rsv); @@ -5511,12 +5522,8 @@ void btrfs_evict_inode(struct inode *inode) * Errors here aren't a big deal, it just means we leave orphan items * in the tree. They will be cleaned up on the next mount. */ - if (ret == 0) { - trans->block_rsv = root->orphan_block_rsv; - btrfs_orphan_del(trans, BTRFS_I(inode)); - } else { - btrfs_orphan_del(NULL, BTRFS_I(inode)); - } + trans->block_rsv = root->orphan_block_rsv; + btrfs_orphan_del(trans, BTRFS_I(inode)); trans->block_rsv = &fs_info->trans_block_rsv; if (!(root == fs_info->tree_root || diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e172d4843eae2d8eb6f0d29dce38fb7f693f4ed0..473ad5985aa378e7f412efa7ee1c469dfa595a63 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2499,6 +2499,21 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, spin_unlock(&fs_info->qgroup_lock); } +/* + * Check if the leaf is the last leaf. Which means all node pointers + * are at their last position. + */ +static bool is_last_leaf(struct btrfs_path *path) +{ + int i; + + for (i = 1; i < BTRFS_MAX_LEVEL && path->nodes[i]; i++) { + if (path->slots[i] != btrfs_header_nritems(path->nodes[i]) - 1) + return false; + } + return true; +} + /* * returns < 0 on error, 0 when more leafs are to be scanned. * returns 1 when done. @@ -2512,6 +2527,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct ulist *roots = NULL; struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); u64 num_bytes; + bool done; int slot; int ret; @@ -2540,6 +2556,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, mutex_unlock(&fs_info->qgroup_rescan_lock); return ret; } + done = is_last_leaf(path); btrfs_item_key_to_cpu(path->nodes[0], &found, btrfs_header_nritems(path->nodes[0]) - 1); @@ -2586,6 +2603,8 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, } btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); + if (done && !ret) + ret = 1; return ret; } diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index fc4c14a72366a90d54d52cd0b8f4122be8afb96c..e1b4a59485dffc85208cad4c1b45084080e878bd 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3041,8 +3041,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&log_root_tree->log_mutex); /* - * The barrier before waitqueue_active is implied by mutex_unlock + * The barrier before waitqueue_active is needed so all the updates + * above are seen by the woken threads. It might not be necessary, but + * proving that seems to be hard. */ + smp_mb(); if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) wake_up(&log_root_tree->log_commit_wait[index2]); out: @@ -3053,8 +3056,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&root->log_mutex); /* - * The barrier before waitqueue_active is implied by mutex_unlock + * The barrier before waitqueue_active is needed so all the updates + * above are seen by the woken threads. It might not be necessary, but + * proving that seems to be hard. */ + smp_mb(); if (waitqueue_active(&root->log_commit_wait[index1])) wake_up(&root->log_commit_wait[index1]); return ret; @@ -4214,6 +4220,110 @@ static int log_one_extent(struct btrfs_trans_handle *trans, return ret; } +/* + * Log all prealloc extents beyond the inode's i_size to make sure we do not + * lose them after doing a fast fsync and replaying the log. We scan the + * subvolume's root instead of iterating the inode's extent map tree because + * otherwise we can log incorrect extent items based on extent map conversion. + * That can happen due to the fact that extent maps are merged when they + * are not in the extent map tree's list of modified extents. + */ +static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, + struct btrfs_inode *inode, + struct btrfs_path *path) +{ + struct btrfs_root *root = inode->root; + struct btrfs_key key; + const u64 i_size = i_size_read(&inode->vfs_inode); + const u64 ino = btrfs_ino(inode); + struct btrfs_path *dst_path = NULL; + u64 last_extent = (u64)-1; + int ins_nr = 0; + int start_slot; + int ret; + + if (!(inode->flags & BTRFS_INODE_PREALLOC)) + return 0; + + key.objectid = ino; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = i_size; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; + + while (true) { + struct extent_buffer *leaf = path->nodes[0]; + int slot = path->slots[0]; + + if (slot >= btrfs_header_nritems(leaf)) { + if (ins_nr > 0) { + ret = copy_items(trans, inode, dst_path, path, + &last_extent, start_slot, + ins_nr, 1, 0); + if (ret < 0) + goto out; + ins_nr = 0; + } + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; + break; + } + continue; + } + + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid > ino) + break; + if (WARN_ON_ONCE(key.objectid < ino) || + key.type < BTRFS_EXTENT_DATA_KEY || + key.offset < i_size) { + path->slots[0]++; + continue; + } + if (last_extent == (u64)-1) { + last_extent = key.offset; + /* + * Avoid logging extent items logged in past fsync calls + * and leading to duplicate keys in the log tree. + */ + do { + ret = btrfs_truncate_inode_items(trans, + root->log_root, + &inode->vfs_inode, + i_size, + BTRFS_EXTENT_DATA_KEY); + } while (ret == -EAGAIN); + if (ret) + goto out; + } + if (ins_nr == 0) + start_slot = slot; + ins_nr++; + path->slots[0]++; + if (!dst_path) { + dst_path = btrfs_alloc_path(); + if (!dst_path) { + ret = -ENOMEM; + goto out; + } + } + } + if (ins_nr > 0) { + ret = copy_items(trans, inode, dst_path, path, &last_extent, + start_slot, ins_nr, 1, 0); + if (ret > 0) + ret = 0; + } +out: + btrfs_release_path(path); + btrfs_free_path(dst_path); + return ret; +} + static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_inode *inode, @@ -4256,6 +4366,11 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, if (em->generation <= test_gen) continue; + /* We log prealloc extents beyond eof later. */ + if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) && + em->start >= i_size_read(&inode->vfs_inode)) + continue; + if (em->start < logged_start) logged_start = em->start; if ((em->start + em->len - 1) > logged_end) @@ -4268,31 +4383,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, num++; } - /* - * Add all prealloc extents beyond the inode's i_size to make sure we - * don't lose them after doing a fast fsync and replaying the log. - */ - if (inode->flags & BTRFS_INODE_PREALLOC) { - struct rb_node *node; - - for (node = rb_last(&tree->map); node; node = rb_prev(node)) { - em = rb_entry(node, struct extent_map, rb_node); - if (em->start < i_size_read(&inode->vfs_inode)) - break; - if (!list_empty(&em->list)) - continue; - /* Same as above loop. */ - if (++num > 32768) { - list_del_init(&tree->modified_extents); - ret = -EFBIG; - goto process; - } - refcount_inc(&em->refs); - set_bit(EXTENT_FLAG_LOGGING, &em->flags); - list_add_tail(&em->list, &extents); - } - } - list_sort(NULL, &extents, extent_cmp); btrfs_get_logged_extents(inode, logged_list, logged_start, logged_end); /* @@ -4337,6 +4427,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, up_write(&inode->dio_sem); btrfs_release_path(path); + if (!ret) + ret = btrfs_log_prealloc_extents(trans, inode, path); + return ret; } diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 48ffe720bf09c1fb0d8d713cf5477fd415bcbde4..b79b1211a2b55540ddd3194ecf16b7e1ef0ce467 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -254,7 +254,7 @@ static int parse_fsopt_token(char *c, void *private) case Opt_rasize: if (intval < 0) return -EINVAL; - fsopt->rasize = ALIGN(intval + PAGE_SIZE - 1, PAGE_SIZE); + fsopt->rasize = ALIGN(intval, PAGE_SIZE); break; case Opt_caps_wanted_delay_min: if (intval < 1) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0480cd9a9e81372b7230b759ac5ea7cfeb7b137b..71b81980787fce27a478e080faf276e80f9d65a1 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -338,10 +338,7 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, return rc; /* BB eventually switch this to SMB2 specific small buf size */ - if (smb2_command == SMB2_SET_INFO) - *request_buf = cifs_buf_get(); - else - *request_buf = cifs_small_buf_get(); + *request_buf = cifs_small_buf_get(); if (*request_buf == NULL) { /* BB should we add a retry in here if not a writepage? */ return -ENOMEM; @@ -3171,7 +3168,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, } rc = SendReceive2(xid, ses, iov, num, &resp_buftype, flags, &rsp_iov); - cifs_buf_release(req); + cifs_small_buf_release(req); rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base; if (rc != 0) diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index e7bee887b605244a95e018727cef195d2548283f..cc42e5e2947293c8ce59220f9be92ff0e098c053 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o -fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o -fscrypto-$(CONFIG_BLOCK) += bio.o ccflags-y += -Ifs/ext4 -fscrypto-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o +ccflags-y += -Ifs/f2fs + +fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypt_ice.o +fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index d32a5c69ca38fd7a0222e0fbd5dc81afa5cae64f..93cd5e567d07f138f1eb22b2626784372ad8667c 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -25,7 +25,6 @@ #include #include #include "fscrypt_private.h" -#include "ext4_ice.h" static void __fscrypt_decrypt_bio(struct bio *bio, bool done) { @@ -34,12 +33,11 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (ext4_should_be_processed_by_ice(page->mapping->host)) { + if (fscrypt_using_hardware_encryption(page->mapping->host)) { SetPageUptodate(page); } else { int ret = fscrypt_decrypt_page(page->mapping->host, - page, PAGE_SIZE, 0, page->index); - + page, PAGE_SIZE, 0, page->index); if (ret) { WARN_ON_ONCE(1); SetPageError(page); diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 0758d32ad01bc284bb7aeb1ae4ced74000cb6195..2f646b1248bca7e85403c547ff94d13d7a54ec3f 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -433,8 +433,17 @@ int fscrypt_initialize(unsigned int cop_flags) */ static int __init fscrypt_init(void) { + /* + * Use an unbound workqueue to allow bios to be decrypted in parallel + * even when they happen to complete on the same CPU. This sacrifices + * locality, but it's worthwhile since decryption is CPU-intensive. + * + * Also use a high-priority workqueue to prioritize decryption work, + * which blocks reads from completing, over regular application tasks. + */ fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue", - WQ_HIGHPRI, 0); + WQ_UNBOUND | WQ_HIGHPRI, + num_online_cpus()); if (!fscrypt_read_workqueue) goto fail; diff --git a/fs/crypto/ext4_ice.c b/fs/crypto/ext4_ice.c deleted file mode 100644 index a8098e338f29be990024168f63ef8b7ae7075364..0000000000000000000000000000000000000000 --- a/fs/crypto/ext4_ice.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "ext4_ice.h" -#include "fscrypt_private.h" - -/* - * Retrieves encryption key from the inode - */ -char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[0]); -} - -/* - * Retrieves encryption salt from the inode - */ -char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]); -} - -/* - * returns true if the cipher mode in inode is AES XTS - */ -int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - ci = inode->i_crypt_info; - if (!ci) - return 0; - - return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); -} - -/* - * returns true if encryption info in both inodes is equal - */ -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2) -{ - char *key1 = NULL; - char *key2 = NULL; - char *salt1 = NULL; - char *salt2 = NULL; - - if (!inode1 || !inode2) - return 0; - - if (inode1 == inode2) - return 1; - - /* both do not belong to ice, so we don't care, they are equal for us */ - if (!ext4_should_be_processed_by_ice(inode1) && - !ext4_should_be_processed_by_ice(inode2)) - return 1; - - /* one belongs to ice, the other does not -> not equal */ - if (ext4_should_be_processed_by_ice(inode1) ^ - ext4_should_be_processed_by_ice(inode2)) - return 0; - - key1 = ext4_get_ice_encryption_key(inode1); - key2 = ext4_get_ice_encryption_key(inode2); - salt1 = ext4_get_ice_encryption_salt(inode1); - salt2 = ext4_get_ice_encryption_salt(inode2); - - /* key and salt should not be null by this point */ - if (!key1 || !key2 || !salt1 || !salt2 || - (ext4_get_ice_encryption_key_size(inode1) != - ext4_get_ice_encryption_key_size(inode2)) || - (ext4_get_ice_encryption_salt_size(inode1) != - ext4_get_ice_encryption_salt_size(inode2))) - return 0; - - return ((memcmp(key1, key2, - ext4_get_ice_encryption_key_size(inode1)) == 0) && - (memcmp(salt1, salt2, - ext4_get_ice_encryption_salt_size(inode1)) == 0)); -} diff --git a/fs/crypto/fscrypt_ice.c b/fs/crypto/fscrypt_ice.c new file mode 100644 index 0000000000000000000000000000000000000000..ae28cdfd83e42d27bef530d7d733f2759af74dd5 --- /dev/null +++ b/fs/crypto/fscrypt_ice.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fscrypt_ice.h" + +int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + return S_ISREG(inode->i_mode) && ci && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; +} +EXPORT_SYMBOL(fscrypt_using_hardware_encryption); + +/* + * Retrieves encryption key from the inode + */ +char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[0]); +} + +/* + * Retrieves encryption salt from the inode + */ +char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[fscrypt_get_ice_encryption_key_size(inode)]); +} + +/* + * returns true if the cipher mode in inode is AES XTS + */ +int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + if (!ci) + return 0; + + return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); +} + +/* + * returns true if encryption info in both inodes is equal + */ +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2) +{ + char *key1 = NULL; + char *key2 = NULL; + char *salt1 = NULL; + char *salt2 = NULL; + + if (!inode1 || !inode2) + return false; + + if (inode1 == inode2) + return true; + + /* both do not belong to ice, so we don't care, they are equal + *for us + */ + if (!fscrypt_should_be_processed_by_ice(inode1) && + !fscrypt_should_be_processed_by_ice(inode2)) + return true; + + /* one belongs to ice, the other does not -> not equal */ + if (fscrypt_should_be_processed_by_ice(inode1) ^ + fscrypt_should_be_processed_by_ice(inode2)) + return false; + + key1 = fscrypt_get_ice_encryption_key(inode1); + key2 = fscrypt_get_ice_encryption_key(inode2); + salt1 = fscrypt_get_ice_encryption_salt(inode1); + salt2 = fscrypt_get_ice_encryption_salt(inode2); + + /* key and salt should not be null by this point */ + if (!key1 || !key2 || !salt1 || !salt2 || + (fscrypt_get_ice_encryption_key_size(inode1) != + fscrypt_get_ice_encryption_key_size(inode2)) || + (fscrypt_get_ice_encryption_salt_size(inode1) != + fscrypt_get_ice_encryption_salt_size(inode2))) + return false; + + if ((memcmp(key1, key2, + fscrypt_get_ice_encryption_key_size(inode1)) == 0) && + (memcmp(salt1, salt2, + fscrypt_get_ice_encryption_salt_size(inode1)) == 0)) + return true; + + return false; +} + +void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun) +{ + if (fscrypt_should_be_processed_by_ice(inode)) + bio->bi_iter.bi_dun = dun; +} +EXPORT_SYMBOL(fscrypt_set_ice_dun); + +void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip) +{ +#ifdef CONFIG_DM_DEFAULT_KEY + bio->bi_crypt_skip = bi_crypt_skip; +#endif +} +EXPORT_SYMBOL(fscrypt_set_ice_skip); + +/* + * This function will be used for filesystem when deciding to merge bios. + * Basic assumption is, if inline_encryption is set, single bio has to + * guarantee consecutive LBAs as well as ino|pg->index. + */ +bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted, + int bi_crypt_skip) +{ + if (!bio) + return true; + +#ifdef CONFIG_DM_DEFAULT_KEY + if (bi_crypt_skip != bio->bi_crypt_skip) + return false; +#endif + /* if both of them are not encrypted, no further check is needed */ + if (!bio_dun(bio) && !bio_encrypted) + return true; + + /* ICE allows only consecutive iv_key stream. */ + return bio_end_dun(bio) == dun; +} +EXPORT_SYMBOL(fscrypt_mergeable_bio); diff --git a/fs/crypto/fscrypt_ice.h b/fs/crypto/fscrypt_ice.h new file mode 100644 index 0000000000000000000000000000000000000000..38e8ba69f3c24d0a7fa49b6b2058134dfad36cdf --- /dev/null +++ b/fs/crypto/fscrypt_ice.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _FSCRYPT_ICE_H +#define _FSCRYPT_ICE_H + +#include +#include "fscrypt_private.h" + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + if (!inode->i_sb->s_cop) + return 0; + if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode)) + return 0; + + return fscrypt_using_hardware_encryption(inode); +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return blk_queue_inlinecrypt(bdev_get_queue(sb->s_bdev)); +} + +int fscrypt_is_aes_xts_cipher(const struct inode *inode); + +char *fscrypt_get_ice_encryption_key(const struct inode *inode); +char *fscrypt_get_ice_encryption_salt(const struct inode *inode); + +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2); + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} +#else +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return 0; +} + +static inline char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + return NULL; +} + +static inline char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + return NULL; +} + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return 0; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_xts_cipher(const struct inode *inode) +{ + return 0; +} + +static inline bool fscrypt_is_ice_encryption_info_equal( + const struct inode *inode1, + const struct inode *inode2) +{ + return 0; +} + +static inline int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + return 0; +} + +#endif + +#endif /* _FSCRYPT_ICE_H */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index c9ca9e79411d1cb6e66a6bba7dfb7a7c0b3f0abd..ca6e75a5cb37ed0170d23da370697cda4c3c9132 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -17,6 +17,7 @@ #endif #include #include +#include /* Encryption parameters */ #define FS_IV_SIZE 16 @@ -61,11 +62,18 @@ struct fscrypt_symlink_data { char encrypted_path[1]; } __packed; +enum ci_mode_info { + CI_NONE_MODE = 0, + CI_DATA_MODE, + CI_FNAME_MODE, +}; + /* * A pointer to this structure is stored in the file system's in-core * representation of an inode. */ struct fscrypt_info { + u8 ci_mode; u8 ci_data_mode; u8 ci_filename_mode; u8 ci_flags; @@ -105,12 +113,12 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, return false; } -static inline bool is_private_mode(struct fscrypt_info *ci) +static inline bool is_private_data_mode(struct fscrypt_info *ci) { - return ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; + return ci->ci_mode == CI_DATA_MODE && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; } - /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 27edc5b9eb66d80800865478ab136b39ada99287..737af4b41f711ac3c449d2e410108bc39e4d8c88 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -16,7 +16,7 @@ #include #include #include "fscrypt_private.h" -#include "ext4_ice.h" +#include "fscrypt_ice.h" static struct crypto_shash *essiv_hash_tfm; @@ -69,7 +69,7 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE], } static int validate_user_key(struct fscrypt_info *crypt_info, - struct fscrypt_context *ctx, u8 *raw_key, + struct fscrypt_context *ctx, const char *prefix, int min_keysize) { char *description; @@ -117,21 +117,20 @@ static int validate_user_key(struct fscrypt_info *crypt_info, res = -ENOKEY; goto out; } - /* - * If we don't need to derive, we still want to do everything + res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); + /* If we don't need to derive, we still want to do everything * up until now to validate the key. It's cleaner to fail now * than to fail in block I/O. */ - if (!is_private_mode(crypt_info)) { + if (!is_private_data_mode(crypt_info)) { res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); } else { - /* - * Inline encryption: no key derivation required because IVs are + /* Inline encryption: no key derivation required because IVs are * assigned based on iv_sector. */ - if (sizeof(crypt_info->ci_raw_key) != sizeof(master_key->raw)) - goto out; + BUILD_BUG_ON(sizeof(crypt_info->ci_raw_key) != + sizeof(master_key->raw)); memcpy(crypt_info->ci_raw_key, master_key->raw, sizeof(crypt_info->ci_raw_key)); res = 0; @@ -156,42 +155,37 @@ static const struct { FS_AES_128_CTS_KEY_SIZE }, [FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { "xts(speck128)", 64 }, [FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { "cts(cbc(speck128))", 32 }, - [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", FS_AES_256_XTS_KEY_SIZE }, + [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", + FS_AES_256_XTS_KEY_SIZE }, }; static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, - const char **cipher_str_ret, int *keysize_ret, int *fname) + const char **cipher_str_ret, int *keysize_ret) { - if (S_ISREG(inode->i_mode)) { - if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) { - *cipher_str_ret = "xts(aes)"; - *keysize_ret = FS_AES_256_XTS_KEY_SIZE; - return 0; - } else if (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE) { - *cipher_str_ret = "bugon"; - *keysize_ret = FS_AES_256_XTS_KEY_SIZE; - return 0; - } - pr_warn_once("fscrypto: unsupported contents encryption mode %d for inode %lu\n", - ci->ci_data_mode, inode->i_ino); - return -ENOKEY; + u32 mode; + + if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) { + pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n", + inode->i_ino, + ci->ci_data_mode, ci->ci_filename_mode); + return -EINVAL; } - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { - if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) { - *cipher_str_ret = "cts(cbc(aes))"; - *keysize_ret = FS_AES_256_CTS_KEY_SIZE; - *fname = 1; - return 0; - } - pr_warn_once("fscrypto: unsupported filenames encryption mode %d for inode %lu\n", - ci->ci_filename_mode, inode->i_ino); - return -ENOKEY; + if (S_ISREG(inode->i_mode)) { + ci->ci_mode = CI_DATA_MODE; + mode = ci->ci_data_mode; + } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + ci->ci_mode = CI_FNAME_MODE; + mode = ci->ci_filename_mode; + } else { + WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n", + inode->i_ino, (inode->i_mode & S_IFMT)); + return -EINVAL; } - pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n", - (inode->i_mode & S_IFMT), inode->i_ino); - return -ENOKEY; + *cipher_str_ret = available_modes[mode].cipher_str; + *keysize_ret = available_modes[mode].keysize; + return 0; } static void put_crypt_info(struct fscrypt_info *ci) @@ -201,6 +195,7 @@ static void put_crypt_info(struct fscrypt_info *ci) crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); + memset(ci, 0, sizeof(*ci)); /* sanitizes ->ci_raw_key */ kmem_cache_free(fscrypt_info_cachep, ci); } @@ -271,20 +266,11 @@ void __exit fscrypt_essiv_cleanup(void) crypto_free_shash(essiv_hash_tfm); } -static int fs_data_encryption_mode(void) +static int fscrypt_data_encryption_mode(struct inode *inode) { - return ext4_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE : - FS_ENCRYPTION_MODE_AES_256_XTS; -} - -int fs_using_hardware_encryption(struct inode *inode) -{ - struct fscrypt_info *ci = inode->i_crypt_info; - - return S_ISREG(inode->i_mode) && ci && - ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; + return fscrypt_should_be_processed_by_ice(inode) ? + FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS; } -EXPORT_SYMBOL(fs_using_hardware_encryption); int fscrypt_get_encryption_info(struct inode *inode) { @@ -293,8 +279,8 @@ int fscrypt_get_encryption_info(struct inode *inode) struct crypto_skcipher *ctfm; const char *cipher_str; int keysize; + u8 *raw_key = NULL; int res; - int fname = 0; if (inode->i_crypt_info) return 0; @@ -311,7 +297,8 @@ int fscrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - ctx.contents_encryption_mode = fs_data_encryption_mode(); + ctx.contents_encryption_mode = + fscrypt_data_encryption_mode(inode); ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); } else if (res != sizeof(ctx)) { @@ -336,8 +323,7 @@ int fscrypt_get_encryption_info(struct inode *inode) memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, sizeof(crypt_info->ci_master_key)); - res = determine_cipher_type(crypt_info, inode, &cipher_str, - &keysize, &fname); + res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); if (res) goto out; @@ -346,17 +332,16 @@ int fscrypt_get_encryption_info(struct inode *inode) * crypto API as part of key derivation. */ res = -ENOMEM; + raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); + if (!raw_key) + goto out; - if (fscrypt_dummy_context_enabled(inode)) { - memset(crypt_info->ci_raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); - goto got_key; - } - res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key, - FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); + res = validate_user_key(crypt_info, &ctx, FS_KEY_DESC_PREFIX, + keysize); if (res && inode->i_sb->s_cop->key_prefix) { int res2 = validate_user_key(crypt_info, &ctx, - crypt_info->ci_raw_key, - inode->i_sb->s_cop->key_prefix, keysize); + inode->i_sb->s_cop->key_prefix, + keysize); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; @@ -366,42 +351,57 @@ int fscrypt_get_encryption_info(struct inode *inode) } else if (res) { goto out; } -got_key: - if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) { - ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); - if (!ctfm || IS_ERR(ctfm)) { - res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; - pr_err("%s: error %d inode %u allocating crypto tfm\n", - __func__, res, (unsigned int) inode->i_ino); + + if (is_private_data_mode(crypt_info)) { + if (!fscrypt_is_ice_capable(inode->i_sb)) { + pr_warn("%s: ICE support not available\n", + __func__); + res = -EINVAL; goto out; } - crypt_info->ci_ctfm = ctfm; - crypto_skcipher_clear_flags(ctfm, ~0); - crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); - /* - * if the provided key is longer than keysize, we use the first - * keysize bytes of the derived key only - */ - res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, - keysize); - if (res) - goto out; - } else if (S_ISREG(inode->i_mode) && + /* Let's encrypt/decrypt by ICE */ + goto do_ice; + } + + + ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", + __func__, res, inode->i_ino); + goto out; + } + crypt_info->ci_ctfm = ctfm; + crypto_skcipher_clear_flags(ctfm, ~0); + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); + /* + * if the provided key is longer than keysize, we use the first + * keysize bytes of the derived key only + */ + res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, keysize); + if (res) + goto out; + + if (S_ISREG(inode->i_mode) && crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) { res = init_essiv_generator(crypt_info, crypt_info->ci_raw_key, - keysize); + keysize); if (res) { pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", __func__, res, inode->i_ino); goto out; } } + memzero_explicit(crypt_info->ci_raw_key, + sizeof(crypt_info->ci_raw_key)); +do_ice: if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); + kzfree(raw_key); return res; } EXPORT_SYMBOL(fscrypt_get_encryption_info); diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 6dabc4a10396b8627f2c8d83d5e634d28b83b517..65872340e301eb51bbb9e418f2e4c6e0495dc45c 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "internal.h" @@ -48,66 +47,108 @@ const struct file_operations debugfs_noop_file_operations = { .llseek = noop_llseek, }; +#define F_DENTRY(filp) ((filp)->f_path.dentry) + +const struct file_operations *debugfs_real_fops(const struct file *filp) +{ + struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; + + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) { + /* + * Urgh, we've been called w/o a protecting + * debugfs_file_get(). + */ + WARN_ON(1); + return NULL; + } + + return fsd->real_fops; +} +EXPORT_SYMBOL_GPL(debugfs_real_fops); + /** - * debugfs_use_file_start - mark the beginning of file data access + * debugfs_file_get - mark the beginning of file data access * @dentry: the dentry object whose data is being accessed. - * @srcu_idx: a pointer to some memory to store a SRCU index in. * - * Up to a matching call to debugfs_use_file_finish(), any - * successive call into the file removing functions debugfs_remove() - * and debugfs_remove_recursive() will block. Since associated private + * Up to a matching call to debugfs_file_put(), any successive call + * into the file removing functions debugfs_remove() and + * debugfs_remove_recursive() will block. Since associated private * file data may only get freed after a successful return of any of * the removal functions, you may safely access it after a successful - * call to debugfs_use_file_start() without worrying about - * lifetime issues. + * call to debugfs_file_get() without worrying about lifetime issues. * * If -%EIO is returned, the file has already been removed and thus, * it is not safe to access any of its data. If, on the other hand, * it is allowed to access the file data, zero is returned. - * - * Regardless of the return code, any call to - * debugfs_use_file_start() must be followed by a matching call - * to debugfs_use_file_finish(). */ -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu) +int debugfs_file_get(struct dentry *dentry) { - *srcu_idx = srcu_read_lock(&debugfs_srcu); - barrier(); + struct debugfs_fsdata *fsd; + void *d_fsd; + + d_fsd = READ_ONCE(dentry->d_fsdata); + if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) { + fsd = d_fsd; + } else { + fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); + if (!fsd) + return -ENOMEM; + + fsd->real_fops = (void *)((unsigned long)d_fsd & + ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); + refcount_set(&fsd->active_users, 1); + init_completion(&fsd->active_users_drained); + if (cmpxchg(&dentry->d_fsdata, d_fsd, fsd) != d_fsd) { + kfree(fsd); + fsd = READ_ONCE(dentry->d_fsdata); + } + } + + /* + * In case of a successful cmpxchg() above, this check is + * strictly necessary and must follow it, see the comment in + * __debugfs_remove_file(). + * OTOH, if the cmpxchg() hasn't been executed or wasn't + * successful, this serves the purpose of not starving + * removers. + */ if (d_unlinked(dentry)) return -EIO; + + if (!refcount_inc_not_zero(&fsd->active_users)) + return -EIO; + return 0; } -EXPORT_SYMBOL_GPL(debugfs_use_file_start); +EXPORT_SYMBOL_GPL(debugfs_file_get); /** - * debugfs_use_file_finish - mark the end of file data access - * @srcu_idx: the SRCU index "created" by a former call to - * debugfs_use_file_start(). + * debugfs_file_put - mark the end of file data access + * @dentry: the dentry object formerly passed to + * debugfs_file_get(). * * Allow any ongoing concurrent call into debugfs_remove() or * debugfs_remove_recursive() blocked by a former call to - * debugfs_use_file_start() to proceed and return to its caller. + * debugfs_file_get() to proceed and return to its caller. */ -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu) +void debugfs_file_put(struct dentry *dentry) { - srcu_read_unlock(&debugfs_srcu, srcu_idx); -} -EXPORT_SYMBOL_GPL(debugfs_use_file_finish); + struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata); -#define F_DENTRY(filp) ((filp)->f_path.dentry) + if (refcount_dec_and_test(&fsd->active_users)) + complete(&fsd->active_users_drained); +} +EXPORT_SYMBOL_GPL(debugfs_file_put); static int open_proxy_open(struct inode *inode, struct file *filp) { - const struct dentry *dentry = F_DENTRY(filp); + struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; - int srcu_idx, r; + int r; - r = debugfs_use_file_start(dentry, &srcu_idx); - if (r) { - r = -ENOENT; - goto out; - } + r = debugfs_file_get(dentry); + if (r) + return r == -EIO ? -ENOENT : r; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -124,7 +165,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp) r = real_fops->open(inode, filp); out: - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -138,16 +179,16 @@ const struct file_operations debugfs_open_proxy_file_operations = { #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \ static ret_type full_proxy_ ## name(proto) \ { \ - const struct dentry *dentry = F_DENTRY(filp); \ - const struct file_operations *real_fops = \ - debugfs_real_fops(filp); \ - int srcu_idx; \ + struct dentry *dentry = F_DENTRY(filp); \ + const struct file_operations *real_fops; \ ret_type r; \ \ - r = debugfs_use_file_start(dentry, &srcu_idx); \ - if (likely(!r)) \ - r = real_fops->name(args); \ - debugfs_use_file_finish(srcu_idx); \ + r = debugfs_file_get(dentry); \ + if (unlikely(r)) \ + return r; \ + real_fops = debugfs_real_fops(filp); \ + r = real_fops->name(args); \ + debugfs_file_put(dentry); \ return r; \ } @@ -172,18 +213,16 @@ FULL_PROXY_FUNC(unlocked_ioctl, long, filp, static unsigned int full_proxy_poll(struct file *filp, struct poll_table_struct *wait) { - const struct dentry *dentry = F_DENTRY(filp); - const struct file_operations *real_fops = debugfs_real_fops(filp); - int srcu_idx; + struct dentry *dentry = F_DENTRY(filp); unsigned int r = 0; + const struct file_operations *real_fops; - if (debugfs_use_file_start(dentry, &srcu_idx)) { - debugfs_use_file_finish(srcu_idx); + if (debugfs_file_get(dentry)) return POLLHUP; - } + real_fops = debugfs_real_fops(filp); r = real_fops->poll(filp, wait); - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -227,16 +266,14 @@ static void __full_proxy_fops_init(struct file_operations *proxy_fops, static int full_proxy_open(struct inode *inode, struct file *filp) { - const struct dentry *dentry = F_DENTRY(filp); + struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; struct file_operations *proxy_fops = NULL; - int srcu_idx, r; + int r; - r = debugfs_use_file_start(dentry, &srcu_idx); - if (r) { - r = -ENOENT; - goto out; - } + r = debugfs_file_get(dentry); + if (r) + return r == -EIO ? -ENOENT : r; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -274,7 +311,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp) kfree(proxy_fops); fops_put(real_fops); out: - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -285,13 +322,14 @@ const struct file_operations debugfs_full_proxy_file_operations = { ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { + struct dentry *dentry = F_DENTRY(file); ssize_t ret; - int srcu_idx; - ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!ret)) - ret = simple_attr_read(file, buf, len, ppos); - debugfs_use_file_finish(srcu_idx); + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_read(file, buf, len, ppos); + debugfs_file_put(dentry); return ret; } EXPORT_SYMBOL_GPL(debugfs_attr_read); @@ -299,13 +337,14 @@ EXPORT_SYMBOL_GPL(debugfs_attr_read); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { + struct dentry *dentry = F_DENTRY(file); ssize_t ret; - int srcu_idx; - ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!ret)) - ret = simple_attr_write(file, buf, len, ppos); - debugfs_use_file_finish(srcu_idx); + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_write(file, buf, len, ppos); + debugfs_file_put(dentry); return ret; } EXPORT_SYMBOL_GPL(debugfs_attr_write); @@ -739,14 +778,14 @@ ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, { char buf[3]; bool val; - int r, srcu_idx; + int r; + struct dentry *dentry = F_DENTRY(file); - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - val = *(bool *)file->private_data; - debugfs_use_file_finish(srcu_idx); - if (r) + r = debugfs_file_get(dentry); + if (unlikely(r)) return r; + val = *(bool *)file->private_data; + debugfs_file_put(dentry); if (val) buf[0] = 'Y'; @@ -764,8 +803,9 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, char buf[32]; size_t buf_size; bool bv; - int r, srcu_idx; + int r; bool *val = file->private_data; + struct dentry *dentry = F_DENTRY(file); buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -773,12 +813,11 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, buf[buf_size] = '\0'; if (strtobool(buf, &bv) == 0) { - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - *val = bv; - debugfs_use_file_finish(srcu_idx); - if (r) + r = debugfs_file_get(dentry); + if (unlikely(r)) return r; + *val = bv; + debugfs_file_put(dentry); } return count; @@ -840,14 +879,15 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct debugfs_blob_wrapper *blob = file->private_data; + struct dentry *dentry = F_DENTRY(file); ssize_t r; - int srcu_idx; - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - r = simple_read_from_buffer(user_buf, count, ppos, blob->data, - blob->size); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(dentry); + if (unlikely(r)) + return r; + r = simple_read_from_buffer(user_buf, count, ppos, blob->data, + blob->size); + debugfs_file_put(dentry); return r; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index c59f015f386eba1e58b4cba397e1b4910e62ace9..9dca4da059b322fdb42e611999b4a507cc974bf1 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -27,14 +27,11 @@ #include #include #include -#include #include "internal.h" #define DEBUGFS_DEFAULT_MODE 0700 -DEFINE_SRCU(debugfs_srcu); - static struct vfsmount *debugfs_mount; static int debugfs_mount_count; static bool debugfs_registered; @@ -185,6 +182,14 @@ static const struct super_operations debugfs_super_operations = { .evict_inode = debugfs_evict_inode, }; +static void debugfs_release_dentry(struct dentry *dentry) +{ + void *fsd = dentry->d_fsdata; + + if (!((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) + kfree(dentry->d_fsdata); +} + static struct vfsmount *debugfs_automount(struct path *path) { debugfs_automount_t f; @@ -194,6 +199,7 @@ static struct vfsmount *debugfs_automount(struct path *path) static const struct dentry_operations debugfs_dops = { .d_delete = always_delete_dentry, + .d_release = debugfs_release_dentry, .d_automount = debugfs_automount, }; @@ -358,7 +364,8 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, inode->i_private = data; inode->i_fop = proxy_fops; - dentry->d_fsdata = (void *)real_fops; + dentry->d_fsdata = (void *)((unsigned long)real_fops | + DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); @@ -615,18 +622,43 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, } EXPORT_SYMBOL_GPL(debugfs_create_symlink); +static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent) +{ + struct debugfs_fsdata *fsd; + + simple_unlink(d_inode(parent), dentry); + d_delete(dentry); + + /* + * Paired with the closing smp_mb() implied by a successful + * cmpxchg() in debugfs_file_get(): either + * debugfs_file_get() must see a dead dentry or we must see a + * debugfs_fsdata instance at ->d_fsdata here (or both). + */ + smp_mb(); + fsd = READ_ONCE(dentry->d_fsdata); + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) + return; + if (!refcount_dec_and_test(&fsd->active_users)) + wait_for_completion(&fsd->active_users_drained); +} + static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; if (simple_positive(dentry)) { dget(dentry); - if (d_is_dir(dentry)) - ret = simple_rmdir(d_inode(parent), dentry); - else - simple_unlink(d_inode(parent), dentry); - if (!ret) - d_delete(dentry); + if (!d_is_reg(dentry)) { + if (d_is_dir(dentry)) + ret = simple_rmdir(d_inode(parent), dentry); + else + simple_unlink(d_inode(parent), dentry); + if (!ret) + d_delete(dentry); + } else { + __debugfs_remove_file(dentry, parent); + } dput(dentry); } return ret; @@ -660,8 +692,6 @@ void debugfs_remove(struct dentry *dentry) inode_unlock(d_inode(parent)); if (!ret) simple_release_fs(&debugfs_mount, &debugfs_mount_count); - - synchronize_srcu(&debugfs_srcu); } EXPORT_SYMBOL_GPL(debugfs_remove); @@ -735,8 +765,6 @@ void debugfs_remove_recursive(struct dentry *dentry) if (!__debugfs_remove(child, parent)) simple_release_fs(&debugfs_mount, &debugfs_mount_count); inode_unlock(d_inode(parent)); - - synchronize_srcu(&debugfs_srcu); } EXPORT_SYMBOL_GPL(debugfs_remove_recursive); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index b3e8443a1f478dd9884aa5ae830260ff1adce9e5..cb1e8139c398f141b0692da3062c45396fde8e21 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -19,4 +19,18 @@ extern const struct file_operations debugfs_noop_file_operations; extern const struct file_operations debugfs_open_proxy_file_operations; extern const struct file_operations debugfs_full_proxy_file_operations; +struct debugfs_fsdata { + const struct file_operations *real_fops; + refcount_t active_users; + struct completion active_users_drained; +}; + +/* + * A dentry's ->d_fsdata either points to the real fops or to a + * dynamically allocated debugfs_fsdata instance. + * In order to distinguish between these two cases, a real fops + * pointer gets its lowest bit set. + */ +#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0) + #endif /* _DEBUGFS_INTERNAL_H_ */ diff --git a/fs/direct-io.c b/fs/direct-io.c index 96a103249a0b21981fc89316394d0443f576e157..c03813a80a349f7a0f88059d64fcc88e158ccc2a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -473,10 +473,9 @@ struct inode *dio_bio_get_inode(struct bio *bio) return NULL; inode = bio->bi_dio_inode; - return inode; } -EXPORT_SYMBOL(dio_bio_get_inode); + /* * Release any resources in case of a failure */ diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 7cf69c14f796b436e0366882bdbad5aabeddf502..8fdfcd3c3e04373b913a6f3bf54807286dfebc0b 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -2,7 +2,6 @@ # # Makefile for the linux ext4-filesystem routines. # -ccflags-y += -Ifs/crypto obj-$(CONFIG_EXT4_FS) += ext4.o diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 9c9eafd6bd7659f79a5ed59a64c0c452448a14cd..70266a3355dc320ef141c4c2b225b5a3e9211003 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -379,6 +379,8 @@ static int ext4_validate_block_bitmap(struct super_block *sb, return -EFSCORRUPTED; ext4_lock_group(sb, block_group); + if (buffer_verified(bh)) + goto verified; if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, desc, bh))) { ext4_unlock_group(sb, block_group); @@ -401,6 +403,7 @@ static int ext4_validate_block_bitmap(struct super_block *sb, return -EFSCORRUPTED; } set_buffer_verified(bh); +verified: ext4_unlock_group(sb, block_group); return 0; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2dd8c7e0f298298c1da0cb93ee223a46262918fc..69e83cf4c69936a7668b9662d5093f67965a3f43 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -40,9 +40,7 @@ #include #endif -#ifndef __FS_HAS_ENCRYPTION #define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION) -#endif #include /* @@ -2352,7 +2350,6 @@ static inline int ext4_fname_setup_filename(struct inode *dir, } static inline void ext4_fname_free_filename(struct ext4_filename *fname) { } -#define fscrypt_set_d_op(i) #endif /* dir.c */ diff --git a/fs/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h deleted file mode 100644 index b0149dd7bad4100492107a4ea8073d58d1b41b0f..0000000000000000000000000000000000000000 --- a/fs/ext4/ext4_ice.h +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _EXT4_ICE_H -#define _EXT4_ICE_H - -#include "ext4.h" -#include - -#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - if (!ext4_encrypted_inode((struct inode *)inode)) - return 0; - - return fs_using_hardware_encryption((struct inode *)inode); -} - -static inline int ext4_is_ice_enabled(void) -{ - return 1; -} - -int ext4_is_aes_xts_cipher(const struct inode *inode); - -char *ext4_get_ice_encryption_key(const struct inode *inode); -char *ext4_get_ice_encryption_salt(const struct inode *inode); - -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2); - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return FS_AES_256_XTS_KEY_SIZE / 2; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return FS_AES_256_XTS_KEY_SIZE / 2; -} - -#else -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - return 0; -} -static inline int ext4_is_ice_enabled(void) -{ - return 0; -} - -static inline char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - return NULL; -} - -static inline char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - return NULL; -} - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return 0; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_xts_cipher(const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_ice_encryption_info_equal( - const struct inode *inode1, - const struct inode *inode2) -{ - return 0; -} - -static inline int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - return 0; -} - -#endif - -#endif /* _EXT4_ICE_H */ diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 8ee65447898719820d920e91605d2004221c86f1..2f46564d3fca98c228522fa97b2ff0336483677a 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -91,6 +91,8 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, return -EFSCORRUPTED; ext4_lock_group(sb, block_group); + if (buffer_verified(bh)) + goto verified; blk = ext4_inode_bitmap(sb, desc); if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh, EXT4_INODES_PER_GROUP(sb) / 8)) { @@ -108,6 +110,7 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, return -EFSBADCRC; } set_buffer_verified(bh); +verified: ext4_unlock_group(sb, block_group); return 0; } diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 29ed8dc155c09bf0cc6701304d594fe64eee3a59..a2deb66b1a6a8c76db4c965f0a51484411380ae3 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -702,6 +702,10 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, goto convert; } + ret = ext4_journal_get_write_access(handle, iloc.bh); + if (ret) + goto out; + flags |= AOP_FLAG_NOFS; page = grab_cache_page_write_begin(mapping, 0, flags); @@ -730,7 +734,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, out_up_read: up_read(&EXT4_I(inode)->xattr_sem); out: - if (handle) + if (handle && (ret != 1)) ext4_journal_stop(handle); brelse(iloc.bh); return ret; @@ -772,6 +776,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, ext4_write_unlock_xattr(inode, &no_expand); brelse(iloc.bh); + mark_inode_dirty(inode); out: return copied; } @@ -918,7 +923,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, goto out; } - page = grab_cache_page_write_begin(mapping, 0, flags); if (!page) { ret = -ENOMEM; @@ -936,6 +940,9 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, if (ret < 0) goto out_release_page; } + ret = ext4_journal_get_write_access(handle, iloc.bh); + if (ret) + goto out_release_page; up_read(&EXT4_I(inode)->xattr_sem); *pagep = page; @@ -956,7 +963,6 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, unsigned copied, struct page *page) { - int i_size_changed = 0; int ret; ret = ext4_write_inline_data_end(inode, pos, len, copied, page); @@ -974,10 +980,8 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, * But it's important to update i_size while still holding page lock: * page writeout could otherwise come in and zero beyond i_size. */ - if (pos+copied > inode->i_size) { + if (pos+copied > inode->i_size) i_size_write(inode, pos+copied); - i_size_changed = 1; - } unlock_page(page); put_page(page); @@ -987,8 +991,7 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, * ordering of page lock and transaction start for journaling * filesystems. */ - if (i_size_changed) - mark_inode_dirty(inode); + mark_inode_dirty(inode); return copied; } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2764b4d1ce32a483772665b9b8f2085993e38e30..332d0224f595f52339522bc4a90c77bdc7e2ab81 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -44,7 +44,6 @@ #include "xattr.h" #include "acl.h" #include "truncate.h" -#include "ext4_ice.h" #include #include @@ -1220,7 +1219,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) && - !ext4_should_be_processed_by_ice(inode); + !fscrypt_using_hardware_encryption(inode); } } /* @@ -1401,10 +1400,11 @@ static int ext4_write_end(struct file *file, loff_t old_size = inode->i_size; int ret = 0, ret2; int i_size_changed = 0; + int inline_data = ext4_has_inline_data(inode); trace_android_fs_datawrite_end(inode, pos, len); trace_ext4_write_end(inode, pos, len, copied); - if (ext4_has_inline_data(inode)) { + if (inline_data) { ret = ext4_write_inline_data_end(inode, pos, len, copied, page); if (ret < 0) { @@ -1432,7 +1432,7 @@ static int ext4_write_end(struct file *file, * ordering of page lock and transaction start for journaling * filesystems. */ - if (i_size_changed) + if (i_size_changed || inline_data) ext4_mark_inode_dirty(handle, inode); if (pos + len > inode->i_size && ext4_can_truncate(inode)) @@ -1506,6 +1506,7 @@ static int ext4_journalled_write_end(struct file *file, int partial = 0; unsigned from, to; int size_changed = 0; + int inline_data = ext4_has_inline_data(inode); trace_android_fs_datawrite_end(inode, pos, len); trace_ext4_journalled_write_end(inode, pos, len, copied); @@ -1514,7 +1515,7 @@ static int ext4_journalled_write_end(struct file *file, BUG_ON(!ext4_handle_valid(handle)); - if (ext4_has_inline_data(inode)) { + if (inline_data) { ret = ext4_write_inline_data_end(inode, pos, len, copied, page); if (ret < 0) { @@ -1545,7 +1546,7 @@ static int ext4_journalled_write_end(struct file *file, if (old_size < pos) pagecache_isize_extended(inode, old_size, pos); - if (size_changed) { + if (size_changed || inline_data) { ret2 = ext4_mark_inode_dirty(handle, inode); if (!ret) ret = ret2; @@ -2042,11 +2043,7 @@ static int __ext4_journalled_writepage(struct page *page, } if (inline_data) { - BUFFER_TRACE(inode_bh, "get write access"); - ret = ext4_journal_get_write_access(handle, inode_bh); - - err = ext4_handle_dirty_metadata(handle, inode, inode_bh); - + ret = ext4_mark_inode_dirty(handle, inode); } else { ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, do_journal_get_write_access); @@ -3716,15 +3713,14 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) get_block_func = ext4_dio_get_block_unwritten_async; dio_flags = DIO_LOCKING; } - -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - return 0; +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + WARN_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)); #endif - ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, - get_block_func, ext4_end_io_dio, NULL, - dio_flags); + ret = __blockdev_direct_IO(iocb, inode, + inode->i_sb->s_bdev, iter, + get_block_func, + ext4_end_io_dio, NULL, dio_flags); if (ret > 0 && !overwrite && ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN)) { @@ -3830,9 +3826,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)) return 0; #endif @@ -4042,7 +4038,7 @@ static int __ext4_block_zero_page_range(handle_t *handle, goto unlock; if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode) && - !ext4_should_be_processed_by_ice(inode)) { + !fscrypt_using_hardware_encryption(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 53bd5d893a586815eedc647224d10d8d8acbfa34..1eb68e62693132a264005b6db50513497a2abe82 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -939,13 +939,11 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case EXT4_IOC_PRECACHE_EXTENTS: return ext4_ext_precache(inode); - case EXT4_IOC_SET_ENCRYPTION_POLICY: { -#ifdef CONFIG_EXT4_FS_ENCRYPTION + case EXT4_IOC_SET_ENCRYPTION_POLICY: + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); -#else - return -EOPNOTSUPP; -#endif - } + case EXT4_IOC_GET_ENCRYPTION_PWSALT: { #ifdef CONFIG_EXT4_FS_ENCRYPTION int err, err2; diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index bc475426f0c3c6af26e609c6b54510608dbc6d89..11566757db265c0763d8478b675337a718e4f2a9 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -29,7 +29,6 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" -#include "ext4_ice.h" static struct kmem_cache *io_end_cachep; @@ -483,9 +482,9 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: - if (!ext4_should_be_processed_by_ice(inode)) - data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, - 0, page->index, gfp_flags); + if (!fscrypt_using_hardware_encryption(inode)) + data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, + page->index, gfp_flags); if (IS_ERR(data_page)) { ret = PTR_ERR(data_page); if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 84a038a6f604c18153389df094f8299a81fc85eb..5951e6316ead377640a7dde1062ad2a0cd190c8c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1235,6 +1235,11 @@ static unsigned ext4_max_namelen(struct inode *inode) EXT4_NAME_LEN; } +static inline bool ext4_is_encrypted(struct inode *inode) +{ + return ext4_encrypted_inode(inode); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1242,6 +1247,7 @@ static const struct fscrypt_operations ext4_cryptops = { .dummy_context = ext4_dummy_context, .empty_dir = ext4_empty_dir, .max_namelen = ext4_max_namelen, + .is_encrypted = ext4_is_encrypted, }; #endif @@ -2298,7 +2304,7 @@ static int ext4_check_descriptors(struct super_block *sb, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext4_fsblk_t last_block; - ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0) + 1; + ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0); ext4_fsblk_t block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; @@ -4035,13 +4041,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount2; } } + sbi->s_gdb_count = db_count; if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); ret = -EFSCORRUPTED; goto failed_mount2; } - sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c9db73e498a6a0b3ccff569bf8a04d1d20c09b1d..d503bdfd3c57801d8b88d4a20e53083532fe3cda 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -439,6 +439,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) struct bio *bio; struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + struct inode *inode = fio->page->mapping->host; verify_block_addr(fio, fio->new_blkaddr); trace_f2fs_submit_page_bio(page, fio); @@ -448,6 +449,10 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc, 1, is_read_io(fio->op), fio->type, fio->temp); + if (f2fs_may_encrypt_bio(inode, fio)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page)); + fscrypt_set_ice_skip(bio, fio->encrypted_page ? 1 : 0); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -467,6 +472,10 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; struct page *bio_page; + struct inode *inode; + bool bio_encrypted; + int bi_crypt_skip; + u64 dun; int err = 0; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -490,6 +499,10 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) verify_block_addr(fio, fio->new_blkaddr); bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; + inode = fio->page->mapping->host; + dun = PG_DUN(inode, fio->page); + bi_crypt_skip = fio->encrypted_page ? 1 : 0; + bio_encrypted = f2fs_may_encrypt_bio(inode, fio); /* set submitted = true as a return value */ fio->submitted = true; @@ -500,6 +513,11 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) || !__same_bdev(sbi, fio->new_blkaddr, io->bio))) __submit_merged_bio(io); + + /* ICE support */ + if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted, bi_crypt_skip)) + __submit_merged_bio(io); + alloc_new: if (io->bio == NULL) { if ((fio->type == DATA || fio->type == NODE) && @@ -511,6 +529,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc, BIO_MAX_PAGES, false, fio->type, fio->temp); + if (bio_encrypted) + fscrypt_set_ice_dun(inode, io->bio, dun); + fscrypt_set_ice_skip(io->bio, bi_crypt_skip); io->fio = *fio; } @@ -577,6 +598,9 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, if (IS_ERR(bio)) return PTR_ERR(bio); + if (f2fs_may_encrypt_bio(inode, NULL)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -1436,6 +1460,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, sector_t last_block_in_file; sector_t block_nr; struct f2fs_map_blocks map; + bool bio_encrypted; + u64 dun; map.m_pblk = 0; map.m_lblk = 0; @@ -1513,6 +1539,14 @@ static int f2fs_mpage_readpages(struct address_space *mapping, __submit_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } + + dun = PG_DUN(inode, page); + bio_encrypted = f2fs_may_encrypt_bio(inode, NULL); + if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted, 0)) { + __submit_bio(F2FS_I_SB(inode), bio, DATA); + bio = NULL; + } + if (bio == NULL) { bio = f2fs_grab_read_bio(inode, block_nr, nr_pages); if (IS_ERR(bio)) { @@ -1520,7 +1554,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, goto set_error_page; } } - + if (bio_encrypted) + fscrypt_set_ice_dun(inode, bio, dun); if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; @@ -1590,6 +1625,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio) f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); retry_encrypt: + if (fscrypt_using_hardware_encryption(inode)) + return 0; + fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, PAGE_SIZE, 0, fio->page->index, gfp_flags); if (!IS_ERR(fio->encrypted_page)) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index bc633925d7b7ffccd63f678ae399040911202aeb..5895204c39d1141460557edf236a9c684cd07c09 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3279,9 +3279,20 @@ static inline bool f2fs_may_encrypt(struct inode *inode) static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) { - return (f2fs_post_read_required(inode) || + return ((f2fs_post_read_required(inode) && + !fscrypt_using_hardware_encryption(inode)) || (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || F2FS_I_SB(inode)->s_ndevs); } +static inline bool f2fs_may_encrypt_bio(struct inode *inode, + struct f2fs_io_info *fio) +{ + if (fio && (fio->type != DATA || fio->encrypted_page)) + return false; + + return (f2fs_encrypted_file(inode) && + fscrypt_using_hardware_encryption(inode)); +} + #endif diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ed72fc2cc68de5fda4430da920114a0dd27b35a6..490f8afed2ce91d98ac5b9e76d1b2bee2dcd498f 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1669,6 +1669,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) inode_lock(inode); + down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); + if (f2fs_is_atomic_file(inode)) goto out; @@ -1698,6 +1700,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) stat_inc_atomic_write(inode); stat_update_max_atomic_write(inode); out: + up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); inode_unlock(inode); mnt_drop_write_file(filp); return ret; @@ -1850,9 +1853,11 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) if (get_user(in, (__u32 __user *)arg)) return -EFAULT; - ret = mnt_want_write_file(filp); - if (ret) - return ret; + if (in != F2FS_GOING_DOWN_FULLSYNC) { + ret = mnt_want_write_file(filp); + if (ret) + return ret; + } switch (in) { case F2FS_GOING_DOWN_FULLSYNC: @@ -1893,7 +1898,8 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) f2fs_update_time(sbi, REQ_TIME); out: - mnt_drop_write_file(filp); + if (in != F2FS_GOING_DOWN_FULLSYNC) + mnt_drop_write_file(filp); return ret; } @@ -2567,7 +2573,9 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) } f2fs_put_page(ipage, 1); - dquot_initialize(inode); + err = dquot_initialize(inode); + if (err) + goto out_unlock; transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); if (!IS_ERR(transfer_to[PRJQUOTA])) { diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 66044faf2b71c552118d390affd272c334083a5e..aede4ed719b69b549abf999778c18ccfab7fb977 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -779,9 +779,14 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, set_cold_data(page); err = do_write_data_page(&fio); - if (err == -ENOMEM && is_dirty) { - congestion_wait(BLK_RW_ASYNC, HZ/50); - goto retry; + if (err) { + clear_cold_data(page); + if (err == -ENOMEM) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry; + } + if (is_dirty) + set_page_dirty(page); } } out: diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index b1e58b10425fe0f2deaa20ec552cff35792f3494..40ae4a9216f820a2391de09eba77527d9a37694c 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -230,6 +230,8 @@ static int __revoke_inmem_pages(struct inode *inode, lock_page(page); + f2fs_wait_on_page_writeback(page, DATA, true); + if (recover) { struct dnode_of_data dn; struct node_info ni; @@ -478,6 +480,9 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) { + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + return; + /* try to shrink extent cache when there is no enough memory */ if (!available_free_memory(sbi, EXTENT_CACHE)) f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2b79c1a7a2f2a020e52c1274734712501dfdf2a0..2191aa5757e26081da00623050ac4b9c59d0a510 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1940,6 +1940,11 @@ static unsigned f2fs_max_namelen(struct inode *inode) inode->i_sb->s_blocksize : F2FS_NAME_LEN; } +static inline bool f2fs_is_encrypted(struct inode *inode) +{ + return f2fs_encrypted_file(inode); +} + static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, @@ -1947,6 +1952,7 @@ static const struct fscrypt_operations f2fs_cryptops = { .dummy_context = f2fs_dummy_context, .empty_dir = f2fs_empty_dir, .max_namelen = f2fs_max_namelen, + .is_encrypted = f2fs_is_encrypted, }; #endif @@ -3067,6 +3073,12 @@ static int __init init_f2fs_fs(void) { int err; + if (PAGE_SIZE != F2FS_BLKSIZE) { + printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n", + PAGE_SIZE, F2FS_BLKSIZE); + return -EINVAL; + } + f2fs_build_trace_ios(); err = init_inodecache(); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index c7a4dee206b9023eecb13da5e7f8adeb9471e2d8..3b40937b942a428c45907daf945c16b662e694c9 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -696,13 +696,21 @@ static void fat_set_state(struct super_block *sb, brelse(bh); } +static void fat_reset_iocharset(struct fat_mount_options *opts) +{ + if (opts->iocharset != fat_default_iocharset) { + /* Note: opts->iocharset can be NULL here */ + kfree(opts->iocharset); + opts->iocharset = fat_default_iocharset; + } +} + static void delayed_free(struct rcu_head *p) { struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu); unload_nls(sbi->nls_disk); unload_nls(sbi->nls_io); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); + fat_reset_iocharset(&sbi->options); kfree(sbi); } @@ -1117,7 +1125,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, opts->fs_fmask = opts->fs_dmask = current_umask(); opts->allow_utime = -1; opts->codepage = fat_default_codepage; - opts->iocharset = fat_default_iocharset; + fat_reset_iocharset(opts); if (is_vfat) { opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95; opts->rodir = 0; @@ -1274,8 +1282,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, /* vfat specific */ case Opt_charset: - if (opts->iocharset != fat_default_iocharset) - kfree(opts->iocharset); + fat_reset_iocharset(opts); iocharset = match_strdup(&args[0]); if (!iocharset) return -ENOMEM; @@ -1866,8 +1873,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, iput(fat_inode); unload_nls(sbi->nls_io); unload_nls(sbi->nls_disk); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); + fat_reset_iocharset(&sbi->options); sb->s_fs_info = NULL; kfree(sbi); return error; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index c60f3d32ee911192c0cd8dae3b7cb11c0f416411..a6797986b625a34d19e097050c58f582c177c30c 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -491,15 +491,17 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) if (size > PSIZE) { /* * To keep the rest of the code simple. Allocate a - * contiguous buffer to work with + * contiguous buffer to work with. Make the buffer large + * enough to make use of the whole extent. */ - ea_buf->xattr = kmalloc(size, GFP_KERNEL); + ea_buf->max_size = (size + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + + ea_buf->xattr = kmalloc(ea_buf->max_size, GFP_KERNEL); if (ea_buf->xattr == NULL) return -ENOMEM; ea_buf->flag = EA_MALLOC; - ea_buf->max_size = (size + sb->s_blocksize - 1) & - ~(sb->s_blocksize - 1); if (ea_size == 0) return 0; diff --git a/fs/namei.c b/fs/namei.c index 055c6c40901b6b6d03de187d0f92bafb4a565c76..d3650e50a6ed8a985c3348040ffae071fb01f592 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3742,11 +3742,9 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u error = dir->i_op->mknod(dir, dentry, mode, dev); if (error) return error; - error = security_inode_post_create(dir, dentry, mode); if (error) return error; - if (!error) fsnotify_create(dir, dentry); return error; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 928bbc397818ad252eb64e4ceadbe9464d57ca97..43fbf44950904a1cc448e413f8ff06b63ce782fd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -745,6 +745,13 @@ static int nfs41_sequence_process(struct rpc_task *task, slot->slot_nr, slot->seq_nr); goto out_retry; + case -NFS4ERR_RETRY_UNCACHED_REP: + case -NFS4ERR_SEQ_FALSE_RETRY: + /* + * The server thinks we tried to replay a request. + * Retry the call after bumping the sequence ID. + */ + goto retry_new_seq; case -NFS4ERR_BADSLOT: /* * The slot id we used was probably retired. Try again @@ -769,10 +776,6 @@ static int nfs41_sequence_process(struct rpc_task *task, goto retry_nowait; } goto session_recover; - case -NFS4ERR_SEQ_FALSE_RETRY: - if (interrupted) - goto retry_new_seq; - goto session_recover; default: /* Just update the slot sequence no. */ slot->seq_done = 1; @@ -2692,7 +2695,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, if (ret != 0) goto out; - state = nfs4_opendata_to_nfs4_state(opendata); + state = _nfs4_opendata_to_nfs4_state(opendata); ret = PTR_ERR(state); if (IS_ERR(state)) goto out; @@ -2728,6 +2731,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, nfs4_schedule_stateid_recovery(server, state); } out: + nfs4_sequence_free_slot(&opendata->o_res.seq_res); return ret; } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7b34534210ce7131987a0e4834c6f5ab463de377..96867fb159bf71b82a92e9ee41678e41d3ebfac9 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1126,7 +1126,7 @@ _pnfs_return_layout(struct inode *ino) LIST_HEAD(tmp_list); nfs4_stateid stateid; int status = 0; - bool send; + bool send, valid_layout; dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino); @@ -1147,6 +1147,7 @@ _pnfs_return_layout(struct inode *ino) goto out_put_layout_hdr; spin_lock(&ino->i_lock); } + valid_layout = pnfs_layout_is_valid(lo); pnfs_clear_layoutcommit(ino, &tmp_list); pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL, 0); @@ -1160,7 +1161,8 @@ _pnfs_return_layout(struct inode *ino) } /* Don't send a LAYOUTRETURN if list was initially empty */ - if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) { + if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) || + !valid_layout) { spin_unlock(&ino->i_lock); dprintk("NFS: %s no layout segments to return\n", __func__); goto out_put_layout_hdr; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f6588cc6816c885ff8625ba33db318a85cdbe0b1..c1e92333401206dcb15a88de849de8edf75a492d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1586,6 +1586,8 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, gdev->gd_maxcount = be32_to_cpup(p++); num = be32_to_cpup(p++); if (num) { + if (num > 1000) + goto xdr_error; READ_BUF(4 * num); gdev->gd_notify_types = be32_to_cpup(p++); for (i = 1; i < num; i++) { diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 88a31e9340a0fb8c658a48b764e66b0926345848..d1516327b7875c9ce3e948c66a6620d9b5b8d5da 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -134,6 +134,19 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, return err; } +static int ocfs2_lock_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + int ret = 0; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + + down_read(&oi->ip_alloc_sem); + ret = ocfs2_get_block(inode, iblock, bh_result, create); + up_read(&oi->ip_alloc_sem); + + return ret; +} + int ocfs2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { @@ -2128,7 +2141,7 @@ static void ocfs2_dio_free_write_ctx(struct inode *inode, * called like this: dio->get_blocks(dio->inode, fs_startblk, * fs_count, map_bh, dio->rw == WRITE); */ -static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock, +static int ocfs2_dio_wr_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); @@ -2154,12 +2167,9 @@ static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock, * while file size will be changed. */ if (pos + total_len <= i_size_read(inode)) { - down_read(&oi->ip_alloc_sem); - /* This is the fast path for re-write. */ - ret = ocfs2_get_block(inode, iblock, bh_result, create); - - up_read(&oi->ip_alloc_sem); + /* This is the fast path for re-write. */ + ret = ocfs2_lock_get_block(inode, iblock, bh_result, create); if (buffer_mapped(bh_result) && !buffer_new(bh_result) && ret == 0) @@ -2424,9 +2434,9 @@ static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter) return 0; if (iov_iter_rw(iter) == READ) - get_block = ocfs2_get_block; + get_block = ocfs2_lock_get_block; else - get_block = ocfs2_dio_get_block; + get_block = ocfs2_dio_wr_get_block; return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, get_block, diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index b17d180bdc163544f05b341d98fe79e95ad5c582..c204ac9b49e5cd5c7f119c606a69a725025752dc 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -40,6 +40,9 @@ char *o2nm_fence_method_desc[O2NM_FENCE_METHODS] = { "panic", /* O2NM_FENCE_PANIC */ }; +static inline void o2nm_lock_subsystem(void); +static inline void o2nm_unlock_subsystem(void); + struct o2nm_node *o2nm_get_node_by_num(u8 node_num) { struct o2nm_node *node = NULL; @@ -181,7 +184,10 @@ static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node) { /* through the first node_set .parent * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */ - return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent); + if (node->nd_item.ci_parent) + return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent); + else + return NULL; } enum { @@ -194,7 +200,7 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page, size_t count) { struct o2nm_node *node = to_o2nm_node(item); - struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node); + struct o2nm_cluster *cluster; unsigned long tmp; char *p = (char *)page; int ret = 0; @@ -214,6 +220,13 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page, !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes)) return -EINVAL; /* XXX */ + o2nm_lock_subsystem(); + cluster = to_o2nm_cluster_from_node(node); + if (!cluster) { + o2nm_unlock_subsystem(); + return -EINVAL; + } + write_lock(&cluster->cl_nodes_lock); if (cluster->cl_nodes[tmp]) ret = -EEXIST; @@ -226,6 +239,8 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page, set_bit(tmp, cluster->cl_nodes_bitmap); } write_unlock(&cluster->cl_nodes_lock); + o2nm_unlock_subsystem(); + if (ret) return ret; @@ -269,7 +284,7 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item, size_t count) { struct o2nm_node *node = to_o2nm_node(item); - struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node); + struct o2nm_cluster *cluster; int ret, i; struct rb_node **p, *parent; unsigned int octets[4]; @@ -286,6 +301,13 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item, be32_add_cpu(&ipv4_addr, octets[i] << (i * 8)); } + o2nm_lock_subsystem(); + cluster = to_o2nm_cluster_from_node(node); + if (!cluster) { + o2nm_unlock_subsystem(); + return -EINVAL; + } + ret = 0; write_lock(&cluster->cl_nodes_lock); if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent)) @@ -298,6 +320,8 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item, rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree); } write_unlock(&cluster->cl_nodes_lock); + o2nm_unlock_subsystem(); + if (ret) return ret; @@ -315,7 +339,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, size_t count) { struct o2nm_node *node = to_o2nm_node(item); - struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node); + struct o2nm_cluster *cluster; unsigned long tmp; char *p = (char *)page; ssize_t ret; @@ -333,17 +357,26 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes)) return -EINVAL; /* XXX */ + o2nm_lock_subsystem(); + cluster = to_o2nm_cluster_from_node(node); + if (!cluster) { + ret = -EINVAL; + goto out; + } + /* the only failure case is trying to set a new local node * when a different one is already set */ if (tmp && tmp == cluster->cl_has_local && - cluster->cl_local_node != node->nd_num) - return -EBUSY; + cluster->cl_local_node != node->nd_num) { + ret = -EBUSY; + goto out; + } /* bring up the rx thread if we're setting the new local node. */ if (tmp && !cluster->cl_has_local) { ret = o2net_start_listening(node); if (ret) - return ret; + goto out; } if (!tmp && cluster->cl_has_local && @@ -358,7 +391,11 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, cluster->cl_local_node = node->nd_num; } - return count; + ret = count; + +out: + o2nm_unlock_subsystem(); + return ret; } CONFIGFS_ATTR(o2nm_node_, num); @@ -738,6 +775,16 @@ static struct o2nm_cluster_group o2nm_cluster_group = { }, }; +static inline void o2nm_lock_subsystem(void) +{ + mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex); +} + +static inline void o2nm_unlock_subsystem(void) +{ + mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex); +} + int o2nm_depend_item(struct config_item *item) { return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index b8f8d666e8d45b0a03fa00513ca910d56df59baa..ba20393d60efc725f41af10ec30ba63fad581f01 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -232,6 +232,7 @@ static void ovl_put_super(struct super_block *sb) kfree(ufs); } +/* Sync real dirty inodes in upper filesystem (if it exists) */ static int ovl_sync_fs(struct super_block *sb, int wait) { struct ovl_fs *ufs = sb->s_fs_info; @@ -240,14 +241,24 @@ static int ovl_sync_fs(struct super_block *sb, int wait) if (!ufs->upper_mnt) return 0; - upper_sb = ufs->upper_mnt->mnt_sb; - if (!upper_sb->s_op->sync_fs) + + /* + * If this is a sync(2) call or an emergency sync, all the super blocks + * will be iterated, including upper_sb, so no need to do anything. + * + * If this is a syncfs(2) call, then we do need to call + * sync_filesystem() on upper_sb, but enough if we do it when being + * called with wait == 1. + */ + if (!wait) return 0; - /* real inodes have already been synced by sync_filesystem(ovl_sb) */ + upper_sb = ufs->upper_mnt->mnt_sb; + down_read(&upper_sb->s_umount); - ret = upper_sb->s_op->sync_fs(upper_sb, wait); + ret = sync_filesystem(upper_sb); up_read(&upper_sb->s_umount); + return ret; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index c18dda53afefddbbf197d0a5e9208490479c83b9..ca443a232de4bcb12b2a2d53670477d30dbc9df8 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1348,8 +1348,9 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, if (pte_swp_soft_dirty(pte)) flags |= PM_SOFT_DIRTY; entry = pte_to_swp_entry(pte); - frame = swp_type(entry) | - (swp_offset(entry) << MAX_SWAPFILES_SHIFT); + if (pm->show_pfn) + frame = swp_type(entry) | + (swp_offset(entry) << MAX_SWAPFILES_SHIFT); flags |= PM_SWAP; if (is_migration_entry(entry)) page = migration_entry_to_page(entry); @@ -1400,11 +1401,14 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION else if (is_swap_pmd(pmd)) { swp_entry_t entry = pmd_to_swp_entry(pmd); - unsigned long offset = swp_offset(entry); + unsigned long offset; - offset += (addr & ~PMD_MASK) >> PAGE_SHIFT; - frame = swp_type(entry) | - (offset << MAX_SWAPFILES_SHIFT); + if (pm->show_pfn) { + offset = swp_offset(entry) + + ((addr & ~PMD_MASK) >> PAGE_SHIFT); + frame = swp_type(entry) | + (offset << MAX_SWAPFILES_SHIFT); + } flags |= PM_SWAP; if (pmd_swp_soft_dirty(pmd)) flags |= PM_SOFT_DIRTY; @@ -1422,10 +1426,12 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, err = add_to_pagemap(addr, &pme, pm); if (err) break; - if (pm->show_pfn && (flags & PM_PRESENT)) - frame++; - else if (flags & PM_SWAP) - frame += (1 << MAX_SWAPFILES_SHIFT); + if (pm->show_pfn) { + if (flags & PM_PRESENT) + frame++; + else if (flags & PM_SWAP) + frame += (1 << MAX_SWAPFILES_SHIFT); + } } spin_unlock(ptl); return err; diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 64f49cafbc5bff7b7c34786e56851408f4f20b55..cfb0c9ac2de430494e8c4609bb04aeb2a7c65027 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -76,83 +76,99 @@ static char *le_type(struct reiserfs_key *key) } /* %k */ -static void sprintf_le_key(char *buf, struct reiserfs_key *key) +static int scnprintf_le_key(char *buf, size_t size, struct reiserfs_key *key) { if (key) - sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id), - le32_to_cpu(key->k_objectid), le_offset(key), - le_type(key)); + return scnprintf(buf, size, "[%d %d %s %s]", + le32_to_cpu(key->k_dir_id), + le32_to_cpu(key->k_objectid), le_offset(key), + le_type(key)); else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } /* %K */ -static void sprintf_cpu_key(char *buf, struct cpu_key *key) +static int scnprintf_cpu_key(char *buf, size_t size, struct cpu_key *key) { if (key) - sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id, - key->on_disk_key.k_objectid, reiserfs_cpu_offset(key), - cpu_type(key)); + return scnprintf(buf, size, "[%d %d %s %s]", + key->on_disk_key.k_dir_id, + key->on_disk_key.k_objectid, + reiserfs_cpu_offset(key), cpu_type(key)); else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } -static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh) +static int scnprintf_de_head(char *buf, size_t size, + struct reiserfs_de_head *deh) { if (deh) - sprintf(buf, - "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", - deh_offset(deh), deh_dir_id(deh), deh_objectid(deh), - deh_location(deh), deh_state(deh)); + return scnprintf(buf, size, + "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", + deh_offset(deh), deh_dir_id(deh), + deh_objectid(deh), deh_location(deh), + deh_state(deh)); else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } -static void sprintf_item_head(char *buf, struct item_head *ih) +static int scnprintf_item_head(char *buf, size_t size, struct item_head *ih) { if (ih) { - strcpy(buf, - (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*"); - sprintf_le_key(buf + strlen(buf), &(ih->ih_key)); - sprintf(buf + strlen(buf), ", item_len %d, item_location %d, " - "free_space(entry_count) %d", - ih_item_len(ih), ih_location(ih), ih_free_space(ih)); + char *p = buf; + char * const end = buf + size; + + p += scnprintf(p, end - p, "%s", + (ih_version(ih) == KEY_FORMAT_3_6) ? + "*3.6* " : "*3.5*"); + + p += scnprintf_le_key(p, end - p, &ih->ih_key); + + p += scnprintf(p, end - p, + ", item_len %d, item_location %d, free_space(entry_count) %d", + ih_item_len(ih), ih_location(ih), + ih_free_space(ih)); + return p - buf; } else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } -static void sprintf_direntry(char *buf, struct reiserfs_dir_entry *de) +static int scnprintf_direntry(char *buf, size_t size, + struct reiserfs_dir_entry *de) { char name[20]; memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen); name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0; - sprintf(buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid); + return scnprintf(buf, size, "\"%s\"==>[%d %d]", + name, de->de_dir_id, de->de_objectid); } -static void sprintf_block_head(char *buf, struct buffer_head *bh) +static int scnprintf_block_head(char *buf, size_t size, struct buffer_head *bh) { - sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ", - B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh)); + return scnprintf(buf, size, + "level=%d, nr_items=%d, free_space=%d rdkey ", + B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh)); } -static void sprintf_buffer_head(char *buf, struct buffer_head *bh) +static int scnprintf_buffer_head(char *buf, size_t size, struct buffer_head *bh) { - sprintf(buf, - "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)", - bh->b_bdev, bh->b_size, - (unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)), - bh->b_state, bh->b_page, - buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE", - buffer_dirty(bh) ? "DIRTY" : "CLEAN", - buffer_locked(bh) ? "LOCKED" : "UNLOCKED"); + return scnprintf(buf, size, + "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)", + bh->b_bdev, bh->b_size, + (unsigned long long)bh->b_blocknr, + atomic_read(&(bh->b_count)), + bh->b_state, bh->b_page, + buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE", + buffer_dirty(bh) ? "DIRTY" : "CLEAN", + buffer_locked(bh) ? "LOCKED" : "UNLOCKED"); } -static void sprintf_disk_child(char *buf, struct disk_child *dc) +static int scnprintf_disk_child(char *buf, size_t size, struct disk_child *dc) { - sprintf(buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc), - dc_size(dc)); + return scnprintf(buf, size, "[dc_number=%d, dc_size=%u]", + dc_block_number(dc), dc_size(dc)); } static char *is_there_reiserfs_struct(char *fmt, int *what) @@ -189,55 +205,60 @@ static void prepare_error_buf(const char *fmt, va_list args) char *fmt1 = fmt_buf; char *k; char *p = error_buf; + char * const end = &error_buf[sizeof(error_buf)]; int what; spin_lock(&error_lock); - strcpy(fmt1, fmt); + if (WARN_ON(strscpy(fmt_buf, fmt, sizeof(fmt_buf)) < 0)) { + strscpy(error_buf, "format string too long", end - error_buf); + goto out_unlock; + } while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) { *k = 0; - p += vsprintf(p, fmt1, args); + p += vscnprintf(p, end - p, fmt1, args); switch (what) { case 'k': - sprintf_le_key(p, va_arg(args, struct reiserfs_key *)); + p += scnprintf_le_key(p, end - p, + va_arg(args, struct reiserfs_key *)); break; case 'K': - sprintf_cpu_key(p, va_arg(args, struct cpu_key *)); + p += scnprintf_cpu_key(p, end - p, + va_arg(args, struct cpu_key *)); break; case 'h': - sprintf_item_head(p, va_arg(args, struct item_head *)); + p += scnprintf_item_head(p, end - p, + va_arg(args, struct item_head *)); break; case 't': - sprintf_direntry(p, - va_arg(args, - struct reiserfs_dir_entry *)); + p += scnprintf_direntry(p, end - p, + va_arg(args, struct reiserfs_dir_entry *)); break; case 'y': - sprintf_disk_child(p, - va_arg(args, struct disk_child *)); + p += scnprintf_disk_child(p, end - p, + va_arg(args, struct disk_child *)); break; case 'z': - sprintf_block_head(p, - va_arg(args, struct buffer_head *)); + p += scnprintf_block_head(p, end - p, + va_arg(args, struct buffer_head *)); break; case 'b': - sprintf_buffer_head(p, - va_arg(args, struct buffer_head *)); + p += scnprintf_buffer_head(p, end - p, + va_arg(args, struct buffer_head *)); break; case 'a': - sprintf_de_head(p, - va_arg(args, - struct reiserfs_de_head *)); + p += scnprintf_de_head(p, end - p, + va_arg(args, struct reiserfs_de_head *)); break; } - p += strlen(p); fmt1 = k + 2; } - vsprintf(p, fmt1, args); + p += vscnprintf(p, end - p, fmt1, args); +out_unlock: spin_unlock(&error_lock); } diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index 05e42441d1065df13838c0fc4af5db085e4c1570..9d9d4aa9a7ba156e9da734de6b3ccbb327aadb9e 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -340,6 +340,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); + if (unlikely(length < 0)) + return -EIO; + while (length) { entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); if (entry->error) { diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index bb2e77ee4209cb38f7f95e06d39c52624e84c0b4..cd3c5c8211a5fc21960ea4fe4a8b249c8ff737a1 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c @@ -195,7 +195,11 @@ static long long read_indexes(struct super_block *sb, int n, } for (i = 0; i < blocks; i++) { - int size = le32_to_cpu(blist[i]); + int size = squashfs_block_size(blist[i]); + if (size < 0) { + err = size; + goto failure; + } block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size); } n -= blocks; @@ -368,7 +372,7 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) sizeof(size)); if (res < 0) return res; - return le32_to_cpu(size); + return squashfs_block_size(size); } /* Copy data into page cache */ diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 0ed6edbc5c7170aa06f191e33df193721206cb3f..0681feab4a8499562ccad42cd53b31f05d5776f3 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -49,11 +49,16 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, u64 *fragment_block) { struct squashfs_sb_info *msblk = sb->s_fs_info; - int block = SQUASHFS_FRAGMENT_INDEX(fragment); - int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); - u64 start_block = le64_to_cpu(msblk->fragment_index[block]); + int block, offset, size; struct squashfs_fragment_entry fragment_entry; - int size; + u64 start_block; + + if (fragment >= msblk->fragments) + return -EIO; + block = SQUASHFS_FRAGMENT_INDEX(fragment); + offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); + + start_block = le64_to_cpu(msblk->fragment_index[block]); size = squashfs_read_metadata(sb, &fragment_entry, &start_block, &offset, sizeof(fragment_entry)); @@ -61,9 +66,7 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, return size; *fragment_block = le64_to_cpu(fragment_entry.start_block); - size = le32_to_cpu(fragment_entry.size); - - return size; + return squashfs_block_size(fragment_entry.size); } diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 24d12fd1417767689778302abf77b21f1efd6350..4e6853f084d071b6291da9891b8a16c730901e48 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -129,6 +129,12 @@ #define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) +static inline int squashfs_block_size(__le32 raw) +{ + u32 size = le32_to_cpu(raw); + return (size >> 25) ? -EIO : size; +} + /* * Inode number ops. Inodes consist of a compressed block number, and an * uncompressed offset within that block diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 8a6995de02773d0387ab36070c1ed1aac8228e6b..3b767ce1e46dbc8bc0c5f590351387320fe0920d 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -75,6 +75,7 @@ struct squashfs_sb_info { unsigned short block_log; long long bytes_used; unsigned int inodes; + unsigned int fragments; int xattr_ids; }; #endif diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index e2a0a7342bf80b37bf01bc3ecd422f0a566636b1..445ce580f06db5b8310dc82880edfeddaf457cbb 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -175,6 +175,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) msblk->inode_table = le64_to_cpu(sblk->inode_table_start); msblk->directory_table = le64_to_cpu(sblk->directory_table_start); msblk->inodes = le32_to_cpu(sblk->inodes); + msblk->fragments = le32_to_cpu(sblk->fragments); flags = le16_to_cpu(sblk->flags); TRACE("Found valid superblock on %pg\n", sb->s_bdev); @@ -185,7 +186,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); TRACE("Block size %d\n", msblk->block_size); TRACE("Number of inodes %d\n", msblk->inodes); - TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); + TRACE("Number of fragments %d\n", msblk->fragments); TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); @@ -272,7 +273,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &squashfs_export_ops; handle_fragments: - fragments = le32_to_cpu(sblk->fragments); + fragments = msblk->fragments; if (fragments == 0) goto check_directory_table; diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 0410facaf68bdca862c3470f58a2d6896546f3c1..23d5f3ff0b987a0459c814aabf6f0b5e09b531f3 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -628,8 +628,10 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, /* the various vma->vm_userfaultfd_ctx still points to it */ down_write(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) - if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) + if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) { vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; + vma->vm_flags &= ~(VM_UFFD_WP | VM_UFFD_MISSING); + } up_write(&mm->mmap_sem); userfaultfd_ctx_put(release_new_ctx); diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 5c16db86b38ffbcbb2c7e400cd04a4e84230a34e..40e53a4fc0a65ee479379a0e55c3c171539eb4a3 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -785,9 +785,8 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) ASSERT(blkno == 0); error = xfs_attr3_leaf_create(args, blkno, &bp); if (error) { - error = xfs_da_shrink_inode(args, 0, bp); - bp = NULL; - if (error) + /* xfs_attr3_leaf_create may not have instantiated a block */ + if (bp && (xfs_da_shrink_inode(args, 0, bp) != 0)) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 43005fbe8b1eefabc84ee762a9427ec784889814..544b5211221cdae3a61c5e1910e9286063fed6b0 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -305,6 +305,46 @@ xfs_reinit_inode( return error; } +/* + * If we are allocating a new inode, then check what was returned is + * actually a free, empty inode. If we are not allocating an inode, + * then check we didn't find a free inode. + * + * Returns: + * 0 if the inode free state matches the lookup context + * -ENOENT if the inode is free and we are not allocating + * -EFSCORRUPTED if there is any state mismatch at all + */ +static int +xfs_iget_check_free_state( + struct xfs_inode *ip, + int flags) +{ + if (flags & XFS_IGET_CREATE) { + /* should be a free inode */ + if (VFS_I(ip)->i_mode != 0) { + xfs_warn(ip->i_mount, +"Corruption detected! Free inode 0x%llx not marked free! (mode 0x%x)", + ip->i_ino, VFS_I(ip)->i_mode); + return -EFSCORRUPTED; + } + + if (ip->i_d.di_nblocks != 0) { + xfs_warn(ip->i_mount, +"Corruption detected! Free inode 0x%llx has blocks allocated!", + ip->i_ino); + return -EFSCORRUPTED; + } + return 0; + } + + /* should be an allocated inode */ + if (VFS_I(ip)->i_mode == 0) + return -ENOENT; + + return 0; +} + /* * Check the validity of the inode we just found it the cache */ @@ -354,12 +394,12 @@ xfs_iget_cache_hit( } /* - * If lookup is racing with unlink return an error immediately. + * Check the inode free state is valid. This also detects lookup + * racing with unlinks. */ - if (VFS_I(ip)->i_mode == 0 && !(flags & XFS_IGET_CREATE)) { - error = -ENOENT; + error = xfs_iget_check_free_state(ip, flags); + if (error) goto out_error; - } /* * If IRECLAIMABLE is set, we've torn down the VFS inode already. @@ -475,10 +515,14 @@ xfs_iget_cache_miss( trace_xfs_iget_miss(ip); - if ((VFS_I(ip)->i_mode == 0) && !(flags & XFS_IGET_CREATE)) { - error = -ENOENT; + + /* + * Check the inode free state is valid. This also detects lookup + * racing with unlinks. + */ + error = xfs_iget_check_free_state(ip, flags); + if (error) goto out_destroy; - } /* * Preload the radix tree so we can insert safely under the diff --git a/include/crypto/ice.h b/include/crypto/ice.h index 558d1366a7893ec42a563dc7ae8f1b7bac5a6f7f..5407e5106243528c9b3ee81e47ae4870c4f5f9e4 100644 --- a/include/crypto/ice.h +++ b/include/crypto/ice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -56,11 +56,13 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node); #ifdef CONFIG_CRYPTO_DEV_QCOM_ICE int qcom_ice_setup_ice_hw(const char *storage_type, int enable); +void qcom_ice_set_fde_flag(int flag); #else static inline int qcom_ice_setup_ice_hw(const char *storage_type, int enable) { return 0; } +static inline void qcom_ice_set_fde_flag(int flag) {} #endif struct qcom_ice_variant_ops { diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index a2a914e7589ecfcb28fd00ad118ea166df99b262..180d2e86151d590a5c3748f8c2a9648444bd4cbf 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -454,6 +454,7 @@ # define DP_PSR_FRAME_CAPTURE (1 << 3) # define DP_PSR_SELECTIVE_UPDATE (1 << 4) # define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS (1 << 5) +# define DP_PSR_ENABLE_PSR2 (1 << 6) /* eDP 1.4a */ #define DP_ADAPTER_CTRL 0x1a0 # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) diff --git a/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h b/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h index 0a119e75cf85d624d060796d178dc89c47ef8dd1..70658ef0713e818eebf4bd6488867962481c2901 100644 --- a/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h @@ -14,49 +14,49 @@ #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SDMMAGPIE_H #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SDMMAGPIE_H -#define DISP_CC_DEBUG_CLK 0 +#define DISP_CC_PLL0 0 #define DISP_CC_MDSS_AHB_CLK 1 #define DISP_CC_MDSS_AHB_CLK_SRC 2 #define DISP_CC_MDSS_BYTE0_CLK 3 #define DISP_CC_MDSS_BYTE0_CLK_SRC 4 -#define DISP_CC_MDSS_BYTE0_INTF_CLK 5 -#define DISP_CC_MDSS_BYTE1_CLK 6 -#define DISP_CC_MDSS_BYTE1_CLK_SRC 7 -#define DISP_CC_MDSS_BYTE1_INTF_CLK 8 -#define DISP_CC_MDSS_DP_AUX_CLK 9 -#define DISP_CC_MDSS_DP_AUX_CLK_SRC 10 -#define DISP_CC_MDSS_DP_CRYPTO_CLK 11 -#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 12 -#define DISP_CC_MDSS_DP_LINK_CLK 13 -#define DISP_CC_MDSS_DP_LINK_CLK_SRC 14 -#define DISP_CC_MDSS_DP_LINK_INTF_CLK 15 -#define DISP_CC_MDSS_DP_PIXEL1_CLK 16 -#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 17 -#define DISP_CC_MDSS_DP_PIXEL_CLK 18 -#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 19 -#define DISP_CC_MDSS_ESC0_CLK 20 -#define DISP_CC_MDSS_ESC0_CLK_SRC 21 -#define DISP_CC_MDSS_ESC1_CLK 22 -#define DISP_CC_MDSS_ESC1_CLK_SRC 23 -#define DISP_CC_MDSS_MDP_CLK 24 -#define DISP_CC_MDSS_MDP_CLK_SRC 25 -#define DISP_CC_MDSS_MDP_LUT_CLK 26 -#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 27 -#define DISP_CC_MDSS_PCLK0_CLK 28 -#define DISP_CC_MDSS_PCLK0_CLK_SRC 29 -#define DISP_CC_MDSS_PCLK1_CLK 30 -#define DISP_CC_MDSS_PCLK1_CLK_SRC 31 -#define DISP_CC_MDSS_ROT_CLK 32 -#define DISP_CC_MDSS_ROT_CLK_SRC 33 -#define DISP_CC_MDSS_RSCC_AHB_CLK 34 -#define DISP_CC_MDSS_RSCC_VSYNC_CLK 35 -#define DISP_CC_MDSS_VSYNC_CLK 36 -#define DISP_CC_MDSS_VSYNC_CLK_SRC 37 -#define DISP_CC_PLL0 38 -#define DISP_CC_PLL_TEST_CLK 39 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 5 +#define DISP_CC_MDSS_BYTE0_INTF_CLK 6 +#define DISP_CC_MDSS_BYTE1_CLK 7 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 8 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 9 +#define DISP_CC_MDSS_BYTE1_INTF_CLK 10 +#define DISP_CC_MDSS_DP_AUX_CLK 11 +#define DISP_CC_MDSS_DP_AUX_CLK_SRC 12 +#define DISP_CC_MDSS_DP_CRYPTO_CLK 13 +#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 14 +#define DISP_CC_MDSS_DP_LINK_CLK 15 +#define DISP_CC_MDSS_DP_LINK_CLK_SRC 16 +#define DISP_CC_MDSS_DP_LINK_INTF_CLK 17 +#define DISP_CC_MDSS_DP_PIXEL1_CLK 18 +#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 19 +#define DISP_CC_MDSS_DP_PIXEL_CLK 20 +#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 21 +#define DISP_CC_MDSS_ESC0_CLK 22 +#define DISP_CC_MDSS_ESC0_CLK_SRC 23 +#define DISP_CC_MDSS_ESC1_CLK 24 +#define DISP_CC_MDSS_ESC1_CLK_SRC 25 +#define DISP_CC_MDSS_MDP_CLK 26 +#define DISP_CC_MDSS_MDP_CLK_SRC 27 +#define DISP_CC_MDSS_MDP_LUT_CLK 28 +#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 29 +#define DISP_CC_MDSS_PCLK0_CLK 30 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 31 +#define DISP_CC_MDSS_PCLK1_CLK 32 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 33 +#define DISP_CC_MDSS_ROT_CLK 34 +#define DISP_CC_MDSS_ROT_CLK_SRC 35 +#define DISP_CC_MDSS_RSCC_AHB_CLK 36 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 37 +#define DISP_CC_MDSS_VSYNC_CLK 38 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 39 #define DISP_CC_XO_CLK 40 #define DISP_CC_XO_CLK_SRC 41 - -#define MDSS_CORE_GDSC 0 +#define DISP_CC_SLEEP_CLK 42 +#define DISP_CC_SLEEP_CLK_SRC 43 #endif diff --git a/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h b/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h index cde774dceb425d23dee844b88e8dd7d7990d0bf6..1159fbbffd53021042db4a7315c5348dd43888cf 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h @@ -183,6 +183,7 @@ #define GCC_VS_CTRL_CLK 163 #define GCC_VS_CTRL_CLK_SRC 164 #define GCC_VSENSOR_CLK_SRC 165 +#define GCC_GPLL0_MAIN_DIV_CDIV 167 /* GCC Resets */ #define GCC_PCIE_0_BCR 0 diff --git a/include/dt-bindings/clock/qcom,gcc-sm6150.h b/include/dt-bindings/clock/qcom,gcc-sm6150.h index 2b1678111e43408bd643bbb685059d74a484b5fe..94f9965d7e45679b1e8058b48aabf945a7e30d31 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm6150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm6150.h @@ -18,7 +18,7 @@ #define GPLL0_OUT_AUX2 0 #define MEASURE_ONLY_SNOC_CLK 1 #define MEASURE_ONLY_CNOC_CLK 2 -#define MEASURE_ONLY_BIMC_CLK 3 +#define MEASURE_ONLY_MMCC_CLK 3 #define MEASURE_ONLY_IPA_2X_CLK 4 /* GCC clock registers */ @@ -204,5 +204,7 @@ #define GCC_PCIE_PHY_COM_BCR 9 #define GCC_UFS_PHY_BCR 10 #define GCC_USB20_SEC_BCR 11 +#define GCC_USB3_DP_PHY_PRIM_SP0_BCR 12 +#define GCC_USB3PHY_PHY_PRIM_SP0_BCR 13 #endif diff --git a/include/dt-bindings/clock/qcom,gcc-sm8150.h b/include/dt-bindings/clock/qcom,gcc-sm8150.h index a75b8238148dd1589486a41fd016e39c993dffc9..04333729ca3c32fd8f40b2fb6050c99bf467f7d1 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm8150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm8150.h @@ -254,5 +254,6 @@ #define MEASURE_ONLY_MCCC_CLK 2 #define MEASURE_ONLY_IPA_2X_CLK 3 #define MMCX_CLK 4 +#define MEASURE_ONLY_CDSP_CLK 5 #endif diff --git a/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h b/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h index d7160420a7d367418460fb7d389217db11ce325f..d0df54ca4099c8958b915cc86112dfaa00577d71 100644 --- a/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h @@ -14,28 +14,25 @@ #ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SDMMAGPIE_H #define _DT_BINDINGS_CLK_QCOM_GPU_CC_SDMMAGPIE_H -#define GPU_CC_ACD_AHB_CLK 0 -#define GPU_CC_ACD_CXO_CLK 1 -#define GPU_CC_AHB_CLK 2 -#define GPU_CC_CRC_AHB_CLK 3 -#define GPU_CC_CX_APB_CLK 4 -#define GPU_CC_CX_GFX3D_CLK 5 -#define GPU_CC_CX_GFX3D_SLV_CLK 6 -#define GPU_CC_CX_GMU_CLK 7 -#define GPU_CC_CX_SNOC_DVM_CLK 8 -#define GPU_CC_CXO_AON_CLK 9 -#define GPU_CC_CXO_CLK 10 -#define GPU_CC_GMU_CLK_SRC 11 -#define GPU_CC_GX_CXO_CLK 12 -#define GPU_CC_GX_GFX3D_CLK 13 -#define GPU_CC_GX_GFX3D_CLK_SRC 14 -#define GPU_CC_GX_GMU_CLK 15 -#define GPU_CC_GX_VSENSE_CLK 16 -#define GPU_CC_PLL0 17 -#define GPU_CC_PLL0_OUT_EVEN 18 +#define GPU_CC_PLL0 0 +#define GPU_CC_PLL0_OUT_EVEN 1 +#define GPU_CC_ACD_AHB_CLK 2 +#define GPU_CC_ACD_CXO_CLK 3 +#define GPU_CC_AHB_CLK 4 +#define GPU_CC_CRC_AHB_CLK 5 +#define GPU_CC_CX_APB_CLK 6 +#define GPU_CC_CX_GFX3D_CLK 7 +#define GPU_CC_CX_GFX3D_SLV_CLK 8 +#define GPU_CC_CX_GMU_CLK 9 +#define GPU_CC_CX_SNOC_DVM_CLK 10 +#define GPU_CC_CXO_AON_CLK 11 +#define GPU_CC_CXO_CLK 12 +#define GPU_CC_GMU_CLK_SRC 13 +#define GPU_CC_GX_CXO_CLK 14 +#define GPU_CC_GX_GFX3D_CLK 15 +#define GPU_CC_GX_GFX3D_CLK_SRC 16 +#define GPU_CC_GX_GMU_CLK 17 +#define GPU_CC_GX_VSENSE_CLK 18 #define GPU_CC_SLEEP_CLK 19 -#define CX_GDSC 0 -#define GX_GDSC 1 - #endif diff --git a/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h b/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h index 6e9b6c377f5bd048cf4e8ac948a1182483173a3e..519eaa3624fb56d0cdb788e45dff55077dc56962 100644 --- a/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h @@ -11,32 +11,34 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_NPU_CC_SM7150_H -#define _DT_BINDINGS_CLK_QCOM_NPU_CC_SM7150_H +#ifndef _DT_BINDINGS_CLK_QCOM_NPU_CC_SDMMAGPIE +#define _DT_BINDINGS_CLK_QCOM_NPU_CC_SDMMAGPIE -#define NPU_CC_ARMWIC_CORE_CLK 0 -#define NPU_CC_BTO_CORE_CLK 1 -#define NPU_CC_BWMON_CLK 2 -#define NPU_CC_CAL_DP_CDC_CLK 3 -#define NPU_CC_CAL_DP_CLK 4 -#define NPU_CC_CAL_DP_CLK_SRC 5 -#define NPU_CC_COMP_NOC_AXI_CLK 6 -#define NPU_CC_CONF_NOC_AHB_CLK 7 -#define NPU_CC_NPU_CORE_APB_CLK 8 -#define NPU_CC_NPU_CORE_ATB_CLK 9 -#define NPU_CC_NPU_CORE_CLK 10 -#define NPU_CC_NPU_CORE_CLK_SRC 11 -#define NPU_CC_NPU_CORE_CTI_CLK 12 -#define NPU_CC_NPU_CPC_CLK 13 -#define NPU_CC_NPU_CPC_TIMER_CLK 14 -#define NPU_CC_PERF_CNT_CLK 15 -#define NPU_CC_PLL0 16 -#define NPU_CC_PLL0_OUT_EVEN 17 -#define NPU_CC_PLL_TEST_CLK 18 -#define NPU_CC_QTIMER_CORE_CLK 19 -#define NPU_CC_SLEEP_CLK 20 -#define NPU_CC_XO_CLK 21 +#define NPU_CC_PLL0 0 +#define NPU_CC_PLL0_OUT_EVEN 1 +#define NPU_CC_PLL1 2 +#define NPU_CC_PLL1_OUT_EVEN 3 +#define NPU_CC_ARMWIC_CORE_CLK 4 +#define NPU_CC_BTO_CORE_CLK 5 +#define NPU_CC_BWMON_CLK 6 +#define NPU_CC_CAL_DP_CDC_CLK 7 +#define NPU_CC_CAL_DP_CLK 8 +#define NPU_CC_CAL_DP_CLK_SRC 9 +#define NPU_CC_COMP_NOC_AXI_CLK 10 +#define NPU_CC_CONF_NOC_AHB_CLK 11 +#define NPU_CC_NPU_CORE_APB_CLK 12 +#define NPU_CC_NPU_CORE_ATB_CLK 13 +#define NPU_CC_NPU_CORE_CLK 14 +#define NPU_CC_NPU_CORE_CLK_SRC 15 +#define NPU_CC_NPU_CORE_CTI_CLK 16 +#define NPU_CC_NPU_CPC_CLK 17 +#define NPU_CC_NPU_CPC_TIMER_CLK 18 +#define NPU_CC_PERF_CNT_CLK 19 +#define NPU_CC_QTIMER_CORE_CLK 20 +#define NPU_CC_SLEEP_CLK 21 +#define NPU_CC_XO_CLK 22 -#define NPU_CORE_GDSC 0 +#define NPU_CC_CAL_DP_BCR 0 +#define NPU_CC_NPU_CORE_BCR 1 #endif diff --git a/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h b/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h index de287ee7e8ee399ca6c4be1258dcb2bde4fae545..2ecc097c6e65c72d5160612dc2ca3f6194518446 100644 --- a/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h @@ -14,25 +14,17 @@ #ifndef _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SDMMAGPIE_H #define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SDMMAGPIE_H -#define VIDEO_CC_APB_CLK 0 -#define VIDEO_CC_AT_CLK 1 -#define VIDEO_CC_IRIS_AHB_CLK 3 -#define VIDEO_CC_IRIS_CLK_SRC 4 -#define VIDEO_CC_MVS0_AXI_CLK 5 -#define VIDEO_CC_MVS0_CORE_CLK 6 -#define VIDEO_CC_MVS1_AXI_CLK 7 -#define VIDEO_CC_MVS1_CORE_CLK 8 -#define VIDEO_CC_MVSC_CORE_CLK 9 -#define VIDEO_CC_MVSC_CTL_AXI_CLK 10 -#define VIDEO_CC_SLEEP_CLK 13 -#define VIDEO_CC_SLEEP_CLK_SRC 14 -#define VIDEO_CC_VENUS_AHB_CLK 15 -#define VIDEO_CC_XO_CLK 16 -#define VIDEO_CC_XO_CLK_SRC 17 -#define VIDEO_PLL0 18 - -#define MVS0_GDSC 0 -#define MVS1_GDSC 1 -#define MVSC_GDSC 2 +#define VIDEO_PLL0 0 +#define VIDEO_CC_IRIS_AHB_CLK 1 +#define VIDEO_CC_IRIS_CLK_SRC 2 +#define VIDEO_CC_MVS0_AXI_CLK 3 +#define VIDEO_CC_MVS0_CORE_CLK 4 +#define VIDEO_CC_MVS1_AXI_CLK 5 +#define VIDEO_CC_MVS1_CORE_CLK 6 +#define VIDEO_CC_MVSC_CORE_CLK 7 +#define VIDEO_CC_MVSC_CTL_AXI_CLK 8 +#define VIDEO_CC_VENUS_AHB_CLK 9 +#define VIDEO_CC_XO_CLK 10 +#define VIDEO_CC_XO_CLK_SRC 11 #endif diff --git a/include/dt-bindings/clock/qcom,videocc-sm6150.h b/include/dt-bindings/clock/qcom,videocc-sm6150.h index cfb27950126b780729ca37f00ccd2d5f067c3d86..8ecdb2d3dbd72bede3049c4f02066b949da4857a 100644 --- a/include/dt-bindings/clock/qcom,videocc-sm6150.h +++ b/include/dt-bindings/clock/qcom,videocc-sm6150.h @@ -26,6 +26,5 @@ #define VIDEO_CC_VENUS_CTL_AXI_CLK 8 #define VIDEO_CC_VENUS_CTL_CORE_CLK 9 #define VIDEO_CC_XO_CLK 10 -#define VIDEO_CC_XO_CLK_SRC 11 #endif diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h index 3fb0f6aedd0cd35d72a8ef35a3a7a0c8d9eb56c3..0fef11f49985cf26476039c35d0537e606fb618d 100644 --- a/include/dt-bindings/msm/msm-bus-ids.h +++ b/include/dt-bindings/msm/msm-bus-ids.h @@ -278,6 +278,7 @@ #define MSM_BUS_MASTER_PCIE_3 167 #define MSM_BUS_MASTER_LPASS_ANOC 168 #define MSM_BUS_MASTER_USB2 169 +#define MSM_BUS_MASTER_SENSORS_AHB 170 #define MSM_BUS_MASTER_LLCC_DISPLAY 20000 #define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001 diff --git a/include/dt-bindings/sound/audio-codec-port-types.h b/include/dt-bindings/sound/audio-codec-port-types.h index b795d0db7db3cce4548fc126adb4301f0c14be6e..8a9d7cf4ca45a8bf9e69123dbe247beb7f7b3f2a 100644 --- a/include/dt-bindings/sound/audio-codec-port-types.h +++ b/include/dt-bindings/sound/audio-codec-port-types.h @@ -9,24 +9,30 @@ #define SPKR_R_BOOST 6 #define SPKR_R_COMP 7 #define SPKR_R_VI 8 -#define HPH 9 -#define COMPANDER 10 -#define CLSH 11 -#define LO 12 -#define DSD 13 -#define MBHC 14 -#define ADC1 15 -#define ADC2 16 -#define ADC3 17 -#define DMIC1 18 -#define DMIC2 19 -#define DMIC3 20 -#define DMIC4 21 -#define DMIC5 22 -#define DMIC6 23 -#define DMIC7 24 -#define DMIC8 25 -#define DMIC9 26 -#define DMIC10 27 +#define HPH_L 9 +#define HPH_R 10 +#define COMP_L 11 +#define COMP_R 12 +#define CLSH 13 +#define LO 14 +#define DSD_L 15 +#define DSD_R 16 +#define MBHC 17 +#define ADC1 18 +#define ADC2 19 +#define ADC3 20 +#define ADC4 21 +#define DMIC0 22 +#define DMIC1 23 +#define DMIC2 24 +#define DMIC3 25 +#define DMIC4 26 +#define DMIC5 27 +#define DMIC6 28 +#define DMIC7 29 +#define DMIC8 30 +#define DMIC9 31 +#define DMIC10 32 +#define PCM_OUT1 33 #endif /* __AUDIO_CODEC_PORT_TYPES_H */ diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 0c27515d2cf6db3683da2341a700283f82a99645..8124815eb1218b5653572fc4a04f5d4d734e3469 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -214,6 +214,7 @@ struct atmphy_ops { struct atm_skb_data { struct atm_vcc *vcc; /* ATM VCC */ unsigned long atm_options; /* ATM layer options */ + unsigned int acct_truesize; /* truesize accounted to vcc */ }; #define VCC_HTABLE_SIZE 32 @@ -241,6 +242,20 @@ void vcc_insert_socket(struct sock *sk); void atm_dev_release_vccs(struct atm_dev *dev); +static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb) +{ + /* + * Because ATM skbs may not belong to a sock (and we don't + * necessarily want to), skb->truesize may be adjusted, + * escaping the hack in pskb_expand_head() which avoids + * doing so for some cases. So stash the value of truesize + * at the time we accounted it, and atm_pop_raw() can use + * that value later, in case it changes. + */ + refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); + ATM_SKB(skb)->acct_truesize = skb->truesize; + ATM_SKB(skb)->atm_options = vcc->atm_options; +} static inline void atm_force_charge(struct atm_vcc *vcc,int truesize) { diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index eac387a3bfef74e59243c6fdacf13e9ba619287d..3c1beffc861a64693f0711c9f4830fc29c5f6331 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -22,7 +22,6 @@ struct dentry; */ enum wb_state { WB_registered, /* bdi_register() was done */ - WB_shutting_down, /* wb_shutdown() in progress */ WB_writeback_running, /* Writeback is in progress */ WB_has_dirty_io, /* Dirty inodes on ->b_{dirty|io|more_io} */ }; @@ -165,6 +164,7 @@ struct backing_dev_info { #ifdef CONFIG_CGROUP_WRITEBACK struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */ struct rb_root cgwb_congested_tree; /* their congested states */ + struct mutex cgwb_release_mutex; /* protect shutdown of wb structs */ #else struct bdi_writeback_congested *wb_congested; #endif diff --git a/include/linux/bio.h b/include/linux/bio.h index 5aa40f4712ff19e932c9bfadeacdcf300a17073d..8988ccdb10c88f3fa0178ca0b71e1aa894d58f7e 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -69,6 +69,9 @@ ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) +#define bio_dun(bio) ((bio)->bi_iter.bi_dun) +#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */ +#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio)) /* * Return the data direction, READ or WRITE. @@ -173,6 +176,11 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, { iter->bi_sector += bytes >> 9; +#ifdef CONFIG_PFK + if (iter->bi_dun) + iter->bi_dun += bytes >> 12; +#endif + if (bio_no_advance_iter(bio)) { iter->bi_size -= bytes; iter->bi_done += bytes; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index be2bee81c748e614f18697f9b1f9e4b7e277395b..30f317099366a47e1e092cf2fbe9fb39325689df 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -100,6 +100,13 @@ struct bio { struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif }; +#ifdef CONFIG_PFK + /* Encryption key to use (NULL if none) */ + const struct blk_encryption_key *bi_crypt_key; +#endif +#ifdef CONFIG_DM_DEFAULT_KEY + int bi_crypt_skip; +#endif unsigned short bi_vcnt; /* how many bio_vec's */ @@ -115,12 +122,8 @@ struct bio { struct bio_set *bi_pool; - /* - * When using dircet-io (O_DIRECT), we can't get the inode from a bio - * by walking bio->bi_io_vec->bv_page->mapping->host - * since the page is anon. - */ struct inode *bi_dio_inode; + /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 64ac8e3c5a40aa9a28139e35ba9f925d608fb7de..c3a488f8b2e149d3d8fa42767824f4db8a29762d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -652,6 +652,7 @@ struct request_queue { #define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */ #define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */ #define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */ +#define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -751,6 +752,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_scsi_passthrough(q) \ test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags) +#define blk_queue_inlinecrypt(q) \ + test_bit(QUEUE_FLAG_INLINECRYPT, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ diff --git a/include/linux/bvec.h b/include/linux/bvec.h index ec8a4d7af6bda55586bc0b0221b3dcfe6e5ab487..41d309fda7777b81d2f1387656eb61313f11a0a8 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -44,6 +44,7 @@ struct bvec_iter { unsigned int bi_bvec_done; /* number of bytes completed in current bvec */ + u64 bi_dun; /* DUN setting for bio */ }; /* diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 065d021c44ac136b840d54ffebd68eb6d27d972c..2c586c0a87cb60a283a21f5fdf834eeec0228e83 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -495,6 +495,7 @@ struct clk_divider { #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) #define CLK_DIVIDER_READ_ONLY BIT(5) #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) +#define CLK_DIVIDER_ROUND_KHZ BIT(7) extern const struct clk_ops clk_divider_ops; extern const struct clk_ops clk_divider_ro_ops; diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index af722dea7562f6f06a926a7a3cbde2ecae9bc421..c456227e898efe854bae16a7e095cf8628d90193 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -17,6 +17,9 @@ */ #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) +#undef __no_sanitize_address +#define __no_sanitize_address __attribute__((no_sanitize("address"))) + /* Clang doesn't have a way to turn it off per-function, yet. */ #ifdef __noretpoline #undef __noretpoline diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index f43113b8890b760ac73b0a370781e67998e055d7..c11032b06d68f0781aa43f52d02b2c0537d36ede 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -65,6 +65,18 @@ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) #endif +/* + * Feature detection for gnu_inline (gnu89 extern inline semantics). Either + * __GNUC_STDC_INLINE__ is defined (not using gnu89 extern inline semantics, + * and we opt in to the gnu89 semantics), or __GNUC_STDC_INLINE__ is not + * defined so the gnu89 semantics are the default. + */ +#ifdef __GNUC_STDC_INLINE__ +# define __gnu_inline __attribute__((gnu_inline)) +#else +# define __gnu_inline +#endif + /* * Force always-inline if the user requests it so via the .config, * or if gcc is too old. @@ -72,19 +84,22 @@ * -Wunused-function. This turns out to avoid the need for complex #ifdef * directives. Suppress the warning in clang as well by using "unused" * function attribute, which is redundant but not harmful for gcc. + * Prefer gnu_inline, so that extern inline functions do not emit an + * externally visible function. This makes extern inline behave as per gnu89 + * semantics rather than c99. This prevents multiple symbol definition errors + * of extern inline functions at link time. + * A lot of inline functions can cause havoc with function tracing. */ #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \ !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4) -#define inline inline __attribute__((always_inline,unused)) notrace -#define __inline__ __inline__ __attribute__((always_inline,unused)) notrace -#define __inline __inline __attribute__((always_inline,unused)) notrace +#define inline \ + inline __attribute__((always_inline, unused)) notrace __gnu_inline #else -/* A lot of inline functions can cause havoc with function tracing */ -#define inline inline __attribute__((unused)) notrace -#define __inline__ __inline__ __attribute__((unused)) notrace -#define __inline __inline __attribute__((unused)) notrace +#define inline inline __attribute__((unused)) notrace __gnu_inline #endif +#define __inline__ inline +#define __inline inline #define __always_inline inline __attribute__((always_inline)) #define noinline __attribute__((noinline)) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index ad33507b34be206abd45495f741a28c1c0883c35..113a14833ad3f8379b5ad7863183e72cf8d3d4aa 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -131,7 +131,8 @@ extern bool cpuidle_not_available(struct cpuidle_driver *drv, struct cpuidle_device *dev); extern int cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev); + struct cpuidle_device *dev, + bool *stop_tick); extern int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index); extern void cpuidle_reflect(struct cpuidle_device *dev, int index); @@ -163,7 +164,7 @@ static inline bool cpuidle_not_available(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return true; } static inline int cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev) + struct cpuidle_device *dev, bool *stop_tick) {return -ENODEV; } static inline int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index) @@ -246,7 +247,8 @@ struct cpuidle_governor { struct cpuidle_device *dev); int (*select) (struct cpuidle_driver *drv, - struct cpuidle_device *dev); + struct cpuidle_device *dev, + bool *stop_tick); void (*reflect) (struct cpuidle_device *dev, int index); }; diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index b93efc8feecd1f67e9b79fdc62abc96b30e13b1b..9f821a43bb0dd9f67f1a0c213a1390324eccf896 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -23,7 +23,6 @@ struct device; struct file_operations; -struct srcu_struct; struct debugfs_blob_wrapper { void *data; @@ -43,25 +42,6 @@ struct debugfs_regset32 { extern struct dentry *arch_debugfs_dir; -extern struct srcu_struct debugfs_srcu; - -/** - * debugfs_real_fops - getter for the real file operation - * @filp: a pointer to a struct file - * - * Must only be called under the protection established by - * debugfs_use_file_start(). - */ -static inline const struct file_operations *debugfs_real_fops(const struct file *filp) - __must_hold(&debugfs_srcu) -{ - /* - * Neither the pointer to the struct file_operations, nor its - * contents ever change -- srcu_dereference() is not needed here. - */ - return filp->f_path.dentry->d_fsdata; -} - #define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ @@ -107,10 +87,10 @@ struct dentry *debugfs_create_automount(const char *name, void debugfs_remove(struct dentry *dentry); void debugfs_remove_recursive(struct dentry *dentry); -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu); +const struct file_operations *debugfs_real_fops(const struct file *filp); -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); +int debugfs_file_get(struct dentry *dentry); +void debugfs_file_put(struct dentry *dentry); ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); @@ -239,15 +219,12 @@ static inline void debugfs_remove(struct dentry *dentry) static inline void debugfs_remove_recursive(struct dentry *dentry) { } -static inline int debugfs_use_file_start(const struct dentry *dentry, - int *srcu_idx) - __acquires(&debugfs_srcu) +static inline int debugfs_file_get(struct dentry *dentry) { return 0; } -static inline void debugfs_use_file_finish(int srcu_idx) - __releases(&debugfs_srcu) +static inline void debugfs_file_put(struct dentry *dentry) { } static inline ssize_t debugfs_attr_read(struct file *file, char __user *buf, diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 5e335b6203f49d429c3c81a158d1bed0830c66b7..31c865d1842e88671d7f29534587311c479fb3e7 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -29,7 +29,7 @@ #ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info { - spinlock_t lock; + raw_spinlock_t lock; unsigned int flags; /* Private per-task flags */ /* For each stat XXX, add following, aligned appropriately @@ -124,7 +124,7 @@ static inline void delayacct_blkio_start(void) static inline void delayacct_blkio_end(struct task_struct *p) { - if (current->delays) + if (p->delays) __delayacct_blkio_end(p); delayacct_clear_flag(DELAYACCT_PF_BLKIO); } diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index 92f20832fd28770c16ab9d34c5560efce2a888c6..e8ca5e6542773fea4c54725f360743e3f1407b7c 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -17,6 +17,7 @@ #define __DMA_IOMMU_H #ifdef __KERNEL__ +#include #include #ifdef CONFIG_IOMMU_DMA diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 2a3957bc2221c8b5157d098a4ef1662d9dc1eebb..129b948bee5a08ec8a341a777eddfaefb3462e67 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -17,10 +17,16 @@ #include #define FS_CRYPTO_BLOCK_SIZE 16 -#define FS_ENCRYPTION_MODE_PRIVATE 127 -#define FS_AES_256_XTS_KEY_SIZE 64 struct fscrypt_ctx; + +/* iv sector for security/pfe/pfk_fscrypt.c and f2fs. sizeof is required + * to accommodate 32 bit targets. + */ +#define PG_DUN(i, p) \ + ((((i)->i_ino & 0xffffffff) << (sizeof((i)->i_ino)/2)) | \ + ((p)->index & 0xffffffff)) + struct fscrypt_info; struct fscrypt_str { @@ -44,8 +50,6 @@ struct fscrypt_name { /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 -extern int fs_using_hardware_encryption(struct inode *inode); - #if __FS_HAS_ENCRYPTION #include #else diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 9770be37c9d421fedce25fb534b6408362c10cbe..68862592d8754ac5903ea23a2e9812f2365a02d0 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -184,6 +184,26 @@ static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, return -EOPNOTSUPP; } +/* fscrypt_ice.c */ +static inline int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + return 0; +} + +static inline void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun){} + +static inline void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip) +{ + return; +} + +static inline bool fscrypt_mergeable_bio(struct bio *bio, + sector_t iv_block, bool bio_encrypted, int bi_crypt_skip) +{ + return true; +} + /* hooks.c */ static inline int fscrypt_file_open(struct inode *inode, struct file *filp) diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 2c9a86ac5e83b9b63f1b95680d9a711d57e0b659..083f1fcf483ef63d4b4863eaae58748f15ba5812 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -30,6 +30,7 @@ struct fscrypt_operations { bool (*dummy_context)(struct inode *); bool (*empty_dir)(struct inode *); unsigned (*max_namelen)(struct inode *); + bool (*is_encrypted)(struct inode *); }; struct fscrypt_ctx { @@ -196,6 +197,14 @@ extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); +/* fscrypt_ice.c */ +extern int fscrypt_using_hardware_encryption(const struct inode *inode); +extern void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun); +extern void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip); +extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted, + int bi_crypt_skip); + /* hooks.c */ extern int fscrypt_file_open(struct inode *inode, struct file *filp); extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir); diff --git a/include/linux/gfp.h b/include/linux/gfp.h index b041f94678de5ac8889f22eedc3f5b01ed656f01..ef8d6d0aaee31f5814a1cdb47f20dd5f68fe4611 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -45,6 +45,7 @@ struct vm_area_struct; #else #define ___GFP_NOLOCKDEP 0 #endif +#define ___GFP_CMA 0x4000000u /* If the above are modified, __GFP_BITS_SHIFT may need updating */ /* @@ -58,8 +59,8 @@ struct vm_area_struct; #define __GFP_HIGHMEM ((__force gfp_t)___GFP_HIGHMEM) #define __GFP_DMA32 ((__force gfp_t)___GFP_DMA32) #define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* ZONE_MOVABLE allowed */ +#define __GFP_CMA ((__force gfp_t)___GFP_CMA) #define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE) - /* * Page mobility and placement hints * @@ -210,7 +211,7 @@ struct vm_area_struct; #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP) /* Room for N __GFP_FOO bits */ -#define __GFP_BITS_SHIFT (25 + IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT 27 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) /* @@ -406,7 +407,14 @@ static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) static inline enum zone_type gfp_zone(gfp_t flags) { enum zone_type z; - int bit = (__force int) (flags & GFP_ZONEMASK); + int bit; + + if (!IS_ENABLED(CONFIG_HIGHMEM)) { + if ((flags & __GFP_MOVABLE) && !(flags & __GFP_CMA)) + flags &= ~__GFP_HIGHMEM; + } + + bit = (__force int) (flags & GFP_ZONEMASK); z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) & ((1 << GFP_ZONES_SHIFT) - 1); diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 4db2f34c4fe5696238886b4abcffa14125495b43..b471a881f3269da045c3f4395fb55261ffe2d633 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -193,7 +193,12 @@ static inline struct page * alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma, unsigned long vaddr) { +#ifndef CONFIG_CMA return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr); +#else + return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma, + vaddr); +#endif } static inline void clear_highpage(struct page *page) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index dd293a8f765e84b640e23d0c7d6a51218ec9a757..ceb4ac2365194fff4e5b02ae7eb854439bca8ccb 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -411,6 +411,7 @@ static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer) } extern u64 hrtimer_get_next_event(void); +extern u64 hrtimer_next_event_without(const struct hrtimer *exclude); extern bool hrtimer_active(const struct hrtimer *timer); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 6b7bf41314c848c6935374b41d15ae01972b335a..3e4f4fedda98ffc759e94b446e597e40f8ea3b20 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -133,6 +133,11 @@ enum iommu_cap { * DOMAIN_ATTR_FSL_PAMUV1 corresponds to the above mentioned contraints. * The caller can invoke iommu_domain_get_attr to check if the underlying * iommu implementation supports these constraints. + * + * DOMAIN_ATTR_NO_CFRE + * Some bus implementations may enter a bad state if iommu reports an error + * on context fault. As context faults are not always fatal, this must be + * avoided. */ enum iommu_attr { @@ -163,6 +168,7 @@ enum iommu_attr { DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR, DOMAIN_ATTR_QCOM_MMU500_ERRATA_MIN_IOVA_ALIGN, DOMAIN_ATTR_USE_LLC_NWA, + DOMAIN_ATTR_NO_CFRE, DOMAIN_ATTR_MAX, }; diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 9385aa57497b80851cbe7bfd6adc83c60f03034c..a27cf66523279c1a5d4aaa0d0087f1e9d48d170f 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -62,8 +62,11 @@ extern int register_refined_jiffies(long clock_tick_rate); /* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ #define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) -/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ -#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) +/* TICK_USEC is the time between ticks in usec assuming SHIFTED_HZ */ +#define TICK_USEC ((USEC_PER_SEC + HZ/2) / HZ) + +/* USER_TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ +#define USER_TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) #ifndef __jiffy_arch_data #define __jiffy_arch_data diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 911aa616461769ec18528d0b091f63b786dd6568..1d8fb03b97ca395ff46054ffe9cc0851982c07f7 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -14,6 +14,9 @@ struct mem_section; struct memory_block; struct resource; +/* Timeout for migration re-tries in seconds */ +#define MIGRATE_TIMEOUT_SEC 60 + #ifdef CONFIG_MEMORY_HOTPLUG /* * Return page for the valid pfn only if the page is online. All pfn diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 40846e64ceaff0ddfc34ea1936249b80c3baf1b9..b6b313944e61b927cf3b112a95a1f11ffe133af5 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -72,6 +72,44 @@ enum mhi_device_type { MHI_CONTROLLER_TYPE, }; +/** + * enum mhi_ee - device current execution enviornment + * @MHI_EE_PBL - device in PBL + * @MHI_EE_SBL - device in SBL + * @MHI_EE_AMSS - device in mission mode (firmware fully loaded) + * @MHI_EE_RDDM - device in ram dump collection mode + * @MHI_EE_WFW - device in WLAN firmware mode + * @MHI_EE_PTHRU - device in PBL but configured in pass thru mode + * @MHI_EE_EDL - device in emergency download mode + */ +enum mhi_ee { + MHI_EE_PBL = 0x0, + MHI_EE_SBL = 0x1, + MHI_EE_AMSS = 0x2, + MHI_EE_RDDM = 0x3, + MHI_EE_WFW = 0x4, + MHI_EE_PTHRU = 0x5, + MHI_EE_EDL = 0x6, + MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, + MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ + MHI_EE_MAX, +}; + +/** + * enum mhi_dev_state - device current MHI state + */ +enum mhi_dev_state { + MHI_STATE_RESET = 0x0, + MHI_STATE_READY = 0x1, + MHI_STATE_M0 = 0x2, + MHI_STATE_M1 = 0x3, + MHI_STATE_M2 = 0x4, + MHI_STATE_M3 = 0x5, + MHI_STATE_BHI = 0x7, + MHI_STATE_SYS_ERR = 0xFF, + MHI_STATE_MAX, +}; + /** * struct image_info - firmware and rddm table table * @mhi_buf - Contain device firmware and rddm table @@ -195,8 +233,8 @@ struct mhi_controller { bool pre_init; rwlock_t pm_lock; u32 pm_state; - u32 ee; - u32 dev_state; + enum mhi_ee ee; + enum mhi_dev_state dev_state; bool wake_set; atomic_t dev_wake; atomic_t alloc_size; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index f3765155fa4d9a61266848fc482d467d8693c897..1d793d86d55fa1ba444fd64cc417cdd9071ecaf8 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -857,7 +857,7 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_at_1a4[0x1]; u8 ets[0x1]; u8 nic_flow_table[0x1]; - u8 eswitch_flow_table[0x1]; + u8 eswitch_manager[0x1]; u8 early_vf_enable[0x1]; u8 mcam_reg[0x1]; u8 pcam_reg[0x1]; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 426f8d78415d23fef435a43ce016d5732f2d5c98..0cf555098c8234447b5a9cbaa147472ba924a517 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -704,6 +704,9 @@ struct mmc_host { */ void *cmdq_private; struct mmc_request *err_mrq; + + atomic_t rpmb_req_pending; + struct mutex rpmb_req_mutex; unsigned long private[0] ____cacheline_aligned; }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index cdd66a5fbd5e00905ff5e6c2623e6efaf12bf225..0a7abe8a407ff223bfdbd18890a0b20bac9f4aee 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -35,6 +35,7 @@ #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 #define SDIO_DEVICE_ID_BROADCOM_4339 0x4339 #define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 +#define SDIO_DEVICE_ID_BROADCOM_43364 0xa9a4 #define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 #define SDIO_DEVICE_ID_BROADCOM_4345 0x4345 #define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index da6bb5bb3658fbeb3fc6d8a91006a8724b6028bb..68b4d9720ab795c669dedf7b97980c11e0a8eb1c 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -40,8 +40,6 @@ enum migratetype { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RECLAIMABLE, - MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ - MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, #ifdef CONFIG_CMA /* * MIGRATE_CMA migration type is designed to mimic the way @@ -58,6 +56,8 @@ enum migratetype { */ MIGRATE_CMA, #endif + MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ + MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, #ifdef CONFIG_MEMORY_ISOLATION MIGRATE_ISOLATE, /* can't allocate from here */ #endif @@ -66,20 +66,15 @@ enum migratetype { /* In mm/page_alloc.c; keep in sync also with show_migration_types() there */ extern char * const migratetype_names[MIGRATE_TYPES]; -/* - * Returns a list which contains the migrate types on to which - * an allocation falls back when the free list for the migrate - * type mtype is depleted. - * The end of the list is delimited by the type MIGRATE_TYPES. - */ -extern int *get_migratetype_fallbacks(int mtype); #ifdef CONFIG_CMA # define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) # define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA) +# define get_cma_migrate_type() MIGRATE_CMA #else # define is_migrate_cma(migratetype) false # define is_migrate_cma_page(_page) false +# define get_cma_migrate_type() MIGRATE_MOVABLE #endif static inline bool is_migrate_movable(int mt) @@ -388,6 +383,10 @@ struct zone { struct pglist_data *zone_pgdat; struct per_cpu_pageset __percpu *pageset; +#ifdef CONFIG_CMA + bool cma_alloc; +#endif + #ifndef CONFIG_SPARSEMEM /* * Flags for a pageblock_nr_pages block. See pageblock-flags.h. diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index bcbc8d727aac3da6bfe3088a494c3bbd48883db1..67959d2e5e9418b4d248b40637b00acf9cc170ab 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -1296,6 +1296,19 @@ int gsi_unmap_base(void); */ int gsi_map_virtual_ch_to_per_ep(u32 ee, u32 chan_num, u32 per_ep_index); +/** + * gsi_alloc_channel_ee - Peripheral should call this function + * to alloc other EE's channel. This is usually done in bootup to allocate all + * chnnels. + * + * @chan_idx: Virtual channel index + * @ee: EE + * @code: [out] response code for operation + + * @Return gsi_status + */ +int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code); + /* * Here is a typical sequence of calls * @@ -1543,5 +1556,11 @@ static inline int gsi_map_virtual_ch_to_per_ep( return -GSI_STATUS_UNSUPPORTED_OP; } +static inline int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, + int *code) +{ + return -GSI_STATUS_UNSUPPORTED_OP; +} + #endif #endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 933259a40671b2a4b873e5f271aeb4d806c6b219..49eb529f546829a4bd06d9d0abcdc63e9fede2ad 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2665,11 +2665,31 @@ static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, if (PTR_ERR(pp) != -EINPROGRESS) NAPI_GRO_CB(skb)->flush |= flush; } +static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb, + struct sk_buff **pp, + int flush, + struct gro_remcsum *grc) +{ + if (PTR_ERR(pp) != -EINPROGRESS) { + NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_remcsum_cleanup(skb, grc); + skb->remcsum_offload = 0; + } +} #else static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush) { NAPI_GRO_CB(skb)->flush |= flush; } +static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb, + struct sk_buff **pp, + int flush, + struct gro_remcsum *grc) +{ + NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_remcsum_cleanup(skb, grc); + skb->remcsum_offload = 0; +} #endif static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, diff --git a/include/linux/netfilter/ipset/ip_set_timeout.h b/include/linux/netfilter/ipset/ip_set_timeout.h index bfb3531fd88a4f7811e6ef9fffbaff672dfa6c53..7ad8ddf9ca8a412cd69096c5780a510470b06778 100644 --- a/include/linux/netfilter/ipset/ip_set_timeout.h +++ b/include/linux/netfilter/ipset/ip_set_timeout.h @@ -65,8 +65,14 @@ ip_set_timeout_set(unsigned long *timeout, u32 value) static inline u32 ip_set_timeout_get(const unsigned long *timeout) { - return *timeout == IPSET_ELEM_PERMANENT ? 0 : - jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC; + u32 t; + + if (*timeout == IPSET_ELEM_PERMANENT) + return 0; + + t = jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC; + /* Zero value in userspace means no timeout */ + return t == 0 ? 1 : t; } #endif /* __KERNEL__ */ diff --git a/include/linux/pfk.h b/include/linux/pfk.h index 3c7a389fd4d4e2e06822fd7fbee330d868b7548e..8cc20edb6802977395d19a33197991aebb2b0f13 100644 --- a/include/linux/pfk.h +++ b/include/linux/pfk.h @@ -19,8 +19,22 @@ struct ice_crypto_setting; #ifdef CONFIG_PFK +/* + * Default key for inline encryption. + * + * For now only AES-256-XTS is supported, so this is a fixed length. But if + * ever needed, this should be made variable-length with a 'mode' and 'size'. + * (Remember to update pfk_allow_merge_bio() when doing so!) + */ +#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64 + +struct blk_encryption_key { + u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS]; +}; + int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, bool *is_pfe, bool); + struct ice_crypto_setting *ice_setting, + bool *is_pfe, bool async); int pfk_load_key_end(const struct bio *bio, bool *is_pfe); int pfk_remove_key(const unsigned char *key, size_t key_size); bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 0d370cd2b3ae38d4e744b4fe45bbf2419c435e96..69ca434d09b4eab722ef7fc25d39c7137ed0d57b 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -307,6 +307,8 @@ enum power_supply_property { POWER_SUPPLY_PROP_ESR_ACTUAL, POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_SOH, + POWER_SUPPLY_PROP_FORCE_RECHARGE, + POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ diff --git a/include/linux/qcom_tspp.h b/include/linux/qcom_tspp.h new file mode 100644 index 0000000000000000000000000000000000000000..a598c8fb3c3d127659a04fd0c09a8cbf254b3aae --- /dev/null +++ b/include/linux/qcom_tspp.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MSM_TSPP_H_ +#define _MSM_TSPP_H_ + +struct tspp_data_descriptor { + void *virt_base; /* logical address of the actual data */ + phys_addr_t phys_base; /* physical address of the actual data */ + dma_addr_t dma_base; /* DMA address of the actual data */ + u32 size; /* size of buffer in bytes */ + int id; /* unique identifier */ + void *user; /* user-defined data */ +}; + +enum tspp_key_parity { + TSPP_KEY_PARITY_EVEN, + TSPP_KEY_PARITY_ODD +}; + +struct tspp_key { + enum tspp_key_parity parity; + int lsb; + int msb; +}; + +enum tspp_source { + TSPP_SOURCE_TSIF0, + TSPP_SOURCE_TSIF1, + TSPP_SOURCE_MEM, + TSPP_SOURCE_NONE = -1 +}; + +enum tspp_mode { + TSPP_MODE_DISABLED, + TSPP_MODE_PES, + TSPP_MODE_RAW, + TSPP_MODE_RAW_NO_SUFFIX +}; + +enum tspp_tsif_mode { + TSPP_TSIF_MODE_LOOPBACK, /* loopback mode */ + TSPP_TSIF_MODE_1, /* without sync */ + TSPP_TSIF_MODE_2 /* with sync signal */ +}; + +struct tspp_filter { + int pid; + int mask; + enum tspp_mode mode; + unsigned int priority; /* 0 - 15 */ + int decrypt; + enum tspp_source source; +}; + +struct tspp_select_source { + enum tspp_source source; + enum tspp_tsif_mode mode; + int clk_inverse; + int data_inverse; + int sync_inverse; + int enable_inverse; +}; + +enum tsif_tts_source { + TSIF_TTS_TCR = 0, /* Time stamps from TCR counter */ + TSIF_TTS_LPASS_TIMER /* Time stamps from AV/Qtimer Timer */ +}; + +struct tspp_ion_dma_buf_info { + struct dma_buf *dbuf; + struct dma_buf_attachment *attach; + struct sg_table *table; + bool smmu_map; + void *va; +}; + +typedef void (tspp_notifier)(int channel_id, void *user); +typedef void* (tspp_allocator)(int channel_id, u32 size, + phys_addr_t *phys_base, dma_addr_t *dma_base, void *user); +typedef void (tspp_memfree)(int channel_id, u32 size, + void *virt_base, phys_addr_t phys_base, void *user); + +/* Kernel API functions */ +int tspp_open_stream(u32 dev, u32 channel_id, + struct tspp_select_source *source); +int tspp_close_stream(u32 dev, u32 channel_id); +int tspp_open_channel(u32 dev, u32 channel_id); +int tspp_close_channel(u32 dev, u32 channel_id); +int tspp_get_ref_clk_counter(u32 dev, + enum tspp_source source, u32 *tcr_counter); +int tspp_add_filter(u32 dev, u32 channel_id, struct tspp_filter *filter); +int tspp_remove_filter(u32 dev, u32 channel_id, struct tspp_filter *filter); +int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key); +int tspp_register_notification(u32 dev, u32 channel_id, tspp_notifier *notify, + void *data, u32 timer_ms); +int tspp_unregister_notification(u32 dev, u32 channel_id); +const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id); +int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id); +int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, + u32 size, u32 int_freq, tspp_allocator *alloc, + tspp_memfree *memfree, void *user); + +int tspp_get_tts_source(u32 dev, int *tts_source); +int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source, + u64 *lpass_time_counter); + +int tspp_attach_ion_dma_buff(u32 dev, + struct tspp_ion_dma_buf_info *ion_dma_buf); + +int tspp_detach_ion_dma_buff(u32 dev, + struct tspp_ion_dma_buf_info *ion_dma_buf); +void *tspp_allocate_dma_buffer(u32 dev, int size, phys_addr_t *paddr); +int tspp_free_dma_buffer(u32 dev, int size, void *vaddr, dma_addr_t paddr); +#endif /* _MSM_TSPP_H_ */ diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 56a81d8112fb2928b7f03b19ee45b550f2bddb3f..6c5dc5d67720d4729ed58450fab98d82dc799386 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -80,6 +80,7 @@ struct regmap; * These modes can be OR'ed together to make up a mask of valid register modes. */ +#define REGULATOR_MODE_INVALID 0x0 #define REGULATOR_MODE_FAST 0x1 #define REGULATOR_MODE_NORMAL 0x2 #define REGULATOR_MODE_IDLE 0x4 diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 289e4d54e3e05e37a620e44199681c8114259bed..5caa062a02b2736b32b90e50783579ff0c6df085 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -160,6 +160,7 @@ void ring_buffer_record_enable(struct ring_buffer *buffer); void ring_buffer_record_off(struct ring_buffer *buffer); void ring_buffer_record_on(struct ring_buffer *buffer); int ring_buffer_record_is_on(struct ring_buffer *buffer); +int ring_buffer_record_is_set_on(struct ring_buffer *buffer); void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); diff --git a/include/linux/sched.h b/include/linux/sched.h index 01a2d42d5589b0d16913596396289c9328ef4ebd..5885ead112314ef8b5e00908e5602ecf5be879f3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -591,6 +591,8 @@ struct ravg { * * 'busy_buckets' groups historical busy time into different buckets * used for prediction + * + * 'demand_scaled' represents task's demand scaled to 1024 */ u64 mark_start; u32 sum, demand; @@ -601,6 +603,8 @@ struct ravg { u16 active_windows; u32 pred_demand; u8 busy_buckets[NUM_BUSY_BUCKETS]; + u16 demand_scaled; + u16 pred_demand_scaled; }; #else static inline void sched_exit(struct task_struct *p) { } @@ -782,7 +786,6 @@ struct task_struct { */ u32 init_load_pct; u64 last_wake_ts; - u64 last_switch_out_ts; u64 last_enqueued_ts; struct related_thread_group *grp; struct list_head grp_list; @@ -1915,6 +1918,7 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu) # define vcpu_is_preempted(cpu) false #endif +extern long msm_sched_setaffinity(pid_t pid, struct cpumask *new_mask); extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask); extern long sched_getaffinity(pid_t pid, struct cpumask *mask); diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 4a059b73eedf891bd013d18b32b832dd859c8b35..d02fb9c24555ef2ad9848518be64e13019fc5494 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -129,4 +129,9 @@ extern int sched_little_cluster_coloc_fmin_khz_handler(struct ctl_table *table, size_t *lenp, loff_t *ppos); #endif +#define LIB_PATH_LENGTH 512 +extern char sched_lib_name[LIB_PATH_LENGTH]; +extern unsigned int sched_lib_mask_check; +extern unsigned int sched_lib_mask_force; + #endif /* _LINUX_SCHED_SYSCTL_H */ diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h index 677c0fcee80441043be25bbebb19bbf6b38b4f43..bb2d62b3a15691b8e48ecb72823503bc69305c6e 100644 --- a/include/linux/sched/task.h +++ b/include/linux/sched/task.h @@ -75,7 +75,7 @@ extern long _do_fork(unsigned long, unsigned long, unsigned long, int __user *, extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); struct task_struct *fork_idle(int); extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); -extern long kernel_wait4(pid_t, int *, int, struct rusage *); +extern long kernel_wait4(pid_t, int __user *, int, struct rusage *); extern void free_task(struct task_struct *tsk); diff --git a/include/linux/security.h b/include/linux/security.h index 30fb23a4ca81ff5717da79e2f8a8ca5e513b4dcb..0cd947e5fb00edc4f6ef7facfe83f56b1df064e9 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -668,8 +668,8 @@ static inline int security_inode_create(struct inode *dir, } static inline int security_inode_post_create(struct inode *dir, - struct dentry *dentry, - umode_t mode) + struct dentry *dentry, + umode_t mode) { return 0; } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 9c7dfd1c3bec50cb68c22238c458ab37bdbfd0c4..c9dac4ae91e584316a588b15aa7ef042107df057 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -349,7 +349,8 @@ struct earlycon_device { }; struct earlycon_id { - char name[16]; + char name[15]; + char name_term; /* In case compiler didn't '\0' term name */ char compatible[128]; int (*setup)(struct earlycon_device *, const char *options); }; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d22d14bda0fc1c62bd5eb0d70084badcb64c3fb9..66220cc6b45c05d50f4a8d7e745745f7cfc82690 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -626,6 +626,7 @@ typedef unsigned char *sk_buff_data_t; * @hash: the packet hash * @queue_mapping: Queue mapping for multiqueue devices * @xmit_more: More SKBs are pending for this queue + * @pfmemalloc: skbuff was allocated from PFMEMALLOC reserves * @ndisc_nodetype: router type (from link layer) * @ooo_okay: allow the mapping of a socket to a queue to be changed * @l4_hash: indicate hash is a canonical 4-tuple hash over transport @@ -724,7 +725,7 @@ struct sk_buff { peeked:1, head_frag:1, xmit_more:1, - __unused:1; /* one bit hole */ + pfmemalloc:1; /* fields enclosed in headers_start/headers_end are copied * using a single memcpy() in __copy_skb_header() @@ -743,31 +744,30 @@ struct sk_buff { __u8 __pkt_type_offset[0]; __u8 pkt_type:3; - __u8 pfmemalloc:1; __u8 ignore_df:1; - __u8 nf_trace:1; __u8 ip_summed:2; __u8 ooo_okay:1; + __u8 l4_hash:1; __u8 sw_hash:1; __u8 wifi_acked_valid:1; __u8 wifi_acked:1; - __u8 no_fcs:1; /* Indicates the inner headers are valid in the skbuff. */ __u8 encapsulation:1; __u8 encap_hdr_csum:1; __u8 csum_valid:1; + __u8 csum_complete_sw:1; __u8 csum_level:2; __u8 csum_not_inet:1; - __u8 dst_pending_confirm:1; #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif __u8 ipvs_property:1; + __u8 inner_protocol_type:1; __u8 remcsum_offload:1; #ifdef CONFIG_NET_SWITCHDEV diff --git a/include/linux/string.h b/include/linux/string.h index cfd83eb2f926c74622f46ed931bb1c58277df49f..96115bf561b452112f411ecbcd61f5e016b00911 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -28,7 +28,7 @@ extern char * strncpy(char *,const char *, __kernel_size_t); size_t strlcpy(char *, const char *, size_t); #endif #ifndef __HAVE_ARCH_STRSCPY -ssize_t __must_check strscpy(char *, const char *, size_t); +ssize_t strscpy(char *, const char *, size_t); #endif #ifndef __HAVE_ARCH_STRCAT extern char * strcat(char *, const char *); diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 34f053a150a969bf03805cd56ee7f5487e041642..cf2862bd134a400b99136aaf2ec1357bd79ba3d2 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -43,11 +43,7 @@ enum { #define THREAD_ALIGN THREAD_SIZE #endif -#if IS_ENABLED(CONFIG_DEBUG_STACK_USAGE) || IS_ENABLED(CONFIG_DEBUG_KMEMLEAK) -# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO) -#else -# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT) -#endif +#define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO) /* * flag set/clear/test wrappers diff --git a/include/linux/tick.h b/include/linux/tick.h index 276573c28ab303fa72eb20b3b6f130b8006fb9a8..06554d5cc6f794da1fef04588eb560c2e35247d2 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -114,26 +114,45 @@ enum tick_dep_bits { #ifdef CONFIG_NO_HZ_COMMON extern bool tick_nohz_enabled; extern int tick_nohz_tick_stopped(void); +extern void tick_nohz_idle_stop_tick(void); +extern void tick_nohz_idle_retain_tick(void); +extern void tick_nohz_idle_restart_tick(void); extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); -extern ktime_t tick_nohz_get_sleep_length(void); +extern bool tick_nohz_idle_got_tick(void); +extern ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next); extern unsigned long tick_nohz_get_idle_calls(void); extern unsigned long tick_nohz_get_idle_calls_cpu(int cpu); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); + +static inline void tick_nohz_idle_stop_tick_protected(void) +{ + local_irq_disable(); + tick_nohz_idle_stop_tick(); + local_irq_enable(); +} + #else /* !CONFIG_NO_HZ_COMMON */ #define tick_nohz_enabled (0) static inline int tick_nohz_tick_stopped(void) { return 0; } +static inline void tick_nohz_idle_stop_tick(void) { } +static inline void tick_nohz_idle_retain_tick(void) { } +static inline void tick_nohz_idle_restart_tick(void) { } static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } +static inline bool tick_nohz_idle_got_tick(void) { return false; } -static inline ktime_t tick_nohz_get_sleep_length(void) +static inline ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next) { - return NSEC_PER_SEC / HZ; + *delta_next = TICK_NSEC; + return *delta_next; } static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; } + +static inline void tick_nohz_idle_stop_tick_protected(void) { } #endif /* !CONFIG_NO_HZ_COMMON */ #ifdef CONFIG_NO_HZ_FULL diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9a1fabc6ff03f1eee6848bd83d35b0be0984c72c..46b467d68b8df60dcbff9b4b8f4639af604e40d6 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -45,6 +45,9 @@ #define FUNC_SUSPEND_OPT_SUSP_MASK BIT(0) #define FUNC_SUSPEND_OPT_RW_EN_MASK BIT(1) +#define FUNC_WAKEUP_CAPABLE_SHIFT 0 +#define FUNC_WAKEUP_ENABLE_SHIFT 1 + /* * USB function drivers should return USB_GADGET_DELAYED_STATUS if they * wish to delay the data/status stages of the control transfer till they diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 8642f030f05a6bc8f64e5848f987ef0024ae9c0b..0ad1073a881616446bb88b220bea7f287550b7a2 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -164,6 +164,7 @@ struct usb_phy { int (*notify_disconnect)(struct usb_phy *x, enum usb_device_speed speed); int (*link_training)(struct usb_phy *x, bool start); + int (*powerup)(struct usb_phy *x, bool start); /* * Charger detection method can be implemented if you need to @@ -406,6 +407,24 @@ usb_phy_stop_link_training(struct usb_phy *x) return 0; } +static inline int +usb_phy_powerup(struct usb_phy *x) +{ + if (x && x->powerup) + return x->powerup(x, true); + else + return 0; +} + +static inline int +usb_phy_powerdown(struct usb_phy *x) +{ + if (x && x->powerup) + return x->powerup(x, false); + else + return 0; +} + static inline int usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) { diff --git a/include/linux/verification.h b/include/linux/verification.h index a10549a6c7cdfa72d805d5509fc9c1286c36324b..5a088dab92e2cbbc93d645893491b3f763d3ab73 100644 --- a/include/linux/verification.h +++ b/include/linux/verification.h @@ -26,9 +26,13 @@ enum key_being_used_for { }; extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; -#ifdef CONFIG_SYSTEM_DATA_VERIFICATION - struct key; +struct public_key_signature; + +extern int verify_signature_one(const struct public_key_signature *sig, + struct key *trusted_keys, const char *keyid); + +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION extern int verify_pkcs7_signature(const void *data, size_t len, const void *raw_pkcs7, size_t pkcs7_len, diff --git a/include/net/ipv6.h b/include/net/ipv6.h index d9ed0372b205b14e45616abaf5d6d754e62a307f..b70bdc382b1fe3bf32ece1839a01781046b09879 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -796,7 +796,7 @@ static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, * to minimize possbility that any useful information to an * attacker is leaked. Only lower 20 bits are relevant. */ - rol32(hash, 16); + hash = rol32(hash, 16); flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; diff --git a/include/net/tcp.h b/include/net/tcp.h index 71082ba003d7360b7ec2b99c377134fb9ab7a5c8..12d992d978442eba3975ab838a61048f93e4ddb1 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -373,6 +373,7 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); +void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks); static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { @@ -561,6 +562,7 @@ void tcp_send_fin(struct sock *sk); void tcp_send_active_reset(struct sock *sk, gfp_t priority); int tcp_send_synack(struct sock *); void tcp_push_one(struct sock *, unsigned int mss_now); +void __tcp_send_ack(struct sock *sk, u32 rcv_nxt); void tcp_send_ack(struct sock *sk); void tcp_send_delayed_ack(struct sock *sk); void tcp_send_loss_probe(struct sock *sk); @@ -858,6 +860,11 @@ struct tcp_skb_cb { * as TCP moves IP6CB into a different location in skb->cb[] */ static inline int tcp_v6_iif(const struct sk_buff *skb) +{ + return TCP_SKB_CB(skb)->header.h6.iif; +} + +static inline int tcp_v6_iif_l3_slave(const struct sk_buff *skb) { bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 00f18dd00372e6722119a16da549c524022eb2db..8fd4cda282c3b2ef7d945fe024e473a86d4b9b57 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -663,6 +663,9 @@ struct Scsi_Host { /* The controller does not support WRITE SAME */ unsigned no_write_same:1; + /* Inline encryption support? */ + unsigned inlinecrypt_support:1; + unsigned use_blk_mq:1; unsigned use_cmd_list:1; diff --git a/include/soc/qcom/rmnet_qmi.h b/include/soc/qcom/rmnet_qmi.h index 4d2fc027754715584ff4f990b36cf608afb58800..0b5debd3157c9d926a280b5bc470772cd093232d 100644 --- a/include/soc/qcom/rmnet_qmi.h +++ b/include/soc/qcom/rmnet_qmi.h @@ -15,6 +15,10 @@ #define _RMNET_QMI_H #include +#include + +void rmnet_map_tx_qmap_cmd(struct sk_buff *qmap_skb); + #ifdef CONFIG_QCOM_QMI_RMNET void *rmnet_get_qmi_pt(void *port); void *rmnet_get_qos_pt(struct net_device *dev); diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index 44202ff897fd93a75e7bc7029d9733ffff2b20ec..f759e0918037baa4286328281cc9efcd416be61d 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -99,6 +99,8 @@ struct tegra_mc_soc { u8 client_id_mask; const struct tegra_smmu_soc *smmu; + + u32 intmask; }; struct tegra_mc { diff --git a/include/trace/events/dfc.h b/include/trace/events/dfc.h index dc8dd5ae23b95d15962b1d896dc4d116cf5bc6c5..dc763220e656756308e0739f1af3e1dde7411717 100644 --- a/include/trace/events/dfc.h +++ b/include/trace/events/dfc.h @@ -18,7 +18,7 @@ #include -TRACE_EVENT(dfc_qmi_tc, +DECLARE_EVENT_CLASS(dfc_tc, TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen, u32 tcm_handle, int enable), @@ -50,6 +50,22 @@ TRACE_EVENT(dfc_qmi_tc, __entry->enable ? "enable" : "disable") ); +DEFINE_EVENT(dfc_tc, dfc_qmi_tc, + + TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen, + u32 tcm_handle, int enable), + + TP_ARGS(bearer_id, flow_id, grant, qlen, tcm_handle, enable) +); + +DEFINE_EVENT(dfc_tc, dfc_qmi_tc_limit, + + TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen, + u32 tcm_handle, int enable), + + TP_ARGS(bearer_id, flow_id, grant, qlen, tcm_handle, enable) +); + TRACE_EVENT(dfc_flow_ind, TP_PROTO(int src, int idx, u8 mux_id, u8 bearer_id, u32 grant, @@ -179,6 +195,33 @@ TRACE_EVENT(dfc_client_state_down, __entry->idx, __entry->from_cb) ); +TRACE_EVENT(dfc_qmap_cmd, + + TP_PROTO(u8 mux_id, u8 bearer_id, u16 seq_num, u8 type, u32 tran), + + TP_ARGS(mux_id, bearer_id, seq_num, type, tran), + + TP_STRUCT__entry( + __field(u8, mid) + __field(u8, bid) + __field(u16, seq) + __field(u8, type) + __field(u32, tran) + ), + + TP_fast_assign( + __entry->mid = mux_id; + __entry->bid = bearer_id; + __entry->seq = seq_num; + __entry->type = type; + __entry->tran = tran; + ), + + TP_printk("mux_id=%u bearer_id=%u seq_num=%u type=%u tran=%u", + __entry->mid, __entry->bid, __entry->seq, + __entry->type, __entry->tran) +); + #endif /* _TRACE_DFC_H */ /* This part must be outside protection */ diff --git a/include/trace/events/net.h b/include/trace/events/net.h index f1a300c8ef8517775f9ad286ee1440f1cc3854f8..135141e93a6ea89dd4e591e3e6c76e8ebab462b3 100644 --- a/include/trace/events/net.h +++ b/include/trace/events/net.h @@ -124,13 +124,6 @@ DEFINE_EVENT(net_dev_template, net_dev_queue, TP_ARGS(skb) ); -DEFINE_EVENT(net_dev_template, netif_receive_skb, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb) -); - DEFINE_EVENT(net_dev_template, netif_rx, TP_PROTO(struct sk_buff *skb), @@ -216,6 +209,13 @@ DEFINE_EVENT(net_dev_rx_verbose_template, napi_gro_receive_entry, TP_ARGS(skb) ); +DEFINE_EVENT(net_dev_rx_verbose_template, netif_receive_skb, + + TP_PROTO(const struct sk_buff *skb), + + TP_ARGS(skb) +); + DEFINE_EVENT(net_dev_rx_verbose_template, netif_receive_skb_entry, TP_PROTO(const struct sk_buff *skb), diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index d1f6a726a4d2152628303907cf83da0090c0fca2..d065ec4d5f7b547969e1e3cf30386a0b4a628f97 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -1020,9 +1020,9 @@ TRACE_EVENT(core_ctl_update_nr_need, TRACE_EVENT(sched_tune_tasks_update, TP_PROTO(struct task_struct *tsk, int cpu, int tasks, int idx, - int boost, int max_boost), + int boost, int max_boost, u64 group_ts), - TP_ARGS(tsk, cpu, tasks, idx, boost, max_boost), + TP_ARGS(tsk, cpu, tasks, idx, boost, max_boost, group_ts), TP_STRUCT__entry( __array( char, comm, TASK_COMM_LEN ) @@ -1032,6 +1032,7 @@ TRACE_EVENT(sched_tune_tasks_update, __field( int, idx ) __field( int, boost ) __field( int, max_boost ) + __field( u64, group_ts ) ), TP_fast_assign( @@ -1042,13 +1043,15 @@ TRACE_EVENT(sched_tune_tasks_update, __entry->idx = idx; __entry->boost = boost; __entry->max_boost = max_boost; + __entry->group_ts = group_ts; ), TP_printk("pid=%d comm=%s " - "cpu=%d tasks=%d idx=%d boost=%d max_boost=%d", + "cpu=%d tasks=%d idx=%d boost=%d max_boost=%d timeout=%llu", __entry->pid, __entry->comm, __entry->cpu, __entry->tasks, __entry->idx, - __entry->boost, __entry->max_boost) + __entry->boost, __entry->max_boost, + __entry->group_ts) ); /* diff --git a/include/trace/events/walt.h b/include/trace/events/walt.h index f98e348cea60b5f722b62b15b3833c0e2fe0268b..888c36b9d8b35dc84a1096d3ac3f30dd674f2fab 100644 --- a/include/trace/events/walt.h +++ b/include/trace/events/walt.h @@ -470,7 +470,7 @@ DECLARE_EVENT_CLASS(sched_cpu_load, __entry->nr_big_tasks = rq->walt_stats.nr_big_tasks; __entry->load_scale_factor = cpu_load_scale_factor(rq->cpu); __entry->capacity = cpu_capacity(rq->cpu); - __entry->cumulative_runnable_avg = rq->walt_stats.cumulative_runnable_avg; + __entry->cumulative_runnable_avg = rq->walt_stats.cumulative_runnable_avg_scaled; __entry->irqload = irqload; __entry->max_freq = cpu_max_freq(rq->cpu); __entry->power_cost = power_cost; @@ -532,7 +532,7 @@ TRACE_EVENT(sched_load_to_gov, __entry->grp_rq_ps = rq->grp_time.prev_runnable_sum; __entry->nt_ps = rq->nt_prev_runnable_sum; __entry->grp_nt_ps = rq->grp_time.nt_prev_runnable_sum; - __entry->pl = rq->walt_stats.pred_demands_sum; + __entry->pl = rq->walt_stats.pred_demands_sum_scaled; __entry->load = load; __entry->big_task_rotation = big_task_rotation; __entry->sysctl_sched_little_cluster_coloc_fmin_khz = diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h index c10f1324b4ca54ba8ed6abb55ea7b75ad18ae155..0a1af707ad58ea6cf2994a6e04722751a1f2e70b 100644 --- a/include/uapi/linux/dvb/dmx.h +++ b/include/uapi/linux/dvb/dmx.h @@ -33,6 +33,11 @@ #define DMX_FILTER_SIZE 16 +/* Min recording chunk upon which event is generated */ +#define DMX_REC_BUFF_CHUNK_MIN_SIZE (100*188) + +#define DMX_MAX_DECODER_BUFFER_NUM (32) + /** * enum dmx_output - Output for the demux. * @@ -178,37 +183,736 @@ struct dmx_sct_filter_params { #define DMX_CHECK_CRC 1 #define DMX_ONESHOT 2 #define DMX_IMMEDIATE_START 4 +#define DMX_KERNEL_CLIENT 0x8000 }; -/** - * struct dmx_pes_filter_params - Specifies Packetized Elementary Stream (PES) - * filter parameters. - * - * @pid: PID to be filtered. - * @input: Demux input, as specified by &enum dmx_input. - * @output: Demux output, as specified by &enum dmx_output. - * @pes_type: Type of the pes filter, as specified by &enum dmx_pes_type. - * @flags: Demux PES flags. - */ +enum dmx_video_codec { + DMX_VIDEO_CODEC_MPEG2, + DMX_VIDEO_CODEC_H264, + DMX_VIDEO_CODEC_VC1 +}; + +/* Index entries types */ +#define DMX_IDX_RAI 0x00000001 +#define DMX_IDX_PUSI 0x00000002 +#define DMX_IDX_MPEG_SEQ_HEADER 0x00000004 +#define DMX_IDX_MPEG_GOP 0x00000008 +#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_START 0x00000010 +#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_END 0x00000020 +#define DMX_IDX_MPEG_I_FRAME_START 0x00000040 +#define DMX_IDX_MPEG_I_FRAME_END 0x00000080 +#define DMX_IDX_MPEG_P_FRAME_START 0x00000100 +#define DMX_IDX_MPEG_P_FRAME_END 0x00000200 +#define DMX_IDX_MPEG_B_FRAME_START 0x00000400 +#define DMX_IDX_MPEG_B_FRAME_END 0x00000800 +#define DMX_IDX_H264_SPS 0x00001000 +#define DMX_IDX_H264_PPS 0x00002000 +#define DMX_IDX_H264_FIRST_SPS_FRAME_START 0x00004000 +#define DMX_IDX_H264_FIRST_SPS_FRAME_END 0x00008000 +#define DMX_IDX_H264_IDR_START 0x00010000 +#define DMX_IDX_H264_IDR_END 0x00020000 +#define DMX_IDX_H264_NON_IDR_START 0x00040000 +#define DMX_IDX_H264_NON_IDR_END 0x00080000 +#define DMX_IDX_VC1_SEQ_HEADER 0x00100000 +#define DMX_IDX_VC1_ENTRY_POINT 0x00200000 +#define DMX_IDX_VC1_FIRST_SEQ_FRAME_START 0x00400000 +#define DMX_IDX_VC1_FIRST_SEQ_FRAME_END 0x00800000 +#define DMX_IDX_VC1_FRAME_START 0x01000000 +#define DMX_IDX_VC1_FRAME_END 0x02000000 +#define DMX_IDX_H264_ACCESS_UNIT_DEL 0x04000000 +#define DMX_IDX_H264_SEI 0x08000000 + struct dmx_pes_filter_params { - __u16 pid; - enum dmx_input input; + __u16 pid; + enum dmx_input input; enum dmx_output output; enum dmx_ts_pes pes_type; + __u32 flags; + + /* + * The following configures when the event + * DMX_EVENT_NEW_REC_CHUNK will be triggered. + * When new recorded data is received with size + * equal or larger than this value a new event + * will be triggered. This is relevant when + * output is DMX_OUT_TS_TAP or DMX_OUT_TSDEMUX_TAP, + * size must be at least DMX_REC_BUFF_CHUNK_MIN_SIZE + * and smaller than buffer size. + */ + __u32 rec_chunk_size; + + enum dmx_video_codec video_codec; +}; + +struct dmx_buffer_status { + /* size of buffer in bytes */ + unsigned int size; + + /* fullness of buffer in bytes */ + unsigned int fullness; + + /* + * How many bytes are free + * It's the same as: size-fullness-1 + */ + unsigned int free_bytes; + + /* read pointer offset in bytes */ + unsigned int read_offset; + + /* write pointer offset in bytes */ + unsigned int write_offset; + + /* non-zero if data error occurred */ + int error; +}; + +/* Events associated with each demux filter */ +enum dmx_event { + /* New PES packet is ready to be consumed */ + DMX_EVENT_NEW_PES = 0x00000001, + + /* New section is ready to be consumed */ + DMX_EVENT_NEW_SECTION = 0x00000002, + + /* New recording chunk is ready to be consumed */ + DMX_EVENT_NEW_REC_CHUNK = 0x00000004, + + /* New PCR value is ready */ + DMX_EVENT_NEW_PCR = 0x00000008, + + /* Overflow */ + DMX_EVENT_BUFFER_OVERFLOW = 0x00000010, + + /* Section was dropped due to CRC error */ + DMX_EVENT_SECTION_CRC_ERROR = 0x00000020, + + /* End-of-stream, no more data from this filter */ + DMX_EVENT_EOS = 0x00000040, + + /* New Elementary Stream data is ready */ + DMX_EVENT_NEW_ES_DATA = 0x00000080, + + /* Data markers */ + DMX_EVENT_MARKER = 0x00000100, + + /* New indexing entry is ready */ + DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200, + + /* + * Section filter timer expired. This is notified + * when timeout is configured to section filter + * (dmx_sct_filter_params) and no sections were + * received for the given time. + */ + DMX_EVENT_SECTION_TIMEOUT = 0x00000400, + + /* Scrambling bits change between clear and scrambled */ + DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800 +}; + +enum dmx_oob_cmd { + /* End-of-stream, no more data from this filter */ + DMX_OOB_CMD_EOS, + + /* Data markers */ + DMX_OOB_CMD_MARKER, +}; + +/* Flags passed in filter events */ + +/* Continuity counter error was detected */ +#define DMX_FILTER_CC_ERROR 0x01 + +/* Discontinuity indicator was set */ +#define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02 + +/* PES length in PES header is not correct */ +#define DMX_FILTER_PES_LENGTH_ERROR 0x04 + + +/* PES info associated with DMX_EVENT_NEW_PES event */ +struct dmx_pes_event_info { + /* Offset at which PES information starts */ + __u32 base_offset; + + /* + * Start offset at which PES data + * from the stream starts. + * Equal to base_offset if PES data + * starts from the beginning. + */ + __u32 start_offset; + + /* Total length holding the PES information */ + __u32 total_length; + + /* Actual length holding the PES data */ + __u32 actual_length; + + /* Local receiver timestamp in 27MHz */ + __u64 stc; + + /* Flags passed in filter events */ + __u32 flags; + + /* + * Number of TS packets with Transport Error Indicator (TEI) + * found while constructing the PES. + */ + __u32 transport_error_indicator_counter; + + /* Number of continuity errors found while constructing the PES */ + __u32 continuity_error_counter; + + /* Total number of TS packets holding the PES */ + __u32 ts_packets_num; +}; + +/* Section info associated with DMX_EVENT_NEW_SECTION event */ +struct dmx_section_event_info { + /* Offset at which section information starts */ + __u32 base_offset; + + /* + * Start offset at which section data + * from the stream starts. + * Equal to base_offset if section data + * starts from the beginning. + */ + __u32 start_offset; + + /* Total length holding the section information */ + __u32 total_length; + + /* Actual length holding the section data */ + __u32 actual_length; + + /* Flags passed in filter events */ + __u32 flags; +}; + +/* Recording info associated with DMX_EVENT_NEW_REC_CHUNK event */ +struct dmx_rec_chunk_event_info { + /* Offset at which recording chunk starts */ + __u32 offset; + + /* Size of recording chunk in bytes */ + __u32 size; +}; + +/* PCR info associated with DMX_EVENT_NEW_PCR event */ +struct dmx_pcr_event_info { + /* Local timestamp in 27MHz + * when PCR packet was received + */ + __u64 stc; + + /* PCR value in 27MHz */ + __u64 pcr; + + /* Flags passed in filter events */ + __u32 flags; +}; + +/* + * Elementary stream data information associated + * with DMX_EVENT_NEW_ES_DATA event + */ +struct dmx_es_data_event_info { + /* Buffer user-space handle */ + int buf_handle; + + /* + * Cookie to provide when releasing the buffer + * using the DMX_RELEASE_DECODER_BUFFER ioctl command + */ + int cookie; + + /* Offset of data from the beginning of the buffer */ + __u32 offset; + + /* Length of data in buffer (in bytes) */ + __u32 data_len; + + /* Indication whether PTS value is valid */ + int pts_valid; + + /* PTS value associated with the buffer */ + __u64 pts; + + /* Indication whether DTS value is valid */ + int dts_valid; + + /* DTS value associated with the buffer */ + __u64 dts; + + /* STC value associated with the buffer in 27MHz */ + __u64 stc; + + /* + * Number of TS packets with Transport Error Indicator (TEI) set + * in the TS packet header since last reported event + */ + __u32 transport_error_indicator_counter; + + /* Number of continuity errors since last reported event */ + __u32 continuity_error_counter; + + /* Total number of TS packets processed since last reported event */ + __u32 ts_packets_num; + + /* + * Number of dropped bytes due to insufficient buffer space, + * since last reported event + */ + __u32 ts_dropped_bytes; +}; + +/* Marker details associated with DMX_EVENT_MARKER event */ +struct dmx_marker_event_info { + /* Marker id */ + __u64 id; +}; + +/* Indexing information associated with DMX_EVENT_NEW_INDEX_ENTRY event */ +struct dmx_index_event_info { + /* Index entry type, one of DMX_IDX_* */ + __u64 type; + + /* + * The PID the index entry belongs to. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl and each can be indexed separately. + */ + __u16 pid; + + /* + * The TS packet number in the recorded data at which + * the indexing event is found. + */ + __u64 match_tsp_num; + + /* + * The TS packet number in the recorded data preceding + * match_tsp_num and has PUSI set. + */ + __u64 last_pusi_tsp_num; + + /* STC associated with match_tsp_num, in 27MHz */ + __u64 stc; +}; + +/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */ +struct dmx_scrambling_status_event_info { + /* + * The PID which its scrambling bit status changed. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have + * different scrambling bits status. + */ + __u16 pid; + + /* old value of scrambling bits */ + __u8 old_value; + + /* new value of scrambling bits */ + __u8 new_value; +}; + +/* + * Filter's event returned through DMX_GET_EVENT. + * poll with POLLPRI would block until events are available. + */ +struct dmx_filter_event { + enum dmx_event type; + + union { + struct dmx_pes_event_info pes; + struct dmx_section_event_info section; + struct dmx_rec_chunk_event_info recording_chunk; + struct dmx_pcr_event_info pcr; + struct dmx_es_data_event_info es_data; + struct dmx_marker_event_info marker; + struct dmx_index_event_info index; + struct dmx_scrambling_status_event_info scrambling_status; + } params; +}; + +/* Filter's buffer requirement returned in dmx_caps */ +struct dmx_buffer_requirement { + /* Buffer size alignment, 0 means no special requirement */ + __u32 size_alignment; + + /* Maximum buffer size allowed */ + __u32 max_size; + + /* Maximum number of linear buffers handled by demux */ + __u32 max_buffer_num; + + /* Feature support bitmap as detailed below */ __u32 flags; + +/* Buffer must be allocated as physically contiguous memory */ +#define DMX_BUFFER_CONTIGUOUS_MEM 0x1 + +/* If the filter's data is decrypted, the buffer should be secured one */ +#define DMX_BUFFER_SECURED_IF_DECRYPTED 0x2 + +/* Buffer can be allocated externally */ +#define DMX_BUFFER_EXTERNAL_SUPPORT 0x4 + +/* Buffer can be allocated internally */ +#define DMX_BUFFER_INTERNAL_SUPPORT 0x8 + +/* Filter output can be output to a linear buffer group */ +#define DMX_BUFFER_LINEAR_GROUP_SUPPORT 0x10 + +/* Buffer may be allocated as cached buffer */ +#define DMX_BUFFER_CACHED 0x20 }; -/** - * struct dmx_stc - Stores System Time Counter (STC) information. - * - * @num: input data: number of the STC, from 0 to N. - * @base: output: divisor for STC to get 90 kHz clock. - * @stc: output: stc in @base * 90 kHz units. +/* Out-of-band (OOB) command */ +struct dmx_oob_command { + enum dmx_oob_cmd type; + + union { + struct dmx_marker_event_info marker; + } params; +}; + +typedef struct dmx_caps { + __u32 caps; + +/* Indicates whether demux support playback from memory in pull mode */ +#define DMX_CAP_PULL_MODE 0x01 + +/* Indicates whether demux support indexing of recorded video stream */ +#define DMX_CAP_VIDEO_INDEXING 0x02 + +/* Indicates whether demux support sending data directly to video decoder */ +#define DMX_CAP_VIDEO_DECODER_DATA 0x04 + +/* Indicates whether demux support sending data directly to audio decoder */ +#define DMX_CAP_AUDIO_DECODER_DATA 0x08 + +/* Indicates whether demux support sending data directly to subtitle decoder */ +#define DMX_CAP_SUBTITLE_DECODER_DATA 0x10 + +/* Indicates whether TS insertion is supported */ +#define DMX_CAP_TS_INSERTION 0x20 + +/* Indicates whether playback from secured input is supported */ +#define DMX_CAP_SECURED_INPUT_PLAYBACK 0x40 + +/* Indicates whether automatic buffer flush upon overflow is allowed */ +#define DMX_CAP_AUTO_BUFFER_FLUSH 0x80 + + /* Number of decoders demux can output data to */ + int num_decoders; + + /* Number of demux devices */ + int num_demux_devices; + + /* Max number of PID filters */ + int num_pid_filters; + + /* Max number of section filters */ + int num_section_filters; + + /* + * Max number of section filters using same PID, + * 0 if not supported + */ + int num_section_filters_per_pid; + + /* + * Length of section filter, not including section + * length field (2 bytes). + */ + int section_filter_length; + + /* Max number of demod based input */ + int num_demod_inputs; + + /* Max number of memory based input */ + int num_memory_inputs; + + /* Overall bitrate from all inputs concurrently. Mbit/sec */ + int max_bitrate; + + /* Max bitrate from single demod input. Mbit/sec */ + int demod_input_max_bitrate; + + /* Max bitrate from single memory input. Mbit/sec */ + int memory_input_max_bitrate; + + /* Max number of supported cipher operations per PID */ + int num_cipher_ops; + + /* Max possible value of STC reported by demux, in 27MHz */ + __u64 max_stc; + + /* + * For indexing support (DMX_CAP_VIDEO_INDEXING capability) this is + * the max number of video pids that can be indexed for a single + * recording filter. If 0, means there is not limitation. */ + int recording_max_video_pids_indexed; + + struct dmx_buffer_requirement section; + + /* For PES not sent to decoder */ + struct dmx_buffer_requirement pes; + + /* For PES sent to decoder */ + struct dmx_buffer_requirement decoder; + + /* Recording buffer for recording of 188 bytes packets */ + struct dmx_buffer_requirement recording_188_tsp; + + /* Recording buffer for recording of 192 bytes packets */ + struct dmx_buffer_requirement recording_192_tsp; + + /* DVR input buffer for playback of 188 bytes packets */ + struct dmx_buffer_requirement playback_188_tsp; + + /* DVR input buffer for playback of 192 bytes packets */ + struct dmx_buffer_requirement playback_192_tsp; +} dmx_caps_t; + +typedef enum dmx_source { + DMX_SOURCE_FRONT0 = 0, + DMX_SOURCE_FRONT1, + DMX_SOURCE_FRONT2, + DMX_SOURCE_FRONT3, + DMX_SOURCE_DVR0 = 16, + DMX_SOURCE_DVR1, + DMX_SOURCE_DVR2, + DMX_SOURCE_DVR3 +} dmx_source_t; + +enum dmx_tsp_format_t { + DMX_TSP_FORMAT_188 = 0, + DMX_TSP_FORMAT_192_TAIL, + DMX_TSP_FORMAT_192_HEAD, + DMX_TSP_FORMAT_204, +}; + +enum dmx_playback_mode_t { + /* + * In push mode, if one of output buffers + * is full, the buffer would overflow + * and demux continue processing incoming stream. + * This is the default mode. When playing from frontend, + * this is the only mode that is allowed. + */ + DMX_PB_MODE_PUSH = 0, + + /* + * In pull mode, if one of output buffers + * is full, demux stalls waiting for free space, + * this would cause DVR input buffer fullness + * to accumulate. + * This mode is possible only when playing + * from DVR. + */ + DMX_PB_MODE_PULL, +}; + struct dmx_stc { - unsigned int num; - unsigned int base; - __u64 stc; + unsigned int num; /* input : which STC? 0..N */ + unsigned int base; /* output: divisor for stc to get 90 kHz clock */ + __u64 stc; /* output: stc in 'base'*90 kHz units */ +}; + +enum dmx_buffer_mode { + /* + * demux buffers are allocated internally + * by the demux driver. This is the default mode. + * DMX_SET_BUFFER_SIZE can be used to set the size of + * this buffer. + */ + DMX_BUFFER_MODE_INTERNAL, + + /* + * demux buffers are allocated externally and provided + * to demux through DMX_SET_BUFFER. + * When this mode is used DMX_SET_BUFFER_SIZE and + * mmap are prohibited. + */ + DMX_BUFFER_MODE_EXTERNAL, +}; + +struct dmx_buffer { + unsigned int size; + int handle; + + /* + * The following indication is relevant only when setting + * DVR input buffer. It indicates whether the input buffer + * being set is secured one or not. Secured (locked) buffers + * are required for playback from secured input. In such case + * write() syscall is not allowed. + */ + int is_protected; +}; + +struct dmx_decoder_buffers { + /* + * Specify if linear buffer support is requested. If set, buffers_num + * must be greater than 1 + */ + int is_linear; + + /* + * Specify number of external buffers allocated by user. + * If set to 0 means internal buffer allocation is requested + */ + __u32 buffers_num; + + /* Specify buffer size, either external or internal */ + __u32 buffers_size; + + /* Array of externally allocated buffer handles */ + int handles[DMX_MAX_DECODER_BUFFER_NUM]; +}; + +struct dmx_secure_mode { + /* + * Specifies whether the filter is secure or not. + * Filter should be set as secured if the filter's data *may* include + * encrypted data that would require decryption configured through + * DMX_SET_CIPHER ioctl. The setting may be done while + * filter is in idle state only. + */ + int is_secured; +}; + +struct dmx_cipher_operation { + /* Indication whether the operation is encryption or decryption */ + int encrypt; + + /* The ID of the key used for decryption or encryption */ + __u32 key_ladder_id; +}; + +#define DMX_MAX_CIPHER_OPERATIONS_COUNT 5 +struct dmx_cipher_operations { + /* + * The PID to perform the cipher operations on. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have different + * cipher operations. + */ + __u16 pid; + + /* Total number of operations */ + __u8 operations_count; + + /* + * Cipher operation to perform on the given PID. + * The operations are performed in the order they are given. + */ + struct dmx_cipher_operation operations[DMX_MAX_CIPHER_OPERATIONS_COUNT]; +}; + +struct dmx_events_mask { + /* + * Bitmask of events to be disabled (dmx_event). + * Disabled events will not be notified to the user. + * By default all events are enabled except for + * DMX_EVENT_NEW_ES_DATA. + * Overflow event can't be disabled. + */ + __u32 disable_mask; + + /* + * Bitmask of events that will not wake-up the user + * when user calls poll with POLLPRI flag. + * Events that are used as wake-up source should not be + * disabled in disable_mask or they would not be used + * as a wake-up source. + * By default all enabled events are set as wake-up events. + * Overflow event can't be disabled as a wake-up source. + */ + __u32 no_wakeup_mask; + + /* + * Number of ready wake-up events which will trigger + * a wake-up when user calls poll with POLLPRI flag. + * Default is set to 1. + */ + __u32 wakeup_threshold; +}; + +struct dmx_indexing_params { + /* + * PID to index. In case of recording filter, multiple PIDs + * may exist in the same filter through DMX_ADD_PID ioctl. + * It is assumed that the PID was already added using DMX_ADD_PID + * or an error will be reported. + */ + __u16 pid; + + /* enable or disable indexing, default is disabled */ + int enable; + + /* combination of DMX_IDX_* bits */ + __u64 types; +}; + +struct dmx_set_ts_insertion { + /* + * Unique identifier managed by the caller. + * This identifier can be used later to remove the + * insertion using DMX_ABORT_TS_INSERTION ioctl. + */ + __u32 identifier; + + /* + * Repetition time in msec, minimum allowed value is 25msec. + * 0 repetition time means one-shot insertion is done. + * Insertion done based on wall-clock. + */ + __u32 repetition_time; + + /* + * TS packets buffer to be inserted. + * The buffer is inserted as-is to the recording buffer + * without any modification. + * It is advised to set discontinuity flag in the very + * first TS packet in the buffer. + */ + const __u8 *ts_packets; + + /* + * Size in bytes of the TS packets buffer to be inserted. + * Should be in multiples of 188 or 192 bytes + * depending on recording filter output format. + */ + size_t size; +}; + +struct dmx_abort_ts_insertion { + /* + * Identifier of the insertion buffer previously set + * using DMX_SET_TS_INSERTION. + */ + __u32 identifier; +}; + +struct dmx_scrambling_bits { + /* + * The PID to return its scrambling bit value. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have different + * scrambling bits status. + */ + __u16 pid; + + /* Current value of scrambling bits: 0, 1, 2 or 3 */ + __u8 value; }; #define DMX_START _IO('o', 41) @@ -217,9 +921,33 @@ struct dmx_stc { #define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params) #define DMX_SET_BUFFER_SIZE _IO('o', 45) #define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5]) +#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t) +#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t) #define DMX_GET_STC _IOWR('o', 50, struct dmx_stc) #define DMX_ADD_PID _IOW('o', 51, __u16) #define DMX_REMOVE_PID _IOW('o', 52, __u16) +#define DMX_SET_TS_PACKET_FORMAT _IOW('o', 53, enum dmx_tsp_format_t) +#define DMX_SET_TS_OUT_FORMAT _IOW('o', 54, enum dmx_tsp_format_t) +#define DMX_SET_DECODER_BUFFER_SIZE _IO('o', 55) +#define DMX_GET_BUFFER_STATUS _IOR('o', 56, struct dmx_buffer_status) +#define DMX_RELEASE_DATA _IO('o', 57) +#define DMX_FEED_DATA _IO('o', 58) +#define DMX_SET_PLAYBACK_MODE _IOW('o', 59, enum dmx_playback_mode_t) +#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event) +#define DMX_SET_BUFFER_MODE _IOW('o', 61, enum dmx_buffer_mode) +#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer) +#define DMX_SET_DECODER_BUFFER _IOW('o', 63, struct dmx_decoder_buffers) +#define DMX_REUSE_DECODER_BUFFER _IO('o', 64) +#define DMX_SET_SECURE_MODE _IOW('o', 65, struct dmx_secure_mode) +#define DMX_SET_EVENTS_MASK _IOW('o', 66, struct dmx_events_mask) +#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask) +#define DMX_PUSH_OOB_COMMAND _IOW('o', 68, struct dmx_oob_command) +#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params) +#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion) +#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion) +#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits) +#define DMX_SET_CIPHER _IOW('o', 73, struct dmx_cipher_operations) +#define DMX_FLUSH_BUFFER _IO('o', 74) #if !defined(__KERNEL__) diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 971e82aec6d0af27ad9ae54a9a099b566730a9d6..5bf4dcb38013c7f33907bcb54639b3dd57d17540 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -277,6 +277,7 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_128_CTS 6 #define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 #define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 +#define FS_ENCRYPTION_MODE_PRIVATE 127 struct fscrypt_policy { __u8 version; diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index c7ca98a65db5b1ce0176ad5e70c778f8cce5b2a2..bdf2c90e9f14d3a2d0bdb205fb864cf33a0577e5 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -100,6 +100,10 @@ #define IPA_IOCTL_GET_VLAN_MODE 58 #define IPA_IOCTL_ADD_BRIDGE_VLAN_MAPPING 59 #define IPA_IOCTL_DEL_BRIDGE_VLAN_MAPPING 60 +#define IPA_IOCTL_ODL_QUERY_ADAPL_EP_INFO 61 +#define IPA_IOCTL_ODL_GET_AGG_BYTE_LIMIT 62 +#define IPA_IOCTL_ODL_QUERY_MODEM_CONFIG 63 + /** * max size of the header to be inserted @@ -311,9 +315,13 @@ enum ipa_client_type { /* RESERVERD PROD = 80, */ IPA_CLIENT_MHI_DPL_CONS = 81, + + /* RESERVERD PROD = 82, */ + IPA_CLIENT_ODL_DPL_CONS = 83, + }; -#define IPA_CLIENT_MAX (IPA_CLIENT_MHI_DPL_CONS + 1) +#define IPA_CLIENT_MAX (IPA_CLIENT_ODL_DPL_CONS + 1) #define IPA_CLIENT_Q6_DL_NLO_DATA_PROD IPA_CLIENT_Q6_DL_NLO_DATA_PROD #define IPA_CLIENT_Q6_UL_NLO_ACK_CONS IPA_CLIENT_Q6_UL_NLO_ACK_CONS @@ -548,7 +556,13 @@ enum ipa_vlan_bridge_event { BRIDGE_VLAN_MAPPING_MAX }; -#define IPA_EVENT_MAX_NUM (BRIDGE_VLAN_MAPPING_MAX) +enum ipa_wlan_fw_ssr_event { + WLAN_FWR_SSR_BEFORE_SHUTDOWN = BRIDGE_VLAN_MAPPING_MAX, + IPA_WLAN_FW_SSR_EVENT_MAX +#define IPA_WLAN_FW_SSR_EVENT_MAX IPA_WLAN_FW_SSR_EVENT_MAX +}; + +#define IPA_EVENT_MAX_NUM (IPA_WLAN_FW_SSR_EVENT_MAX) #define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) /** @@ -1930,6 +1944,22 @@ struct ipa_ioc_bridge_vlan_mapping_info { uint32_t subnet_mask; }; +struct ipa_odl_ep_info { + __u32 cons_pipe_num; + __u32 prod_pipe_num; + __u32 peripheral_iface_id; + __u32 ep_type; +}; + +struct odl_agg_pipe_info { + __u16 agg_byte_limit; +}; + +struct ipa_odl_modem_config { + __u8 config_status; +}; + + /** * actual IOCTLs supported by IPA driver */ @@ -2122,6 +2152,18 @@ struct ipa_ioc_bridge_vlan_mapping_info { IPA_IOCTL_CLEANUP) #define IPA_IOC_QUERY_WLAN_CLIENT _IO(IPA_IOC_MAGIC,\ IPA_IOCTL_QUERY_WLAN_CLIENT) + +#define IPA_IOC_ODL_QUERY_ADAPL_EP_INFO _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ODL_QUERY_ADAPL_EP_INFO, \ + struct ipa_odl_ep_info) +#define IPA_IOC_ODL_GET_AGG_BYTE_LIMIT _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ODL_GET_AGG_BYTE_LIMIT, \ + struct odl_agg_pipe_info) + +#define IPA_IOC_ODL_QUERY_MODEM_CONFIG _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ODL_QUERY_MODEM_CONFIG, \ + struct ipa_odl_modem_config) + /* * unique magic number of the Tethering bridge ioctls */ diff --git a/include/uapi/linux/msm_npu.h b/include/uapi/linux/msm_npu.h index 77102ff8a2b21ee0f791284ad889e81c0832eeed..d1c61b7839c952703896dbb3f448f2184cef3d34 100644 --- a/include/uapi/linux/msm_npu.h +++ b/include/uapi/linux/msm_npu.h @@ -45,6 +45,15 @@ #define MSM_NPU_EXEC_NETWORK_V2 \ _IOWR(MSM_NPU_IOCTL_MAGIC, 8, struct msm_npu_exec_network_ioctl_v2) +/* receive event */ +#define MSM_NPU_RECEIVE_EVENT \ + _IOR(MSM_NPU_IOCTL_MAGIC, 9, struct msm_npu_event) + +#define MSM_NPU_EVENT_TYPE_START 0x10000000 +#define MSM_NPU_EVENT_TYPE_EXEC_DONE (MSM_NPU_EVENT_TYPE_START + 1) +#define MSM_NPU_EVENT_TYPE_EXEC_V2_DONE (MSM_NPU_EVENT_TYPE_START + 2) +#define MSM_NPU_EVENT_TYPE_SSR (MSM_NPU_EVENT_TYPE_START + 3) + #define MSM_NPU_MAX_INPUT_LAYER_NUM 8 #define MSM_NPU_MAX_OUTPUT_LAYER_NUM 4 #define MSM_NPU_MAX_PATCH_LAYER_NUM (MSM_NPU_MAX_INPUT_LAYER_NUM +\ @@ -219,4 +228,31 @@ struct msm_npu_exec_network_ioctl_v2 { uint32_t reserved; }; +struct msm_npu_event_execute_done { + uint32_t network_hdl; + int32_t exec_result; +}; + +struct msm_npu_event_execute_v2_done { + uint32_t network_hdl; + int32_t exec_result; + /* stats buf size filled */ + uint32_t stats_buf_size; +}; + +struct msm_npu_event_ssr { + uint32_t network_hdl; +}; + +struct msm_npu_event { + uint32_t type; + union { + struct msm_npu_event_execute_done exec_done; + struct msm_npu_event_execute_v2_done exec_v2_done; + struct msm_npu_event_ssr ssr; + uint8_t data[128]; + } u; + uint32_t reserved[4]; +}; + #endif /*_UAPI_MSM_NPU_H_*/ diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index 55c71ddc7d200480ff3777ba3ee6e2ebe59cb1f4..961316839280a01496a136c8e981ba6c19c647ea 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -268,6 +268,10 @@ struct qseecom_ce_pipe_entry { unsigned int ce_pipe_pair; }; +struct qseecom_ice_data_t { + int flag; +}; + #define MAX_CE_INFO_HANDLE_SIZE 32 struct qseecom_ce_info_req { unsigned char handle[MAX_CE_INFO_HANDLE_SIZE]; @@ -385,5 +389,7 @@ struct file; #define QSEECOM_IOCTL_QUERY_CE_PIPE_INFO \ _IOWR(QSEECOM_IOC_MAGIC, 42, struct qseecom_ce_info_req) +#define QSEECOM_IOCTL_SET_ICE_INFO \ + _IOWR(QSEECOM_IOC_MAGIC, 43, struct qseecom_ice_data_t) #endif /* _UAPI_QSEECOM_H_ */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 85bdb5631399f4fc7c888b68a0882918452da2b9..2f226b145f7d86e975c9c2ca0c7296793db0ab09 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -941,6 +941,12 @@ enum v4l2_mpeg_vidc_video_vp9_level { V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41 = 8, V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5 = 9, V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51 = 10, +#define V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 \ + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 = 11, +#define V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 \ + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 = 12, }; #define V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B \ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 68133f9f250a612586b9d3cb6453d427b64cc6f9..f4f6d8423ae307ad8c5b4241834166cc11be58d3 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1053,8 +1053,7 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_LAST 0x00100000 /* Vendor extensions */ #define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x00020000 -#define V4L2_QCOM_BUF_DATA_CORRUPT 0x00400000 -#define V4L2_BUF_DATA_CORRUPT 0x00400000 +#define V4L2_BUF_FLAG_DATA_CORRUPT 0x00400000 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x01000000 #define V4L2_QCOM_BUF_FLAG_EOS 0x02000000 #define V4L2_QCOM_BUF_FLAG_READONLY 0x04000000 diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 69c37ecbff7ee389cb31b7dc49be4021e9a6fd14..f3c4b46e39d8b081f67b0e0b6b8ddadc64b00652 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -139,6 +139,11 @@ #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) +/* DAI clock gating */ +#define SND_SOC_TPLG_DAI_CLK_GATE_UNDEFINED 0 +#define SND_SOC_TPLG_DAI_CLK_GATE_GATED 1 +#define SND_SOC_TPLG_DAI_CLK_GATE_CONT 2 + /* DAI physical PCM data formats. * Add new formats to the end of the list. */ @@ -160,6 +165,18 @@ #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) #define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) +/* DAI topology BCLK parameter + * For the backwards capability, by default codec is bclk master + */ +#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */ +#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */ + +/* DAI topology FSYNC parameter + * For the backwards capability, by default codec is fsync master + */ +#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */ +#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */ + /* * Block Header. * This header precedes all object and object arrays below. @@ -312,11 +329,11 @@ struct snd_soc_tplg_hw_config { __le32 size; /* in bytes of this structure */ __le32 id; /* unique ID - - used to match */ __le32 fmt; /* SND_SOC_DAI_FORMAT_ format value */ - __u8 clock_gated; /* 1 if clock can be gated to save power */ + __u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - __u8 bclk_master; /* 1 for master of BCLK, 0 for slave */ - __u8 fsync_master; /* 1 for master of FSYNC, 0 for slave */ + __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ + __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ __u8 mclk_direction; /* 0 for input, 1 for output */ __le16 reserved; /* for 32bit alignment */ __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 0b0aa5854dac1ed41959f9383af95d4097ad4646..8dd4063647c2c7db83a612a3dc307044a83fae4e 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -407,7 +407,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) return -EINVAL; break; case AUDIT_EXE: - if (f->op != Audit_equal) + if (f->op != Audit_not_equal && f->op != Audit_equal) return -EINVAL; if (entry->rule.listnr != AUDIT_FILTER_EXIT) return -EINVAL; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index ecc23e25c9eb2b3aedf5db585905d7b044d6b276..76d789d6cea060a4e7d85901f22e5752764a915b 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -471,6 +471,8 @@ static int audit_filter_rules(struct task_struct *tsk, break; case AUDIT_EXE: result = audit_exe_compare(tsk, rule->exe); + if (f->op == Audit_not_equal) + result = !result; break; case AUDIT_UID: result = audit_uid_comparator(cred->uid, f->op, f->uid); @@ -1272,8 +1274,12 @@ static void show_special(struct audit_context *context, int *call_panic) break; case AUDIT_KERN_MODULE: audit_log_format(ab, "name="); - audit_log_untrustedstring(ab, context->module.name); - kfree(context->module.name); + if (context->module.name) { + audit_log_untrustedstring(ab, context->module.name); + kfree(context->module.name); + } else + audit_log_format(ab, "(null)"); + break; } audit_log_end(ab); @@ -2385,8 +2391,9 @@ void __audit_log_kern_module(char *name) { struct audit_context *context = current->audit_context; - context->module.name = kmalloc(strlen(name) + 1, GFP_KERNEL); - strcpy(context->module.name, name); + context->module.name = kstrdup(name, GFP_KERNEL); + if (!context->module.name) + audit_log_lost("out of memory in __audit_log_kern_module"); context->type = AUDIT_KERN_MODULE; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3ceb269c0ebd90225fc05436ced1013186091dd2..450e2cd31ed604a6c70e8b7356a1640d2029c38f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4110,7 +4110,7 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) /* 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() + * and all maps are released in free_used_maps() */ map = bpf_map_inc(map, false); if (IS_ERR(map)) { @@ -4623,7 +4623,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) vfree(log_buf); if (!env->prog->aux->used_maps) /* if we didn't copy map pointers into bpf_prog_info, release - * them now. Otherwise free_bpf_prog_info() will release them. + * them now. Otherwise free_used_maps() will release them. */ release_maps(env); *prog = env->prog; diff --git a/kernel/compat.c b/kernel/compat.c index 7e83733d4c95c854c1a4acf2b8b7a96bf91c0d59..f3925fca93391b85ab53b524143b1a6ccc3d9610 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -334,7 +334,7 @@ COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid, if (retval) goto out; - retval = sched_setaffinity(pid, new_mask); + retval = msm_sched_setaffinity(pid, new_mask); out: free_cpumask_var(new_mask); return retval; diff --git a/kernel/delayacct.c b/kernel/delayacct.c index e2764d767f186eb7965b514b7d9636659608dcf5..ca8ac2824f0b666d880154602f313db7e4112b42 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -44,23 +44,24 @@ void __delayacct_tsk_init(struct task_struct *tsk) { tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL); if (tsk->delays) - spin_lock_init(&tsk->delays->lock); + raw_spin_lock_init(&tsk->delays->lock); } /* * Finish delay accounting for a statistic using its timestamps (@start), * accumalator (@total) and @count */ -static void delayacct_end(spinlock_t *lock, u64 *start, u64 *total, u32 *count) +static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total, + u32 *count) { s64 ns = ktime_get_ns() - *start; unsigned long flags; if (ns > 0) { - spin_lock_irqsave(lock, flags); + raw_spin_lock_irqsave(lock, flags); *total += ns; (*count)++; - spin_unlock_irqrestore(lock, flags); + raw_spin_unlock_irqrestore(lock, flags); } } @@ -127,7 +128,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */ - spin_lock_irqsave(&tsk->delays->lock, flags); + raw_spin_lock_irqsave(&tsk->delays->lock, flags); tmp = d->blkio_delay_total + tsk->delays->blkio_delay; d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp; tmp = d->swapin_delay_total + tsk->delays->swapin_delay; @@ -137,7 +138,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->blkio_count += tsk->delays->blkio_count; d->swapin_count += tsk->delays->swapin_count; d->freepages_count += tsk->delays->freepages_count; - spin_unlock_irqrestore(&tsk->delays->lock, flags); + raw_spin_unlock_irqrestore(&tsk->delays->lock, flags); return 0; } @@ -147,10 +148,10 @@ __u64 __delayacct_blkio_ticks(struct task_struct *tsk) __u64 ret; unsigned long flags; - spin_lock_irqsave(&tsk->delays->lock, flags); + raw_spin_lock_irqsave(&tsk->delays->lock, flags); ret = nsec_to_clock_t(tsk->delays->blkio_delay + tsk->delays->swapin_delay); - spin_unlock_irqrestore(&tsk->delays->lock, flags); + raw_spin_unlock_irqrestore(&tsk->delays->lock, flags); return ret; } diff --git a/kernel/fork.c b/kernel/fork.c index 8e94f499277a55ac0f813262cc1fcf8eeeb803a7..88b065b2c2e97e1adaa3a865235d762994a8f329 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -216,10 +216,9 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node) if (!s) continue; -#ifdef CONFIG_DEBUG_KMEMLEAK /* Clear stale pointers from reused stack. */ memset(s->addr, 0, THREAD_SIZE); -#endif + tsk->stack_vm_area = s; return s->addr; } diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 751593ed7c0b0b9cc9bf74735fb9bd5d7e100be2..32b479468e4d50d69530ad766ba7e3897afa5cc3 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -44,6 +44,7 @@ int __read_mostly sysctl_hung_task_warnings = 10; static int __read_mostly did_panic; static bool hung_task_show_lock; +static bool hung_task_call_panic; static struct task_struct *watchdog_task; @@ -127,10 +128,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) touch_nmi_watchdog(); if (sysctl_hung_task_panic) { - if (hung_task_show_lock) - debug_show_all_locks(); - trigger_all_cpu_backtrace(); - panic("hung_task: blocked tasks"); + hung_task_show_lock = true; + hung_task_call_panic = true; } } @@ -193,6 +192,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) rcu_read_unlock(); if (hung_task_show_lock) debug_show_all_locks(); + if (hung_task_call_panic) { + trigger_all_cpu_backtrace(); + panic("hung_task: blocked tasks"); + } } static long hung_timeout_jiffies(unsigned long last_checked, diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 6674c7c8844b062763588a3e2b48644da8645159..89c841a0d51d0514f9fd82a0dd519450cd2837d7 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1033,6 +1033,13 @@ static int irq_setup_forced_threading(struct irqaction *new) if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)) return 0; + /* + * No further action required for interrupts which are requested as + * threaded interrupts already + */ + if (new->handler == irq_default_primary_handler) + return 0; + new->flags |= IRQF_ONESHOT; /* @@ -1040,7 +1047,7 @@ static int irq_setup_forced_threading(struct irqaction *new) * thread handler. We force thread them as well by creating a * secondary action. */ - if (new->handler != irq_default_primary_handler && new->thread_fn) { + if (new->handler && new->thread_fn) { /* Allocate the secondary action */ new->secondary = kzalloc(sizeof(struct irqaction), GFP_KERNEL); if (!new->secondary) diff --git a/kernel/kcov.c b/kernel/kcov.c index b11ef6e51f7e762c3cd20ae06637b9c44ad1aa89..f1e060b04ef626188361c924979803f7e937b627 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -108,7 +108,8 @@ static void kcov_put(struct kcov *kcov) void kcov_task_init(struct task_struct *t) { - t->kcov_mode = KCOV_MODE_DISABLED; + WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); + barrier(); t->kcov_size = 0; t->kcov_area = NULL; t->kcov = NULL; diff --git a/kernel/kthread.c b/kernel/kthread.c index df461383a2a79333f89b781718c4a2fef2fc50a9..6027968af92d37c17b62cbb1970fdc4feb6ce630 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -318,8 +318,14 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data), task = create->result; if (!IS_ERR(task)) { static const struct sched_param param = { .sched_priority = 0 }; + char name[TASK_COMM_LEN]; - vsnprintf(task->comm, sizeof(task->comm), namefmt, args); + /* + * task is already visible to other tasks, so updating + * COMM must be protected. + */ + vsnprintf(name, sizeof(name), namefmt, args); + set_task_comm(task, name); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index a57b0c869d7eca9bc2006795696c477266d5ee43..fb096c288bb983b08f19a6dcfad9ba78f0c7baa3 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -62,7 +62,7 @@ static const struct platform_s2idle_ops *s2idle_ops; static DECLARE_WAIT_QUEUE_HEAD(s2idle_wait_head); enum s2idle_states __read_mostly s2idle_state; -static DEFINE_SPINLOCK(s2idle_lock); +static DEFINE_RAW_SPINLOCK(s2idle_lock); void s2idle_set_ops(const struct platform_s2idle_ops *ops) { @@ -80,12 +80,12 @@ static void s2idle_enter(void) { trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, true); - spin_lock_irq(&s2idle_lock); + raw_spin_lock_irq(&s2idle_lock); if (pm_wakeup_pending()) goto out; s2idle_state = S2IDLE_STATE_ENTER; - spin_unlock_irq(&s2idle_lock); + raw_spin_unlock_irq(&s2idle_lock); get_online_cpus(); cpuidle_resume(); @@ -99,11 +99,11 @@ static void s2idle_enter(void) cpuidle_pause(); put_online_cpus(); - spin_lock_irq(&s2idle_lock); + raw_spin_lock_irq(&s2idle_lock); out: s2idle_state = S2IDLE_STATE_NONE; - spin_unlock_irq(&s2idle_lock); + raw_spin_unlock_irq(&s2idle_lock); trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, false); } @@ -158,12 +158,12 @@ void s2idle_wake(void) { unsigned long flags; - spin_lock_irqsave(&s2idle_lock, flags); + raw_spin_lock_irqsave(&s2idle_lock, flags); if (s2idle_state > S2IDLE_STATE_NONE) { s2idle_state = S2IDLE_STATE_WAKE; wake_up(&s2idle_wait_head); } - spin_unlock_irqrestore(&s2idle_lock, flags); + raw_spin_unlock_irqrestore(&s2idle_lock, flags); } EXPORT_SYMBOL_GPL(s2idle_wake); diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index d989cc2381988e4574b76194bd7bf9e401ef4403..64825b2df3a5fcbf0efab285c931d06527d19da6 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c @@ -284,7 +284,7 @@ void printk_safe_flush_on_panic(void) * Make sure that we could access the main ring buffer. * Do not risk a double release when more CPUs are up. */ - if (in_nmi() && raw_spin_is_locked(&logbuf_lock)) { + if (raw_spin_is_locked(&logbuf_lock)) { if (num_online_cpus() > 1) return; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b08d42b6185b14fe5075f012025a49651e566974..0e333632e5efb37eacef90a495028d4c6b10daed 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -783,6 +783,10 @@ static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) sched_info_dequeued(rq, p); p->sched_class->dequeue_task(rq, p, flags); +#ifdef CONFIG_SCHED_WALT + if (p == rq->ed_task) + early_detection_notify(rq, sched_ktime_clock()); +#endif trace_sched_enq_deq_task(p, 0, cpumask_bits(&p->cpus_allowed)[0]); } @@ -2037,7 +2041,7 @@ static inline void walt_try_to_wake_up(struct task_struct *p) rq_lock_irqsave(rq, &rf); old_load = task_load(p); - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_WAKE, wallclock, 0); rq_unlock_irqrestore(rq, &rf); @@ -2171,7 +2175,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags, set_task_cpu(p, cpu); } - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); note_task_waking(p, wallclock); #else /* CONFIG_SMP */ @@ -2236,7 +2240,7 @@ static void try_to_wake_up_local(struct task_struct *p, struct rq_flags *rf) trace_sched_waking(p); if (!task_on_rq_queued(p)) { - u64 wallclock = ktime_get_ns(); + u64 wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_WAKE, wallclock, 0); @@ -3159,7 +3163,7 @@ void scheduler_tick(void) old_load = task_load(curr); set_window_start(rq); - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_rq_clock(rq); curr->sched_class->task_tick(rq, curr, 0); @@ -3543,7 +3547,7 @@ static void __sched notrace __schedule(bool preempt) clear_tsk_need_resched(prev); clear_preempt_need_resched(); - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); if (likely(prev != next)) { if (!prev->on_rq) prev->last_sleep_ts = wallclock; @@ -4906,6 +4910,71 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) return retval; } +char sched_lib_name[LIB_PATH_LENGTH]; +unsigned int sched_lib_mask_check; +unsigned int sched_lib_mask_force; +static inline bool is_sched_lib_based_app(pid_t pid) +{ + const char *name = NULL; + struct vm_area_struct *vma; + char path_buf[LIB_PATH_LENGTH]; + bool found = false; + struct task_struct *p; + + if (strnlen(sched_lib_name, LIB_PATH_LENGTH) == 0) + return false; + + rcu_read_lock(); + + p = find_process_by_pid(pid); + if (!p) { + rcu_read_unlock(); + return false; + } + + /* Prevent p going away */ + get_task_struct(p); + rcu_read_unlock(); + + if (!p->mm) + goto put_task_struct; + + down_read(&p->mm->mmap_sem); + for (vma = p->mm->mmap; vma ; vma = vma->vm_next) { + if (vma->vm_file && vma->vm_flags & VM_EXEC) { + name = d_path(&vma->vm_file->f_path, + path_buf, LIB_PATH_LENGTH); + if (IS_ERR(name)) + goto release_sem; + + if (strnstr(name, sched_lib_name, + strnlen(name, LIB_PATH_LENGTH))) { + found = true; + break; + } + } + } + +release_sem: + up_read(&p->mm->mmap_sem); +put_task_struct: + put_task_struct(p); + return found; +} + +long msm_sched_setaffinity(pid_t pid, struct cpumask *new_mask) +{ + if (sched_lib_mask_check != 0 && sched_lib_mask_force != 0 && + (cpumask_bits(new_mask)[0] == sched_lib_mask_check) && + is_sched_lib_based_app(pid)) { + + cpumask_t forced_mask = { {sched_lib_mask_force} }; + + cpumask_copy(new_mask, &forced_mask); + } + return sched_setaffinity(pid, new_mask); +} + static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, struct cpumask *new_mask) { @@ -4936,7 +5005,7 @@ SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, retval = get_user_cpu_mask(user_mask_ptr, len, new_mask); if (retval == 0) - retval = sched_setaffinity(pid, new_mask); + retval = msm_sched_setaffinity(pid, new_mask); free_cpumask_var(new_mask); return retval; } @@ -6408,7 +6477,7 @@ void __init sched_init(void) rq->avg_idle = 2*sysctl_sched_migration_cost; rq->max_idle_balance_cost = sysctl_sched_migration_cost; rq->push_task = NULL; - walt_sched_init(rq); + walt_sched_init_rq(rq); INIT_LIST_HEAD(&rq->cfs_tasks); @@ -7422,7 +7491,7 @@ void sched_exit(struct task_struct *p) rq = task_rq_lock(p, &rf); /* rq->curr == p */ - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); dequeue_task(rq, p, 0); /* diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 98739c5f55c478458a242c95408c78525721811b..1e23ffb7a0995a157fc1cadab568f1c4a91758c0 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -540,7 +540,7 @@ static void sugov_work(struct kthread_work *work) mutex_lock(&sg_policy->work_lock); raw_spin_lock_irqsave(&sg_policy->update_lock, flags); sugov_track_cycles(sg_policy, sg_policy->policy->cur, - ktime_get_ns()); + sched_ktime_clock()); raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags); __cpufreq_driver_target(sg_policy->policy, sg_policy->next_freq, CPUFREQ_RELATION_L); @@ -993,7 +993,7 @@ static void sugov_limits(struct cpufreq_policy *policy) mutex_lock(&sg_policy->work_lock); raw_spin_lock_irqsave(&sg_policy->update_lock, flags); sugov_track_cycles(sg_policy, sg_policy->policy->cur, - ktime_get_ns()); + sched_ktime_clock()); raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags); cpufreq_policy_apply_limits(policy); mutex_unlock(&sg_policy->work_lock); diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 943f308dd66d3697a3a82a221729d9c0754e6900..84e28cfe54d0c4ea413ee7b6d1de98cea9d016f2 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -759,7 +759,7 @@ do { \ P(cluster->exec_scale_factor); P(walt_stats.nr_big_tasks); SEQ_printf(m, " .%-30s: %llu\n", "walt_stats.cumulative_runnable_avg", - rq->walt_stats.cumulative_runnable_avg); + rq->walt_stats.cumulative_runnable_avg_scaled); #endif #undef P #undef PN diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index 5e7247c8180e8c06a7c2c5d667361fa5effd0163..b4764309dac4a0e6257ab834372a59428c183d8c 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -52,6 +52,20 @@ static void free_resources(void) } static bool sge_ready; +void check_max_cap_vs_cpu_scale(int cpu, struct sched_group_energy *sge) +{ + unsigned long max_cap, cpu_scale; + + max_cap = sge->cap_states[sge->nr_cap_states - 1].cap; + cpu_scale = topology_get_cpu_scale(NULL, cpu); + + if (max_cap == cpu_scale) + return; + + pr_debug("CPU%d max energy model capacity=%ld != cpu_scale=%ld\n", cpu, + max_cap, cpu_scale); +} + void init_sched_energy_costs(void) { struct device_node *cn, *cp; @@ -137,6 +151,8 @@ void init_sched_energy_costs(void) sge_array[cpu][sd_level] = sge; } + + check_max_cap_vs_cpu_scale(cpu, sge_array[cpu][SD_LEVEL0]); } sge_ready = true; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index d886396ba4c8f4fc3ba1aeaa5d92e76b2f23372b..a91718f1c30754eef205404d44b367e661927d2c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -47,7 +47,8 @@ static inline bool task_fits_max(struct task_struct *p, int cpu); #ifdef CONFIG_SCHED_WALT static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand); + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled); static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p, int delta, bool inc); #endif /* CONFIG_SCHED_WALT */ @@ -3726,8 +3727,7 @@ static inline unsigned long task_util_est(struct task_struct *p) { #ifdef CONFIG_SCHED_WALT if (likely(!walt_disabled && sysctl_sched_use_walt_task_util)) - return (p->ravg.demand / - (sched_ravg_window >> SCHED_CAPACITY_SHIFT)); + return p->ravg.demand_scaled; #endif return max(task_util(p), _task_util_est(p)); } @@ -7578,6 +7578,13 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, if (capacity_orig < capacity_orig_of(cpu)) continue; + /* + * Favor CPUs with smaller capacity for non latency + * sensitive tasks. + */ + if (capacity_orig > target_capacity) + continue; + /* * Case B) Non latency sensitive tasks on IDLE CPUs. * @@ -8114,7 +8121,7 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, } /* find most energy-efficient CPU */ - energy_cpu = select_energy_cpu_idx(eenv) < 0 ? -1 : + target_cpu = select_energy_cpu_idx(eenv) < 0 ? -1 : eenv->cpu[eenv->next_idx].cpu_id; out: @@ -10697,15 +10704,15 @@ static int need_active_balance(struct lb_env *env) return 1; } - if (env->src_grp_type == group_misfit_task) + if (env->idle != CPU_NOT_IDLE && + env->src_grp_type == group_misfit_task) return 1; if (env->src_grp_type == group_overloaded && env->src_rq->misfit_task_load) return 1; - return unlikely(sd->nr_balance_failed > - sd->cache_nice_tries + NEED_ACTIVE_BALANCE_THRESHOLD); + return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2); } static int group_balance_cpu_not_isolated(struct sched_group *sg) @@ -10952,6 +10959,19 @@ static int load_balance(int this_cpu, struct rq *this_rq, raw_spin_lock_irqsave(&busiest->lock, flags); + /* + * The CPUs are marked as reserved if tasks + * are pushed/pulled from other CPUs. In that case, + * bail out from the load balancer. + */ + if (is_reserved(this_cpu) || + is_reserved(cpu_of(busiest))) { + raw_spin_unlock_irqrestore(&busiest->lock, + flags); + *continue_balancing = 0; + goto out; + } + /* don't kick the active_load_balance_cpu_stop, * if the curr task on busiest cpu can't be * moved to this_cpu @@ -12505,22 +12525,24 @@ __init void init_sched_fair_class(void) static void walt_init_cfs_rq_stats(struct cfs_rq *cfs_rq) { cfs_rq->walt_stats.nr_big_tasks = 0; - cfs_rq->walt_stats.cumulative_runnable_avg = 0; + cfs_rq->walt_stats.cumulative_runnable_avg_scaled = 0; cfs_rq->walt_stats.pred_demands_sum = 0; } static void walt_inc_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) { inc_nr_big_task(&cfs_rq->walt_stats, p); - fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, p->ravg.demand, - p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, + p->ravg.demand_scaled, + p->ravg.pred_demand_scaled); } static void walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) { dec_nr_big_task(&cfs_rq->walt_stats, p); - fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, -(s64)p->ravg.demand, - -(s64)p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, + -(s64)p->ravg.demand_scaled, + -(s64)p->ravg.pred_demand_scaled); } static void walt_inc_throttled_cfs_rq_stats(struct walt_sched_stats *stats, @@ -12530,12 +12552,12 @@ static void walt_inc_throttled_cfs_rq_stats(struct walt_sched_stats *stats, stats->nr_big_tasks += tcfs_rq->walt_stats.nr_big_tasks; fixup_cumulative_runnable_avg(stats, - tcfs_rq->walt_stats.cumulative_runnable_avg, - tcfs_rq->walt_stats.pred_demands_sum); + tcfs_rq->walt_stats.cumulative_runnable_avg_scaled, + tcfs_rq->walt_stats.pred_demands_sum_scaled); if (stats == &rq->walt_stats) walt_fixup_cum_window_demand(rq, - tcfs_rq->walt_stats.cumulative_runnable_avg); + tcfs_rq->walt_stats.cumulative_runnable_avg_scaled); } @@ -12546,8 +12568,8 @@ static void walt_dec_throttled_cfs_rq_stats(struct walt_sched_stats *stats, stats->nr_big_tasks -= tcfs_rq->walt_stats.nr_big_tasks; fixup_cumulative_runnable_avg(stats, - -tcfs_rq->walt_stats.cumulative_runnable_avg, - -tcfs_rq->walt_stats.pred_demands_sum); + -tcfs_rq->walt_stats.cumulative_runnable_avg_scaled, + -tcfs_rq->walt_stats.pred_demands_sum_scaled); /* * We remove the throttled cfs_rq's tasks's contribution from the @@ -12556,16 +12578,19 @@ static void walt_dec_throttled_cfs_rq_stats(struct walt_sched_stats *stats, */ if (stats == &rq->walt_stats) walt_fixup_cum_window_demand(rq, - -tcfs_rq->walt_stats.cumulative_runnable_avg); + -tcfs_rq->walt_stats.cumulative_runnable_avg_scaled); } static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; - s64 task_load_delta = (s64)new_task_load - task_load(p); - s64 pred_demand_delta = PRED_DEMAND_DELTA; + s64 task_load_delta = (s64)updated_demand_scaled - + p->ravg.demand_scaled; + s64 pred_demand_delta = (s64)updated_pred_demand_scaled - + p->ravg.pred_demand_scaled; for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); @@ -12637,9 +12662,11 @@ static int task_will_be_throttled(struct task_struct *p) #else /* CONFIG_CFS_BANDWIDTH */ static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { - fixup_walt_sched_stats_common(rq, p, new_task_load, new_pred_demand); + fixup_walt_sched_stats_common(rq, p, updated_demand_scaled, + updated_pred_demand_scaled); } static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p, @@ -12729,7 +12756,7 @@ static void walt_check_for_rotation(struct rq *src_rq) if (!is_min_capacity_cpu(src_cpu)) return; - wc = ktime_get_ns(); + wc = sched_ktime_clock(); for_each_possible_cpu(i) { struct rq *rq = cpu_rq(i); diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 245139741555d87cdeb5bc74a70e8f9ad74a1dbe..68c92b6709e9b30b8f06d5379a9290ad52f356af 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -118,3 +118,14 @@ SCHED_FEAT(ENERGY_AWARE, false) SCHED_FEAT(EAS_PREFER_IDLE, true) SCHED_FEAT(FIND_BEST_TARGET, true) SCHED_FEAT(FBT_STRICT_ORDER, false) + +/* + * Apply schedtune boost hold to tasks of all sched classes. + * If enabled, schedtune will hold the boost applied to a CPU + * for 50ms regardless of task activation - if the task is + * still running 50ms later, the boost hold expires and schedtune + * boost will expire immediately the task stops. + * If disabled, this behaviour will only apply to tasks of the + * RT class. + */ +SCHED_FEAT(SCHEDTUNE_BOOST_HOLD_ALL, false) diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index c1dbb2cc1f29c8a936f5a0fe4b1a467c10e2b9b5..2e973e667b0d1857d7e0cd27860f0dec4b48e439 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -147,13 +147,15 @@ static void cpuidle_idle_call(void) } /* - * Tell the RCU framework we are entering an idle section, - * so no more rcu read side critical sections and one more + * The RCU framework needs to be told that we are entering an idle + * section, so no more rcu read side critical sections and one more * step to the grace period */ - rcu_idle_enter(); if (cpuidle_not_available(drv, dev)) { + tick_nohz_idle_stop_tick(); + rcu_idle_enter(); + default_idle_call(); goto exit_idle; } @@ -170,20 +172,37 @@ static void cpuidle_idle_call(void) if (idle_should_enter_s2idle() || dev->use_deepest_state) { if (idle_should_enter_s2idle()) { + rcu_idle_enter(); + entered_state = cpuidle_enter_s2idle(drv, dev); if (entered_state > 0) { local_irq_enable(); goto exit_idle; } + + rcu_idle_exit(); } + tick_nohz_idle_stop_tick(); + rcu_idle_enter(); + next_state = cpuidle_find_deepest_state(drv, dev); call_cpuidle(drv, dev, next_state); } else { + bool stop_tick = true; + /* * Ask the cpuidle framework to choose a convenient idle state. */ - next_state = cpuidle_select(drv, dev); + next_state = cpuidle_select(drv, dev, &stop_tick); + + if (stop_tick) + tick_nohz_idle_stop_tick(); + else + tick_nohz_idle_retain_tick(); + + rcu_idle_enter(); + entered_state = call_cpuidle(drv, dev, next_state); /* * Give the governor an opportunity to reflect on the outcome @@ -228,6 +247,7 @@ static void do_idle(void) rmb(); if (cpu_is_offline(smp_processor_id())) { + tick_nohz_idle_stop_tick_protected(); cpuhp_report_idle_dead(); arch_cpu_idle_dead(); } @@ -241,10 +261,12 @@ static void do_idle(void) * broadcast device expired for us, we don't want to go deep * idle as we know that the IPI is going to arrive right away. */ - if (cpu_idle_force_poll || tick_check_broadcast_expired()) + if (cpu_idle_force_poll || tick_check_broadcast_expired()) { + tick_nohz_idle_restart_tick(); cpu_idle_poll(); - else + } else { cpuidle_idle_call(); + } arch_cpu_idle_exit(); } diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 093077acd2d5252ec241d73dce038eb9539391ca..e0d3e14c8df16388a34a474d4dac20238a03a9b3 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -9,6 +9,7 @@ #include #include #include +#include "tune.h" #include "walt.h" @@ -1395,6 +1396,8 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags) { struct sched_rt_entity *rt_se = &p->rt; + schedtune_enqueue_task(p, cpu_of(rq)); + if (flags & ENQUEUE_WAKEUP) rt_se->timeout = 0; @@ -1409,6 +1412,8 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) { struct sched_rt_entity *rt_se = &p->rt; + schedtune_dequeue_task(p, cpu_of(rq)); + update_curr_rt(rq); dequeue_rt_entity(rt_se, flags); walt_dec_cumulative_runnable_avg(rq, p); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 240f5e9486a4b68ee8f216fd5527ad41658a9922..21e7d2c54e6bdef6cc858ab8e895c1078ac06d58 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -58,8 +58,8 @@ extern unsigned int walt_cpu_util_freq_divisor; struct walt_sched_stats { int nr_big_tasks; - u64 cumulative_runnable_avg; - u64 pred_demands_sum; + u64 cumulative_runnable_avg_scaled; + u64 pred_demands_sum_scaled; }; struct cpu_cycle { @@ -565,6 +565,9 @@ struct cfs_rq { u64 throttled_clock_task_time; int throttled, throttle_count; struct list_head throttled_list; +#ifdef CONFIG_SCHED_WALT + u64 cumulative_runnable_avg; +#endif /* CONFIG_SCHED_WALT */ #endif /* CONFIG_CFS_BANDWIDTH */ #endif /* CONFIG_FAIR_GROUP_SCHED */ }; @@ -882,7 +885,7 @@ struct rq { u64 prev_runnable_sum; u64 nt_curr_runnable_sum; u64 nt_prev_runnable_sum; - u64 cum_window_demand; + u64 cum_window_demand_scaled; struct group_cpu_time grp_time; struct load_subtractions load_subs[NUM_TRACKED_WINDOWS]; DECLARE_BITMAP_ARRAY(top_tasks_bitmap, @@ -1615,7 +1618,8 @@ struct sched_class { #ifdef CONFIG_SCHED_WALT void (*fixup_walt_sched_stats)(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand); + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled); #endif }; @@ -1840,6 +1844,15 @@ static inline int hrtick_enabled(struct rq *rq) #endif /* CONFIG_SCHED_HRTICK */ +#ifdef CONFIG_SCHED_WALT +u64 sched_ktime_clock(void); +#else +static inline u64 sched_ktime_clock(void) +{ + return 0; +} +#endif + #ifdef CONFIG_SMP extern void sched_avg_update(struct rq *rq); extern unsigned long sched_get_rt_rq_util(int cpu); @@ -1889,8 +1902,7 @@ static inline unsigned long task_util(struct task_struct *p) { #ifdef CONFIG_SCHED_WALT if (likely(!walt_disabled && sysctl_sched_use_walt_task_util)) - return p->ravg.demand / - (sched_ravg_window >> SCHED_CAPACITY_SHIFT); + return p->ravg.demand_scaled; #endif return READ_ONCE(p->se.avg.util_avg); } @@ -1941,10 +1953,7 @@ static inline unsigned long cpu_util(int cpu) #ifdef CONFIG_SCHED_WALT if (likely(!walt_disabled && sysctl_sched_use_walt_cpu_util)) { u64 walt_cpu_util = - cpu_rq(cpu)->walt_stats.cumulative_runnable_avg; - - walt_cpu_util <<= SCHED_CAPACITY_SHIFT; - do_div(walt_cpu_util, sched_ravg_window); + cpu_rq(cpu)->walt_stats.cumulative_runnable_avg_scaled; return min_t(unsigned long, walt_cpu_util, capacity_orig_of(cpu)); @@ -1973,11 +1982,8 @@ static inline unsigned long cpu_util_cum(int cpu, int delta) unsigned long capacity = capacity_orig_of(cpu); #ifdef CONFIG_SCHED_WALT - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) { - util = cpu_rq(cpu)->cum_window_demand; - util = div64_u64(util, - sched_ravg_window >> SCHED_CAPACITY_SHIFT); - } + if (!walt_disabled && sysctl_sched_use_walt_cpu_util) + util = cpu_rq(cpu)->cum_window_demand_scaled; #endif delta += util; if (delta < 0) @@ -2011,19 +2017,17 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) if (walt_load) { u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum + rq->grp_time.nt_prev_runnable_sum; - u64 pl = rq->walt_stats.pred_demands_sum; + u64 pl = rq->walt_stats.pred_demands_sum_scaled; /* do_pl_notif() needs unboosted signals */ rq->old_busy_time = div64_u64(util_unboosted, sched_ravg_window >> SCHED_CAPACITY_SHIFT); - rq->old_estimated_time = div64_u64(pl, sched_ravg_window >> - SCHED_CAPACITY_SHIFT); + rq->old_estimated_time = pl; nl = div64_u64(nl * (100 + boost), walt_cpu_util_freq_divisor); - pl = div64_u64(pl * (100 + boost), - walt_cpu_util_freq_divisor); + pl = div64_u64(pl * (100 + boost), 100); walt_load->prev_window_util = util; walt_load->nl = nl; @@ -2487,7 +2491,7 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data, cpu_of(rq))); if (data) - data->func(data, ktime_get_ns(), flags); + data->func(data, sched_ktime_clock(), flags); } #else static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} @@ -2810,8 +2814,6 @@ struct related_thread_group *task_related_thread_group(struct task_struct *p) return rcu_dereference(p->grp); } -#define PRED_DEMAND_DELTA ((s64)new_pred_demand - p->ravg.pred_demand) - /* Is frequency of two cpus synchronized with each other? */ static inline int same_freq_domain(int src_cpu, int dst_cpu) { @@ -2890,11 +2892,11 @@ task_in_cum_window_demand(struct rq *rq, struct task_struct *p) rq->window_start); } -static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 delta) +static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 scaled_delta) { - rq->cum_window_demand += delta; - if (unlikely((s64)rq->cum_window_demand < 0)) - rq->cum_window_demand = 0; + rq->cum_window_demand_scaled += scaled_delta; + if (unlikely((s64)rq->cum_window_demand_scaled < 0)) + rq->cum_window_demand_scaled = 0; } extern void update_cpu_cluster_capacity(const cpumask_t *cpus); @@ -3037,8 +3039,6 @@ static inline int update_preferred_cluster(struct related_thread_group *grp, static inline void add_new_task_to_grp(struct task_struct *new) {} -#define PRED_DEMAND_DELTA (0) - static inline int same_freq_domain(int src_cpu, int dst_cpu) { return 1; @@ -3052,7 +3052,8 @@ static inline int alloc_related_thread_groups(void) { return 0; } #define trace_sched_cpu_load_cgroup(...) #define trace_sched_cpu_load_wakeup(...) -static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 delta) { } +static inline void walt_fixup_cum_window_demand(struct rq *rq, + s64 scaled_delta) { } static inline void update_cpu_cluster_capacity(const cpumask_t *cpus) { } diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 1e9899cf6ed671e0634d1c9b101418bbfd161dea..be0fe4ac752e7bdcd308a3075e9d14505f3372e3 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -307,6 +307,8 @@ static int init_rootdomain(struct root_domain *rd) init_max_cpu_capacity(&rd->max_cpu_capacity); + init_max_cpu_capacity(&rd->max_cpu_capacity); + return 0; free_cpudl: diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index e52a82fe5369436d5fe314cf3ea02f58bd0263d6..dc49ffb4278f16325b97bae8d7bf02e06a8b2e39 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -14,6 +14,9 @@ bool schedtune_initialized = false; extern struct reciprocal_value schedtune_spc_rdiv; +/* We hold schedtune boost in effect for at least this long */ +#define SCHEDTUNE_BOOST_HOLD_NS 50000000ULL + /* * EAS scheduler tunables for task groups. */ @@ -129,11 +132,14 @@ struct boost_groups { /* Maximum boost value for all RUNNABLE tasks on a CPU */ bool idle; int boost_max; + u64 boost_ts; struct { /* The boost for tasks on that boost group */ int boost; /* Count of RUNNABLE tasks on that boost group */ unsigned tasks; + /* Timestamp of boost activation */ + u64 ts; } group[BOOSTGROUPS_COUNT]; /* CPU's boost group locking */ raw_spinlock_t lock; @@ -213,30 +219,53 @@ static int sched_boost_override_write(struct cgroup_subsys_state *css, #endif /* CONFIG_SCHED_WALT */ +static inline bool schedtune_boost_timeout(u64 now, u64 ts) +{ + return ((now - ts) > SCHEDTUNE_BOOST_HOLD_NS); +} + +static inline bool +schedtune_boost_group_active(int idx, struct boost_groups* bg, u64 now) +{ + if (bg->group[idx].tasks) + return true; + + return !schedtune_boost_timeout(now, bg->group[idx].ts); +} + static void -schedtune_cpu_update(int cpu) +schedtune_cpu_update(int cpu, u64 now) { struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu); int boost_max; + u64 boost_ts; int idx; /* The root boost group is always active */ boost_max = bg->group[0].boost; + boost_ts = now; for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx) { /* * A boost group affects a CPU only if it has - * RUNNABLE tasks on that CPU + * RUNNABLE tasks on that CPU or it has hold + * in effect from a previous task. */ - if (bg->group[idx].tasks == 0) + if (!schedtune_boost_group_active(idx, bg, now)) + continue; + + /* This boost group is active */ + if (boost_max > bg->group[idx].boost) continue; - boost_max = max(boost_max, bg->group[idx].boost); + boost_max = bg->group[idx].boost; + boost_ts = bg->group[idx].ts; } /* Ensures boost_max is non-negative when all cgroup boost values * are neagtive. Avoids under-accounting of cpu capacity which may cause * task stacking and frequency spikes.*/ boost_max = max(boost_max, 0); bg->boost_max = boost_max; + bg->boost_ts = boost_ts; } static int @@ -246,6 +275,7 @@ schedtune_boostgroup_update(int idx, int boost) int cur_boost_max; int old_boost; int cpu; + u64 now; /* Update per CPU boost groups */ for_each_possible_cpu(cpu) { @@ -263,15 +293,19 @@ schedtune_boostgroup_update(int idx, int boost) bg->group[idx].boost = boost; /* Check if this update increase current max */ - if (boost > cur_boost_max && bg->group[idx].tasks) { + now = sched_clock_cpu(cpu); + if (boost > cur_boost_max && + schedtune_boost_group_active(idx, bg, now)) { bg->boost_max = boost; + bg->boost_ts = bg->group[idx].ts; + trace_sched_tune_boostgroup_update(cpu, 1, bg->boost_max); continue; } /* Check if this update has decreased current max */ if (cur_boost_max == old_boost && old_boost > boost) { - schedtune_cpu_update(cpu); + schedtune_cpu_update(cpu, now); trace_sched_tune_boostgroup_update(cpu, -1, bg->boost_max); continue; } @@ -285,6 +319,15 @@ schedtune_boostgroup_update(int idx, int boost) #define ENQUEUE_TASK 1 #define DEQUEUE_TASK -1 +static inline bool +schedtune_update_timestamp(struct task_struct *p) +{ + if (sched_feat(SCHEDTUNE_BOOST_HOLD_ALL)) + return true; + + return task_has_rt_policy(p); +} + static inline void schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count) { @@ -294,12 +337,21 @@ schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count) /* Update boosted tasks count while avoiding to make it negative */ bg->group[idx].tasks = max(0, tasks); - trace_sched_tune_tasks_update(p, cpu, tasks, idx, - bg->group[idx].boost, bg->boost_max); + /* Update timeout on enqueue */ + if (task_count > 0) { + u64 now = sched_clock_cpu(cpu); + + if (schedtune_update_timestamp(p)) + bg->group[idx].ts = now; - /* Boost group activation or deactivation on that RQ */ - if (tasks == 1 || tasks == 0) - schedtune_cpu_update(cpu); + /* Boost group activation or deactivation on that RQ */ + if (bg->group[idx].tasks == 1) + schedtune_cpu_update(cpu, now); + } + + trace_sched_tune_tasks_update(p, cpu, tasks, idx, + bg->group[idx].boost, bg->boost_max, + bg->group[idx].ts); } /* @@ -343,6 +395,7 @@ int schedtune_can_attach(struct cgroup_taskset *tset) int src_bg; /* Source boost group index */ int dst_bg; /* Destination boost group index */ int tasks; + u64 now; if (unlikely(!schedtune_initialized)) return 0; @@ -393,13 +446,15 @@ int schedtune_can_attach(struct cgroup_taskset *tset) bg->group[src_bg].tasks = max(0, tasks); bg->group[dst_bg].tasks += 1; - raw_spin_unlock(&bg->lock); - task_rq_unlock(rq, task, &rq_flags); + /* Update boost hold start for this group */ + now = sched_clock_cpu(cpu); + bg->group[dst_bg].ts = now; - /* Update CPU boost group */ - if (bg->group[src_bg].tasks == 0 || bg->group[dst_bg].tasks == 1) - schedtune_cpu_update(task_cpu(task)); + /* Force boost group re-evaluation at next boost check */ + bg->boost_ts = now - SCHEDTUNE_BOOST_HOLD_NS; + raw_spin_unlock(&bg->lock); + task_rq_unlock(rq, task, &rq_flags); } return 0; @@ -493,8 +548,15 @@ void schedtune_dequeue_task(struct task_struct *p, int cpu) int schedtune_cpu_boost(int cpu) { struct boost_groups *bg; + u64 now; bg = &per_cpu(cpu_boost_groups, cpu); + now = sched_clock_cpu(cpu); + + /* Check to see if we have a hold in effect */ + if (schedtune_boost_timeout(now, bg->boost_ts)) + schedtune_cpu_update(cpu, now); + return bg->boost_max; } @@ -643,6 +705,7 @@ schedtune_boostgroup_init(struct schedtune *st) bg = &per_cpu(cpu_boost_groups, cpu); bg->group[st->idx].boost = 0; bg->group[st->idx].tasks = 0; + bg->group[st->idx].ts = 0; } return 0; diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index b093b1961fe1198cfd71b5238915224433024e4c..52fd3d25837cb02b05aef2b94336a93aa9e936fd 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -19,6 +19,7 @@ * and Todd Kjos */ +#include #include #include #include @@ -42,6 +43,8 @@ const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", #define EARLY_DETECTION_DURATION 9500000 +static ktime_t ktime_last; +static bool sched_ktime_suspended; static struct cpu_cycle_counter_cb cpu_cycle_counter_cb; static bool use_cycle_counter; DEFINE_MUTEX(cluster_lock); @@ -51,6 +54,37 @@ u64 walt_load_reported_window; static struct irq_work walt_cpufreq_irq_work; static struct irq_work walt_migration_irq_work; +u64 sched_ktime_clock(void) +{ + if (unlikely(sched_ktime_suspended)) + return ktime_to_ns(ktime_last); + return ktime_get_ns(); +} + +static void sched_resume(void) +{ + sched_ktime_suspended = false; +} + +static int sched_suspend(void) +{ + ktime_last = ktime_get(); + sched_ktime_suspended = true; + return 0; +} + +static struct syscore_ops sched_syscore_ops = { + .resume = sched_resume, + .suspend = sched_suspend +}; + +static int __init sched_init_ops(void) +{ + register_syscore_ops(&sched_syscore_ops); + return 0; +} +late_initcall(sched_init_ops); + static void acquire_rq_locks_irqsave(const cpumask_t *cpus, unsigned long *flags) { @@ -122,6 +156,7 @@ __read_mostly unsigned int walt_cpu_util_freq_divisor; /* Initial task load. Newly created tasks are assigned this load. */ unsigned int __read_mostly sched_init_task_load_windows; +unsigned int __read_mostly sched_init_task_load_windows_scaled; unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15; /* @@ -195,6 +230,9 @@ static int __init set_sched_predl(char *str) } early_param("sched_predl", set_sched_predl); +__read_mostly unsigned int walt_scale_demand_divisor; +#define scale_demand(d) ((d)/walt_scale_demand_divisor) + void inc_rq_walt_stats(struct rq *rq, struct task_struct *p) { inc_nr_big_task(&rq->walt_stats, p); @@ -208,10 +246,13 @@ void dec_rq_walt_stats(struct rq *rq, struct task_struct *p) } void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { - s64 task_load_delta = (s64)new_task_load - task_load(p); - s64 pred_demand_delta = PRED_DEMAND_DELTA; + s64 task_load_delta = (s64)updated_demand_scaled - + p->ravg.demand_scaled; + s64 pred_demand_delta = (s64)updated_pred_demand_scaled - + p->ravg.pred_demand_scaled; fixup_cumulative_runnable_avg(&rq->walt_stats, task_load_delta, pred_demand_delta); @@ -272,22 +313,15 @@ update_window_start(struct rq *rq, u64 wallclock, int event) u64 old_window_start = rq->window_start; delta = wallclock - rq->window_start; - /* - * If the MPM global timer is cleared, set delta as 0 to - * avoid kernel BUG happening - */ - if (delta < 0) { - delta = 0; - WARN_ONCE(1, "WALT wallclock appears to have gone backwards or reset\n"); - } - + BUG_ON(delta < 0); if (delta < sched_ravg_window) return old_window_start; nr_windows = div64_u64(delta, sched_ravg_window); rq->window_start += (u64)nr_windows * (u64)sched_ravg_window; - rq->cum_window_demand = rq->walt_stats.cumulative_runnable_avg; + rq->cum_window_demand_scaled = + rq->walt_stats.cumulative_runnable_avg_scaled; return old_window_start; } @@ -321,6 +355,11 @@ void clear_ed_task(struct task_struct *p, struct rq *rq) rq->ed_task = NULL; } +static inline bool is_ed_task(struct task_struct *p, u64 wallclock) +{ + return (wallclock - p->last_wake_ts >= EARLY_DETECTION_DURATION); +} + bool early_detection_notify(struct rq *rq, u64 wallclock) { struct task_struct *p; @@ -335,7 +374,7 @@ bool early_detection_notify(struct rq *rq, u64 wallclock) if (!loop_max) break; - if (wallclock - p->last_wake_ts >= EARLY_DETECTION_DURATION) { + if (is_ed_task(p, wallclock)) { rq->ed_task = p; return 1; } @@ -356,7 +395,7 @@ void sched_account_irqstart(int cpu, struct task_struct *curr, u64 wallclock) if (is_idle_task(curr)) { /* We're here without rq->lock held, IRQ disabled */ raw_spin_lock(&rq->lock); - update_task_cpu_cycles(curr, cpu, ktime_get_ns()); + update_task_cpu_cycles(curr, cpu, sched_ktime_clock()); raw_spin_unlock(&rq->lock); } } @@ -411,7 +450,7 @@ void sched_account_irqtime(int cpu, struct task_struct *curr, cur_jiffies_ts = get_jiffies_64(); if (is_idle_task(curr)) - update_task_ravg(curr, rq, IRQ_UPDATE, ktime_get_ns(), + update_task_ravg(curr, rq, IRQ_UPDATE, sched_ktime_clock(), delta); nr_windows = cur_jiffies_ts - rq->irqload_ts; @@ -655,14 +694,11 @@ static inline void inter_cluster_migration_fixup BUG_ON((s64)src_rq->nt_curr_runnable_sum < 0); } -static int load_to_index(u32 load) +static u32 load_to_index(u32 load) { - if (load < sched_load_granule) - return 0; - else if (load >= sched_ravg_window) - return NUM_LOAD_INDICES - 1; - else - return load / sched_load_granule; + u32 index = load / sched_load_granule; + + return min(index, (u32)(NUM_LOAD_INDICES - 1)); } static void @@ -754,7 +790,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (sched_disable_window_stats) goto done; - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(task_rq(p)->curr, task_rq(p), TASK_UPDATE, @@ -774,8 +810,9 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) */ if (p->state == TASK_WAKING && p->last_sleep_ts >= src_rq->window_start) { - walt_fixup_cum_window_demand(src_rq, -(s64)p->ravg.demand); - walt_fixup_cum_window_demand(dest_rq, p->ravg.demand); + walt_fixup_cum_window_demand(src_rq, + -(s64)p->ravg.demand_scaled); + walt_fixup_cum_window_demand(dest_rq, p->ravg.demand_scaled); } new_task = is_new_task(p); @@ -839,6 +876,8 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (p == src_rq->ed_task) { src_rq->ed_task = NULL; dest_rq->ed_task = p; + } else if (is_ed_task(p, wallclock)) { + dest_rq->ed_task = p; } done: @@ -1031,6 +1070,7 @@ static inline u32 calc_pred_demand(struct rq *rq, struct task_struct *p) void update_task_pred_demand(struct rq *rq, struct task_struct *p, int event) { u32 new, old; + u16 new_scaled; if (!sched_predl) return; @@ -1059,14 +1099,16 @@ void update_task_pred_demand(struct rq *rq, struct task_struct *p, int event) if (old >= new) return; + new_scaled = scale_demand(new); if (task_on_rq_queued(p) && (!task_has_dl_policy(p) || !p->dl.dl_throttled) && p->sched_class->fixup_walt_sched_stats) p->sched_class->fixup_walt_sched_stats(rq, p, - p->ravg.demand, - new); + p->ravg.demand_scaled, + new_scaled); p->ravg.pred_demand = new; + p->ravg.pred_demand_scaled = new_scaled; } void clear_top_tasks_bitmap(unsigned long *bitmap) @@ -1291,7 +1333,7 @@ static inline unsigned int load_to_freq(struct rq *rq, unsigned int load) bool do_pl_notif(struct rq *rq) { u64 prev = rq->old_busy_time; - u64 pl = rq->walt_stats.pred_demands_sum; + u64 pl = rq->walt_stats.pred_demands_sum_scaled; int cpu = cpu_of(rq); /* If already at max freq, bail out */ @@ -1300,8 +1342,6 @@ bool do_pl_notif(struct rq *rq) prev = max(prev, rq->old_estimated_time); - pl = div64_u64(pl, sched_ravg_window >> SCHED_CAPACITY_SHIFT); - /* 400 MHz filter. */ return (pl > prev) && (load_to_freq(rq, pl - prev) > 400000); } @@ -1649,14 +1689,12 @@ static void update_history(struct rq *rq, struct task_struct *p, int ridx, widx; u32 max = 0, avg, demand, pred_demand; u64 sum = 0; - u64 prev_demand; + u16 demand_scaled, pred_demand_scaled; /* Ignore windows where task had no activity */ if (!runtime || is_idle_task(p) || exiting_task(p) || !samples) goto done; - prev_demand = p->ravg.demand; - /* Push new 'runtime' value onto stack */ widx = sched_ravg_hist_size - 1; ridx = widx - samples; @@ -1688,6 +1726,8 @@ static void update_history(struct rq *rq, struct task_struct *p, demand = max(avg, runtime); } pred_demand = predict_and_update_buckets(rq, p, runtime); + demand_scaled = scale_demand(demand); + pred_demand_scaled = scale_demand(pred_demand); /* * A throttled deadline sched class task gets dequeued without @@ -1704,15 +1744,17 @@ static void update_history(struct rq *rq, struct task_struct *p, if (!task_has_dl_policy(p) || !p->dl.dl_throttled) { if (task_on_rq_queued(p) && p->sched_class->fixup_walt_sched_stats) - p->sched_class->fixup_walt_sched_stats(rq, p, demand, - pred_demand); + p->sched_class->fixup_walt_sched_stats(rq, p, + demand_scaled, pred_demand_scaled); else if (rq->curr == p) - walt_fixup_cum_window_demand(rq, demand); + walt_fixup_cum_window_demand(rq, demand_scaled); } p->ravg.demand = demand; + p->ravg.demand_scaled = demand_scaled; p->ravg.coloc_demand = div64_u64(sum, sched_ravg_hist_size); p->ravg.pred_demand = pred_demand; + p->ravg.pred_demand_scaled = pred_demand_scaled; done: trace_sched_update_history(rq, p, runtime, samples, event); @@ -1961,6 +2003,7 @@ void init_new_task_load(struct task_struct *p, bool idle_task) { int i; u32 init_load_windows = sched_init_task_load_windows; + u32 init_load_windows_scaled = sched_init_task_load_windows_scaled; u32 init_load_pct = current->init_load_pct; p->init_load_pct = 0; @@ -1978,13 +2021,17 @@ void init_new_task_load(struct task_struct *p, bool idle_task) if (idle_task) return; - if (init_load_pct) + if (init_load_pct) { init_load_windows = div64_u64((u64)init_load_pct * (u64)sched_ravg_window, 100); + init_load_windows_scaled = scale_demand(init_load_windows); + } p->ravg.demand = init_load_windows; + p->ravg.demand_scaled = init_load_windows_scaled; p->ravg.coloc_demand = init_load_windows; p->ravg.pred_demand = 0; + p->ravg.pred_demand_scaled = 0; for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i) p->ravg.sum_history[i] = init_load_windows; p->misfit = false; @@ -2042,10 +2089,9 @@ void mark_task_starting(struct task_struct *p) return; } - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); p->ravg.mark_start = p->last_wake_ts = wallclock; p->last_enqueued_ts = wallclock; - p->last_switch_out_ts = 0; update_task_cpu_cycles(p, cpu_of(rq), wallclock); } @@ -2389,7 +2435,7 @@ static int cpufreq_notifier_trans(struct notifier_block *nb, raw_spin_lock_irqsave(&rq->lock, flags); update_task_ravg(rq->curr, rq, TASK_UPDATE, - ktime_get_ns(), 0); + sched_ktime_clock(), 0); raw_spin_unlock_irqrestore(&rq->lock, flags); } @@ -2549,7 +2595,7 @@ static void _set_preferred_cluster(struct related_thread_group *grp) if (list_empty(&grp->tasks)) return; - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); /* * wakeup of two or more related tasks could race with each other and @@ -2575,7 +2621,7 @@ static void _set_preferred_cluster(struct related_thread_group *grp) grp->preferred_cluster = best_cluster(grp, combined_demand, group_boost); - grp->last_update = ktime_get_ns(); + grp->last_update = sched_ktime_clock(); trace_sched_set_preferred_cluster(grp, combined_demand); } @@ -2599,7 +2645,7 @@ int update_preferred_cluster(struct related_thread_group *grp, * has passed since we last updated preference */ if (abs(new_load - old_load) > sched_ravg_window / 4 || - ktime_get_ns() - grp->last_update > sched_ravg_window) + sched_ktime_clock() - grp->last_update > sched_ravg_window) return 1; return 0; @@ -2982,7 +3028,7 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp, bool new_task; int i; - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_UPDATE, wallclock, 0); @@ -3154,7 +3200,7 @@ void walt_irq_work(struct irq_work *irq_work) for_each_cpu(cpu, cpu_possible_mask) raw_spin_lock(&cpu_rq(cpu)->lock); - wc = ktime_get_ns(); + wc = sched_ktime_clock(); walt_load_reported_window = atomic64_read(&walt_irq_work_lastq_ws); for_each_sched_cluster(cluster) { u64 aggr_grp_load = 0; @@ -3256,16 +3302,33 @@ int walt_proc_update_handler(struct ctl_table *table, int write, return ret; } -void walt_sched_init(struct rq *rq) +static void walt_init_once(void) { - int j; - - cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask); init_irq_work(&walt_migration_irq_work, walt_irq_work); init_irq_work(&walt_cpufreq_irq_work, walt_irq_work); walt_rotate_work_init(); - rq->walt_stats.cumulative_runnable_avg = 0; + walt_cpu_util_freq_divisor = + (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100; + walt_scale_demand_divisor = sched_ravg_window >> SCHED_CAPACITY_SHIFT; + + sched_init_task_load_windows = + div64_u64((u64)sysctl_sched_init_task_load_pct * + (u64)sched_ravg_window, 100); + sched_init_task_load_windows_scaled = + scale_demand(sched_init_task_load_windows); +} + +void walt_sched_init_rq(struct rq *rq) +{ + int j; + + if (cpu_of(rq) == 0) + walt_init_once(); + + cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask); + + rq->walt_stats.cumulative_runnable_avg_scaled = 0; rq->window_start = 0; rq->cum_window_start = 0; rq->walt_stats.nr_big_tasks = 0; @@ -3292,7 +3355,7 @@ void walt_sched_init(struct rq *rq) rq->old_busy_time = 0; rq->old_estimated_time = 0; rq->old_busy_time_group = 0; - rq->walt_stats.pred_demands_sum = 0; + rq->walt_stats.pred_demands_sum_scaled = 0; rq->ed_task = NULL; rq->curr_table = 0; rq->prev_top = 0; @@ -3308,13 +3371,6 @@ void walt_sched_init(struct rq *rq) BUG_ON(!rq->top_tasks[j]); clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]); } - rq->cum_window_demand = 0; + rq->cum_window_demand_scaled = 0; rq->notif_pending = false; - - walt_cpu_util_freq_divisor = - (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100; - - sched_init_task_load_windows = - div64_u64((u64)sysctl_sched_init_task_load_pct * - (u64)sched_ravg_window, 100); } diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h index cb84786556aa6726708369a44b71bd946d04d342..7575063b40acd3953a27c96331ca974f42b4c0f6 100644 --- a/kernel/sched/walt.h +++ b/kernel/sched/walt.h @@ -95,16 +95,17 @@ walt_adjust_nr_big_tasks(struct rq *rq, int delta, bool inc) static inline void fixup_cumulative_runnable_avg(struct walt_sched_stats *stats, - s64 task_load_delta, s64 pred_demand_delta) + s64 demand_scaled_delta, + s64 pred_demand_scaled_delta) { if (sched_disable_window_stats) return; - stats->cumulative_runnable_avg += task_load_delta; - BUG_ON((s64)stats->cumulative_runnable_avg < 0); + stats->cumulative_runnable_avg_scaled += demand_scaled_delta; + BUG_ON((s64)stats->cumulative_runnable_avg_scaled < 0); - stats->pred_demands_sum += pred_demand_delta; - BUG_ON((s64)stats->pred_demands_sum < 0); + stats->pred_demands_sum_scaled += pred_demand_scaled_delta; + BUG_ON((s64)stats->pred_demands_sum_scaled < 0); } static inline void @@ -113,8 +114,8 @@ walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) if (sched_disable_window_stats) return; - fixup_cumulative_runnable_avg(&rq->walt_stats, p->ravg.demand, - p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&rq->walt_stats, p->ravg.demand_scaled, + p->ravg.pred_demand_scaled); /* * Add a task's contribution to the cumulative window demand when @@ -124,7 +125,7 @@ walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) * (2) task is waking for the first time in this window. */ if (p->on_rq || (p->last_sleep_ts < rq->window_start)) - walt_fixup_cum_window_demand(rq, p->ravg.demand); + walt_fixup_cum_window_demand(rq, p->ravg.demand_scaled); } static inline void @@ -133,8 +134,9 @@ walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) if (sched_disable_window_stats) return; - fixup_cumulative_runnable_avg(&rq->walt_stats, -(s64)p->ravg.demand, - -(s64)p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&rq->walt_stats, + -(s64)p->ravg.demand_scaled, + -(s64)p->ravg.pred_demand_scaled); /* * on_rq will be 1 for sleeping tasks. So check if the task @@ -142,12 +144,12 @@ walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) * prio/cgroup/class. */ if (task_on_rq_migrating(p) || p->state == TASK_RUNNING) - walt_fixup_cum_window_demand(rq, -(s64)p->ravg.demand); + walt_fixup_cum_window_demand(rq, -(s64)p->ravg.demand_scaled); } extern void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p, - u32 new_task_load, - u32 new_pred_demand); + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled); extern void inc_rq_walt_stats(struct rq *rq, struct task_struct *p); extern void dec_rq_walt_stats(struct rq *rq, struct task_struct *p); extern void fixup_busy_time(struct task_struct *p, int new_cpu); @@ -293,11 +295,11 @@ void sort_clusters(void); void walt_irq_work(struct irq_work *irq_work); -void walt_sched_init(struct rq *rq); +void walt_sched_init_rq(struct rq *rq); static inline void walt_update_last_enqueue(struct task_struct *p) { - p->last_enqueued_ts = ktime_get_ns(); + p->last_enqueued_ts = sched_ktime_clock(); } extern void walt_rotate_work_init(void); extern void walt_rotation_checkpoint(int nr_big); @@ -305,7 +307,7 @@ extern unsigned int walt_rotation_enabled; #else /* CONFIG_SCHED_WALT */ -static inline void walt_sched_init(struct rq *rq) { } +static inline void walt_sched_init_rq(struct rq *rq) { } static inline void walt_rotate_work_init(void) { } static inline void walt_rotation_checkpoint(int nr_big) { } @@ -374,7 +376,8 @@ dec_rq_walt_stats(struct rq *rq, struct task_struct *p) { } static inline void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { } diff --git a/kernel/softirq.c b/kernel/softirq.c index 81740f20ca1344dd7e645760b6f866b552e37ad9..ee4f0e018424dd1f8bdb4cd7cdf2b38d22f006cc 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -390,7 +390,7 @@ static inline void tick_irq_exit(void) /* Make sure that timer wheel updates are propagated */ if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) { - if (!in_interrupt()) + if (!in_irq()) tick_nohz_irq_exit(); } #endif diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index b140029388dbe9233b0ab9f297db05dc9ed0ef86..eb5af33555ea1d2b4c008979d4e8e30f90507032 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -37,7 +37,7 @@ struct cpu_stop_done { struct cpu_stopper { struct task_struct *thread; - spinlock_t lock; + raw_spinlock_t lock; bool enabled; /* is this stopper enabled? */ struct list_head works; /* list of pending works */ @@ -82,13 +82,13 @@ static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work) bool enabled; preempt_disable(); - spin_lock_irqsave(&stopper->lock, flags); + raw_spin_lock_irqsave(&stopper->lock, flags); enabled = stopper->enabled; if (enabled) __cpu_stop_queue_work(stopper, work, &wakeq); else if (work->done) cpu_stop_signal_done(work->done); - spin_unlock_irqrestore(&stopper->lock, flags); + raw_spin_unlock_irqrestore(&stopper->lock, flags); wake_up_q(&wakeq); preempt_enable(); @@ -239,8 +239,8 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1, DEFINE_WAKE_Q(wakeq); int err; retry: - spin_lock_irq(&stopper1->lock); - spin_lock_nested(&stopper2->lock, SINGLE_DEPTH_NESTING); + raw_spin_lock_irq(&stopper1->lock); + raw_spin_lock_nested(&stopper2->lock, SINGLE_DEPTH_NESTING); err = -ENOENT; if (!stopper1->enabled || !stopper2->enabled) @@ -272,8 +272,8 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1, */ preempt_disable(); unlock: - spin_unlock(&stopper2->lock); - spin_unlock_irq(&stopper1->lock); + raw_spin_unlock(&stopper2->lock); + raw_spin_unlock_irq(&stopper1->lock); if (unlikely(err == -EDEADLK)) { while (stop_cpus_in_progress) @@ -471,9 +471,9 @@ static int cpu_stop_should_run(unsigned int cpu) unsigned long flags; int run; - spin_lock_irqsave(&stopper->lock, flags); + raw_spin_lock_irqsave(&stopper->lock, flags); run = !list_empty(&stopper->works); - spin_unlock_irqrestore(&stopper->lock, flags); + raw_spin_unlock_irqrestore(&stopper->lock, flags); return run; } @@ -484,13 +484,13 @@ static void cpu_stopper_thread(unsigned int cpu) repeat: work = NULL; - spin_lock_irq(&stopper->lock); + raw_spin_lock_irq(&stopper->lock); if (!list_empty(&stopper->works)) { work = list_first_entry(&stopper->works, struct cpu_stop_work, list); list_del_init(&work->list); } - spin_unlock_irq(&stopper->lock); + raw_spin_unlock_irq(&stopper->lock); if (work) { cpu_stop_fn_t fn = work->fn; @@ -564,7 +564,7 @@ static int __init cpu_stop_init(void) for_each_possible_cpu(cpu) { struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); - spin_lock_init(&stopper->lock); + raw_spin_lock_init(&stopper->lock); INIT_LIST_HEAD(&stopper->works); } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3a4e11d61f8780127f98d1da464738c4a5514a26..3727de0c9c4666330bec28750e9a71e167014e2b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -139,6 +139,7 @@ static int ten_thousand = 10000; #ifdef CONFIG_PERF_EVENTS static int six_hundred_forty_kb = 640 * 1024; #endif +static int two_hundred_fifty_five = 255; /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; @@ -578,6 +579,31 @@ static struct ctl_table kern_table[] = { .extra1 = &one, }, #endif + { + .procname = "sched_lib_name", + .data = sched_lib_name, + .maxlen = LIB_PATH_LENGTH, + .mode = 0644, + .proc_handler = proc_dostring, + }, + { + .procname = "sched_lib_mask_check", + .data = &sched_lib_mask_check, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred_fifty_five, + }, + { + .procname = "sched_lib_mask_force", + .data = &sched_lib_mask_force, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred_fifty_five, + }, #ifdef CONFIG_PROVE_LOCKING { .procname = "prove_locking", @@ -3264,7 +3290,7 @@ static int do_proc_douintvec_capacity_conv(bool *negp, unsigned long *lvalp, int *valp, int write, void *data) { if (write) { - if (*negp) + if (*negp || *lvalp == 0) return -EINVAL; *valp = SCHED_FIXEDPOINT_SCALE * 100 / *lvalp; } else { diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index b1e5728745ffb3aa50427962b49d8df8e914d6a0..e13d32706b74be029b8eb048cc767e0848ec2559 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -322,6 +322,8 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs) { unsigned long flags; + INIT_LIST_HEAD(&cs->wd_list); + spin_lock_irqsave(&watchdog_lock, flags); if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { /* cs is a clocksource to be watched. */ diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 98d08d32f2aeff41e68b6525137cbd3cd8be06e8..cca5b31675a203e875fb07a51fe80702a21c931f 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -463,7 +463,8 @@ static inline void hrtimer_update_next_timer(struct hrtimer_cpu_base *cpu_base, #endif } -static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base) +static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, + const struct hrtimer *exclude) { struct hrtimer_clock_base *base = cpu_base->clock_base; unsigned int active = cpu_base->active_bases; @@ -479,9 +480,24 @@ static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base) next = timerqueue_getnext(&base->active); timer = container_of(next, struct hrtimer, node); + if (timer == exclude) { + /* Get to the next timer in the queue. */ + struct rb_node *rbn = rb_next(&next->node); + + next = rb_entry_safe(rbn, struct timerqueue_node, node); + if (!next) + continue; + + timer = container_of(next, struct hrtimer, node); + } expires = ktime_sub(hrtimer_get_expires(timer), base->offset); if (expires < expires_next) { expires_next = expires; + + /* Skip cpu_base update if a timer is being excluded. */ + if (exclude) + continue; + hrtimer_update_next_timer(cpu_base, timer); } } @@ -560,7 +576,7 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) if (!cpu_base->hres_active) return; - expires_next = __hrtimer_get_next_event(cpu_base); + expires_next = __hrtimer_get_next_event(cpu_base, NULL); if (skip_equal && expires_next == cpu_base->expires_next) return; @@ -1086,7 +1102,30 @@ u64 hrtimer_get_next_event(void) raw_spin_lock_irqsave(&cpu_base->lock, flags); if (!__hrtimer_hres_active(cpu_base)) - expires = __hrtimer_get_next_event(cpu_base); + expires = __hrtimer_get_next_event(cpu_base, NULL); + + raw_spin_unlock_irqrestore(&cpu_base->lock, flags); + + return expires; +} + +/** + * hrtimer_next_event_without - time until next expiry event w/o one timer + * @exclude: timer to exclude + * + * Returns the next expiry time over all timers except for the @exclude one or + * KTIME_MAX if none of them is pending. + */ +u64 hrtimer_next_event_without(const struct hrtimer *exclude) +{ + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); + u64 expires = KTIME_MAX; + unsigned long flags; + + raw_spin_lock_irqsave(&cpu_base->lock, flags); + + if (__hrtimer_hres_active(cpu_base)) + expires = __hrtimer_get_next_event(cpu_base, exclude); raw_spin_unlock_irqrestore(&cpu_base->lock, flags); @@ -1328,7 +1367,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) __hrtimer_run_queues(cpu_base, now); /* Reevaluate the clock bases for the next expiry */ - expires_next = __hrtimer_get_next_event(cpu_base); + expires_next = __hrtimer_get_next_event(cpu_base, NULL); /* * Store the new expiry value so the migration code can verify * against it. diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 99e03bec68e4cbaa3ba103f3097eeb1e5d38e3ee..9de770228cb0ec0197cc5df75b44d55ac760e553 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -31,7 +31,7 @@ /* USER_HZ period (usecs): */ -unsigned long tick_usec = TICK_USEC; +unsigned long tick_usec = USER_TICK_USEC; /* SHIFTED_HZ period (nsecs): */ unsigned long tick_nsec; diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 0ae8aa5a8911305003b82a9dccbbb7bf8233cf2c..26152997d1b39490c65fbc708c1c552dff5de82c 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -569,14 +569,11 @@ static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now) sched_clock_idle_wakeup_event(); } -static ktime_t tick_nohz_start_idle(struct tick_sched *ts) +static void tick_nohz_start_idle(struct tick_sched *ts) { - ktime_t now = ktime_get(); - - ts->idle_entrytime = now; + ts->idle_entrytime = ktime_get(); ts->idle_active = 1; sched_clock_idle_sleep_event(); - return now; } /** @@ -682,16 +679,13 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) static inline bool local_timer_softirq_pending(void) { - return local_softirq_pending() & TIMER_SOFTIRQ; + return local_softirq_pending() & BIT(TIMER_SOFTIRQ); } -static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, - ktime_t now, int cpu) +static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu) { - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); u64 basemono, next_tick, next_tmr, next_rcu, delta, expires; unsigned long seq, basejiff; - ktime_t tick; /* Read jiffies and the time when jiffies were updated last */ do { @@ -700,6 +694,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, basejiff = jiffies; } while (read_seqretry(&jiffies_lock, seq)); ts->last_jiffies = basejiff; + ts->timer_expires_base = basemono; /* * Keep the periodic tick, when RCU, architecture or irq_work @@ -744,32 +739,20 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, * next period, so no point in stopping it either, bail. */ if (!ts->tick_stopped) { - tick = 0; + ts->timer_expires = 0; goto out; } } /* - * If this CPU is the one which updates jiffies, then give up - * the assignment and let it be taken by the CPU which runs - * the tick timer next, which might be this CPU as well. If we - * don't drop this here the jiffies might be stale and - * do_timer() never invoked. Keep track of the fact that it - * was the one which had the do_timer() duty last. If this CPU - * is the one which had the do_timer() duty last, we limit the - * sleep time to the timekeeping max_deferment value. + * If this CPU is the one which had the do_timer() duty last, we limit + * the sleep time to the timekeeping max_deferment value. * Otherwise we can sleep as long as we want. */ delta = timekeeping_max_deferment(); - if (cpu == tick_do_timer_cpu) { - tick_do_timer_cpu = TICK_DO_TIMER_NONE; - ts->do_timer_last = 1; - } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) { + if (cpu != tick_do_timer_cpu && + (tick_do_timer_cpu != TICK_DO_TIMER_NONE || !ts->do_timer_last)) delta = KTIME_MAX; - ts->do_timer_last = 0; - } else if (!ts->do_timer_last) { - delta = KTIME_MAX; - } #ifdef CONFIG_NO_HZ_FULL /* Limit the tick delta to the maximum scheduler deferment */ @@ -783,14 +766,42 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, else expires = KTIME_MAX; - expires = min_t(u64, expires, next_tick); - tick = expires; + ts->timer_expires = min_t(u64, expires, next_tick); + +out: + return ts->timer_expires; +} + +static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu) +{ + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); + u64 basemono = ts->timer_expires_base; + u64 expires = ts->timer_expires; + ktime_t tick = expires; + + /* Make sure we won't be trying to stop it twice in a row. */ + ts->timer_expires_base = 0; + + /* + * If this CPU is the one which updates jiffies, then give up + * the assignment and let it be taken by the CPU which runs + * the tick timer next, which might be this CPU as well. If we + * don't drop this here the jiffies might be stale and + * do_timer() never invoked. Keep track of the fact that it + * was the one which had the do_timer() duty last. + */ + if (cpu == tick_do_timer_cpu) { + tick_do_timer_cpu = TICK_DO_TIMER_NONE; + ts->do_timer_last = 1; + } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) { + ts->do_timer_last = 0; + } /* Skip reprogram of event if its not changed */ if (ts->tick_stopped && (expires == ts->next_tick)) { /* Sanity check: make sure clockevent is actually programmed */ if (tick == KTIME_MAX || ts->next_tick == hrtimer_get_expires(&ts->sched_timer)) - goto out; + return; WARN_ON_ONCE(1); printk_once("basemono: %llu ts->next_tick: %llu dev->next_event: %llu timer->active: %d timer->expires: %llu\n", @@ -823,7 +834,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, if (unlikely(expires == KTIME_MAX)) { if (ts->nohz_mode == NOHZ_MODE_HIGHRES) hrtimer_cancel(&ts->sched_timer); - goto out; + return; } if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { @@ -832,15 +843,22 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, hrtimer_set_expires(&ts->sched_timer, tick); tick_program_event(tick, 1); } +} -out: - /* - * Update the estimated sleep length until the next timer - * (not only the tick). - */ - ts->sleep_length = ktime_sub(dev->next_event, now); - return tick; +static void tick_nohz_retain_tick(struct tick_sched *ts) +{ + ts->timer_expires_base = 0; +} + +#ifdef CONFIG_NO_HZ_FULL +static void tick_nohz_stop_sched_tick(struct tick_sched *ts, int cpu) +{ + if (tick_nohz_next_event(ts, cpu)) + tick_nohz_stop_tick(ts, cpu); + else + tick_nohz_retain_tick(ts); } +#endif /* CONFIG_NO_HZ_FULL */ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) { @@ -877,7 +895,7 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts) return; if (can_stop_full_tick(cpu, ts)) - tick_nohz_stop_sched_tick(ts, ktime_get(), cpu); + tick_nohz_stop_sched_tick(ts, cpu); else if (ts->tick_stopped) tick_nohz_restart_sched_tick(ts, ktime_get()); #endif @@ -903,10 +921,8 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) return false; } - if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) { - ts->sleep_length = NSEC_PER_SEC / HZ; + if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) return false; - } if (need_resched()) return false; @@ -941,47 +957,70 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) return true; } -static void __tick_nohz_idle_enter(struct tick_sched *ts) +static void __tick_nohz_idle_stop_tick(struct tick_sched *ts) { - ktime_t now, expires; + ktime_t expires; int cpu = smp_processor_id(); - now = tick_nohz_start_idle(ts); - #ifdef CONFIG_SMP if (check_pending_deferrable_timers(cpu)) raise_softirq_irqoff(TIMER_SOFTIRQ); #endif - if (can_stop_idle_tick(cpu, ts)) { + /* + * If tick_nohz_get_sleep_length() ran tick_nohz_next_event(), the + * tick timer expiration time is known already. + */ + if (ts->timer_expires_base) + expires = ts->timer_expires; + else if (can_stop_idle_tick(cpu, ts)) + expires = tick_nohz_next_event(ts, cpu); + else + return; + + ts->idle_calls++; + + if (expires > 0LL) { int was_stopped = ts->tick_stopped; - ts->idle_calls++; + tick_nohz_stop_tick(ts, cpu); - expires = tick_nohz_stop_sched_tick(ts, now, cpu); - if (expires > 0LL) { - ts->idle_sleeps++; - ts->idle_expires = expires; - } + ts->idle_sleeps++; + ts->idle_expires = expires; if (!was_stopped && ts->tick_stopped) { ts->idle_jiffies = ts->last_jiffies; nohz_balance_enter_idle(cpu); } + } else { + tick_nohz_retain_tick(ts); } } /** - * tick_nohz_idle_enter - stop the idle tick from the idle task + * tick_nohz_idle_stop_tick - stop the idle tick from the idle task * * When the next event is more than a tick into the future, stop the idle tick - * Called when we start the idle loop. - * - * The arch is responsible of calling: + */ +void tick_nohz_idle_stop_tick(void) +{ + __tick_nohz_idle_stop_tick(this_cpu_ptr(&tick_cpu_sched)); +} + +void tick_nohz_idle_retain_tick(void) +{ + tick_nohz_retain_tick(this_cpu_ptr(&tick_cpu_sched)); + /* + * Undo the effect of get_next_timer_interrupt() called from + * tick_nohz_next_event(). + */ + timer_clear_idle(); +} + +/** + * tick_nohz_idle_enter - prepare for entering idle on the current CPU * - * - rcu_idle_enter() after its last use of RCU before the CPU is put - * to sleep. - * - rcu_idle_exit() before the first use of RCU after the CPU is woken up. + * Called when we start the idle loop. */ void tick_nohz_idle_enter(void) { @@ -991,7 +1030,7 @@ void tick_nohz_idle_enter(void) /* * Update the idle state in the scheduler domain hierarchy - * when tick_nohz_stop_sched_tick() is called from the idle loop. + * when tick_nohz_stop_tick() is called from the idle loop. * State will be updated to busy during the first busy tick after * exiting idle. */ @@ -1000,8 +1039,11 @@ void tick_nohz_idle_enter(void) local_irq_disable(); ts = this_cpu_ptr(&tick_cpu_sched); + + WARN_ON_ONCE(ts->timer_expires_base); + ts->inidle = 1; - __tick_nohz_idle_enter(ts); + tick_nohz_start_idle(ts); local_irq_enable(); } @@ -1019,21 +1061,62 @@ void tick_nohz_irq_exit(void) struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); if (ts->inidle) - __tick_nohz_idle_enter(ts); + tick_nohz_start_idle(ts); else tick_nohz_full_update_tick(ts); } /** - * tick_nohz_get_sleep_length - return the length of the current sleep + * tick_nohz_idle_got_tick - Check whether or not the tick handler has run + */ +bool tick_nohz_idle_got_tick(void) +{ + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); + + if (ts->inidle > 1) { + ts->inidle = 1; + return true; + } + return false; +} + +/** + * tick_nohz_get_sleep_length - return the expected length of the current sleep + * @delta_next: duration until the next event if the tick cannot be stopped * * Called from power state control code with interrupts disabled */ -ktime_t tick_nohz_get_sleep_length(void) +ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next) { + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); + int cpu = smp_processor_id(); + /* + * The idle entry time is expected to be a sufficient approximation of + * the current time at this point. + */ + ktime_t now = ts->idle_entrytime; + ktime_t next_event; + + WARN_ON_ONCE(!ts->inidle); + + *delta_next = ktime_sub(dev->next_event, now); - return ts->sleep_length; + if (!can_stop_idle_tick(cpu, ts)) + return *delta_next; + + next_event = tick_nohz_next_event(ts, cpu); + if (!next_event) + return *delta_next; + + /* + * If the next highres timer to expire is earlier than next_event, the + * idle governor needs to know that. + */ + next_event = min_t(u64, next_event, + hrtimer_next_event_without(&ts->sched_timer)); + + return ktime_sub(next_event, now); } /** @@ -1082,6 +1165,20 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts) #endif } +static void __tick_nohz_idle_restart_tick(struct tick_sched *ts, ktime_t now) +{ + tick_nohz_restart_sched_tick(ts, now); + tick_nohz_account_idle_ticks(ts); +} + +void tick_nohz_idle_restart_tick(void) +{ + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); + + if (ts->tick_stopped) + __tick_nohz_idle_restart_tick(ts, ktime_get()); +} + /** * tick_nohz_idle_exit - restart the idle tick from the idle task * @@ -1097,6 +1194,7 @@ void tick_nohz_idle_exit(void) local_irq_disable(); WARN_ON_ONCE(!ts->inidle); + WARN_ON_ONCE(ts->timer_expires_base); ts->inidle = 0; @@ -1106,10 +1204,8 @@ void tick_nohz_idle_exit(void) if (ts->idle_active) tick_nohz_stop_idle(ts, now); - if (ts->tick_stopped) { - tick_nohz_restart_sched_tick(ts, now); - tick_nohz_account_idle_ticks(ts); - } + if (ts->tick_stopped) + __tick_nohz_idle_restart_tick(ts, now); local_irq_enable(); } @@ -1123,6 +1219,9 @@ static void tick_nohz_handler(struct clock_event_device *dev) struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); + if (ts->inidle) + ts->inidle = 2; + dev->next_event = KTIME_MAX; tick_sched_do_timer(now); @@ -1231,6 +1330,9 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); + if (ts->inidle) + ts->inidle = 2; + tick_sched_do_timer(now); /* diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h index 954b43dbf21cb7f64f31bb6a849a0654a63620a5..2b845f2c44b1b3c72ed827d9bf8542beb8af46f7 100644 --- a/kernel/time/tick-sched.h +++ b/kernel/time/tick-sched.h @@ -38,7 +38,8 @@ enum tick_nohz_mode { * @idle_exittime: Time when the idle state was left * @idle_sleeptime: Sum of the time slept in idle with sched tick stopped * @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding - * @sleep_length: Duration of the current idle sleep + * @timer_expires: Anticipated timer expiration time (in case sched tick is stopped) + * @timer_expires_base: Base time clock monotonic for @timer_expires * @do_timer_lst: CPU was the last one doing do_timer before going idle */ struct tick_sched { @@ -58,8 +59,9 @@ struct tick_sched { ktime_t idle_exittime; ktime_t idle_sleeptime; ktime_t iowait_sleeptime; - ktime_t sleep_length; unsigned long last_jiffies; + u64 timer_expires; + u64 timer_expires_base; u64 next_timer; ktime_t idle_expires; int do_timer_last; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 55447b2a956044cf9e0f3dca8d2a38f05dcb2f7f..8f9d95f9cb50ca532b232eb4de2da037d2cd66ad 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1660,6 +1660,22 @@ static inline void __run_timers(struct timer_base *base) raw_spin_lock_irq(&base->lock); + /* + * timer_base::must_forward_clk must be cleared before running + * timers so that any timer functions that call mod_timer() will + * not try to forward the base. Idle tracking / clock forwarding + * logic is only used with BASE_STD timers. + * + * The must_forward_clk flag is cleared unconditionally also for + * the deferrable base. The deferrable base is not affected by idle + * tracking and never forwarded, so clearing the flag is a NOOP. + * + * The fact that the deferrable base is never forwarded can cause + * large variations in granularity for deferrable timers, but they + * can be deferred for long periods due to idle anyway. + */ + base->must_forward_clk = false; + while (time_after_eq(jiffies, base->clk)) { levels = collect_expired_timers(base, heads); @@ -1679,19 +1695,6 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) { struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - /* - * must_forward_clk must be cleared before running timers so that any - * timer functions that call mod_timer will not try to forward the - * base. idle trcking / clock forwarding logic is only used with - * BASE_STD timers. - * - * The deferrable base does not do idle tracking at all, so we do - * not forward it. This can result in very large variations in - * granularity for deferrable timers, but they can be deferred for - * long periods due to idle. - */ - base->must_forward_clk = false; - __run_timers(base); if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) { __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/kernel/trace/ipc_logging_debug.c b/kernel/trace/ipc_logging_debug.c index d7337249fa75b2ddd9deb22f1875442f9011639c..576afd71c45d2dea6689ce33554d88572f2c7988 100644 --- a/kernel/trace/ipc_logging_debug.c +++ b/kernel/trace/ipc_logging_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -78,18 +78,19 @@ static ssize_t debug_read_helper(struct file *file, char __user *buff, struct dentry *d = file->f_path.dentry; char *buffer; int bsize; - int srcu_idx; int r; - r = debugfs_use_file_start(d, &srcu_idx); - if (!r) { - ilctxt = file->private_data; - r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; - } - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); if (r) return r; + ilctxt = file->private_data; + r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; + if (r) { + debugfs_file_put(d); + return r; + } + buffer = kmalloc(count, GFP_KERNEL); if (!buffer) { bsize = -ENOMEM; @@ -110,6 +111,7 @@ static ssize_t debug_read_helper(struct file *file, char __user *buff, done: ipc_log_context_put(ilctxt); + debugfs_file_put(d); return bsize; } diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 36f018b1539246b63817c20c6c34d56f131a80ae..fd78090042973ceaae2fab46daa10021509bee13 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3109,6 +3109,22 @@ int ring_buffer_record_is_on(struct ring_buffer *buffer) return !atomic_read(&buffer->record_disabled); } +/** + * ring_buffer_record_is_set_on - return true if the ring buffer is set writable + * @buffer: The ring buffer to see if write is set enabled + * + * Returns true if the ring buffer is set writable by ring_buffer_record_on(). + * Note that this does NOT mean it is in a writable state. + * + * It may return true when the ring buffer has been disabled by + * ring_buffer_record_disable(), as that is a temporary disabling of + * the ring buffer. + */ +int ring_buffer_record_is_set_on(struct ring_buffer *buffer) +{ + return !(atomic_read(&buffer->record_disabled) & RB_BUFFER_OFF); +} + /** * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer * @buffer: The ring buffer to stop writes to. diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2f12af99a4baeb72ab70e6127bcd785ca1ae55d3..8de773161495ac40493cb7998e2c559e962738ec 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1367,6 +1367,12 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) arch_spin_lock(&tr->max_lock); + /* Inherit the recordable setting from trace_buffer */ + if (ring_buffer_record_is_set_on(tr->trace_buffer.buffer)) + ring_buffer_record_on(tr->max_buffer.buffer); + else + ring_buffer_record_off(tr->max_buffer.buffer); + buf = tr->trace_buffer.buffer; tr->trace_buffer.buffer = tr->max_buffer.buffer; tr->max_buffer.buffer = buf; diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index b413fab7d75becb63fec1e9c795e135463ee552c..43254c5e7e1649323d4cfd3e91c75a80c2e2fb19 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -680,6 +680,8 @@ event_trigger_callback(struct event_command *cmd_ops, goto out_free; out_reg: + /* Up the trigger_data count to make sure reg doesn't free it on failure */ + event_trigger_init(trigger_ops, trigger_data); ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file); /* * The above returns on success the # of functions enabled, @@ -687,11 +689,13 @@ event_trigger_callback(struct event_command *cmd_ops, * Consider no functions a failure too. */ if (!ret) { + cmd_ops->unreg(glob, trigger_ops, trigger_data, file); ret = -ENOENT; - goto out_free; - } else if (ret < 0) - goto out_free; - ret = 0; + } else if (ret > 0) + ret = 0; + + /* Down the counter of trigger_data or free it if not used anymore */ + event_trigger_free(trigger_ops, trigger_data); out: return ret; @@ -1392,6 +1396,9 @@ int event_enable_trigger_func(struct event_command *cmd_ops, goto out; } + /* Up the trigger_data count to make sure nothing frees it on failure */ + event_trigger_init(trigger_ops, trigger_data); + if (trigger) { number = strsep(&trigger, ":"); @@ -1442,6 +1449,7 @@ int event_enable_trigger_func(struct event_command *cmd_ops, goto out_disable; /* Just return zero, not the number of enabled functions */ ret = 0; + event_trigger_free(trigger_ops, trigger_data); out: return ret; @@ -1452,7 +1460,7 @@ int event_enable_trigger_func(struct event_command *cmd_ops, out_free: if (cmd_ops->set_filter) cmd_ops->set_filter(NULL, trigger_data, NULL); - kfree(trigger_data); + event_trigger_free(trigger_ops, trigger_data); kfree(enable_data); goto out; } diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index f8d3bd974bcc41032ecc11f958be3f72cfe75863..ea20274a105aed94ce34d96e30ffc2304cc038ae 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -376,11 +376,10 @@ static struct trace_kprobe *find_trace_kprobe(const char *event, static int enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) { + struct event_file_link *link = NULL; int ret = 0; if (file) { - struct event_file_link *link; - link = kmalloc(sizeof(*link), GFP_KERNEL); if (!link) { ret = -ENOMEM; @@ -400,6 +399,18 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) else ret = enable_kprobe(&tk->rp.kp); } + + if (ret) { + if (file) { + /* Notice the if is true on not WARN() */ + if (!WARN_ON_ONCE(!link)) + list_del_rcu(&link->list); + kfree(link); + tk->tp.flags &= ~TP_FLAG_TRACE; + } else { + tk->tp.flags &= ~TP_FLAG_PROFILE; + } + } out: return ret; } diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 74506964a51719641d8195e875defa3d7805b723..40f399a8eda3e60462323a6fa15797c4a4a3b9ce 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -291,7 +291,6 @@ config PAGE_OWNER_ENABLE_DEFAULT config DEBUG_FS bool "Debug Filesystem" - select SRCU help debugfs is a virtual file system that kernel developers use to put debugging files into. Enable this option to be able to read and diff --git a/lib/rhashtable.c b/lib/rhashtable.c index b734ce731a7a5c6873cac5f931cd44ea8017e7cf..39215c724fc72213a6fa2fda6f07186956300605 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -878,8 +878,16 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_stop); static size_t rounded_hashtable_size(const struct rhashtable_params *params) { - return max(roundup_pow_of_two(params->nelem_hint * 4 / 3), - (unsigned long)params->min_size); + size_t retsize; + + if (params->nelem_hint) + retsize = max(roundup_pow_of_two(params->nelem_hint * 4 / 3), + (unsigned long)params->min_size); + else + retsize = max(HASH_DEFAULT_SIZE, + (unsigned long)params->min_size); + + return retsize; } static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed) @@ -936,8 +944,6 @@ int rhashtable_init(struct rhashtable *ht, struct bucket_table *tbl; size_t size; - size = HASH_DEFAULT_SIZE; - if ((!params->key_len && !params->obj_hashfn) || (params->obj_hashfn && !params->obj_cmpfn)) return -EINVAL; @@ -964,8 +970,7 @@ int rhashtable_init(struct rhashtable *ht, ht->p.min_size = max_t(u16, ht->p.min_size, HASH_MIN_SIZE); - if (params->nelem_hint) - size = rounded_hashtable_size(&ht->p); + size = rounded_hashtable_size(&ht->p); if (params->locks_mul) ht->p.locks_mul = roundup_pow_of_two(params->locks_mul); diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 6774e0369ebecf79484aa2f1b55fabb7b89ab042..9386c98dac123bc48d3744eb988bafef69da49c6 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -356,15 +356,8 @@ static void wb_shutdown(struct bdi_writeback *wb) spin_lock_bh(&wb->work_lock); if (!test_and_clear_bit(WB_registered, &wb->state)) { spin_unlock_bh(&wb->work_lock); - /* - * Wait for wb shutdown to finish if someone else is just - * running wb_shutdown(). Otherwise we could proceed to wb / - * bdi destruction before wb_shutdown() is finished. - */ - wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE); return; } - set_bit(WB_shutting_down, &wb->state); spin_unlock_bh(&wb->work_lock); cgwb_remove_from_bdi_list(wb); @@ -376,12 +369,6 @@ static void wb_shutdown(struct bdi_writeback *wb) mod_delayed_work(bdi_wq, &wb->dwork, 0); flush_delayed_work(&wb->dwork); WARN_ON(!list_empty(&wb->work_list)); - /* - * Make sure bit gets cleared after shutdown is finished. Matches with - * the barrier provided by test_and_clear_bit() above. - */ - smp_wmb(); - clear_and_wake_up_bit(WB_shutting_down, &wb->state); } static void wb_exit(struct bdi_writeback *wb) @@ -505,10 +492,12 @@ static void cgwb_release_workfn(struct work_struct *work) struct bdi_writeback *wb = container_of(work, struct bdi_writeback, release_work); + mutex_lock(&wb->bdi->cgwb_release_mutex); wb_shutdown(wb); css_put(wb->memcg_css); css_put(wb->blkcg_css); + mutex_unlock(&wb->bdi->cgwb_release_mutex); fprop_local_destroy_percpu(&wb->memcg_completions); percpu_ref_exit(&wb->refcnt); @@ -694,6 +683,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC); bdi->cgwb_congested_tree = RB_ROOT; + mutex_init(&bdi->cgwb_release_mutex); ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); if (!ret) { @@ -714,7 +704,10 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi) spin_lock_irq(&cgwb_lock); radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0) cgwb_kill(*slot); + spin_unlock_irq(&cgwb_lock); + mutex_lock(&bdi->cgwb_release_mutex); + spin_lock_irq(&cgwb_lock); while (!list_empty(&bdi->wb_list)) { wb = list_first_entry(&bdi->wb_list, struct bdi_writeback, bdi_node); @@ -723,6 +716,7 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi) spin_lock_irq(&cgwb_lock); } spin_unlock_irq(&cgwb_lock); + mutex_unlock(&bdi->cgwb_release_mutex); } /** diff --git a/mm/cma.c b/mm/cma.c index e4a219fa0a2d0f42b9c846309dbf4c1e5b17b989..c5ee6148a8a7a8acca0ccd0b5e428d94e1541c8a 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -461,7 +461,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, bitmap_maxno, start, bitmap_count, mask, offset); if (bitmap_no >= bitmap_maxno) { - if (retry_after_sleep < max_retries) { + if ((retry_after_sleep < max_retries) && + (ret == -EBUSY)) { start = 0; /* * update max retries if available free regions diff --git a/mm/filemap.c b/mm/filemap.c index e77e15d08670f57c81f2c92d0d4d5214b72f3762..3729f2b93052eb80ad9ed141254421a94e050986 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2409,6 +2409,11 @@ int filemap_fault(struct vm_fault *vmf) do_async_mmap_readahead(vmf->vma, ra, file, page, offset); } else if (!page) { /* No page in the page cache at all */ + struct address_space *mapping = file->f_mapping; + + if (mapping && (mapping->gfp_mask & __GFP_MOVABLE)) + mapping->gfp_mask |= __GFP_CMA; + do_sync_mmap_readahead(vmf->vma, ra, file, offset); count_vm_event(PGMAJFAULT); count_memcg_event_mm(vmf->vma->vm_mm, PGMAJFAULT); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 5cb7aee06f761e5b63fc9626004a486b27518995..8d1b8a685ca0d5d7480c04a1860127e1c05c12f9 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2069,6 +2069,8 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, if (vma_is_dax(vma)) return; page = pmd_page(_pmd); + if (!PageDirty(page) && pmd_dirty(_pmd)) + set_page_dirty(page); if (!PageReferenced(page) && pmd_young(_pmd)) SetPageReferenced(page); page_remove_rmap(page, true); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 942d9342b63bcf744aa4c23c278b91e79f7bbf32..db69d938e9ed0a7105241efd78a105d7d77c8e3c 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -879,7 +879,7 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg) int nid; int i; - while ((memcg = parent_mem_cgroup(memcg))) { + for (; memcg; memcg = parent_mem_cgroup(memcg)) { for_each_node(nid) { mz = mem_cgroup_nodeinfo(memcg, nid); for (i = 0; i <= DEF_PRIORITY; i++) { diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index d5364921ccaf134b0d2080aec4f1ebbfb4f5ad9f..c1ee2d3ddc03e96dae5e3fa153adf85d1ffcc45e 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1766,7 +1766,8 @@ static int __ref __offline_pages(unsigned long start_pfn, /* Must be protected by mem_hotplug_begin() or a device_lock */ int offline_pages(unsigned long start_pfn, unsigned long nr_pages) { - return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ); + return __offline_pages(start_pfn, start_pfn + nr_pages, + MIGRATE_TIMEOUT_SEC * HZ); } #endif /* CONFIG_MEMORY_HOTREMOVE */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d1c2ffd7960ba49ffbce83a98c683650f4238309..c4db6573db789f2e071bdc04e4062ddd6b8d6574 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -239,10 +239,10 @@ char * const migratetype_names[MIGRATE_TYPES] = { "Unmovable", "Movable", "Reclaimable", - "HighAtomic", #ifdef CONFIG_CMA "CMA", #endif + "HighAtomic", #ifdef CONFIG_MEMORY_ISOLATION "Isolate", #endif @@ -1855,11 +1855,6 @@ static int fallbacks[MIGRATE_TYPES][4] = { #endif }; -int *get_migratetype_fallbacks(int mtype) -{ - return fallbacks[mtype]; -} - #ifdef CONFIG_CMA static struct page *__rmqueue_cma_fallback(struct zone *zone, unsigned int order) @@ -2321,18 +2316,32 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order, retry: page = __rmqueue_smallest(zone, order, migratetype); - if (unlikely(!page)) { - if (migratetype == MIGRATE_MOVABLE) - page = __rmqueue_cma_fallback(zone, order); - if (!page && __rmqueue_fallback(zone, order, migratetype)) - goto retry; - } + if (unlikely(!page) && __rmqueue_fallback(zone, order, migratetype)) + goto retry; trace_mm_page_alloc_zone_locked(page, order, migratetype); return page; } +#ifdef CONFIG_CMA +static struct page *__rmqueue_cma(struct zone *zone, unsigned int order) +{ + struct page *page = 0; + + if (IS_ENABLED(CONFIG_CMA)) + if (!zone->cma_alloc) + page = __rmqueue_cma_fallback(zone, order); + trace_mm_page_alloc_zone_locked(page, order, MIGRATE_CMA); + return page; +} +#else +static inline struct page *__rmqueue_cma(struct zone *zone, unsigned int order) +{ + return NULL; +} +#endif + /* * Obtain a specified number of elements from the buddy allocator, all under * a single hold of the lock, for efficiency. Add them to the supplied list. @@ -2346,7 +2355,18 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, spin_lock(&zone->lock); for (i = 0; i < count; ++i) { - struct page *page = __rmqueue(zone, order, migratetype); + struct page *page; + + /* + * If migrate type CMA is being requested only try to + * satisfy the request with CMA pages to try and increase + * CMA utlization. + */ + if (is_migrate_cma(migratetype)) + page = __rmqueue_cma(zone, order); + else + page = __rmqueue(zone, order, migratetype); + if (unlikely(page == NULL)) break; @@ -2384,6 +2404,28 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, return alloced; } +/* + * Return the pcp list that corresponds to the migrate type if that list isn't + * empty. + * If the list is empty return NULL. + */ +static struct list_head *get_populated_pcp_list(struct zone *zone, + unsigned int order, struct per_cpu_pages *pcp, + int migratetype, int cold) +{ + struct list_head *list = &pcp->lists[migratetype]; + + if (list_empty(list)) { + pcp->count += rmqueue_bulk(zone, order, + pcp->batch, list, + migratetype, cold); + + if (list_empty(list)) + list = NULL; + } + return list; +} + #ifdef CONFIG_NUMA /* * Called from the vmstat counter updater to drain pagesets of this @@ -2771,17 +2813,30 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z) /* Remove page from the per-cpu list, caller must protect the list */ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, bool cold, struct per_cpu_pages *pcp, - struct list_head *list) + gfp_t gfp_flags) { - struct page *page; + struct page *page = NULL; + struct list_head *list = NULL; do { - if (list_empty(list)) { - pcp->count += rmqueue_bulk(zone, 0, - pcp->batch, list, + /* First try to get CMA pages */ + if (migratetype == MIGRATE_MOVABLE && + gfp_flags & __GFP_CMA) { + list = get_populated_pcp_list(zone, 0, pcp, + get_cma_migrate_type(), cold); + } + + if (list == NULL) { + /* + * Either CMA is not suitable or there are no + * free CMA pages. + */ + list = get_populated_pcp_list(zone, 0, pcp, migratetype, cold); - if (unlikely(list_empty(list))) + if (unlikely(list == NULL) || + unlikely(list_empty(list))) return NULL; + } if (cold) @@ -2802,15 +2857,14 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone, gfp_t gfp_flags, int migratetype) { struct per_cpu_pages *pcp; - struct list_head *list; bool cold = ((gfp_flags & __GFP_COLD) != 0); struct page *page; unsigned long flags; local_irq_save(flags); pcp = &this_cpu_ptr(zone->pageset)->pcp; - list = &pcp->lists[migratetype]; - page = __rmqueue_pcplist(zone, migratetype, cold, pcp, list); + page = __rmqueue_pcplist(zone, migratetype, cold, pcp, + gfp_flags); if (page) { __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); zone_statistics(preferred_zone, zone); @@ -2846,14 +2900,21 @@ struct page *rmqueue(struct zone *preferred_zone, do { page = NULL; + if (alloc_flags & ALLOC_HARDER) { page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); if (page) trace_mm_page_alloc_zone_locked(page, order, migratetype); } + + if (!page && migratetype == MIGRATE_MOVABLE && + gfp_flags & __GFP_CMA) + page = __rmqueue_cma(zone, order); + if (!page) page = __rmqueue(zone, order, migratetype); } while (page && check_new_pages(page, order)); + spin_unlock(&zone->lock); if (!page) goto failed; @@ -3019,6 +3080,14 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, continue; for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) { +#ifdef CONFIG_CMA + /* + * Note that this check is needed only + * when MIGRATE_CMA < MIGRATE_PCPTYPES. + */ + if (mt == MIGRATE_CMA) + continue; +#endif if (!list_empty(&area->free_list[mt])) return true; } @@ -3729,7 +3798,8 @@ gfp_to_alloc_flags(gfp_t gfp_mask) alloc_flags |= ALLOC_HARDER; #ifdef CONFIG_CMA - if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE) + if ((gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE) && + (gfp_mask & __GFP_CMA)) alloc_flags |= ALLOC_CMA; #endif return alloc_flags; @@ -4209,7 +4279,8 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order, if (should_fail_alloc_page(gfp_mask, order)) return false; - if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE) + if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE && + (gfp_mask & __GFP_CMA)) *alloc_flags |= ALLOC_CMA; return true; @@ -7638,6 +7709,7 @@ int alloc_contig_range(unsigned long start, unsigned long end, if (ret) return ret; + cc.zone->cma_alloc = 1; /* * In case of -EBUSY, we'd like to know which page causes problem. * So, just fall through. test_pages_isolated() has a tracepoint @@ -7720,6 +7792,7 @@ int alloc_contig_range(unsigned long start, unsigned long end, done: undo_isolate_page_range(pfn_max_align_down(start), pfn_max_align_up(end), migratetype); + cc.zone->cma_alloc = 0; return ret; } diff --git a/mm/slub.c b/mm/slub.c index fbfe6393be1b3c3e62e0abf5da1cca523bd42585..59c33eec7728d38a3ae505a01eae17f39e277f2a 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -718,7 +718,7 @@ void object_err(struct kmem_cache *s, struct page *page, slab_panic(reason); } -static void slab_err(struct kmem_cache *s, struct page *page, +static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...) { va_list args; diff --git a/mm/vmalloc.c b/mm/vmalloc.c index ebff729cc9562709500353f30121f2c423296cc8..9ff21a12ea009d1b535d1e60eb20bdd2fa795e50 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1519,7 +1519,7 @@ static void __vunmap(const void *addr, int deallocate_pages) addr)) return; - area = remove_vm_area(addr); + area = find_vmap_area((unsigned long)addr)->vm; if (unlikely(!area)) { WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); @@ -1529,6 +1529,7 @@ static void __vunmap(const void *addr, int deallocate_pages) debug_check_no_locks_freed(addr, get_vm_area_size(area)); debug_check_no_obj_freed(addr, get_vm_area_size(area)); + remove_vm_area(addr); if (deallocate_pages) { int i; diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 685049a9048d8e9f8b53041cba43b96317b112fa..9bfea0171c5a1ee34705ed69d39690a3165b9130 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -345,7 +345,7 @@ static void destroy_cache(struct zs_pool *pool) static unsigned long cache_alloc_handle(struct zs_pool *pool, gfp_t gfp) { return (unsigned long)kmem_cache_alloc(pool->handle_cachep, - gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); + gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE|__GFP_CMA)); } static void cache_free_handle(struct zs_pool *pool, unsigned long handle) @@ -356,7 +356,7 @@ static void cache_free_handle(struct zs_pool *pool, unsigned long handle) static struct zspage *cache_alloc_zspage(struct zs_pool *pool, gfp_t flags) { return kmem_cache_alloc(pool->zspage_cachep, - flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); + flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE|__GFP_CMA)); } static void cache_free_zspage(struct zs_pool *pool, struct zspage *zspage) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index cf2e70003a534fa87cdf6bbc34ed29e9e0be0f4e..cf82d970b0e48c7ab7d537e83d1a889dc3d05cd7 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 4e111196f90216488de317efc8a5a792e75603a0..bc21f8e8daf28e22cc2a3226c97ae1341923516b 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -252,8 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev, ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); - refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = atmvcc->atm_options; + atm_account_tx(atmvcc, skb); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; diff --git a/net/atm/clip.c b/net/atm/clip.c index 65f706e4344c39f47dc27c4f2b12d742c1dd0547..60920a42f64057d8bb8de21fa54c88347c108ce7 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -381,8 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, memcpy(here, llc_oui, sizeof(llc_oui)); ((__be16 *) here)[3] = skb->protocol; } - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = vcc->atm_options; + atm_account_tx(vcc, skb); entry->vccs->last_use = jiffies; pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev); old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ diff --git a/net/atm/common.c b/net/atm/common.c index 8a4f99114cd2b5c2a80fa964b00f52a10160b36f..9e812c782a372d03e30ef5b97f4ef2c69cfa9100 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -630,10 +630,9 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) goto out; } pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); - refcount_add(skb->truesize, &sk->sk_wmem_alloc); + atm_account_tx(vcc, skb); skb->dev = NULL; /* for paths shared with net_device interfaces */ - ATM_SKB(skb)->atm_options = vcc->atm_options; if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { kfree_skb(skb); error = -EFAULT; diff --git a/net/atm/lec.c b/net/atm/lec.c index 5741b6474dd996188b5eb64100bbc7be47e3235c..9f2365694ad4a4e76dec293fdcfed6705338f6bc 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -182,9 +182,8 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb) struct net_device *dev = skb->dev; ATM_SKB(skb)->vcc = vcc; - ATM_SKB(skb)->atm_options = vcc->atm_options; + atm_account_tx(vcc, skb); - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); if (vcc->send(vcc, skb) < 0) { dev->stats.tx_dropped++; return; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 5677147209e8181ce2e9eff308bc0ed82b548e45..db9a1838687ce1dcc62d1cdd7ab2d5d0b0efa2e2 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -555,8 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) sizeof(struct llc_snap_hdr)); } - refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; + atm_account_tx(entry->shortcut, skb); entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; mpc->in_ops->put(entry); diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 21d9d341a6199255a017437954e4b688f1ba5bfd..af8c4b38b7463e03bf4b060735ce852b515d526c 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -350,8 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) return 1; } - refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; + atm_account_tx(vcc, skb); pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) diff --git a/net/atm/raw.c b/net/atm/raw.c index ee10e8d46185173067f459aa5efdf5a77f8f9f06..b3ba44aab0ee6c9425fd278ebf8e2df1590a6d7a 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -35,8 +35,8 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb) struct sock *sk = sk_atm(vcc); pr_debug("(%d) %d -= %d\n", - vcc->vci, sk_wmem_alloc_get(sk), skb->truesize); - WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc)); + vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize); + WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc)); dev_kfree_skb_any(skb); sk->sk_write_space(sk); } diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 25738b20676d50d98f573f0c609738d4ee62c103..54c7fe68040f7e060cdd0b1bd56f54da23f630b1 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -398,6 +398,12 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par, watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0); if (IS_ERR(watcher)) return PTR_ERR(watcher); + + if (watcher->family != NFPROTO_BRIDGE) { + module_put(watcher->me); + return -ENOENT; + } + w->u.watcher = watcher; par->target = watcher; @@ -719,6 +725,13 @@ ebt_check_entry(struct ebt_entry *e, struct net *net, goto cleanup_watchers; } + /* Reject UNSPEC, xtables verdicts/return values are incompatible */ + if (target->family != NFPROTO_BRIDGE) { + module_put(target->me); + ret = -ENOENT; + goto cleanup_watchers; + } + t->u.target = target; if (t->u.target == &ebt_standard_target) { if (gap < sizeof(struct ebt_standard_target)) { diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index 87f28557b3298f30b1cf79dccf3bc6b761cd6623..441c04adedba0d21ede168d1e6c09415b5db07d3 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type, d->lock = lock; spin_lock_bh(lock); } - if (d->tail) - return gnet_stats_copy(d, type, NULL, 0, padattr); + if (d->tail) { + int ret = gnet_stats_copy(d, type, NULL, 0, padattr); + + /* The initial attribute added in gnet_stats_copy() may be + * preceded by a padding attribute, in which case d->tail will + * end up pointing at the padding instead of the real attribute. + * Fix this so gnet_stats_finish_copy() adjusts the length of + * the right attribute. + */ + if (ret == 0 && d->tail->nla_type == padattr) + d->tail = (struct nlattr *)((char *)d->tail + + NLA_ALIGN(d->tail->nla_len)); + return ret; + } return 0; } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4cfdad08aca04d067a67875f97c13510dc456c0b..efe396cc77b5fa8330a5029e09e5d9ceac754551 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2402,9 +2402,12 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) return err; } - dev->rtnl_link_state = RTNL_LINK_INITIALIZED; - - __dev_notify_flags(dev, old_flags, ~0U); + if (dev->rtnl_link_state == RTNL_LINK_INITIALIZED) { + __dev_notify_flags(dev, old_flags, 0U); + } else { + dev->rtnl_link_state = RTNL_LINK_INITIALIZED; + __dev_notify_flags(dev, old_flags, ~0U); + } return 0; } EXPORT_SYMBOL(rtnl_configure_link); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index db973bf72b76ec04e52707d2765452a76347b497..00042186f9426d34e29270d2075fc52d678be741 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -858,6 +858,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->peeked = 0; + C(pfmemalloc); n->destructor = NULL; C(tail); C(end); @@ -3678,6 +3679,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, net_warn_ratelimited( "skb_segment: too many frags: %u %u\n", pos, mss); + err = -EINVAL; goto err; } @@ -3716,11 +3718,10 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, perform_csum_check: if (!csum) { - if (skb_has_shared_frag(nskb)) { - err = __skb_linearize(nskb); - if (err) - goto err; - } + if (skb_has_shared_frag(nskb) && + __skb_linearize(nskb)) + goto err; + if (!nskb->remcsum_offload) nskb->ip_summed = CHECKSUM_NONE; SKB_GSO_CB(nskb)->csum = diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 119c04317d48eed4abcb2bbf6071062c8d9784fd..03fcf3ee15346cb450d76f314fd3c137a16ed50f 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -599,7 +599,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk, { struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); - ktime_t now = ktime_get_real(); + ktime_t now = ktime_get(); s64 delta = 0; switch (fbtype) { @@ -624,15 +624,14 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk, case CCID3_FBACK_PERIODIC: delta = ktime_us_delta(now, hc->rx_tstamp_last_feedback); if (delta <= 0) - DCCP_BUG("delta (%ld) <= 0", (long)delta); - else - hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta); + delta = 1; + hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta); break; default: return; } - ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta, + ccid3_pr_debug("Interval %lldusec, X_recv=%u, 1/p=%u\n", delta, hc->rx_x_recv, hc->rx_pinv); hc->rx_tstamp_last_feedback = now; @@ -679,7 +678,8 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) static u32 ccid3_first_li(struct sock *sk) { struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk); - u32 x_recv, p, delta; + u32 x_recv, p; + s64 delta; u64 fval; if (hc->rx_rtt == 0) { @@ -687,7 +687,9 @@ static u32 ccid3_first_li(struct sock *sk) hc->rx_rtt = DCCP_FALLBACK_RTT; } - delta = ktime_to_us(net_timedelta(hc->rx_tstamp_last_feedback)); + delta = ktime_us_delta(ktime_get(), hc->rx_tstamp_last_feedback); + if (delta <= 0) + delta = 1; x_recv = scaled_div32(hc->rx_bytes_recv, delta); if (x_recv == 0) { /* would also trigger divide-by-zero */ DCCP_WARN("X_recv==0\n"); diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index f0252768ecf4c39219a58626198f58e5278031ad..5f5d9eafccf5965b3deb23b2449a1392e07e6c61 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -87,35 +87,39 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) opt++; kdebug("options: '%s'", opt); do { + int opt_len, opt_nlen; const char *eq; - int opt_len, opt_nlen, opt_vlen, tmp; + char optval[128]; next_opt = memchr(opt, '#', end - opt) ?: end; opt_len = next_opt - opt; - if (opt_len <= 0 || opt_len > 128) { + if (opt_len <= 0 || opt_len > sizeof(optval)) { pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n", opt_len); return -EINVAL; } - eq = memchr(opt, '=', opt_len) ?: end; - opt_nlen = eq - opt; - eq++; - opt_vlen = next_opt - eq; /* will be -1 if no value */ + eq = memchr(opt, '=', opt_len); + if (eq) { + opt_nlen = eq - opt; + eq++; + memcpy(optval, eq, next_opt - eq); + optval[next_opt - eq] = '\0'; + } else { + opt_nlen = opt_len; + optval[0] = '\0'; + } - tmp = opt_vlen >= 0 ? opt_vlen : 0; - kdebug("option '%*.*s' val '%*.*s'", - opt_nlen, opt_nlen, opt, tmp, tmp, eq); + kdebug("option '%*.*s' val '%s'", + opt_nlen, opt_nlen, opt, optval); /* see if it's an error number representing a DNS error * that's to be recorded as the result in this key */ if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 && memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) { kdebug("dns error number option"); - if (opt_vlen <= 0) - goto bad_option_value; - ret = kstrtoul(eq, 10, &derrno); + ret = kstrtoul(optval, 10, &derrno); if (ret < 0) goto bad_option_value; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 865e29e62bad87e7fede6599ace0645ebbd2d196..242e74b9d4540a65da0a2011eb7663e01fc1c1ce 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1219,6 +1219,9 @@ int dsa_slave_suspend(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); + if (!netif_running(slave_dev)) + return 0; + netif_device_detach(slave_dev); if (p->phy) { @@ -1236,6 +1239,9 @@ int dsa_slave_resume(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); + if (!netif_running(slave_dev)) + return 0; + netif_device_attach(slave_dev); if (p->phy) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index df8fd3ce713d757c9ea8f227176cf9e4269366f7..5bbdd05d0cd306b276207c9cd3c3b79d263dc638 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -282,18 +282,19 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) return ip_hdr(skb)->daddr; in_dev = __in_dev_get_rcu(dev); - BUG_ON(!in_dev); net = dev_net(dev); scope = RT_SCOPE_UNIVERSE; if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { + bool vmark = in_dev && IN_DEV_SRC_VMARK(in_dev); struct flowi4 fl4 = { .flowi4_iif = LOOPBACK_IFINDEX, + .flowi4_oif = l3mdev_master_ifindex_rcu(dev), .daddr = ip_hdr(skb)->saddr, .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), .flowi4_scope = scope, - .flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0, + .flowi4_mark = vmark ? skb->mark : 0, }; if (!fib_lookup(net, &fl4, &res, 0)) return FIB_RES_PREFSRC(net, res); diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 1540db65241a6fd4d96b00546f13a3e3d3cd1815..c9ec1603666bffcfb24597b933a05f53b6d83440 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -448,9 +448,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; - skb_gro_remcsum_cleanup(skb, &grc); - skb->remcsum_offload = 0; + skb_gro_flush_final_remcsum(skb, pp, flush, &grc); return pp; } diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 1859c473b21a862b383edebbcf2c1656f9c58b3b..6a7d980105f60514c8180e6333f0a4a53912c3d5 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -223,7 +223,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index fbeb35ad804bd4af4f8092ff190bb07224146760..502aae3e3ab8e9c263ab25a0e9dcf9e38d48a5f4 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1201,8 +1201,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im) if (pmc) { im->interface = pmc->interface; im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - im->sfmode = pmc->sfmode; - if (pmc->sfmode == MCAST_INCLUDE) { + if (im->sfmode == MCAST_INCLUDE) { im->tomb = pmc->tomb; im->sources = pmc->sources; for (psf = im->sources; psf; psf = psf->sf_next) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index e691705f0a85a1a43a331063bb4ff571651af759..ba4454ecdf0f64708ae19cfd88d2e22230f60d41 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -356,11 +356,6 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, { struct inet_frag_queue *q; - if (!nf->high_thresh || frag_mem_limit(nf) > nf->high_thresh) { - inet_frag_schedule_worker(f); - return NULL; - } - q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); if (!q) return NULL; @@ -397,6 +392,11 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; + if (!nf->high_thresh || frag_mem_limit(nf) > nf->high_thresh) { + inet_frag_schedule_worker(f); + return NULL; + } + if (frag_mem_limit(nf) > nf->low_thresh) inet_frag_schedule_worker(f); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index e7d15fb0d94d9790675356d3144d204b91eab984..24b066c32e06f62a8041c305f80e7e3c3c691816 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -188,9 +188,9 @@ static inline int compute_score(struct sock *sk, struct net *net, bool dev_match = (sk->sk_bound_dev_if == dif || sk->sk_bound_dev_if == sdif); - if (exact_dif && !dev_match) + if (!dev_match) return -1; - if (sk->sk_bound_dev_if && dev_match) + if (sk->sk_bound_dev_if) score += 4; } if (sk->sk_incoming_cpu == raw_smp_processor_id()) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index df8fe0503de0e5050699be822ce04b383a677aa9..4cb1befc39494fcec05f6a93f949bb6eefc4e0a3 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -447,11 +447,16 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */ if (i < next->len) { + int delta = -next->truesize; + /* Eat head of the next overlapped fragment * and leave the loop. The next ones cannot overlap. */ if (!pskb_pull(next, i)) goto err; + delta += next->truesize; + if (delta) + add_frag_mem_limit(qp->q.net, delta); FRAG_CB(next)->offset += i; qp->q.meat -= i; if (next->ip_summed != CHECKSUM_UNNECESSARY) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 20a0ca768f7a618a9d52bdeaa8573cc272d88d06..a6b403a2f791d74f655cb9e80f74598b750d91c8 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -523,6 +523,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->dev = from->dev; to->mark = from->mark; + skb_copy_hash(to, from); + /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index d07ba4d5917b4559ea1f97a81095904d759dbe50..048d5f6dd320e1f5cbf32438b572b02630387666 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -148,15 +148,18 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) { struct sockaddr_in sin; const struct iphdr *iph = ip_hdr(skb); - __be16 *ports = (__be16 *)skb_transport_header(skb); + __be16 *ports; + int end; - if (skb_transport_offset(skb) + 4 > (int)skb->len) + end = skb_transport_offset(skb) + 4; + if (end > 0 && !pskb_may_pull(skb, end)) return; /* All current transport protocols have the port numbers in the * first four bytes of the transport header and this function is * written with this assumption in mind. */ + ports = (__be16 *)skb_transport_header(skb); sin.sin_family = AF_INET; sin.sin_addr.s_addr = iph->daddr; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index abdebca848c977dc3c3c7c0a8fd862100373209e..f0782c91514ce28bd62a37740d8cfa0f55895106 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -781,6 +781,11 @@ static void __init ic_bootp_init_ext(u8 *e) */ static inline void __init ic_bootp_init(void) { + /* Re-initialise all name servers to NONE, in case any were set via the + * "ip=" or "nfsaddrs=" kernel command line parameters: any IP addresses + * specified there will already have been decoded but are no longer + * needed + */ ic_nameservers_predef(); dev_add_pack(&bootp_packet_type); @@ -1402,6 +1407,13 @@ static int __init ip_auto_config(void) int err; unsigned int i; + /* Initialise all name servers to NONE (but only if the "ip=" or + * "nfsaddrs=" kernel command line parameters weren't decoded, otherwise + * we'll overwrite the IP addresses specified there) + */ + if (ic_set_manually == 0) + ic_nameservers_predef(); + #ifdef CONFIG_PROC_FS proc_create("pnp", S_IRUGO, init_net.proc_net, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ @@ -1622,6 +1634,7 @@ static int __init ip_auto_config_setup(char *addrs) return 1; } + /* Initialise all name servers to NONE */ ic_nameservers_predef(); /* Parse string for static IP assignment. */ diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c5de100e614b26022b3b49a77e08defa7db4776f..2171324cdb5c95667d01a2edb98651c09128f569 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -186,8 +186,9 @@ static int ipv4_ping_group_range(struct ctl_table *table, int write, if (write && ret == 0) { low = make_kgid(user_ns, urange[0]); high = make_kgid(user_ns, urange[1]); - if (!gid_valid(low) || !gid_valid(high) || - (urange[1] < urange[0]) || gid_lt(high, low)) { + if (!gid_valid(low) || !gid_valid(high)) + return -EINVAL; + if (urange[1] < urange[0] || gid_lt(high, low)) { low = make_kgid(&init_user_ns, 1); high = make_kgid(&init_user_ns, 0); } @@ -273,8 +274,9 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, { struct ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) }; struct tcp_fastopen_context *ctxt; - int ret; u32 user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */ + __le32 key[4]; + int ret, i; tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL); if (!tbl.data) @@ -283,11 +285,14 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, rcu_read_lock(); ctxt = rcu_dereference(tcp_fastopen_ctx); if (ctxt) - memcpy(user_key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); + memcpy(key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); else - memset(user_key, 0, sizeof(user_key)); + memset(key, 0, sizeof(key)); rcu_read_unlock(); + for (i = 0; i < ARRAY_SIZE(key); i++) + user_key[i] = le32_to_cpu(key[i]); + snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x", user_key[0], user_key[1], user_key[2], user_key[3]); ret = proc_dostring(&tbl, write, buffer, lenp, ppos); @@ -303,12 +308,16 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, * first invocation of tcp_fastopen_cookie_gen */ tcp_fastopen_init_key_once(false); - tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH); + + for (i = 0; i < ARRAY_SIZE(user_key); i++) + key[i] = cpu_to_le32(user_key[i]); + + tcp_fastopen_reset_cipher(key, TCP_FASTOPEN_KEY_LENGTH); } bad_key: pr_debug("proc FO key set 0x%x-%x-%x-%x <- 0x%s: %u\n", - user_key[0], user_key[1], user_key[2], user_key[3], + user_key[0], user_key[1], user_key[2], user_key[3], (char *)tbl.data, ret); kfree(tbl.data); return ret; diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 9a0b952dd09b5d380a66fe519ba8c230e43044fc..06f247ca9197e3e34728ef688be74d26b465edc7 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -353,6 +353,10 @@ static u32 bbr_target_cwnd(struct sock *sk, u32 bw, int gain) /* Reduce delayed ACKs by rounding up cwnd to the next even number. */ cwnd = (cwnd + 1) & ~1U; + /* Ensure gain cycling gets inflight above BDP even for small BDPs. */ + if (bbr->mode == BBR_PROBE_BW && gain > BBR_UNIT) + cwnd += 2; + return cwnd; } diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 5f5e5936760e65739859d0d8d9717b3204482a43..1a9b88c8cf7263c016277163636eb361f57960d3 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -131,23 +131,14 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) struct dctcp *ca = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); - /* State has changed from CE=0 to CE=1 and delayed - * ACK has not sent yet. - */ - if (!ca->ce_state && ca->delayed_ack_reserved) { - u32 tmp_rcv_nxt; - - /* Save current rcv_nxt. */ - tmp_rcv_nxt = tp->rcv_nxt; - - /* Generate previous ack with CE=0. */ - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; - tp->rcv_nxt = ca->prior_rcv_nxt; - - tcp_send_ack(sk); - - /* Recover current rcv_nxt. */ - tp->rcv_nxt = tmp_rcv_nxt; + if (!ca->ce_state) { + /* State has changed from CE=0 to CE=1, force an immediate + * ACK to reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); + tcp_enter_quickack_mode(sk, 1); } ca->prior_rcv_nxt = tp->rcv_nxt; @@ -161,23 +152,14 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) struct dctcp *ca = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); - /* State has changed from CE=1 to CE=0 and delayed - * ACK has not sent yet. - */ - if (ca->ce_state && ca->delayed_ack_reserved) { - u32 tmp_rcv_nxt; - - /* Save current rcv_nxt. */ - tmp_rcv_nxt = tp->rcv_nxt; - - /* Generate previous ack with CE=1. */ - tp->ecn_flags |= TCP_ECN_DEMAND_CWR; - tp->rcv_nxt = ca->prior_rcv_nxt; - - tcp_send_ack(sk); - - /* Recover current rcv_nxt. */ - tp->rcv_nxt = tmp_rcv_nxt; + if (ca->ce_state) { + /* State has changed from CE=1 to CE=0, force an immediate + * ACK to reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); + tcp_enter_quickack_mode(sk, 1); } ca->prior_rcv_nxt = tp->rcv_nxt; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 59a1fb811c00ee04e6827abbd689fbcc1cc35e39..9466531062039d0242ece30654a6a8ff2277cbf0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -199,24 +199,27 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) } } -static void tcp_incr_quickack(struct sock *sk) +static void tcp_incr_quickack(struct sock *sk, unsigned int max_quickacks) { struct inet_connection_sock *icsk = inet_csk(sk); unsigned int quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss); if (quickacks == 0) quickacks = 2; + quickacks = min(quickacks, max_quickacks); if (quickacks > icsk->icsk_ack.quick) - icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS); + icsk->icsk_ack.quick = quickacks; } -static void tcp_enter_quickack_mode(struct sock *sk) +void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks) { struct inet_connection_sock *icsk = inet_csk(sk); - tcp_incr_quickack(sk); + + tcp_incr_quickack(sk, max_quickacks); icsk->icsk_ack.pingpong = 0; icsk->icsk_ack.ato = TCP_ATO_MIN; } +EXPORT_SYMBOL(tcp_enter_quickack_mode); /* Send ACKs quickly, if "quick" count is not exhausted * and the session is not interactive. @@ -248,8 +251,10 @@ static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp) tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; } -static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) +static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) { + struct tcp_sock *tp = tcp_sk(sk); + switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) { case INET_ECN_NOT_ECT: /* Funny extension: if ECT is not set on a segment, @@ -257,31 +262,31 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp); + tcp_enter_quickack_mode(sk, 2); break; case INET_ECN_CE: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_IS_CE); + if (tcp_ca_needs_ecn(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp); + tcp_enter_quickack_mode(sk, 2); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; break; default: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_NO_CE); + if (tcp_ca_needs_ecn(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_NO_CE); tp->ecn_flags |= TCP_ECN_SEEN; break; } } -static void tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) +static void tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) { - if (tp->ecn_flags & TCP_ECN_OK) - __tcp_ecn_check_ce(tp, skb); + if (tcp_sk(sk)->ecn_flags & TCP_ECN_OK) + __tcp_ecn_check_ce(sk, skb); } static void tcp_ecn_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th) @@ -686,7 +691,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) /* The _first_ data packet received, initialize * delayed ACK engine. */ - tcp_incr_quickack(sk); + tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); icsk->icsk_ack.ato = TCP_ATO_MIN; } else { int m = now - icsk->icsk_ack.lrcvtime; @@ -702,13 +707,13 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) /* Too long gap. Apparently sender failed to * restart window, so that we send ACKs quickly. */ - tcp_incr_quickack(sk); + tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); sk_mem_reclaim(sk); } } icsk->icsk_ack.lrcvtime = now; - tcp_ecn_check_ce(tp, skb); + tcp_ecn_check_ce(sk, skb); if (skb->len >= 128) tcp_grow_window(sk, skb); @@ -3195,6 +3200,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, if (tcp_is_reno(tp)) { tcp_remove_reno_sacks(sk, pkts_acked); + + /* If any of the cumulatively ACKed segments was + * retransmitted, non-SACK case cannot confirm that + * progress was due to original transmission due to + * lack of TCPCB_SACKED_ACKED bits even if some of + * the packets may have been never retransmitted. + */ + if (flag & FLAG_RETRANS_DATA_ACKED) + flag &= ~FLAG_ORIG_SACK_ACKED; } else { int delta; @@ -4151,7 +4165,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); if (tcp_is_sack(tp) && sysctl_tcp_dsack) { u32 end_seq = TCP_SKB_CB(skb)->end_seq; @@ -4432,7 +4446,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) u32 seq, end_seq; bool fragstolen; - tcp_ecn_check_ce(tp, skb); + tcp_ecn_check_ce(sk, skb); if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) { NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFODROP); @@ -4701,7 +4715,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); out_of_window: - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); inet_csk_schedule_ack(sk); drop: tcp_drop(sk, skb); @@ -4712,8 +4726,6 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp))) goto out_of_window; - tcp_enter_quickack_mode(sk); - if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { /* Partial packet, seq < rcv_next < end_seq */ SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", @@ -5784,7 +5796,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, * to stand against the temptation 8) --ANK */ inet_csk_schedule_ack(sk); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, TCP_DELACK_MAX, TCP_RTO_MAX); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 9e8a95a555dfd18e8184772cdd322227f64c66a1..635714a9e9c62a38c1ee8885b80ca45caef60d1e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -175,8 +175,13 @@ static void tcp_event_data_sent(struct tcp_sock *tp, } /* Account for an ACK we sent. */ -static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts) +static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts, + u32 rcv_nxt) { + struct tcp_sock *tp = tcp_sk(sk); + + if (unlikely(rcv_nxt != tp->rcv_nxt)) + return; /* Special ACK sent by DCTCP to reflect ECN */ tcp_dec_quickack_mode(sk, pkts); inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); } @@ -984,8 +989,8 @@ static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb) * We are working here with either a clone of the original * SKB, or a fresh unique copy made by the retransmit engine. */ -static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, - gfp_t gfp_mask) +static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + int clone_it, gfp_t gfp_mask, u32 rcv_nxt) { const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_sock *inet; @@ -1057,7 +1062,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, th->source = inet->inet_sport; th->dest = inet->inet_dport; th->seq = htonl(tcb->seq); - th->ack_seq = htonl(tp->rcv_nxt); + th->ack_seq = htonl(rcv_nxt); *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | tcb->tcp_flags); @@ -1098,7 +1103,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, icsk->icsk_af_ops->send_check(sk, skb); if (likely(tcb->tcp_flags & TCPHDR_ACK)) - tcp_event_ack_sent(sk, tcp_skb_pcount(skb)); + tcp_event_ack_sent(sk, tcp_skb_pcount(skb), rcv_nxt); if (skb->len != tcp_header_size) { tcp_event_data_sent(tp, sk); @@ -1135,6 +1140,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, return err; } +static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, + gfp_t gfp_mask) +{ + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +} + /* This routine just queues the buffer for sending. * * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, @@ -3551,7 +3563,7 @@ void tcp_send_delayed_ack(struct sock *sk) } /* This routine sends an ack and also updates the window. */ -void tcp_send_ack(struct sock *sk) +void __tcp_send_ack(struct sock *sk, u32 rcv_nxt) { struct sk_buff *buff; @@ -3586,9 +3598,14 @@ void tcp_send_ack(struct sock *sk) skb_set_tcp_pure_ack(buff); /* Send it off, this clears delayed acks for us. */ - tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0); + __tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0, rcv_nxt); +} +EXPORT_SYMBOL_GPL(__tcp_send_ack); + +void tcp_send_ack(struct sock *sk) +{ + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); } -EXPORT_SYMBOL_GPL(tcp_send_ack); /* This routine sends a packet with an out of date sequence * number. It assumes the other end will try to ack it. diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index c4724f2a2f3132113acd5e68dd9f1117ea4a5be7..8721164375c0f7f43b01a7f7311a875ddefc3232 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -360,7 +360,7 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } EXPORT_SYMBOL(udp_gro_receive); diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ea71e4b0ab7aea80fc6b564fddeea7a6b01feaeb..2d36fd09729907c6d1a32fde8bef71d757345efe 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -109,6 +109,7 @@ config IPV6_MIP6 config IPV6_ILA tristate "IPv6: Identifier Locator Addressing (ILA)" depends on NETFILTER + select DST_CACHE select LWTUNNEL ---help--- Support for IPv6 Identifier Locator Addressing (ILA). diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index e438c709706a1ff19de7566d6f9df7839b7d6b63..b17210fe3ae3e87fd787d943cc7498d24b0ed625 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -708,13 +708,16 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, } if (np->rxopt.bits.rxorigdstaddr) { struct sockaddr_in6 sin6; - __be16 *ports = (__be16 *) skb_transport_header(skb); + __be16 *ports; + int end; - if (skb_transport_offset(skb) + 4 <= (int)skb->len) { + end = skb_transport_offset(skb) + 4; + if (end <= 0 || pskb_may_pull(skb, end)) { /* All current transport protocols have the port numbers in the * first four bytes of the transport header and this function is * written with this assumption in mind. */ + ports = (__be16 *)skb_transport_header(skb); sin6.sin6_family = AF_INET6; sin6.sin6_addr = ipv6_hdr(skb)->daddr; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5acb54405b10b637962a7c59c9badb6b4f4f17bd..c5f2b17b7ee1a70d9acb13931de0c1e4e1a4c96b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -405,9 +405,10 @@ static int icmp6_iif(const struct sk_buff *skb) /* for local traffic to local address, skb dev is the loopback * device. Check if there is a dst attached to the skb and if so - * get the real device index. + * get the real device index. Same is needed for replies to a link + * local address on a device enslaved to an L3 master device */ - if (unlikely(iif == LOOPBACK_IFINDEX)) { + if (unlikely(iif == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) { const struct rt6_info *rt6 = skb_rt6_info(skb); if (rt6) diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index b01858f5deb1711f24c0c38cba0a3e61d43b390c..6dc93ac2826102b54a6c109fe9953744aaa28062 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -113,9 +113,9 @@ static inline int compute_score(struct sock *sk, struct net *net, bool dev_match = (sk->sk_bound_dev_if == dif || sk->sk_bound_dev_if == sdif); - if (exact_dif && !dev_match) + if (!dev_match) return -1; - if (sk->sk_bound_dev_if && dev_match) + if (sk->sk_bound_dev_if) score++; } if (sk->sk_incoming_cpu == raw_smp_processor_id()) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 345e643134bc5680d57de24606fab19e7be90282..48003bc3976fbdbee6fb863d2beda6b2f7820ba6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -595,6 +595,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->dev = from->dev; to->mark = from->mark; + skb_copy_hash(to, from); + #ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 9a38a2c641facdf54f8e94f3e7e64496ea31304a..6fd913d63835761a43e7cf6e0dd348df44732a9f 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -771,8 +771,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) if (pmc) { im->idev = pmc->idev; im->mca_crcount = idev->mc_qrv; - im->mca_sfmode = pmc->mca_sfmode; - if (pmc->mca_sfmode == MCAST_INCLUDE) { + if (im->mca_sfmode == MCAST_INCLUDE) { im->mca_tomb = pmc->mca_tomb; im->mca_sources = pmc->mca_sources; for (psf = im->mca_sources; psf; psf = psf->sf_next) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d081db125905225c269bf17803bd26d576138a43..528218460bc5973aec0a38f63fd64a35ce2ded84 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -803,7 +803,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) return; } } - if (ndopts.nd_opts_nonce) + if (ndopts.nd_opts_nonce && ndopts.nd_opts_nonce->nd_opt_len == 1) memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6); inc = ipv6_addr_is_multicast(daddr); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 64ec23388450c7bd9b24a7d04d4a96b011573ae9..722a9db8c6a7b786500f29cc8bfe732b1e3e23c5 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -618,6 +618,8 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) fq->q.meat == fq->q.len && nf_ct_frag6_reasm(fq, skb, dev)) ret = 0; + else + skb_dst_drop(skb); out_unlock: spin_unlock_bh(&fq->q.lock); diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c index 33fb35cbfac132b1a85cd2c9ce62b4344cbe8afe..558fe8cc6d43858ca828cbd8dc8ea65e63bc6602 100644 --- a/net/ipv6/seg6_hmac.c +++ b/net/ipv6/seg6_hmac.c @@ -373,7 +373,7 @@ static int seg6_hmac_init_algo(void) return -ENOMEM; for_each_possible_cpu(cpu) { - tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL); + tfm = crypto_alloc_shash(algo->name, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); p_tfm = per_cpu_ptr(algo->tfms, cpu); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 00b67c2adfbee5c59502c216b26e6b601c945bb1..4d2bdcbe806c07c1a6897e184f0f8c4a83d2a2dc 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -918,7 +918,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) &tcp_hashinfo, NULL, 0, &ipv6h->saddr, th->source, &ipv6h->daddr, - ntohs(th->source), tcp_v6_iif(skb), + ntohs(th->source), + tcp_v6_iif_l3_slave(skb), tcp_v6_sdif(skb)); if (!sk1) goto out; @@ -1573,7 +1574,8 @@ static int tcp_v6_rcv(struct sk_buff *skb) skb, __tcp_hdrlen(th), &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, - ntohs(th->dest), tcp_v6_iif(skb), + ntohs(th->dest), + tcp_v6_iif_l3_slave(skb), sdif); if (sk2) { struct inet_timewait_sock *tw = inet_twsk(sk); diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 51063d9ed0f75d53be7a59738bf859570cd67d9b..dfd268166e427ebe60cd3927391816d9fe7a19cc 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -1241,7 +1241,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, pr_debug("Create set %s with family %s\n", set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6"); -#ifndef IP_SET_PROTO_UNDEF +#ifdef IP_SET_PROTO_UNDEF + if (set->family != NFPROTO_UNSPEC) + return -IPSET_ERR_INVALID_FAMILY; +#else if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; #endif diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 85b549e84104a1f260dddf7dbf66256021ac3fd6..9a945024a0b6379fc83d7dc6f49a9625314dd1e7 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2710,12 +2710,13 @@ static struct nft_set *nf_tables_set_lookup_byid(const struct net *net, u32 id = ntohl(nla_get_be32(nla)); list_for_each_entry(trans, &net->nft.commit_list, list) { - struct nft_set *set = nft_trans_set(trans); + if (trans->msg_type == NFT_MSG_NEWSET) { + struct nft_set *set = nft_trans_set(trans); - if (trans->msg_type == NFT_MSG_NEWSET && - id == nft_trans_set_id(trans) && - nft_active_genmask(set, genmask)) - return set; + if (id == nft_trans_set_id(trans) && + nft_active_genmask(set, genmask)) + return set; + } } return ERR_PTR(-ENOENT); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b3932846f6c4661b5e2f31794ee8fde1ca152218..c67abda5d6391b3a208ab949913a8d2b9df9fc30 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -647,6 +648,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, if (protocol < 0 || protocol >= MAX_LINKS) return -EPROTONOSUPPORT; + protocol = array_index_nospec(protocol, MAX_LINKS); netlink_lock_table(); #ifdef CONFIG_MODULES @@ -977,6 +979,11 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, return err; } + if (nlk->ngroups == 0) + groups = 0; + else if (nlk->ngroups < 8*sizeof(groups)) + groups &= (1UL << nlk->ngroups) - 1; + bound = nlk->bound; if (bound) { /* Ensure nlk->portid is up-to-date. */ diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 2ceefa183ceed6ba3d06f2aae958104a514f2146..6a196e438b6c03d4c86e0a8a78af1c496a7e599b 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -752,11 +752,14 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, pr_debug("Fragment %zd bytes remaining %zd", frag_len, remaining_len); - pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT, + pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, 0, frag_len + LLCP_HEADER_SIZE, &err); if (pdu == NULL) { - pr_err("Could not allocate PDU\n"); - continue; + pr_err("Could not allocate PDU (error=%d)\n", err); + len -= remaining_len; + if (len == 0) + len = err; + break; } pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI); diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c index 6df6f58a810388af5a1e69fcba99702894041c08..5647905c88d664a7bc1b418aadd271a47c754662 100644 --- a/net/nsh/nsh.c +++ b/net/nsh/nsh.c @@ -42,7 +42,7 @@ static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, __skb_pull(skb, nsh_len); skb_reset_mac_header(skb); - skb_reset_mac_len(skb); + skb->mac_len = proto == htons(ETH_P_TEB) ? ETH_HLEN : 0; skb->protocol = proto; features &= NETIF_F_SG; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4fe2e34522d6c1512d3235aa7ab8199fc5f8138f..27dafe36f29c0876a383852ccfe32424f1ab50a7 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2303,6 +2303,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (po->stats.stats1.tp_drops) status |= TP_STATUS_LOSING; } + + if (do_vnet && + virtio_net_hdr_from_skb(skb, h.raw + macoff - + sizeof(struct virtio_net_hdr), + vio_le(), true, 0)) + goto drop_n_account; + po->stats.stats1.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; @@ -2310,15 +2317,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, } spin_unlock(&sk->sk_receive_queue.lock); - if (do_vnet) { - if (virtio_net_hdr_from_skb(skb, h.raw + macoff - - sizeof(struct virtio_net_hdr), - vio_le(), true, 0)) { - spin_lock(&sk->sk_receive_queue.lock); - goto drop_n_account; - } - } - skb_copy_bits(skb, 0, h.raw + macoff, snaplen); if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp))) diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index 9370e48b5cbeb9b3da73af78367928ae1d7b7b0a..85a8a1a99944afb689a131520f82ee33948e89f9 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "qrtr.h" @@ -21,9 +22,29 @@ struct qrtr_mhi_dev { struct qrtr_endpoint ep; struct mhi_device *mhi_dev; struct device *dev; - struct completion ul_done; + spinlock_t ul_lock; /* lock to protect ul_pkts */ + struct list_head ul_pkts; }; +struct qrtr_mhi_pkt { + struct list_head node; + struct sk_buff *skb; + struct kref refcount; + struct completion done; +}; + +static void qrtr_mhi_pkt_release(struct kref *ref) +{ + struct qrtr_mhi_pkt *pkt = container_of(ref, struct qrtr_mhi_pkt, + refcount); + struct sock *sk = pkt->skb->sk; + + consume_skb(pkt->skb); + if (sk) + sock_put(sk); + kfree(pkt); +} + /* from mhi to qrtr */ static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev, struct mhi_result *mhi_res) @@ -45,39 +66,63 @@ static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev, struct mhi_result *mhi_res) { struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); - struct sk_buff *skb = mhi_res->buf_addr; + struct qrtr_mhi_pkt *pkt; - if (!mhi_res->transaction_status) { - complete(&qdev->ul_done); - consume_skb(skb); - } else { - kfree_skb(skb); - } + spin_lock_bh(&qdev->ul_lock); + pkt = list_first_entry(&qdev->ul_pkts, struct qrtr_mhi_pkt, node); + list_del(&pkt->node); + complete_all(&pkt->done); + + kref_put(&pkt->refcount, qrtr_mhi_pkt_release); + spin_unlock_bh(&qdev->ul_lock); } /* from qrtr to mhi */ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb) { struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep); + struct qrtr_mhi_pkt *pkt; int rc; rc = skb_linearize(skb); - if (rc) - goto out; + if (rc) { + kfree_skb(skb); + return rc; + } + + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) { + kfree_skb(skb); + return -ENOMEM; + } - reinit_completion(&qdev->ul_done); + init_completion(&pkt->done); + kref_init(&pkt->refcount); + kref_get(&pkt->refcount); + pkt->skb = skb; + + spin_lock_bh(&qdev->ul_lock); + list_add_tail(&pkt->node, &qdev->ul_pkts); rc = mhi_queue_transfer(qdev->mhi_dev, DMA_TO_DEVICE, skb, skb->len, MHI_EOT); - if (rc) - goto out; + if (rc) { + list_del(&pkt->node); + kfree_skb(skb); + kfree(pkt); + spin_unlock_bh(&qdev->ul_lock); + return rc; + } + spin_unlock_bh(&qdev->ul_lock); + if (skb->sk) + sock_hold(skb->sk); - rc = wait_for_completion_interruptible_timeout(&qdev->ul_done, HZ * 5); + rc = wait_for_completion_interruptible_timeout(&pkt->done, HZ * 5); if (rc > 0) rc = 0; else if (rc == 0) rc = -ETIMEDOUT; -out: + kref_put(&pkt->refcount, qrtr_mhi_pkt_release); return rc; } @@ -95,7 +140,8 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, qdev->dev = &mhi_dev->dev; qdev->ep.xmit = qcom_mhi_qrtr_send; - init_completion(&qdev->ul_done); + INIT_LIST_HEAD(&qdev->ul_pkts); + spin_lock_init(&qdev->ul_lock); rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO); if (rc) @@ -113,7 +159,6 @@ static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev) struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); qrtr_endpoint_unregister(&qdev->ep); - complete(&qdev->ul_done); dev_set_drvdata(&mhi_dev->dev, NULL); } diff --git a/net/rds/loop.c b/net/rds/loop.c index f2bf78de5688a3ee44862fe158bffee4ca94d91a..dac6218a460ed4d4a5b7b03ad4f6056a68784a16 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c @@ -193,4 +193,5 @@ struct rds_transport rds_loop_transport = { .inc_copy_to_user = rds_message_inc_copy_to_user, .inc_free = rds_loop_inc_free, .t_name = "loopback", + .t_type = RDS_TRANS_LOOP, }; diff --git a/net/rds/rds.h b/net/rds/rds.h index d09f6c1facb4a83c5d47340e5ae7134230089388..f685d8b514e553ceaba724918489717cba46bfc2 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -454,6 +454,11 @@ struct rds_notifier { int n_status; }; +/* Available as part of RDS core, so doesn't need to participate + * in get_preferred transport etc + */ +#define RDS_TRANS_LOOP 3 + /** * struct rds_transport - transport specific behavioural hooks * diff --git a/net/rds/recv.c b/net/rds/recv.c index 555f07ccf0dc60d480adb0495091a748dca9b3ba..c27cceae52e1f118ef9c5a4b19831d7654327f96 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -103,6 +103,11 @@ static void rds_recv_rcvbuf_delta(struct rds_sock *rs, struct sock *sk, rds_stats_add(s_recv_bytes_added_to_socket, delta); else rds_stats_add(s_recv_bytes_removed_from_socket, -delta); + + /* loop transport doesn't send/recv congestion updates */ + if (rs->rs_transport->t_type == RDS_TRANS_LOOP) + return; + now_congested = rs->rs_rcv_bytes > rds_sk_rcvbuf(rs); rdsdebug("rs %p (%pI4:%u) recv bytes %d buf %d " diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c index 3028298ca56134e86b1ef60c9987b37490e12f19..62b1581d44a5af8c66a5c3cdeef2b7fb631558a1 100644 --- a/net/rxrpc/call_accept.c +++ b/net/rxrpc/call_accept.c @@ -115,9 +115,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, while (*pp) { parent = *pp; xcall = rb_entry(parent, struct rxrpc_call, sock_node); - if (user_call_ID < call->user_call_ID) + if (user_call_ID < xcall->user_call_ID) pp = &(*pp)->rb_left; - else if (user_call_ID > call->user_call_ID) + else if (user_call_ID > xcall->user_call_ID) pp = &(*pp)->rb_right; else goto id_in_use; diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c index c98a61e980baa68931f7e974582eb1c43ed60cf5..9c4c2bb547d7ea1da26e956a77b23592d467365b 100644 --- a/net/sched/sch_blackhole.c +++ b/net/sched/sch_blackhole.c @@ -21,7 +21,7 @@ static int blackhole_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { qdisc_drop(skb, sch, to_free); - return NET_XMIT_SUCCESS; + return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; } static struct sk_buff *blackhole_dequeue(struct Qdisc *sch) diff --git a/net/socket.c b/net/socket.c index 84faf10210e8d43dbb5f8aa64d117ae4c6f8cfd3..bc9619ee0b9659001a9066c48fa6b5e4267ebe7d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include @@ -2468,6 +2469,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) if (call < 1 || call > SYS_SENDMMSG) return -EINVAL; + call = array_index_nospec(call, SYS_SENDMMSG + 1); len = nargs[call]; if (len > sizeof(a)) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index c741365f77daf9e92b6485d212c50ab6be3f6430..a68c754e84ea639bf30e0086732b5138d454ce0f 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -35,7 +35,6 @@ struct _strp_msg { */ struct strp_msg strp; int accum_len; - int early_eaten; }; static inline struct _strp_msg *_strp_msg(struct sk_buff *skb) @@ -115,20 +114,6 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, head = strp->skb_head; if (head) { /* Message already in progress */ - - stm = _strp_msg(head); - if (unlikely(stm->early_eaten)) { - /* Already some number of bytes on the receive sock - * data saved in skb_head, just indicate they - * are consumed. - */ - eaten = orig_len <= stm->early_eaten ? - orig_len : stm->early_eaten; - stm->early_eaten -= eaten; - - return eaten; - } - if (unlikely(orig_offset)) { /* Getting data with a non-zero offset when a message is * in progress is not expected. If it does happen, we @@ -297,9 +282,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, } stm->accum_len += cand_len; + eaten += cand_len; strp->need_bytes = stm->strp.full_len - stm->accum_len; - stm->early_eaten = cand_len; STRP_STATS_ADD(strp->stats.bytes, cand_len); desc->count = 0; /* Stop reading socket */ break; diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 97b9d4f671ac3a639399dd0e1bfd698672c5d68f..2aaf46599126e55eee01e819f06cf0ff1b61d858 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -270,7 +270,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) wait_for_completion(&ia->ri_remove_done); ia->ri_id = NULL; - ia->ri_pd = NULL; ia->ri_device = NULL; /* Return 1 to ensure the core destroys the id. */ return 1; @@ -464,7 +463,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia) ia->ri_id->qp = NULL; } ib_free_cq(ep->rep_attr.recv_cq); + ep->rep_attr.recv_cq = NULL; ib_free_cq(ep->rep_attr.send_cq); + ep->rep_attr.send_cq = NULL; /* The ULP is responsible for ensuring all DMA * mappings and MRs are gone. @@ -477,6 +478,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia) rpcrdma_dma_unmap_regbuf(req->rl_recvbuf); } rpcrdma_destroy_mrs(buf); + ib_dealloc_pd(ia->ri_pd); + ia->ri_pd = NULL; /* Allow waiters to continue */ complete(&ia->ri_remove_done); @@ -650,14 +653,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) cancel_delayed_work_sync(&ep->rep_connect_worker); - if (ia->ri_id->qp) { + if (ia->ri_id && ia->ri_id->qp) { rpcrdma_ep_disconnect(ep, ia); rdma_destroy_qp(ia->ri_id); ia->ri_id->qp = NULL; } - ib_free_cq(ep->rep_attr.recv_cq); - ib_free_cq(ep->rep_attr.send_cq); + if (ep->rep_attr.recv_cq) + ib_free_cq(ep->rep_attr.recv_cq); + if (ep->rep_attr.send_cq) + ib_free_cq(ep->rep_attr.send_cq); } /* Re-establish a connection after a device removal event. diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 3c86614462f6d31c3c54caa7809fc82f92834e5f..fb79caf56d0e8fe4ec0a8baf08b3067c54666315 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -135,9 +135,10 @@ static int alloc_sg(struct sock *sk, int len, struct scatterlist *sg, pfrag->offset += use; sge = sg + num_elem - 1; - if (num_elem > first_coalesce && sg_page(sg) == pfrag->page && - sg->offset + sg->length == orig_offset) { - sg->length += use; + + if (num_elem > first_coalesce && sg_page(sge) == pfrag->page && + sge->offset + sge->length == orig_offset) { + sge->length += use; } else { sge++; sg_unmark_end(sge); @@ -449,7 +450,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) ret = tls_push_record(sk, msg->msg_flags, record_type); if (!ret) continue; - if (ret == -EAGAIN) + if (ret < 0) goto send_end; copied -= try_to_copy; diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 403d86e80162e7796fd75249b1ae876d1eee1e6a..fdb294441682b0a3249b9270540bf9f6c8d0c0c6 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -201,7 +201,7 @@ virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt) return -ENODEV; } - if (le32_to_cpu(pkt->hdr.dst_cid) == vsock->guest_cid) + if (le64_to_cpu(pkt->hdr.dst_cid) == vsock->guest_cid) return virtio_transport_send_pkt_loopback(vsock, pkt); if (pkt->reply) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 30683891305f30a540f5863618a961ef5950b4f2..c2a52658f2734c999ba993cd7549797d4382c524 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11737,6 +11737,7 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; if (!info->attrs[NL80211_ATTR_MDID] || + !info->attrs[NL80211_ATTR_IE] || !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bbd39109aad61e648e4f39693afcbdaeaa652da9..480ceb868663100c86b1c7d5f66d2c3abe943191 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1691,7 +1691,9 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, * as some drivers used this to restore its orig_* reg domain. */ if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG && + !(wiphy->regulatory_flags & + REGULATORY_WIPHY_SELF_MANAGED)) reg_call_notifier(wiphy, lr); return; } @@ -2243,26 +2245,6 @@ static void notify_self_managed_wiphys(struct regulatory_request *request) } } -static bool reg_only_self_managed_wiphys(void) -{ - struct cfg80211_registered_device *rdev; - struct wiphy *wiphy; - bool self_managed_found = false; - - ASSERT_RTNL(); - - list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - wiphy = &rdev->wiphy; - if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) - self_managed_found = true; - else - return false; - } - - /* make sure at least one self-managed wiphy exists */ - return self_managed_found; -} - /* * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* * Regulatory hints come on a first come first serve basis and we @@ -2295,10 +2277,6 @@ static void reg_process_pending_hints(void) spin_unlock(®_requests_lock); notify_self_managed_wiphys(reg_request); - if (reg_only_self_managed_wiphys()) { - reg_free_request(reg_request); - return; - } reg_process_hint(reg_request); diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index a7ecdb1237319dd698384c4d7f2555b06f2d3188..2e879e714be222e1abe7b25eba3f2b6334904e97 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2663,7 +2663,7 @@ sub process { $sig_nospace =~ s/\s//g; $sig_nospace = lc($sig_nospace); if (defined $signatures{$sig_nospace}) { - WARN("BAD_SIGN_OFF", + WARN("DUPLICATE_SIGN_OFF", "Duplicate signature\n" . $herecurr); } else { $signatures{$sig_nospace} = 1; diff --git a/security/Kconfig b/security/Kconfig index 87d8bb2df7c8fa394e5f48efaff38a6028f5f53f..1996a6bace8a4a325c4ca4252147a479182ca658 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -10,7 +10,6 @@ if ARCH_QCOM source security/pfe/Kconfig endif - config SECURITY_DMESG_RESTRICT bool "Restrict unprivileged access to the kernel syslog" default n diff --git a/security/Makefile b/security/Makefile index f15945d3800b8d397c7d7d5b5737d7b39a246599..47bffaa3f5f8de2e2aaf1d3058ce7586f01ff8a2 100644 --- a/security/Makefile +++ b/security/Makefile @@ -10,7 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin -subdir-$(CONFIG_ARCH_QCOM) += pfe +subdir-$(CONFIG_ARCH_QCOM) += pfe # always enable default capabilities obj-y += commoncap.o @@ -26,8 +26,8 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ -obj-$(CONFIG_ARCH_QCOM) += pfe/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o +obj-$(CONFIG_ARCH_QCOM) += pfe/ # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 7e334fd31c154380f83c88fb0b6bd9c73d50efcf..f8553179bdd78f670dfb911c07bb1df47c9c12da 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -379,6 +379,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) static int read_idmap[READING_MAX_ID] = { [READING_FIRMWARE] = FIRMWARE_CHECK, + [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, [READING_MODULE] = MODULE_CHECK, [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig index 0cd9e81a49528dd7e63177c1b983106c767b7c88..45640adf8101dab7d4f2c62be47347b93706e7e7 100644 --- a/security/pfe/Kconfig +++ b/security/pfe/Kconfig @@ -25,4 +25,15 @@ config PFK Information is used when file is encrypted later using ICE or dm crypto engine +config PFK_WRAPPED_KEY_SUPPORTED + bool "Per-File-Key driver with wrapped key support" + depends on SECURITY + depends on SECURITY_SELINUX + depends on QSEECOM + depends on PFK + default n + help + Adds wrapped key support in PFK driver. Instead of setting + the key directly in ICE, it unwraps the key and sets the key + in ICE. endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile index 242a2165fccba01327093f1a650c9f4de2a483ee..2507557837dbe1a6c6043b833c66cb6a9a303d05 100644 --- a/security/pfe/Makefile +++ b/security/pfe/Makefile @@ -3,8 +3,8 @@ # ccflags-y += -Isecurity/selinux -Isecurity/selinux/include -ccflags-y += -Ifs/ext4 ccflags-y += -Ifs/crypto +ccflags-y += -Idrivers/misc obj-$(CONFIG_PFT) += pft.o -obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o +obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o pfk_f2fs.o diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index b38cd5c4b05dee4cef9f87dbde01ea5da7b6fb32..f66577307573c8c8071f8e257cc38575c95f9cdb 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -37,6 +37,9 @@ * */ + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ #define pr_fmt(fmt) "pfk [%s]: " fmt, __func__ #include @@ -45,24 +48,27 @@ #include #include #include -#include +#include #include -#include "ext4.h" -#include "objsec.h" +#include + #include "pfk_kc.h" +#include "objsec.h" #include "pfk_ice.h" #include "pfk_ext4.h" +#include "pfk_f2fs.h" #include "pfk_internal.h" static bool pfk_ready; + /* might be replaced by a table when more than one cipher is supported */ #define PFK_SUPPORTED_KEY_SIZE 32 #define PFK_SUPPORTED_SALT_SIZE 32 /* Various PFE types and function tables to support each one of them */ -enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE}; +enum pfe_type {EXT4_CRYPT_PFE, F2FS_CRYPT_PFE, INVALID_PFE}; typedef int (*pfk_parse_inode_type)(const struct bio *bio, const struct inode *inode, @@ -76,31 +82,40 @@ typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_parse_inode, }; static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_allow_merge_bio, }; static void __exit pfk_exit(void) { pfk_ready = false; pfk_ext4_deinit(); + pfk_f2fs_deinit(); pfk_kc_deinit(); } static int __init pfk_init(void) { + int ret = 0; ret = pfk_ext4_init(); if (ret != 0) goto fail; + ret = pfk_f2fs_init(); + if (ret != 0) + goto fail; + ret = pfk_kc_init(); if (ret != 0) { pr_err("could init pfk key cache, error %d\n", ret); pfk_ext4_deinit(); + pfk_f2fs_deinit(); goto fail; } @@ -126,6 +141,9 @@ static enum pfe_type pfk_get_pfe_type(const struct inode *inode) if (pfk_is_ext4_type(inode)) return EXT4_CRYPT_PFE; + if (pfk_is_f2fs_type(inode)) + return F2FS_CRYPT_PFE; + return INVALID_PFE; } @@ -142,6 +160,9 @@ char *inode_to_filename(const struct inode *inode) struct dentry *dentry = NULL; char *filename = NULL; + if (!inode) + return "NULL"; + if (hlist_empty(&inode->i_dentry)) return "unknown"; @@ -176,30 +197,30 @@ static inline bool pfk_is_ready(void) */ static struct inode *pfk_bio_get_inode(const struct bio *bio) { - struct address_space *mapping; - if (!bio) return NULL; + if (!bio_has_data((struct bio *)bio)) + return NULL; if (!bio->bi_io_vec) return NULL; if (!bio->bi_io_vec->bv_page) return NULL; - if (!bio_has_data((struct bio *)bio)) - return NULL; if (PageAnon(bio->bi_io_vec->bv_page)) { struct inode *inode; + /* Using direct-io (O_DIRECT) without page cache */ inode = dio_bio_get_inode((struct bio *)bio); pr_debug("inode on direct-io, inode = 0x%pK.\n", inode); + return inode; } - mapping = page_mapping(bio->bi_io_vec->bv_page); - if (!mapping) + if (!page_mapping(bio->bi_io_vec->bv_page)) return NULL; - if (!mapping->host) + if (!bio->bi_io_vec->bv_page->mapping->host) + return NULL; return bio->bi_io_vec->bv_page->mapping->host; @@ -250,6 +271,60 @@ bool pfe_is_inode_filesystem_type(const struct inode *inode, return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); } +/** + * pfk_get_key_for_bio() - get the encryption key to be used for a bio + * + * @bio: pointer to the BIO + * @key_info: pointer to the key information which will be filled in + * @algo_mode: optional pointer to the algorithm identifier which will be set + * @is_pfe: will be set to false if the BIO should be left unencrypted + * + * Return: 0 if a key is being used, otherwise a -errno value + */ +static int pfk_get_key_for_bio(const struct bio *bio, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo_mode, + bool *is_pfe) +{ + const struct inode *inode; + enum pfe_type which_pfe; + const struct blk_encryption_key *key = NULL; + + inode = pfk_bio_get_inode(bio); + which_pfe = pfk_get_pfe_type(inode); + + if (which_pfe != INVALID_PFE) { + /* Encrypted file; override ->bi_crypt_key */ + pr_debug("parsing inode %lu with PFE type %d\n", + inode->i_ino, which_pfe); + return (*(pfk_parse_inode_ftable[which_pfe])) + (bio, inode, key_info, algo_mode, is_pfe); + } + + /* + * bio is not for an encrypted file. Use ->bi_crypt_key if it was set. + * Otherwise, don't encrypt/decrypt the bio. + */ +#ifdef CONFIG_DM_DEFAULT_KEY + key = bio->bi_crypt_key; +#endif + if (!key) { + *is_pfe = false; + return -EINVAL; + } + + /* Note: the "salt" is really just the second half of the XTS key. */ + BUILD_BUG_ON(sizeof(key->raw) != + PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE); + key_info->key = &key->raw[0]; + key_info->key_size = PFK_SUPPORTED_KEY_SIZE; + key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE]; + key_info->salt_size = PFK_SUPPORTED_SALT_SIZE; + if (algo_mode) + *algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; + return 0; +} + /** * pfk_load_key_start() - loads PFE encryption key to the ICE @@ -279,8 +354,6 @@ int pfk_load_key_start(const struct bio *bio, enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; enum ice_crpto_key_size key_size_type = 0; u32 key_index = 0; - struct inode *inode = NULL; - enum pfe_type which_pfe = INVALID_PFE; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -301,26 +374,16 @@ int pfk_load_key_start(const struct bio *bio, pr_err("ice setting is NULL\n"); return -EINVAL; } - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - pr_debug("parsing file %s with PFE %d\n", - inode_to_filename(inode), which_pfe); - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, &algo_mode, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe); + if (ret != 0) return ret; + ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type); if (ret != 0) return ret; + ret = pfk_kc_load_key_start(key_info.key, key_info.key_size, key_info.salt, key_info.salt_size, &key_index, async); if (ret) { @@ -338,7 +401,7 @@ int pfk_load_key_start(const struct bio *bio, ice_setting->key_index = key_index; pr_debug("loaded key for file %s key_index %d\n", - inode_to_filename(inode), key_index); + inode_to_filename(pfk_bio_get_inode(bio)), key_index); return 0; } @@ -357,9 +420,7 @@ int pfk_load_key_start(const struct bio *bio, int pfk_load_key_end(const struct bio *bio, bool *is_pfe) { int ret = 0; - struct pfk_key_info key_info = {0}; - enum pfe_type which_pfe = INVALID_PFE; - struct inode *inode = NULL; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -375,20 +436,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) if (!pfk_is_ready()) return -ENODEV; - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, NULL, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe); if (ret != 0) return ret; @@ -396,7 +444,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) key_info.salt, key_info.salt_size); pr_debug("finished using key for file %s\n", - inode_to_filename(inode)); + inode_to_filename(pfk_bio_get_inode(bio))); return 0; } @@ -418,10 +466,17 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) */ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) { - struct inode *inode1 = NULL; - struct inode *inode2 = NULL; - enum pfe_type which_pfe1 = INVALID_PFE; - enum pfe_type which_pfe2 = INVALID_PFE; + const struct blk_encryption_key *key1 = NULL; + const struct blk_encryption_key *key2 = NULL; + const struct inode *inode1; + const struct inode *inode2; + enum pfe_type which_pfe1; + enum pfe_type which_pfe2; + +#ifdef CONFIG_DM_DEFAULT_KEY + key1 = bio1->bi_crypt_key; + key2 = bio2->bi_crypt_key; +#endif if (!pfk_is_ready()) return false; @@ -432,24 +487,38 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) if (bio1 == bio2) return true; + key1 = bio1->bi_crypt_key; + key2 = bio2->bi_crypt_key; + inode1 = pfk_bio_get_inode(bio1); inode2 = pfk_bio_get_inode(bio2); - which_pfe1 = pfk_get_pfe_type(inode1); which_pfe2 = pfk_get_pfe_type(inode2); - /* nodes with different encryption, do not merge */ + /* + * If one bio is for an encrypted file and the other is for a different + * type of encrypted file or for blocks that are not part of an + * encrypted file, do not merge. + */ if (which_pfe1 != which_pfe2) return false; - /* both nodes do not have encryption, allow merge */ - if (which_pfe1 == INVALID_PFE) - return true; + if (which_pfe1 != INVALID_PFE) { + /* Both bios are for the same type of encrypted file. */ + return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, + inode1, inode2); + } - return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, - inode1, inode2); + /* + * Neither bio is for an encrypted file. Merge only if the default keys + * are the same (or both are NULL). + */ + return key1 == key2 || + (key1 && key2 && + !crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw))); } + /** * Flush key table on storage core reset. During core reset key configuration * is lost in ICE. We need to flash the cache, so that the keys will be diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c index 05a8628e34b8549deaa0f46a2de268c6d989bd0e..0eb122565ecc047e3c8244fa1073b0a5cc8c4591 100644 --- a/security/pfe/pfk_ext4.c +++ b/security/pfe/pfk_ext4.c @@ -26,6 +26,9 @@ * */ + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ #define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__ #include @@ -33,8 +36,9 @@ #include #include -#include "ext4_ice.h" +#include "fscrypt_ice.h" #include "pfk_ext4.h" +//#include "ext4_ice.h" static bool pfk_ext4_ready; @@ -67,6 +71,29 @@ static inline bool pfk_ext4_is_ready(void) return pfk_ext4_ready; } +/** + * pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen + * + * + */ +/* + * static void pfk_ext4_dump_inode(const struct inode* inode) + * { + * struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode); + * + * pr_debug("dumping inode with address 0x%p\n", inode); + * pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode)); + * pr_debug("EXT4_INODE_ENCRYPT flag is %d\n", + * ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT)); + * if (ci) { + * pr_debug("crypt_info address 0x%p\n", ci); + * pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode); + * } else { + * pr_debug("crypt_info is NULL\n"); + * } + * } + */ + /** * pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE * @inode: inode pointer @@ -76,7 +103,7 @@ bool pfk_is_ext4_type(const struct inode *inode) if (!pfe_is_inode_filesystem_type(inode, "ext4")) return false; - return ext4_should_be_processed_by_ice(inode); + return fscrypt_should_be_processed_by_ice(inode); } /** @@ -98,7 +125,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, if (!inode) return -EINVAL; - if (!ext4_is_aes_xts_cipher(inode)) { + if (!fscrypt_is_aes_xts_cipher(inode)) { pr_err("ext4 alghoritm is not supported by pfk\n"); return -EINVAL; } @@ -109,6 +136,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, return 0; } + int pfk_ext4_parse_inode(const struct bio *bio, const struct inode *inode, struct pfk_key_info *key_info, @@ -136,25 +164,25 @@ int pfk_ext4_parse_inode(const struct bio *bio, if (!key_info) return -EINVAL; - key_info->key = ext4_get_ice_encryption_key(inode); + key_info->key = fscrypt_get_ice_encryption_key(inode); if (!key_info->key) { pr_err("could not parse key from ext4\n"); return -EINVAL; } - key_info->key_size = ext4_get_ice_encryption_key_size(inode); + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); if (!key_info->key_size) { pr_err("could not parse key size from ext4\n"); return -EINVAL; } - key_info->salt = ext4_get_ice_encryption_salt(inode); + key_info->salt = fscrypt_get_ice_encryption_salt(inode); if (!key_info->salt) { pr_err("could not parse salt from ext4\n"); return -EINVAL; } - key_info->salt_size = ext4_get_ice_encryption_salt_size(inode); + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); if (!key_info->salt_size) { pr_err("could not parse salt size from ext4\n"); return -EINVAL; @@ -180,5 +208,5 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1, if (!inode1 || !inode2) return false; - return ext4_is_ice_encryption_info_equal(inode1, inode2); + return fscrypt_is_ice_encryption_info_equal(inode1, inode2); } diff --git a/security/pfe/pfk_f2fs.c b/security/pfe/pfk_f2fs.c new file mode 100644 index 0000000000000000000000000000000000000000..8b9d515043e8693291fd2c44f5d168f4b3ae62e1 --- /dev/null +++ b/security/pfe/pfk_f2fs.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Per-File-Key (PFK) - f2fs + * + * This driver is used for working with EXT4/F2FS crypt extension + * + * The key information is stored in node by EXT4/F2FS when file is first opened + * and will be later accessed by Block Device Driver to actually load the key + * to encryption hw. + * + * PFK exposes API's for loading and removing keys from encryption hw + * and also API to determine whether 2 adjacent blocks can be agregated by + * Block Layer in one request to encryption hw. + * + */ + + +/* Uncomment the line below to enable debug messages */ +#define DEBUG 1 +#define pr_fmt(fmt) "pfk_f2fs [%s]: " fmt, __func__ + +#include +#include +#include +#include + +#include "fscrypt_ice.h" +#include "pfk_f2fs.h" + +static bool pfk_f2fs_ready; + +/* + * pfk_f2fs_deinit() - Deinit function, should be invoked by upper PFK layer + */ +void pfk_f2fs_deinit(void) +{ + pfk_f2fs_ready = false; +} + +/* + * pfk_f2fs_init() - Init function, should be invoked by upper PFK layer + */ +int __init pfk_f2fs_init(void) +{ + pfk_f2fs_ready = true; + pr_info("PFK F2FS inited successfully\n"); + + return 0; +} + +/** + * pfk_f2fs_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_f2fs_is_ready(void) +{ + return pfk_f2fs_ready; +} + +/** + * pfk_is_f2fs_type() - return true if inode belongs to ICE F2FS PFE + * @inode: inode pointer + */ +bool pfk_is_f2fs_type(const struct inode *inode) +{ + if (!pfe_is_inode_filesystem_type(inode, "f2fs")) + return false; + + return fscrypt_should_be_processed_by_ice(inode); +} + +/** + * pfk_f2fs_parse_cipher() - parse cipher from inode to enum + * @inode: inode + * @algo: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported cipher) + */ +static int pfk_f2fs_parse_cipher(const struct inode *inode, + enum ice_cryto_algo_mode *algo) +{ + /* + * currently only AES XTS algo is supported + * in the future, table with supported ciphers might + * be introduced + */ + if (!inode) + return -EINVAL; + + if (!fscrypt_is_aes_xts_cipher(inode)) { + pr_err("f2fs alghoritm is not supported by pfk\n"); + return -EINVAL; + } + + if (algo) + *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; + + return 0; +} + + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe) +{ + int ret = 0; + + if (!is_pfe) + return -EINVAL; + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_f2fs_is_ready()) + return -ENODEV; + + if (!inode) + return -EINVAL; + + if (!key_info) + return -EINVAL; + + key_info->key = fscrypt_get_ice_encryption_key(inode); + if (!key_info->key) { + pr_err("could not parse key from f2fs\n"); + return -EINVAL; + } + + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); + if (!key_info->key_size) { + pr_err("could not parse key size from f2fs\n"); + return -EINVAL; + } + + key_info->salt = fscrypt_get_ice_encryption_salt(inode); + if (!key_info->salt) { + pr_err("could not parse salt from f2fs\n"); + return -EINVAL; + } + + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); + if (!key_info->salt_size) { + pr_err("could not parse salt size from f2fs\n"); + return -EINVAL; + } + + ret = pfk_f2fs_parse_cipher(inode, algo); + if (ret != 0) { + pr_err("not supported cipher\n"); + return ret; + } + + return 0; +} + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2) +{ + bool mergeable; + + /* if there is no f2fs pfk, don't disallow merging blocks */ + if (!pfk_f2fs_is_ready()) + return true; + + if (!inode1 || !inode2) + return false; + + mergeable = fscrypt_is_ice_encryption_info_equal(inode1, inode2); + if (!mergeable) + return false; + + + /* ICE allows only consecutive iv_key stream. */ + if (!bio_dun(bio1) && !bio_dun(bio2)) + return true; + else if (!bio_dun(bio1) || !bio_dun(bio2)) + return false; + + return bio_end_dun(bio1) == bio_dun(bio2); +} diff --git a/security/pfe/pfk_f2fs.h b/security/pfe/pfk_f2fs.h new file mode 100644 index 0000000000000000000000000000000000000000..551d529bced6afb58bdb66be95d8552925e7864b --- /dev/null +++ b/security/pfe/pfk_f2fs.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PFK_F2FS_H_ +#define _PFK_F2FS_H_ + +#include +#include +#include +#include "pfk_internal.h" + +bool pfk_is_f2fs_type(const struct inode *inode); + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +int __init pfk_f2fs_init(void); + +void pfk_f2fs_deinit(void); + +#endif /* _PFK_F2FS_H_ */ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index bf60dd18dd76163b4d3239148109cbcc186fbb8d..6452b42201366b0f3a68349ad6e082e215919d8a 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -24,7 +24,7 @@ #include #include #include "pfk_ice.h" - +#include "qseecom_kernel.h" /**********************************/ /** global definitions **/ @@ -55,48 +55,120 @@ TZ_SYSCALL_CREATE_PARAM_ID_1( \ TZ_SYSCALL_PARAM_TYPE_VAL) +#define CONTEXT_SIZE 0x1000 + +#define KEYMASTER_UTILS_CMD_ID 0x200UL +#define KEYMASTER_SET_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 18UL) +#define KEYMASTER_CLEAR_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 19UL) + #define ICE_KEY_SIZE 32 #define ICE_SALT_SIZE 32 static uint8_t ice_key[ICE_KEY_SIZE]; static uint8_t ice_salt[ICE_KEY_SIZE]; -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type) +static struct qseecom_handle *qhandle; + +static int set_wrapped_key(uint32_t index, const uint8_t *key, + const uint8_t *salt) +{ + int ret = 0; + u32 set_req_len = 0; + u32 set_rsp_len = 0; + struct pfk_ice_key_req *set_req_buf; + struct pfk_ice_key_rsp *set_rsp_buf; + + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); + + if (!qhandle) { + ret = qseecom_start_app(&qhandle, "keymaster64", + CONTEXT_SIZE); + if (ret) { + pr_err("Qseecom start app failed\n"); + return ret; + } + } + + set_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + set_req_buf->cmd_id = KEYMASTER_SET_ICE_KEY; + set_req_buf->index = index; + set_req_buf->ice_key_offset = sizeof(struct pfk_ice_key_req); + set_req_buf->ice_key_size = ICE_KEY_SIZE; + set_req_buf->ice_salt_offset = set_req_buf->ice_key_offset + + set_req_buf->ice_key_size; + set_req_buf->ice_salt_size = ICE_SALT_SIZE; + + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_key_offset, ice_key, + set_req_buf->ice_key_size); + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_salt_offset, ice_salt, + set_req_buf->ice_salt_size); + + set_req_len = sizeof(struct pfk_ice_key_req) + set_req_buf->ice_key_size + + set_req_buf->ice_salt_size; + + set_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + set_req_len); + set_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, + set_req_buf, set_req_len, + set_rsp_buf, set_rsp_len); + + if (ret) + pr_err("%s: Set wrapped key error: Status %d\n", __func__, + set_rsp_buf->ret); + + return ret; +} + +static int clear_wrapped_key(uint32_t index) +{ + int ret = 0; + + u32 clear_req_len = 0; + u32 clear_rsp_len = 0; + struct pfk_ice_key_req *clear_req_buf; + struct pfk_ice_key_rsp *clear_rsp_buf; + + clear_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + memset(clear_req_buf, 0, sizeof(qhandle->sbuf)); + clear_req_buf->cmd_id = KEYMASTER_CLEAR_ICE_KEY; + clear_req_buf->index = index; + clear_req_len = sizeof(struct pfk_ice_key_req); + clear_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + QSEECOM_ALIGN(clear_req_len)); + clear_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, clear_req_buf, clear_req_len, + clear_rsp_buf, clear_rsp_len); + if (ret) + pr_err("%s: Clear wrapped key error: Status %d\n", __func__, + clear_rsp_buf->ret); + + return ret; +} + +static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt) { struct scm_desc desc = {0}; - int ret, ret1; + int ret = 0; + uint32_t smc_id = 0; char *tzbuf_key = (char *)ice_key; char *tzbuf_salt = (char *)ice_salt; - char *s_type = storage_type; - uint32_t smc_id = 0; u32 tzbuflen_key = sizeof(ice_key); u32 tzbuflen_salt = sizeof(ice_salt); - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - if (!key || !salt) { - pr_err("%s Invalid key/salt\n", __func__); - return -EINVAL; - } - if (!tzbuf_key || !tzbuf_salt) { pr_err("%s No Memory\n", __func__); return -ENOMEM; } - if (s_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); - memcpy(ice_key, key, tzbuflen_key); - memcpy(ice_salt, salt, tzbuflen_salt); + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); @@ -110,33 +182,84 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + + return ret; +} + +static int clear_key(uint32_t index) +{ + struct scm_desc desc = {0}; + int ret = 0; + uint32_t smc_id = 0; + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + return ret; +} + +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) +{ + int ret = 0, ret1 = 0; + char *s_type = storage_type; + + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); + return -EINVAL; + } + + if (s_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + ret = qcom_ice_setup_ice_hw((const char *)s_type, true); if (ret) { pr_err("%s: could not enable clocks: %d\n", __func__, ret); goto out; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + pr_debug("%s: Setting wrapped key\n", __func__); + ret = set_wrapped_key(index, key, salt); + } else { + pr_debug("%s: Setting keys with QSEE kernel\n", __func__); + ret = set_key(index, key, salt); + } + if (ret) { pr_err("%s: Set Key Error: %d\n", __func__, ret); if (ret == -EBUSY) { if (qcom_ice_setup_ice_hw((const char *)s_type, false)) pr_err("%s: clock disable failed\n", __func__); - goto out; + goto out; } /* Try to invalidate the key to keep ICE in proper state */ - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret1 = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) + ret1 = clear_wrapped_key(index); + else + ret1 = clear_key(index); + if (ret1) - pr_err("%s: Invalidate Key Error: %d\n", __func__, - ret1); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); } ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); - if (ret1) - pr_err("%s: Error %d disabling clocks\n", __func__, ret1); + if (ret) + pr_err("%s: Error %d disabling clocks\n", __func__, ret); out: return ret; @@ -144,11 +267,8 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) { - struct scm_desc desc = {0}; int ret = 0; - uint32_t smc_id = 0; - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; @@ -159,20 +279,22 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) return -EINVAL; } - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + ret = clear_wrapped_key(index); + pr_debug("%s: Clearing wrapped key\n", __func__); + } else { + pr_debug("%s: Clearing keys with QSEE kernel\n", __func__); + ret = clear_key(index); + } + if (ret) - pr_err("%s: Error: 0x%x\n", __func__, ret); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) pr_err("%s: could not disable clocks\n", __func__); diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index a0019391911601f76f737e477e2f132fb0f52457..5adfcb200b6882a2914465e0be3325e4f059254a 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -22,9 +22,35 @@ #include +struct __attribute__ ((__packed__)) pfk_ice_key_req { + uint32_t cmd_id; + uint32_t index; + uint32_t ice_key_offset; + uint32_t ice_key_size; + uint32_t ice_salt_offset; + uint32_t ice_salt_size; +}; + +struct __attribute__ ((__packed__)) pfk_ice_key_rsp { + uint32_t ret; + uint32_t cmd_id; +}; + int pfk_ice_init(void); int pfk_ice_deinit(void); +#ifdef CONFIG_PFK_WRAPPED_KEY_SUPPORTED +static inline bool pfk_wrapped_key_supported(void) +{ + return true; +} +#else +static inline bool pfk_wrapped_key_supported(void) +{ + return false; +} +#endif + int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, char *storage_type); int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 6ccfbd1a54840b63e4bd75ca0e4f45d613998bd9..041a02f1b3ee443f586e6585ecb844c808f9b14b 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -435,6 +435,7 @@ int pfk_kc_init(void) } kc_ready = true; kc_spin_unlock(); + return 0; } @@ -448,6 +449,7 @@ int pfk_kc_deinit(void) int res = pfk_kc_clear(); kc_ready = false; + return res; } diff --git a/security/security.c b/security/security.c index d0d99921b75138e8579f76edcf53859743dc5639..2ba27d75f0521af98ad1a400036acc400f94c491 100644 --- a/security/security.c +++ b/security/security.c @@ -613,7 +613,7 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode EXPORT_SYMBOL_GPL(security_inode_create); int security_inode_post_create(struct inode *dir, struct dentry *dentry, - umode_t mode) + umode_t mode) { if (unlikely(IS_PRIVATE(dir))) return 0; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index af8582501f93c21c6f505fd57b3b83eeecede767..9cec304b6937f853563d9358f0420db319de8f70 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -66,7 +66,7 @@ struct inode_security_struct { u16 sclass; /* security class of this object */ unsigned char initialized; /* initialization flag */ u32 tag; /* Per-File-Encryption tag */ - void *pfk_data; /* Per-File-Key data from ecryptfs */ + void *pfk_data; /* Per-File-Key data from ecryptfs */ spinlock_t lock; }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index de4c7d32b955e26aa2badacd8617809ec6a5eed6..99203f1b32ffd5645d7e04770013c2dc0c245b12 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -13,6 +13,7 @@ #include #include #include +//#include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_WILD 0xffffffff /* wildcard SID */ diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 2683b971721532acd8867308e57fc4fcd6a331be..56be1630bd3e6cbb52eb321d3ec64b8e9d728c18 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1850,7 +1850,9 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) if (!kctl) return -ENOMEM; kctl->id.device = device; - snd_ctl_add(emu->card, kctl); + err = snd_ctl_add(emu->card, kctl); + if (err < 0) + return err; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 4f1f69be18651b7c692f9feb812c239e8f911386..8c778fa33031733d9c30c1782c991101e50ed462 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -237,13 +237,13 @@ search_empty(struct snd_emu10k1 *emu, int size) static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) { if (addr & ~emu->dma_mask) { - dev_err(emu->card->dev, + dev_err_ratelimited(emu->card->dev, "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); return 0; } if (addr & (EMUPAGESIZE-1)) { - dev_err(emu->card->dev, "page is not aligned\n"); + dev_err_ratelimited(emu->card->dev, "page is not aligned\n"); return 0; } return 1; @@ -334,7 +334,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst else addr = snd_pcm_sgbuf_get_addr(substream, ofs); if (! is_valid_page(emu, addr)) { - dev_err(emu->card->dev, + dev_err_ratelimited(emu->card->dev, "emu: failure page = %d\n", idx); mutex_unlock(&hdr->block_mutex); return NULL; diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 73a67bc3586bcd55e6e0387093fcda8917e6c2e7..e3fb9c61017c6535e3d8fb4cb4f9694bce2e2bb1 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1068,11 +1068,19 @@ static int snd_fm801_mixer(struct fm801 *chip) if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0) return err; } - for (i = 0; i < FM801_CONTROLS; i++) - snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls[i], chip)); + for (i = 0; i < FM801_CONTROLS; i++) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&snd_fm801_controls[i], chip)); + if (err < 0) + return err; + } if (chip->multichannel) { - for (i = 0; i < FM801_CONTROLS_MULTI; i++) - snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls_multi[i], chip)); + for (i = 0; i < FM801_CONTROLS_MULTI; i++) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&snd_fm801_controls_multi[i], chip)); + if (err < 0) + return err; + } } return 0; } diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 3e73d5c6ccfc95155d79557d0a5292f865afe777..119f3b504765ef994c02917b7b80b10ae4063aa9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -38,6 +38,10 @@ /* Enable this to see controls for tuning purpose. */ /*#define ENABLE_TUNING_CONTROLS*/ +#ifdef ENABLE_TUNING_CONTROLS +#include +#endif + #define FLOAT_ZERO 0x00000000 #define FLOAT_ONE 0x3f800000 #define FLOAT_TWO 0x40000000 @@ -3067,8 +3071,8 @@ static int equalizer_ctl_put(struct snd_kcontrol *kcontrol, return 1; } -static const DECLARE_TLV_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); -static const DECLARE_TLV_DB_SCALE(eq_db_scale, -2400, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(eq_db_scale, -2400, 100, 0); static int add_tuning_control(struct hda_codec *codec, hda_nid_t pnid, hda_nid_t nid, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ba9a7e552183392b1d07d535a91bdd9206cea65d..88ce2f1022e1a5d5d8d551e17ee6e44b87545b03 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -965,6 +965,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bf7737fc3b28fefdf5389012601953f170141348..dcc9e6551b51eac7eb4e3821e458ce37deacf91b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6402,6 +6402,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), + SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6383b95416ee87af02698354d234754b7dab9ad0..174da18a0e454389ee23f67e3681968e4dd700b3 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1896,8 +1896,10 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) continue; if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) - continue; + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) { + soc_pcm_hw_free(be_substream); + be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; + } dev_dbg(be->dev, "ASoC: close BE %s\n", be->dai_link->name); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 30cdad2eab7f2b19d43879a9219f647c79ac415a..c1619860a5de1e964a0045e126b0dcf1ec53020a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1997,6 +1997,13 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + /* clock gating */ + if (hw_config->clock_gated == SND_SOC_TPLG_DAI_CLK_GATE_GATED) + link->dai_fmt |= SND_SOC_DAIFMT_GATED; + else if (hw_config->clock_gated == + SND_SOC_TPLG_DAI_CLK_GATE_CONT) + link->dai_fmt |= SND_SOC_DAIFMT_CONT; + /* clock signal polarity */ invert_bclk = hw_config->invert_bclk; invert_fsync = hw_config->invert_fsync; @@ -2010,13 +2017,15 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, link->dai_fmt |= SND_SOC_DAIFMT_IB_IF; /* clock masters */ - bclk_master = hw_config->bclk_master; - fsync_master = hw_config->fsync_master; - if (!bclk_master && !fsync_master) + bclk_master = (hw_config->bclk_master == + SND_SOC_TPLG_BCLK_CM); + fsync_master = (hw_config->fsync_master == + SND_SOC_TPLG_FSYNC_CM); + if (bclk_master && fsync_master) link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - else if (bclk_master && !fsync_master) - link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; else if (!bclk_master && fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; + else if (bclk_master && !fsync_master) link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; else link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index e30ec91cd681054bad6de5f0219b916eeaf15d04..f97f309d94b8a33cb24ddc6d3a91b87d44bf19bd 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1441,7 +1441,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs, if (bytes % (runtime->sample_bits >> 3) != 0) { int oldbytes = bytes; bytes = frames * stride; - dev_warn(&subs->dev->dev, + dev_warn_ratelimited(&subs->dev->dev, "Corrected urb data len. %d->%d\n", oldbytes, bytes); } diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 9c3e49b12800100fdded5691f7f04d799b10c97a..c300d4642a6308df6de78f6a42072cdc90063478 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -758,25 +758,6 @@ static void uaudio_dev_intf_cleanup(struct usb_device *udev, struct intf_info *info) { - struct usb_host_endpoint *ep; - - if (info->data_ep_pipe) { - ep = usb_pipe_endpoint(udev, info->data_ep_pipe); - if (!ep) - pr_debug("%s: no data ep\n", __func__); - else - usb_stop_endpoint(udev, ep); - info->data_ep_pipe = 0; - } - if (info->sync_ep_pipe) { - ep = usb_pipe_endpoint(udev, info->sync_ep_pipe); - if (!ep) - pr_debug("%s: no sync ep\n", __func__); - else - usb_stop_endpoint(udev, ep); - info->sync_ep_pipe = 0; - } - uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, info->data_xfer_ring_size, info->data_xfer_ring_size); info->data_xfer_ring_va = 0; @@ -1016,6 +997,7 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, struct snd_usb_audio *chip = NULL; struct uaudio_qmi_svc *svc = uaudio_svc; struct intf_info *info; + struct usb_host_endpoint *ep; int pcm_format; u8 pcm_card_num, pcm_dev_num, direction; int info_idx = -EINVAL, datainterval = -EINVAL, ret = 0; @@ -1108,6 +1090,29 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf; + if (!req_msg->enable) { + info = &uadev[pcm_card_num].info[info_idx]; + if (info->data_ep_pipe) { + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->data_ep_pipe); + if (!ep) + pr_debug("%s: no data ep\n", __func__); + else + usb_stop_endpoint(uadev[pcm_card_num].udev, ep); + info->data_ep_pipe = 0; + } + + if (info->sync_ep_pipe) { + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->sync_ep_pipe); + if (!ep) + pr_debug("%s: no sync ep\n", __func__); + else + usb_stop_endpoint(uadev[pcm_card_num].udev, ep); + info->sync_ep_pipe = 0; + } + } + ret = snd_usb_enable_audio_stream(subs, datainterval, req_msg->enable); if (!ret && req_msg->enable) @@ -1184,6 +1189,25 @@ static void uaudio_qmi_disconnect_work(struct work_struct *w) } } +static void uaudio_qmi_bye_cb(struct qmi_handle *handle, unsigned int node) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + pr_debug("%s: node:\n", __func__, node); + if (svc->uaudio_svc_hdl != handle) { + pr_err("%s: handle mismatch\n", __func__); + return; + } + + if (svc->client_connected && svc->client_sq.sq_node == node) { + queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work); + svc->client_sq.sq_node = 0; + svc->client_sq.sq_port = 0; + svc->client_sq.sq_family = 0; + svc->client_connected = false; + } +} + static void uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, unsigned int node, unsigned int port) { @@ -1206,6 +1230,7 @@ static void uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, } static struct qmi_ops uaudio_svc_ops_options = { + .bye = uaudio_qmi_bye_cb, .del_client = uaudio_qmi_svc_disconnect_cb, }; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index e81a20ea8d7df1d2c7d8313279daa834eda88415..988310cd3049cba330a16ebc07b67994ce3ba973 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -72,6 +72,7 @@ static void inc_group_count(struct list_head *list, %type value_sym %type event_config %type opt_event_config +%type opt_pmu_config %type event_term %type event_pmu %type event_legacy_symbol @@ -223,7 +224,7 @@ event_def: event_pmu | event_bpf_file event_pmu: -PE_NAME opt_event_config +PE_NAME opt_pmu_config { struct list_head *list, *orig_terms, *terms; @@ -486,6 +487,17 @@ opt_event_config: $$ = NULL; } +opt_pmu_config: +'/' event_config '/' +{ + $$ = $2; +} +| +'/' '/' +{ + $$ = NULL; +} + start_terms: event_config { struct parse_events_state *parse_state = _parse_state; diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index c670359becc6c2d0d6f0ba750a40cc6aad9a9e27..92897880434241fe08c36580997b42a18a4f2546 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh @@ -30,9 +30,12 @@ EVALUATE_ONLY=0 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + if ! uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ | grep -q x86; then echo "$0 # Skipped: Test can only run on x86 architectures." - exit 0 + exit $ksft_skip fi max_cpus=$(($(nproc)-1)) @@ -48,11 +51,12 @@ function run_test () { echo "sleeping for 5 seconds" sleep 5 - num_freqs=$(cat /proc/cpuinfo | grep MHz | sort -u | wc -l) - if [ $num_freqs -le 2 ]; then - cat /proc/cpuinfo | grep MHz | sort -u | tail -1 > /tmp/result.$1 + grep MHz /proc/cpuinfo | sort -u > /tmp/result.freqs + num_freqs=$(wc -l /tmp/result.freqs | awk ' { print $1 } ') + if [ $num_freqs -ge 2 ]; then + tail -n 1 /tmp/result.freqs > /tmp/result.$1 else - cat /proc/cpuinfo | grep MHz | sort -u > /tmp/result.$1 + cp /tmp/result.freqs /tmp/result.$1 fi ./msr 0 >> /tmp/result.$1 @@ -82,21 +86,20 @@ _max_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $2 } ') max_freq=$(($_max_freq / 1000)) -for freq in `seq $max_freq -100 $min_freq` +[ $EVALUATE_ONLY -eq 0 ] && for freq in `seq $max_freq -100 $min_freq` do echo "Setting maximum frequency to $freq" cpupower frequency-set -g powersave --max=${freq}MHz >& /dev/null - [ $EVALUATE_ONLY -eq 0 ] && run_test $freq + run_test $freq done -echo "==============================================================================" +[ $EVALUATE_ONLY -eq 0 ] && cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null +echo "==============================================================================" echo "The marketing frequency of the cpu is $mkt_freq MHz" echo "The maximum frequency of the cpu is $max_freq MHz" echo "The minimum frequency of the cpu is $min_freq MHz" -cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null - # make a pretty table echo "Target Actual Difference MSR(0x199) max_perf_pct" for freq in `seq $max_freq -100 $min_freq` @@ -104,10 +107,6 @@ do result_freq=$(cat /tmp/result.${freq} | grep "cpu MHz" | awk ' { print $4 } ' | awk -F "." ' { print $1 } ') msr=$(cat /tmp/result.${freq} | grep "msr" | awk ' { print $3 } ') max_perf_pct=$(cat /tmp/result.${freq} | grep "max_perf_pct" | awk ' { print $2 } ' ) - if [ $result_freq -eq $freq ]; then - echo " $freq $result_freq 0 $msr $(($max_perf_pct*3300))" - else - echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))" - fi + echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))" done exit 0 diff --git a/tools/testing/selftests/memfd/run_tests.sh b/tools/testing/selftests/memfd/run_tests.sh index daabb350697c6ac83bd06016062ad8e66fc641fe..bf83db61013ab533e10f07688af024649294ee35 100755 --- a/tools/testing/selftests/memfd/run_tests.sh +++ b/tools/testing/selftests/memfd/run_tests.sh @@ -1,6 +1,9 @@ #!/bin/bash # please run as root +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + # # Normal tests requiring no special resources # @@ -29,12 +32,13 @@ if [ -n "$freepgs" ] && [ $freepgs -lt $hpages_test ]; then nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` hpages_needed=`expr $hpages_test - $freepgs` + if [ $UID != 0 ]; then + echo "Please run memfd with hugetlbfs test as root" + exit $ksft_skip + fi + echo 3 > /proc/sys/vm/drop_caches echo $(( $hpages_needed + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages - if [ $? -ne 0 ]; then - echo "Please run this test as root" - exit 1 - fi while read name size unit; do if [ "$name" = "HugePages_Free:" ]; then freepgs=$size @@ -53,7 +57,7 @@ if [ $freepgs -lt $hpages_test ]; then fi printf "Not enough huge pages available (%d < %d)\n" \ $freepgs $needpgs - exit 1 + exit $ksft_skip fi # diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index d1fc0f9f00fb8cb50242e83e20234fdffd3b610f..ed8c9d360c0f8e80cf65b564728db0bec52af168 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -135,11 +135,11 @@ static int refresh_imported_device_list(void) return 0; } -static int get_nports(void) +static int get_nports(struct udev_device *hc_device) { const char *attr_nports; - attr_nports = udev_device_get_sysattr_value(vhci_driver->hc_device, "nports"); + attr_nports = udev_device_get_sysattr_value(hc_device, "nports"); if (!attr_nports) { err("udev_device_get_sysattr_value nports failed"); return -1; @@ -242,35 +242,41 @@ static int read_record(int rhport, char *host, unsigned long host_len, int usbip_vhci_driver_open(void) { + int nports; + struct udev_device *hc_device; + udev_context = udev_new(); if (!udev_context) { err("udev_new failed"); return -1; } - vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); - /* will be freed in usbip_driver_close() */ - vhci_driver->hc_device = + hc_device = udev_device_new_from_subsystem_sysname(udev_context, USBIP_VHCI_BUS_TYPE, USBIP_VHCI_DEVICE_NAME); - if (!vhci_driver->hc_device) { + if (!hc_device) { err("udev_device_new_from_subsystem_sysname failed"); goto err; } - vhci_driver->nports = get_nports(); - dbg("available ports: %d", vhci_driver->nports); - - if (vhci_driver->nports <= 0) { + nports = get_nports(hc_device); + if (nports <= 0) { err("no available ports"); goto err; - } else if (vhci_driver->nports > MAXNPORT) { - err("port number exceeds %d", MAXNPORT); + } + dbg("available ports: %d", nports); + + vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver) + + nports * sizeof(struct usbip_imported_device)); + if (!vhci_driver) { + err("vhci_driver allocation failed"); goto err; } + vhci_driver->nports = nports; + vhci_driver->hc_device = hc_device; vhci_driver->ncontrollers = get_ncontrollers(); dbg("available controllers: %d", vhci_driver->ncontrollers); @@ -285,7 +291,7 @@ int usbip_vhci_driver_open(void) return 0; err: - udev_device_unref(vhci_driver->hc_device); + udev_device_unref(hc_device); if (vhci_driver) free(vhci_driver); diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index 418b404d5121079837aade8ba692c977e441ef52..6c9aca2167051cd5ee15674092c5aee31e0f895d 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -13,7 +13,6 @@ #define USBIP_VHCI_BUS_TYPE "platform" #define USBIP_VHCI_DEVICE_NAME "vhci_hcd.0" -#define MAXNPORT 128 enum hub_speed { HUB_SPEED_HIGH = 0, @@ -41,7 +40,7 @@ struct usbip_vhci_driver { int ncontrollers; int nports; - struct usbip_imported_device idev[MAXNPORT]; + struct usbip_imported_device idev[]; }; diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c index 9db9d21bb2ecee75c89c027ccb07cfdeb21062de..6a8db858caa5f3d3f908185afdc09b43d6db774e 100644 --- a/tools/usb/usbip/src/usbip_detach.c +++ b/tools/usb/usbip/src/usbip_detach.c @@ -43,7 +43,7 @@ void usbip_detach_usage(void) static int detach_port(char *port) { - int ret; + int ret = 0; uint8_t portnum; char path[PATH_MAX+1]; @@ -73,9 +73,12 @@ static int detach_port(char *port) } ret = usbip_vhci_detach_device(portnum); - if (ret < 0) - return -1; + if (ret < 0) { + ret = -1; + goto call_driver_close; + } +call_driver_close: usbip_vhci_driver_close(); return ret; diff --git a/verity_dev_keys.x509 b/verity_dev_keys.x509 new file mode 100644 index 0000000000000000000000000000000000000000..86399c3c1dd7d5ae8dcee2c0b68b3f12a7237f28 --- /dev/null +++ b/verity_dev_keys.x509 @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAJcPmDkJqolJMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g +VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE +AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xNDExMDYxOTA3NDBaFw00MjAzMjQxOTA3NDBaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAOjreE0vTVSRenuzO9vnaWfk0eQzYab0gqpi +6xAzi6dmD+ugoEKJmbPiuE5Dwf21isZ9uhUUu0dQM46dK4ocKxMRrcnmGxydFn6o +fs3ODJMXOkv2gKXL/FdbEPdDbxzdu8z3yk+W67udM/fW7WbaQ3DO0knu+izKak/3 +T41c5uoXmQ81UNtAzRGzGchNVXMmWuTGOkg6U+0I2Td7K8yvUMWhAWPPpKLtVH9r +AL5TzjYNR92izdKcz3AjRsI3CTjtpiVABGeX0TcjRSuZB7K9EK56HV+OFNS6I1NP +jdD7FIShyGlqqZdUOkAUZYanbpgeT5N7QL6uuqcGpoTOkalu6kkCAwEAAaNQME4w +HQYDVR0OBBYEFH5DM/m7oArf4O3peeKO0ZIEkrQPMB8GA1UdIwQYMBaAFH5DM/m7 +oArf4O3peeKO0ZIEkrQPMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AHO3NSvDE5jFvMehGGtS8BnFYdFKRIglDMc4niWSzhzOVYRH4WajxdtBWc5fx0ix +NF/+hVKVhP6AIOQa+++sk+HIi7RvioPPbhjcsVlZe7cUEGrLSSveGouQyc+j0+m6 +JF84kszIl5GGNMTnx0XRPO+g8t6h5LWfnVydgZfpGRRg+WHewk1U2HlvTjIceb0N +dcoJ8WKJAFWdcuE7VIm4w+vF/DYX/A2Oyzr2+QRhmYSv1cusgAeC1tvH4ap+J1Lg +UnOu5Kh/FqPLLSwNVQp4Bu7b9QFfqK8Moj84bj88NqRGZgDyqzuTrFxn6FW7dmyA +yttuAJAEAymk1mipd9+zp38= +-----END CERTIFICATE----- diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 9bee849db682d26f1f7969f0ff6b4dd911e1a4f7..d5f1d83645716e37d70136a29644f54ecb353512 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -51,8 +51,8 @@ __asm__(".arch_extension virt"); #endif +DEFINE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state); static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); -static kvm_cpu_context_t __percpu *kvm_host_cpu_state; /* Per-CPU variable containing the currently running vcpu. */ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu); @@ -351,7 +351,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } vcpu->cpu = cpu; - vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state); + vcpu->arch.host_cpu_context = this_cpu_ptr(&kvm_host_cpu_state); kvm_arm_set_running_vcpu(vcpu); @@ -1259,19 +1259,8 @@ static inline void hyp_cpu_pm_exit(void) } #endif -static void teardown_common_resources(void) -{ - free_percpu(kvm_host_cpu_state); -} - static int init_common_resources(void) { - kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t); - if (!kvm_host_cpu_state) { - kvm_err("Cannot allocate host CPU state\n"); - return -ENOMEM; - } - /* set size of VMID supported by CPU */ kvm_vmid_bits = kvm_get_vmid_bits(); kvm_info("%d-bit VMID\n", kvm_vmid_bits); @@ -1413,7 +1402,7 @@ static int init_hyp_mode(void) for_each_possible_cpu(cpu) { kvm_cpu_context_t *cpu_ctxt; - cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu); + cpu_ctxt = per_cpu_ptr(&kvm_host_cpu_state, cpu); err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP); if (err) { @@ -1422,6 +1411,10 @@ static int init_hyp_mode(void) } } + err = hyp_map_aux_data(); + if (err) + kvm_err("Cannot map host auxilary data: %d\n", err); + return 0; out_err: @@ -1497,7 +1490,6 @@ int kvm_arch_init(void *opaque) if (!in_hyp_mode) teardown_hyp_mode(); out_err: - teardown_common_resources(); return err; } diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c index d7fd46fe9efb35ca28a0685b333f8c68a61b2d64..4b4221b0d4ba07ade93319ea9b685ce9ad5a79a7 100644 --- a/virt/kvm/arm/hyp/vgic-v2-sr.c +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c @@ -139,7 +139,7 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu) return -1; rd = kvm_vcpu_dabt_get_rd(vcpu); - addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va); + addr = kern_hyp_va(hyp_symbol_addr(kvm_vgic_global_state)->vcpu_base_va); addr += fault_ipa - vgic->vgic_cpu_base; if (kvm_vcpu_dabt_iswrite(vcpu)) { diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c index c4762bef13c6d389ff0c1e4f656322d66bb167b0..c95ab4c5a47516067737b1612d7545fa9543b3b1 100644 --- a/virt/kvm/arm/psci.c +++ b/virt/kvm/arm/psci.c @@ -405,7 +405,7 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu) int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { u32 func_id = smccc_get_function(vcpu); - u32 val = PSCI_RET_NOT_SUPPORTED; + u32 val = SMCCC_RET_NOT_SUPPORTED; u32 feature; switch (func_id) { @@ -417,7 +417,21 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) switch(feature) { case ARM_SMCCC_ARCH_WORKAROUND_1: if (kvm_arm_harden_branch_predictor()) - val = 0; + val = SMCCC_RET_SUCCESS; + break; + case ARM_SMCCC_ARCH_WORKAROUND_2: + switch (kvm_arm_have_ssbd()) { + case KVM_SSBD_FORCE_DISABLE: + case KVM_SSBD_UNKNOWN: + break; + case KVM_SSBD_KERNEL: + val = SMCCC_RET_SUCCESS; + break; + case KVM_SSBD_FORCE_ENABLE: + case KVM_SSBD_MITIGATED: + val = SMCCC_RET_NOT_REQUIRED; + break; + } break; } break; diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index f2ac53ab82438f0b473ecd8ed91b1e2548af7ca2..58a9b31b0dd54192e35e1821ba2399d0c780fce5 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -119,8 +119,12 @@ irqfd_shutdown(struct work_struct *work) { struct kvm_kernel_irqfd *irqfd = container_of(work, struct kvm_kernel_irqfd, shutdown); + struct kvm *kvm = irqfd->kvm; u64 cnt; + /* Make sure irqfd has been initalized in assign path. */ + synchronize_srcu(&kvm->irq_srcu); + /* * Synchronize with the wait-queue and unhook ourselves to prevent * further events. @@ -387,7 +391,6 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) idx = srcu_read_lock(&kvm->irq_srcu); irqfd_update(kvm, irqfd); - srcu_read_unlock(&kvm->irq_srcu, idx); list_add_tail(&irqfd->list, &kvm->irqfds.items); @@ -421,6 +424,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) } #endif + srcu_read_unlock(&kvm->irq_srcu, idx); return 0; fail: