diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 47e11eb5f71dbb35e1000c98ae4121f4ed533eb5..270dc28d357a84ef821ff3ce9646738b55041ec0 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -6,6 +6,11 @@ ifeq ($(KERNEL_TARGET),) INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel endif +ifneq ($(TARGET_KERNEL_APPEND_DTB), true) +$(info Using DTB Image) +INSTALLED_DTBIMAGE_TARGET := $(PRODUCT_OUT)/dtb.img +endif + TARGET_KERNEL_MAKE_ENV := $(strip $(TARGET_KERNEL_MAKE_ENV)) ifeq ($(TARGET_KERNEL_MAKE_ENV),) KERNEL_MAKE_ENV := @@ -160,14 +165,31 @@ $(KERNEL_CONFIG): $(KERNEL_OUT) echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) oldconfig; fi -$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) +ifeq ($(TARGET_KERNEL_APPEND_DTB), true) +TARGET_PREBUILT_INT_KERNEL_IMAGE := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image +$(TARGET_PREBUILT_INT_KERNEL_IMAGE): $(KERNEL_USR) +$(TARGET_PREBUILT_INT_KERNEL_IMAGE): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) + $(hide) echo "Building kernel modules..." + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) Image + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) modules_install + $(mv-modules) + $(clean-module-folder) + +$(TARGET_PREBUILT_INT_KERNEL): $(TARGET_PREBUILT_INT_KERNEL_IMAGE) $(hide) echo "Building kernel..." $(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) +else +TARGET_PREBUILT_INT_KERNEL_IMAGE := $(TARGET_PREBUILT_INT_KERNEL) +$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) + $(hide) echo "Building kernel..." + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) modules_install $(mv-modules) $(clean-module-folder) +endif $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ @@ -187,6 +209,14 @@ $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) oldconfig; fi +# Creating a dtb.img once the kernel is compiled if TARGET_KERNEL_APPEND_DTB is set to be false +$(INSTALLED_DTBIMAGE_TARGET): $(TARGET_PREBUILT_INT_KERNEL) + $(hide) if [ -d "$(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts/vendor/" ]; then \ + cat $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts/vendor/qcom/*.dtb > $@; \ + else \ + cat $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts/qcom/*.dtb > $@; \ + fi + .PHONY: kerneltags kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) tags diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a73f7b1765b20de6b5e21eeeac3920b01adf9cc0..d3065c1e337b51df191224e0d01d18b709a90fdd 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2689,7 +2689,11 @@ nosmt=force: Force disable SMT, cannot be undone via the sysfs control file. - nospectre_v2 [X86] Disable all mitigations for the Spectre variant 2 + nospectre_v1 [PPC] Disable mitigations for Spectre Variant 1 (bounds + check bypass). With this option data leaks are possible + in the system. + + nospectre_v2 [X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2 (indirect branch prediction) vulnerability. System may allow data leaks with this option, which is equivalent to spectre_v2=off. @@ -3800,6 +3804,17 @@ (that will set all pages holding image data during restoration read-only). + noswap_randomize + Kernel uses random disk offsets to help with wear-levelling + of SSD devices, while saving the hibernation snapshot image to + disk. Use this parameter to disable this feature for SSD + devices in scenarios when, such randomization is addressed at + the firmware level and hibenration image is not re-generated + frequently. + (Useful for improving hibernation resume time as snapshot pages + are available in disk serially and can be read in bigger chunks + without seeking) + retain_initrd [RAM] Keep initrd memory after extraction rfkill.default_state= diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 72f246712541313196b3e368e3b7b8f1d39cfb38..28ca9693a6fdbbce21f41e77ad73d7dc9251e9e4 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -62,6 +62,12 @@ SoCs: - QCS401 compatible = "qcom,qcs401" +- QCS404 + compatible = "qcom,qcs404" + +- QCS407 + compatible = "qcom,qcs407" + - SDXPRAIRIE compatible = "qcom,sdxprairie" @@ -195,6 +201,8 @@ compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-iot" compatible = "qcom,qcs403-iot" compatible = "qcom,qcs401-iot" +compatible = "qcom,qcs404-iot" +compatible = "qcom,qcs407-iot" compatible = "qcom,sa8155-adp-star" compatible = "qcom,sa8155p-adp-star" compatible = "qcom,sa8195p-adp-star" @@ -209,6 +217,7 @@ compatible = "qcom,sa8155p-adp-alcor" compatible = "qcom,sdxprairie-rumi" compatible = "qcom,sdxprairie-mtp" compatible = "qcom,sdxprairie-cdp" +compatible = "qcom,sa515m-ccard" compatible = "qcom,sdmmagpie-rumi" compatible = "qcom,sdmmagpie-idp" compatible = "qcom,sdmmagpie-atp" @@ -221,5 +230,7 @@ compatible = "qcom,trinket-rumi" compatible = "qcom,trinket-idp" compatible = "qcom,trinket-qrd" compatible = "qcom,atoll-rumi" +compatible = "qcom,atoll-idp" +compatible = "qcom,atoll-qrd" compatible = "qcom,qcs610-iot" compatible = "qcom,qcs410-iot" diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index 4b688137043574cbffa43dbe5616e21f24089d89..6a8128765ff736a8604d1be197411526ee38af63 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -12,7 +12,8 @@ Properties: Definition: must be "qcom,clk-cpu-osm" or "qcom,clk-cpu-osm-sdmshrike" or "qcom,clk-cpu-osm-sm6150" or "qcom,clk-cpu-osm-sdmmagpie" or - "qcom,clk-cpu-osm-trinket". + "qcom,clk-cpu-osm-trinket" or + "qcom,clk-cpu-osm-atoll". - reg Usage: required diff --git a/Documentation/devicetree/bindings/arm/msm/subsystem_notif_virt.txt b/Documentation/devicetree/bindings/arm/msm/subsystem_notif_virt.txt new file mode 100644 index 0000000000000000000000000000000000000000..38e997797a04a3747b0757eb23d8b4bd565d9f6a --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/subsystem_notif_virt.txt @@ -0,0 +1,49 @@ +Subsystem Notification Virtual Driver + +The guest VM uses this driver to communicate +subsystem state notifications to a backend driver +via the virtual device's registers. + +[Root level node] +Required Properties: +-compatible : Should be "qcom,subsys-notif-virt" +-reg : The start and size of the virtual device's + register set. +-reg-names : Should be "vdev_base" for virtual device's + base address. + +[Child nodes] +-subsys-names : The name of the subsystem that the + driver is registering to notifications for. +-offset : The offset from the virtual device's register + base where the subsystem state will be written. +-type : The type of the subsystem. + "virtual" - When the subsystem is loaded by the host VM + "native" - When the subsystem is loaded by the guest VM + +Required Property for "virtual" subsystem types: +-interrupts : Tuple defining the interrupt which the driver must + register for to receive subsystem state notifications + from the backend. +-interrupt-names: Must be "state-irq" + +Example: + + subsys_notif_virt: qcom,subsys_notif_virt@2D000000 { + compatible = "qcom,subsys-notif-virt"; + reg = <0x2D000000 0x400>; + reg-names = "vdev_base"; + adsp { + subsys-name = "adsp"; + interrupts = <0 43 0>; + interrupt-names = "state-irq"; + type = "virtual"; + offset = <0>; + }; + mpss { + subsys-name = "modem"; + type = "native"; + offset = <256>; + }; + }; + diff --git a/Documentation/devicetree/bindings/batterydata/batterydata.txt b/Documentation/devicetree/bindings/batterydata/batterydata.txt index 8224139e7d8f3347795570e59d88d6e37e149351..4509d6cfae21d5fff03df772e6b2f9e857508525 100644 --- a/Documentation/devicetree/bindings/batterydata/batterydata.txt +++ b/Documentation/devicetree/bindings/batterydata/batterydata.txt @@ -146,6 +146,12 @@ Profile data node optional properties: Element 1 - FV value for soft warm. - qcom,batt-age-level: Battery age level. This is used only when multiple profile loading is supported. +- qcom,soh-range: A tuple entry to specify the values of SOH range that + the battery profile has to be used for. This needs to + be specified along with "qcom,batt-age-level" for the + proper functionality. + Element 0 - SOH minimum level. + Element 1 - SOH maximum level. - qcom,taper-fcc: A bool property to enable gradual reduction in FCC in steps of pre-configured value, whenever step charging thresholds are crossed-over. diff --git a/Documentation/devicetree/bindings/clock/clock-bindings.txt b/Documentation/devicetree/bindings/clock/clock-bindings.txt index 2ec489eebe723afb0f6cf1700d7869e9d84f0ac6..b646bbcf7f92489063b9f44acdb449ef8c84b416 100644 --- a/Documentation/devicetree/bindings/clock/clock-bindings.txt +++ b/Documentation/devicetree/bindings/clock/clock-bindings.txt @@ -168,3 +168,19 @@ a shared clock is forbidden. Configuration of common clocks, which affect multiple consumer devices can be similarly specified in the clock provider node. + +==Protected clocks== + +Some platforms or firmwares may not fully expose all the clocks to the OS, such +as in situations where those clks are used by drivers running in ARM secure +execution levels. Such a configuration can be specified in device tree with the +protected-clocks property in the form of a clock specifier list. This property should +only be specified in the node that is providing the clocks being protected: + + clock-controller@a000f000 { + compatible = "vendor,clk95; + reg = <0xa000f000 0x1000> + #clocks-cells = <1>; + ... + protected-clocks = , ; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 1d3fe751ae78aaeda9716227c0d9f8d9ede2f622..8136c5458220d18739ccae8d0c48f4eff6f4b2ef 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -28,6 +28,7 @@ Required properties : "qcom,gcc-sdxprairie" "qcom,gcc-trinket" "qcom,gcc-sa6155" + "qcom,gcc-sdxprairie-v2" - reg : shall contain base register location and length - #clock-cells : shall contain 1 diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt index ece6b9e5b769e413ceae8a7ceeb2eb9bc34ece96..a244c6376f11c3d982d3c8116aad94bef3919ebd 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt @@ -6,7 +6,8 @@ Required properties: "qcom,rpmh-clk-sm8150", "qcom,rpmh-clk-sdmshrike", "qcom,rpmh-clk-sdmmagpie" - "qcom,rpmh-clk-sdxprairie". + "qcom,rpmh-clk-sdxprairie", + "qcom,rpmh-clk-atoll". - #clock-cells: Must contain 1. - mboxes: List of RPMh mailbox phandle and channel identifier tuples. - mbox-names: List of names to identify the RPMh mailboxes used. diff --git a/Documentation/devicetree/bindings/clock/qcom,scc.txt b/Documentation/devicetree/bindings/clock/qcom,scc.txt index d095b3eb57f30bf37d9bdfe95f3f3499e7bdede1..d60889ad94f286c44eea5bd83503dd512a2ca82f 100644 --- a/Documentation/devicetree/bindings/clock/qcom,scc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,scc.txt @@ -2,7 +2,7 @@ Qualcomm Technologies, Inc. Sensor Clock Controller Bindings Required properties: - compatible: shall contain "qcom,scc-sm8150" or "qcom,scc-sm8150-v2" or - "qcom,scc-sm6150" or qcom,scc-sa6155". + "qcom,scc-sm6150" or "qcom,scc-sa6155" or "qcom,scc-sa8195". - reg: shall contain base register location and length. - vdd_scc_cx-supply: the logic rail supply. - #clock-cells: shall contain 1. diff --git a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbd136e147e259dc63f4164c2ec171a6d8105cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt @@ -0,0 +1,63 @@ +* Qualcomm Technologies, Inc. Connectivity SubSystem Platform Driver + +This platform driver adds support for the CNSS subsystem used for SDIO +based Wi-Fi devices. It also adds support to manage two 1.8V voltage +regulators and WLAN power enable 3.3V regulators. The main purpose of this +device tree entry below is to invoke the CNSS SDIO platform driver +and provide handle to the WLAN power enable 3.3V pmic GPIO and two 1.8V +PMIC voltage regulator resources. + +Required properties: + - compatible: "qcom,cnss_sdio" + - reg: memory resource to save firmware dump, optional. + - reg-names: memory resource name. + - subsys-name: cnss sdio subsytem device name, required. + - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node. + - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node. + - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node. + - vdd-wlan-xtal-supply: phandle to the WLAM XTAL regulator device tree node. + +Optional properties: + - pinctrl-names: Names corresponding to the numbered pinctrl states + - pinctrl-: Pinctrl states as described in + bindings/pinctrl/pinctrl-bindings.txt + - qcom,is-antenna-shared: Enabled for Platforms with both sdio and pcie QCA + Chipsets are attached. + - qcom,cnss-enable-bus-bandwidth: Boolean - Define this property when target + support to vote for bus bandwidth. + - qcom,msm-bus,name: client name for msm bus register. + - qcom,msm-bus,num-cases: number of cases for bus scaling. + - qcom,msm-bus,num-paths: number of paths for bus scale vector. + - qcom,msm-bus,vectors-KBps: bus scale vector table. + - qcom,skip-wlan-en-toggle: Boolean property to be enabled for platforms where + wlan_en toggling is not supported. + - vdd-wlan-xtal-min: Minimum required voltage in uV for VDD_XTAL regulator. + Minimum required voltage is 1620000. + If not set, a typical 1800000 will be set. + - vdd-wlan-xtal-max: Maximum acceptable voltage in uV for VDD_XTAL regulator. + Maximum acceptable voltage is 3465000. + If not set, a typical 1800000 will be set. +Example: + qcom,cnss-sdio { + compatible = "qcom,cnss_sdio"; + reg = <0x87a00000, 0x200000>; + reg-names = "ramdump"; + subsys-name = "AR6320"; + vdd-wlan-supply = <&rome_vreg>; + vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>; + vdd-wlan-io-supply = <&mdm9607_l11>; + vdd-wlan-xtal-supply = <&mdm9607_l2>; + qcom,is-antenna-shared; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&cnss_sdio_active>; + pinctrl-1 = <&cnss_sdio_sleep>; + qcom,cnss-enable-bus-bandwidth; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; diff --git a/Documentation/devicetree/bindings/dma/qcom_gpi.txt b/Documentation/devicetree/bindings/dma/qcom_gpi.txt index f1b4a429ed391fe01ba18240efa5a4581a9362f9..bb4a7ca3ae3106788e09975a8f809ec9f6c67312 100644 --- a/Documentation/devicetree/bindings/dma/qcom_gpi.txt +++ b/Documentation/devicetree/bindings/dma/qcom_gpi.txt @@ -79,6 +79,12 @@ Main node properties: Value type: Array of Definition: Pair of values describing iova base and size to allocate. +Optional property: +- qcom,gpi-ee-offset + Usage: optional + Value type: u64 + Definition: Specifies the gsi ee register offset for the QUP. + ======== Example: ======== diff --git a/Documentation/devicetree/bindings/gnsssirf/gnss_sirf.txt b/Documentation/devicetree/bindings/gnsssirf/gnss_sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..18e8b251d9c53b8695ff50ee236393153b4e939d --- /dev/null +++ b/Documentation/devicetree/bindings/gnsssirf/gnss_sirf.txt @@ -0,0 +1,47 @@ +Binding for SIRF GNSS receiver control driver +GPIO pins are toggled to control GNSS receiver power states either to +wake it from sleep or put receiver into sleep mode + +Required properties: +- compatible: must be "gnss_sirf" +- #gpio-pins: + 0: GPIO 18 + 1: GPIO 87 + +Example: + ss5_pwr_ctrl0 { + compatible = "gnss_sirf"; + pinctrl-0 = <&ss5_pwr_ctrl_rst_on>; + ssVreset-gpio = <&tlmm 87 1>; + ssVonoff-gpio = <&tlmm 18 1>; + }; + + ss5_pwr_ctrl_pins: ss5_pwr_ctrl_pins { + ss5_pwr_ctrl_rst_on: ss5_pwr_ctrl_rst_on { + mux { + pins = "gpio87", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-pull-up; + output-high; + }; + }; + + ss5_pwr_ctrl_rst_off: ss5_pwr_ctrl_off { + mux { + pins = "gpio87", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-pull-up; + output-high; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-ppi.txt b/Documentation/devicetree/bindings/media/video/msm-cam-ppi.txt new file mode 100644 index 0000000000000000000000000000000000000000..aeed60fa6055f199629a9f2ad51b62889041d291 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-ppi.txt @@ -0,0 +1,102 @@ +* Qualcomm Technologies, Inc. MSM camera PPI + +======================= +Required Node Structure +======================= +The camera PPI node must be described in First level of device nodes. The +first level describe the overall PPI node structure. + +====================================== +First Level Node - PPI device +====================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,ppi-v1.0", + "qcom,ppi-v1.1", "qcom,ppi-v1.2", + "qcom,ppi-v2.0", "qcom,ppi". + +- cell-index: ppi hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the ppi operating in + compatible mode. + +- reg-names + Usage: required + Value type: + Definition: Should specify relevant names to each + reg property defined. + +- reg-cam-base + Usage: required + Value type: + Definition: offset of PPI in camera hw block + +- interrupts + Usage: required + Value type: + Definition: Interrupt associated with PPI HW. + +- interrupt-names + Usage: required + Value type: + Definition: Name of the interrupt. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for PPI HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clock rates in Hz for PPI HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- regulator-names + Usage: required + Value type: + Definition: name of the voltage regulators required for the device. + +- gdscr-supply + Usage: required + Value type: + Definition: should contain gdsr regulator used for PPI clocks. + +Example: + qcom,ppi0@ace0000 { + cell-index = <0>; + compatible = "qcom,ppi170"; + reg-names = "ppi"; + reg = <0xace0000 0x200>; + reg-cam-base = <0xe0000>; + interrupt-names = "ppi"; + interrupts = <0 202 0>; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_PPI0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", "ppi0_clk" + clock-rates = <400000000 0 300000000 0>; + clock-cntl-level = "turbo"; + status = "ok"; +}; diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt index 08af0e2d8ff47704e8bd3b0132640e5605639484..d613450cdc59eb38de9ff4e0177ad0151a49a430 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt @@ -13,6 +13,7 @@ Required properties: - "qcom,trinket-vidc" : Invokes driver specific data for trinket. - "qcom,sdm845-vidc" : Invokes driver specific data for SDM845. - "qcom,sdm670-vidc" : Invokes driver specific data for SDM670. + - "qcom,atoll-vidc" : Invokes driver specific data for atoll. Optional properties: - reg : offset and length of the register set for the device. diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt index 30174680a91dfbea2ebac23b08cfdda860ffad61..ece30e43d308d4f0062f218242452922d98d4cab 100644 --- a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt +++ b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt @@ -31,6 +31,18 @@ Optional property: MHI driver on the host. This property is required if iatu property qcom,mhi-config-iatu is present. +MSM MHI DEV NET + +MSM MHI DEV enables communication with the host over a PCIe link using the +Network Interface. + +Required properties: + - compatible: should be "qcom,msm-mhi-dev-net" for MHI net device driver. + +Optional property: + - qcom,mhi-ethernet-interface;: If property is present use ethernet packet + parsing support. + Example: mhi: qcom,msm-mhi-dev { @@ -44,3 +56,8 @@ Example: qcom,mhi-ep-msi = <1>; qcom,mhi-version = <0x1000000>; }; + + qcom,mhi_net_dev { + compatible = "qcom,msm-mhi-dev-net"; + qcom,mhi-ethernet-interface; + }; diff --git a/Documentation/devicetree/bindings/net/qrtr-mhi-dev.txt b/Documentation/devicetree/bindings/net/qrtr-mhi-dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d15e9d6fe9fcda9e778419183a383e28af86c85 --- /dev/null +++ b/Documentation/devicetree/bindings/net/qrtr-mhi-dev.txt @@ -0,0 +1,30 @@ +QTI QRTR MHI Dev transport binding + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,qrtr-mhi-dev" + +- qcom,net-id: + Usage: optional + Value type: + Definition: indicates what subnet this transport belongs to. Should be + passed into the qrtr core logic to determine if forwarding + is needed on this endpoint. + +- qcom,low-latency: + Usage: optional + Value type: + Definition: indicates whether this transport receiving thread needs to + be set to realtime priority for enhanced performance. + += EXAMPLE +The following example represents the qrtr mhi dev transport node on a device +configured as a pcie endpoint and needs to forward data from the host to a +modem co-processor. + + qcom,mhi_dev_qrtr { + compatible = "qcom,qrtr-mhi-dev"; + qcom,net-id = <3>; + qcom,low-latency; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl index 30fe7bdc947e8e8b0320ccd41b9aa617ff2c8f01..ff7848aeee2d0e5df3d007c250d44d711d771296 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl @@ -46,6 +46,12 @@ SM6150 platform. Value type: Definition: must be 2. Specifying the pin number and flags, as defined in +- dirconn-list: + Usage: optional + Value type: + Definition: a 3-tuple list which contains mapping of GPIO pin to + hardware IRQ, and a boolean for enabling the TLMM direct + connect interrupt for the pin. Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for a general description of GPIO and interrupt bindings. diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl index 64fef96c75d666155d7a0b448515e369accbf413..71ceabd31110c79421cad20b238b21843d7b9802 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl @@ -47,6 +47,13 @@ SM8150 platform. Definition: must be 2. Specifying the pin number and flags, as defined in +- dirconn-list: + Usage: optional + Value type: + Definition: a 3-tuple list which contains mapping of GPIO pin to + hardware IRQ, and a boolean for enabling the TLMM direct + connect interrupt for the pin. + Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for a general description of GPIO and interrupt bindings. 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 fadf4793cc5c4919ad189e2f1c5e3590964baf70..167edfef140c5912ff1a6981459f765056167683 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt @@ -29,6 +29,12 @@ First Level Node - FG Gen4 device Definition: Should specify the phandle of PMIC revid module. This is used to identify the PMIC subtype. +- qcom,pmic-pbs + Usage: optional + Value type: + Definition: Should specify the phandle of PMIC PBS module. This is + used to trigger PBS for certain configurations. + - #thermal-sensor-cells: Should be 0. See thermal.txt for the description. - nvmem-names: diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt index e81bdbde95f950cb10b5c5b29f7f3abbb373db4f..3daca154bb525298f774316d4a21ac6eed2e537a 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt @@ -342,6 +342,68 @@ First Level Node - QGAUGE device Value type: Definition: Boolean property to use S7 for PON OCV. +- qcom,min-sleep-time-secs + Usage: optional + Value type: + Definition: The minimum sleep time in secs to allow a SOC + jump if there has been a GOOD_OCV. + +- qcom,qg-sys-min-voltage + Usage: optional + Value type: + Definition: The voltage threshold (in mV) which describes the system + minimum voltage as per the hardware recommendation. This + is not used for any configuration but only for calculating + the available power. If this property is not specified, + then the default value used is 2800 mV. + +- qcom,qg-sleep-config + Usage: optional + Value type: bool + Definition: Enables sleep-state configurtion for QG. This + allows configuring the FIFO length, accumulator + interval and the accumulator length when system + enters sleep. + +- qcom,sleep-s2-fifo-length + Usage: optional + Value type: + Definition: The FIFO length to be applied when system enters sleep + while discharging. Takes effect only if + 'qcom,qg-sleep-config' is enabled. the default value + if not specified is 8. + +- qcom,sleep-s2-acc-length + Usage: optional + Value type: + Definition: The accululator length to be applied when system + enters sleep while discharging. Takes effect only if + 'qcom,qg-sleep-config' is enabled. the default value + if not specified is 256. + +- qcom,sleep-s2-acc-intvl-ms + Usage: optional + Value type: + Definition: The accululator count to be applied when system + enters sleep while discharging. Takes effect only if + 'qcom,qg-sleep-config' is enabled. the default value + if not specified is 200ms. + +- qcom,qg-fast-chg-config + Usage: optional + Value type: bool + Definition: Enables fast-charge configurtion for QG. This + allows configuring the FIFO length during + fast charge. + +- qcom,fast-chg-s2-fifo-length + Usage: optional + Value type: + Definition: The FIFO length to be applied when system enters + fast-chargging. Takes effect only if + 'qcom,qg-fast-chg-config' is enabled. The + default value if not specified is 1. + ========================================================== Second Level Nodes - Peripherals managed by QGAUGE driver ========================================================== diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index 23803b2992e0f6aeadd376a33649241da1605001..f8f71c90176126f7a022c3b95232f29f98c58c41 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -306,6 +306,12 @@ Charger specific properties: Definition: Boolean flag which when present enables h/w based skin temperature mitigation. +- qcom,en-skin-therm-mitigation + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables skin + thermal mitigation. + - qcom,connector-internal-pull-kohm Usage: optional Value type: @@ -313,6 +319,13 @@ Charger specific properties: connector THERM, only valid values are (0/30/100/400). If not specified 100K is used as default pull-up. +- qcom,smb-internal-pull-kohm + Usage: optional + Value type: + Definition: Specifies internal pull-up configuration to be applied to + smb THERM, only valid values are (0/30/100/400). + If not specified 100K is used as default pull-up. + - qcom,wd-snarl-time-config Usage: optional Value type: diff --git a/Documentation/devicetree/bindings/sound/qcom,hsi2s.txt b/Documentation/devicetree/bindings/sound/qcom,hsi2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3331cb6e376ee7cd9948aea11bc7139b98301d7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,hsi2s.txt @@ -0,0 +1,87 @@ +Qualcomm Technologies, Inc. High Speed I2S Interface + +* HS-I2S generic node + +Required properties: + + - compatible : Should include "qcom,hsi2s" + Should include target specific compatible field + "qcom,sa6155-hsi2s" for SA6155 + "qcom,sa8155-hsi2s" for SA8155 + - number-of-interfaces : Denotes the number of HS-I2S interfaces + - reg : Specifies the base physical address and the size of the HS-I2S + register space + - reg-names : "lpa_if" - string to identify the HS-I2S base register + - interrupts : Interrupt number used by this interface + - clocks : Core clocks used by this interface + - clock-names : Clock names for each core clock + - bit-clock-hz : Default bit clock frequency in hertz + - interrupt-interval-ms : Default interrupt interval in milliseconds + +* HS-I2S interface nodes + +Required properties: + + - compatible : Should be "qcom,hsi2s-interface" + - minor-number : Minor number of the character device interface + Should be 0 for HS0 interface + Should be 1 for HS1 interface + Should be 2 for HS2 interface + - clocks : Interface clock used by this interface + - clock-names : Clock name for the interface clock + - pinctrl-names : Pinctrl state names for each pin group configuration + - pinctrl-x : Defines pinctrl state for each pin group + - iommus: The phandle and stream IDs for the SMMU used by this root + - qcom,iova-mapping: Specifies the start address and size of iova space + +Optional properties: + + - qcom,smmu-s1-bypass: Boolean, if present S1 bypass is enabled + +Example: + +hsi2s: qcom,hsi2s { + compatible = "qcom,sa6155-hsi2s", "qcom,hsi2s"; + number-of-interfaces = <2>; + reg = <0x1B40000 0x28000>; + reg-names = "lpa_if"; + interrupts = ; + clocks = <&clock_gcc GCC_SDR_CORE_CLK>, + <&clock_gcc GCC_SDR_WR0_MEM_CLK>, + <&clock_gcc GCC_SDR_WR1_MEM_CLK>, + <&clock_gcc GCC_SDR_WR2_MEM_CLK>, + <&clock_gcc GCC_SDR_CSR_HCLK>; + clock-names = "core_clk", "wr0_mem_clk", + "wr1_mem_clk", "wr2_mem_clk", + "csr_hclk"; + + sdr0: qcom,hs0_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs0_i2s_sck_active &hs0_i2s_data0_active + &hs0_i2s_data1_active>; + pinctrl-1 = <&hs0_i2s_sck_sleep &hs0_i2s_data0_sleep + &hs0_i2s_data1_sleep>; + clocks = <&clock_gcc GCC_SDR_PRI_MI2S_CLK>; + clock-names = "pri_mi2s_clk"; + iommus = <&apps_smmu 0x035C 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + + sdr1: qcom,hs1_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs1_i2s_sck_active &hs1_i2s_data0_active + &hs1_i2s_data1_active>; + pinctrl-1 = <&hs1_i2s_sck_sleep &hs1_i2s_data0_sleep + &hs1_i2s_data1_sleep>; + clocks = <&clock_gcc GCC_SDR_SEC_MI2S_CLK>; + clock-names = "sec_mi2s_clk"; + iommus = <&apps_smmu 0x035D 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; +}; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index e5f44ae56a8b5ded3b9d1b9ce03356eb1461af91..02fd42028944c91295177a8995f3fd70c89b1e59 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1859,6 +1859,77 @@ Example: "msm-dai-q6-auxpcm.2"; }; +* SDX ASoC Auto Machine driver + +Required properties: +- compatible : "qcom,sdx-asoc-snd-auto" +- qcom,model : The user-visible name of this sound card. +- qcom,prim_mi2s_aux_master : Handle to prim_master pinctrl configurations +- qcom,prim_mi2s_aux_slave : Handle to prim_slave pinctrl configurations +- qcom,sec_mi2s_aux_master : Handle to sec_master pinctrl configurations +- qcom,sec_mi2s_aux_slave : Handle to sec_slave pinctrl configurations +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order give + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". + +Example: + + sound-auto { + compatible = "qcom,sdx-asoc-snd-auto"; + qcom,model = "sdx-auto-i2s-snd-card"; + qcom,prim_mi2s_aux_master = <&prim_master>; + qcom,prim_mi2s_aux_slave = <&prim_slave>; + qcom,sec_mi2s_aux_master = <&sec_master>; + qcom,sec_mi2s_aux_slave = <&sec_slave>; + + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&hostless>, <&afe>, <&routing>, + <&pcm_dtmf>, <&host_pcm>, <&compress>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-voip-dsp", "msm-pcm-voice", + "msm-pcm-loopback", "msm-pcm-hostless", + "msm-pcm-afe", "msm-pcm-routing", + "msm-pcm-dtmf", "msm-voice-host-pcm", + "msm-compress-dsp"; + asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>, + <&dtmf_tx>, + <&rx_capture_tx>, <&rx_playback_rx>, + <&tx_capture_tx>, <&tx_playback_rx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_sec_auxpcm>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", + "msm-dai-stub-dev.6", "msm-dai-stub-dev.7", + "msm-dai-stub-dev.8", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-auxpcm.2"; + asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; + asoc-codec-names = "tlv320aic3x-codec", "msm-stub-codec.1"; + }; + * voice-mhi-audio Required properties: diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index ba5b45c483f5da6c3b1ced1d3d43416fc0f1851e..41fec22d6480d0851fc10aad3980c64675c16af4 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: -- gpio-reset - gpio pin number used for codec reset +- gpio-reset - gpio pin number used for codec reset, default active low +- reset-inverted - set the reset gpio mode as active high - ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality - Not supported on tlv320aic3104 - ai3x-micbias-vg - MicBias Voltage required. diff --git a/Documentation/devicetree/bindings/spmi/qcom,viospmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,viospmi-pmic-arb.txt new file mode 100644 index 0000000000000000000000000000000000000000..2221ecea91cd175234683d26a4721365cd2fe96b --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/qcom,viospmi-pmic-arb.txt @@ -0,0 +1,38 @@ +QTI Virtio SPMI controller (Virtio PMIC Arbiter) + +The Virtio SPMI PMIC Arbiter is a frontend proxy based on backend virtio device. + +Required properties: +- compatible : should be "qcom,viospmi-pmic-arb". +- #address-cells : must be set to 2 +- #size-cells : must be set to 0 +- interrupt-controller : boolean indicator that the PMIC arbiter is an interrupt controller +- #interrupt-cells : must be set to 4. Interrupts are specified as a 4-tuple: + cell 1: slave ID for the requested interrupt (0-15) + cell 2: peripheral ID for requested interrupt (0-255) + cell 3: the requested peripheral interrupt (0-7) + cell 4: interrupt flags indicating level-sense information, as defined in + dt-bindings/interrupt-controller/irq.h + +Example Virtio PMIC-Arbiter: + + spmi_bus: qcom,spmi { + compatible = "qcom,viospmi-pmic-arb"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + viospmi: virtio-spmi@c440000 { + compatible = "virtio,mmio"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xc440000 0x1100>; + interrupts = ; + status = "okay"; + }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt b/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt index 82da0186853255947e1f8b3dbba7538fea25e3be..8e5ba1b7e9140e6f667066d499d5c1b7f11c5168 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt @@ -26,11 +26,9 @@ Required Parameters: interrupt names will be used by the drivers to identify the interrupts, instead of specifying the ID's. bcl driver will accept these standard interrupts. - "bcl-ibat-lvl0", - "bcl-ibat-lvl1", - "bcl-vbat-lvl0", - "bcl-vbat-lvl1", - "bcl-vbat-lvl2", + "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2", Optional Parameters: - qcom,ibat-use-qg-adc-5a: This optional property is used to divide Ibat @@ -44,7 +42,7 @@ Example: reg = <0x4200 0x100>; interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>, <0x2 0x42 0x1 IRQ_TYPE_NONE>; - interrupt-names = "bcl-ibat-lvl0", - "bcl-vbat-lvl0"; + interrupt-names = "bcl-lvl0", + "bcl-lvl1"; qcom,ibat-use-qg-adc-5a; }; diff --git a/Documentation/devicetree/bindings/thermal/qti-qmi-sensor.txt b/Documentation/devicetree/bindings/thermal/qti-qmi-sensor.txt index 12cf0276805d5de308147ef6995611c05abbef89..e558027e9c916e606cf16727de43a3de2834250d 100644 --- a/Documentation/devicetree/bindings/thermal/qti-qmi-sensor.txt +++ b/Documentation/devicetree/bindings/thermal/qti-qmi-sensor.txt @@ -32,8 +32,8 @@ Subsystem properties: Definition: Remote sensor names. Below strings are the only acceptable sensor names, 1. pa - 2. pa1 - 3. pa2 + 2. pa_1 + 3. pa_2 4. qfe_pa0 5. qfe_wtr0 6. modem_tsens @@ -44,6 +44,19 @@ Subsystem properties: 11. xo_therm 12. qfe_pa_mdm 13. qfe_pa_wtr + 14. qfe_mmw_streamer0 + 15. qfe_mmw0_mod + 16. qfe_mmw1_mod + 17. qfe_mmw2_mod + 18. qfe_mmw3_mod + 19. qfe_ret_pa0 + 20. qfe_wtr_pa0 + 21. qfe_wtr_pa1 + 22. qfe_wtr_pa2 + 23. qfe_wtr_pa3 + 24. sys_therm1 + 25. sys_therm2 + 26. modem_tsens1 Example: diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index 12eb1f3ae1d79214f445d6f738c01378126f7478..0c451273a926b22df7450d0ac6fb756d16c4388f 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -29,6 +29,7 @@ Optional properties : - qcom,msm_bus,num_cases - qcom,msm_bus,num_paths - qcom,msm_bus,vectors +- qcom,default-bus-vote: To use default bus voting other than NOMINAL. Default is NOMINAL. - interrupt-names : Optional interrupt resource entries are: "ss_phy_irq" : Interrupt from super speed phy for wake up notification. "hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM. @@ -74,6 +75,8 @@ Optional properties : - qcom,gsi-reg-offset: USB GSI wrapper registers offset. It is must to provide this if qcom,num-gsi-evt-buffs property is specified. Check dwc3-msm driver for order and name of register offset need to provide. +- qcom,gsi-disable-io-coherency: IO-coherency is enabled by default in usb gsi driver. + This property disables io-coherency in usb gsi driver. - qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs, which is used as a vote by driver to get max performance in perf mode. - qcom,smmu-s1-bypass: If present, configure SMMU to bypass stage 1 translation. diff --git a/Documentation/driver-api/usb/power-management.rst b/Documentation/driver-api/usb/power-management.rst index 79beb807996b7a3a17e08b5f1d6e31d4176d3fc2..4a74cf6f2797274b96510685a44f4066fac558d3 100644 --- a/Documentation/driver-api/usb/power-management.rst +++ b/Documentation/driver-api/usb/power-management.rst @@ -370,11 +370,15 @@ autosuspend the interface's device. When the usage counter is = 0 then the interface is considered to be idle, and the kernel may autosuspend the device. -Drivers need not be concerned about balancing changes to the usage -counter; the USB core will undo any remaining "get"s when a driver -is unbound from its interface. As a corollary, drivers must not call -any of the ``usb_autopm_*`` functions after their ``disconnect`` -routine has returned. +Drivers must be careful to balance their overall changes to the usage +counter. Unbalanced "get"s will remain in effect when a driver is +unbound from its interface, preventing the device from going into +runtime suspend should the interface be bound to a driver again. On +the other hand, drivers are allowed to achieve this balance by calling +the ``usb_autopm_*`` functions even after their ``disconnect`` routine +has returned -- say from within a work-queue routine -- provided they +retain an active reference to the interface (via ``usb_get_intf`` and +``usb_put_intf``). Drivers using the async routines are responsible for their own synchronization and mutual exclusion. diff --git a/Documentation/gnsssirf/gnss_sirf.txt b/Documentation/gnsssirf/gnss_sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..77cc06a07374d5209dfc1c4d2ba9f55719073e3e --- /dev/null +++ b/Documentation/gnsssirf/gnss_sirf.txt @@ -0,0 +1,17 @@ +GNSS Driver for SiRFStar Chip +============================= + +Description: +This is a driver to handle SiRFStar GNSS chip power controls, a device node +is created to interact with driver power controls and exposes set of IOCTLs. +These IOCTLs provide mechanisms to transition of GNSS receiver power state. + +GPIO Usage: + probe will provide GPIO pins information to driver to control GNSS power + +Device Node Creation: + A device node is will be created as /dev/gnss_sirf + +Device Node Usage: + Device node /dev/gnss_sirf can be used to control ON_OFF & RESET pins of + SiRFStar GNSS receiver using exposed IOCTLS diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index ddf326e3fcb9063b4d5d6c1c6a7e3084f16b58aa..b56448cdbb10d621c498d4a7da797559ce799fd2 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -402,6 +402,7 @@ tcp_min_rtt_wlen - INTEGER minimum RTT when it is moved to a longer path (e.g., due to traffic engineering). A longer window makes the filter more resistant to RTT inflations such as transient congestion. The unit is seconds. + Possible values: 0 - 86400 (1 day) Default: 300 tcp_moderate_rcvbuf - BOOLEAN diff --git a/Makefile b/Makefile index ba5b7841ff78fe2f4bc1bd434bd2848a81d3a0a0..582c1acd42aea63d1eaa9bafc374d43e4f1cfaed 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 111 +SUBLEVEL = 117 EXTRAVERSION = NAME = Petit Gorille @@ -494,7 +494,7 @@ CLANG_FLAGS := --target=$(notdir $(CLANG_TRIPLE:%-=%)) ifeq ($(shell $(srctree)/scripts/clang-android.sh $(CC) $(CLANG_FLAGS)), y) $(error "Clang with Android --target detected. Did you specify CLANG_TRIPLE?") endif -GCC_TOOLCHAIN_DIR := $(dir $(shell which $(LD))) +GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit)) CLANG_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR) GCC_TOOLCHAIN := $(realpath $(GCC_TOOLCHAIN_DIR)/..) endif @@ -683,8 +683,7 @@ 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) -KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) +KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) else ifdef CONFIG_PROFILE_ALL_BRANCHES KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,) @@ -853,7 +852,7 @@ export LDFINAL_vmlinux LDFLAGS_FINAL_vmlinux endif ifdef CONFIG_CFI_CLANG -cfi-clang-flags += -fsanitize=cfi +cfi-clang-flags += -fsanitize=cfi $(call cc-option, -fsplit-lto-unit) DISABLE_CFI_CLANG := -fno-sanitize=cfi ifdef CONFIG_MODULES cfi-clang-flags += -fsanitize-cfi-cross-dso diff --git a/arch/arc/configs/hsdk_defconfig b/arch/arc/configs/hsdk_defconfig index 083560e9e571351ca7af9d9f031ffc37c53e3e64..4dac1169f528eda3e70d0e66edeea19940c4e5a0 100644 --- a/arch/arc/configs/hsdk_defconfig +++ b/arch/arc/configs/hsdk_defconfig @@ -9,6 +9,7 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_RAM=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S index 1f945d0f40daa4d5803428867d8111bb93ba14a0..208bf2c9e7b0d98b97e1778addd3bfea3e3424ce 100644 --- a/arch/arc/kernel/head.S +++ b/arch/arc/kernel/head.S @@ -107,6 +107,7 @@ ENTRY(stext) ; r2 = pointer to uboot provided cmdline or external DTB in mem ; These are handled later in handle_uboot_args() st r0, [@uboot_tag] + st r1, [@uboot_magic] st r2, [@uboot_arg] #endif diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 709649e5f9bc1ca4063bb5c273819c7e778765ba..6b8d106e0d53f78bbe684d1e09ff9e05db274748 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -35,6 +35,7 @@ unsigned int intr_to_DE_cnt; /* Part of U-boot ABI: see head.S */ int __initdata uboot_tag; +int __initdata uboot_magic; char __initdata *uboot_arg; const struct machine_desc *machine_desc; @@ -433,6 +434,8 @@ static inline bool uboot_arg_invalid(unsigned long addr) #define UBOOT_TAG_NONE 0 #define UBOOT_TAG_CMDLINE 1 #define UBOOT_TAG_DTB 2 +/* We always pass 0 as magic from U-boot */ +#define UBOOT_MAGIC_VALUE 0 void __init handle_uboot_args(void) { @@ -448,6 +451,11 @@ void __init handle_uboot_args(void) goto ignore_uboot_args; } + if (uboot_magic != UBOOT_MAGIC_VALUE) { + pr_warn(IGNORE_ARGS "non zero uboot magic\n"); + goto ignore_uboot_args; + } + if (uboot_tag != UBOOT_TAG_NONE && uboot_arg_invalid((unsigned long)uboot_arg)) { pr_warn(IGNORE_ARGS "invalid uboot arg: '%px'\n", uboot_arg); diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 03c122779783d36ee9c86936933b20ffee954362..f0de0b356cd4d39d79fd249bd252e237ae7d9285 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -1395,7 +1395,21 @@ ENTRY(efi_stub_entry) @ Preserve return value of efi_entry() in r4 mov r4, r0 - bl cache_clean_flush + + @ our cache maintenance code relies on CP15 barrier instructions + @ but since we arrived here with the MMU and caches configured + @ by UEFI, we must check that the CP15BEN bit is set in SCTLR. + @ Note that this bit is RAO/WI on v6 and earlier, so the ISB in + @ the enable path will be executed on v7+ only. + mrc p15, 0, r1, c1, c0, 0 @ read SCTLR + tst r1, #(1 << 5) @ CP15BEN bit set? + bne 0f + orr r1, r1, #(1 << 5) @ CP15 barrier instructions + mcr p15, 0, r1, c1, c0, 0 @ write SCTLR + ARM( .inst 0xf57ff06f @ v7+ isb ) + THUMB( isb ) + +0: bl cache_clean_flush bl cache_off @ Set parameters for booting zImage according to boot protocol diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index ddd897556e035b6306306ca33eccc65c7ed45e3b..478434ebff92dbc81ef3db42ab00808c442f8c35 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -57,6 +57,24 @@ enable-active-high; }; + /* TPS79501 */ + v1_8d_reg: fixedregulator-v1_8d { + compatible = "regulator-fixed"; + regulator-name = "v1_8d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* TPS79501 */ + v3_3d_reg: fixedregulator-v3_3d { + compatible = "regulator-fixed"; + regulator-name = "v3_3d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + matrix_keypad: matrix_keypad0 { compatible = "gpio-matrix-keypad"; debounce-delay-ms = <5>; @@ -492,10 +510,10 @@ status = "okay"; /* Regulators */ - AVDD-supply = <&vaux2_reg>; - IOVDD-supply = <&vaux2_reg>; - DRVDD-supply = <&vaux2_reg>; - DVDD-supply = <&vbat>; + AVDD-supply = <&v3_3d_reg>; + IOVDD-supply = <&v3_3d_reg>; + DRVDD-supply = <&v3_3d_reg>; + DVDD-supply = <&v1_8d_reg>; }; }; diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 9ba4b18c0cb21711dcd8ef60648a0916914819e7..bbd828892fcbf35668967afdce88fd54ebd67329 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -73,6 +73,24 @@ enable-active-high; }; + /* TPS79518 */ + v1_8d_reg: fixedregulator-v1_8d { + compatible = "regulator-fixed"; + regulator-name = "v1_8d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* TPS78633 */ + v3_3d_reg: fixedregulator-v3_3d { + compatible = "regulator-fixed"; + regulator-name = "v3_3d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + leds { pinctrl-names = "default"; pinctrl-0 = <&user_leds_s0>; @@ -493,10 +511,10 @@ status = "okay"; /* Regulators */ - AVDD-supply = <&vaux2_reg>; - IOVDD-supply = <&vaux2_reg>; - DRVDD-supply = <&vaux2_reg>; - DVDD-supply = <&vbat>; + AVDD-supply = <&v3_3d_reg>; + IOVDD-supply = <&v3_3d_reg>; + DRVDD-supply = <&v3_3d_reg>; + DVDD-supply = <&v1_8d_reg>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts index 4bc70efe43d6f227c60cb473d3a5d66c662eb6b7..3178a56649425a472e4eb6367bb8c343727c048e 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts @@ -93,7 +93,7 @@ }; &hdmi { - hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; }; &uart0 { diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi index 7ca291e9dbdb234b253d09b72fd1cb2a3f5aac71..80f1b3fb6abc37a7fd7474b9041993d7a8560853 100644 --- a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi +++ b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi @@ -222,7 +222,7 @@ pinctrl-2 = <&pinctrl_usdhc3_200mhz>; vmcc-supply = <®_sd3_vmmc>; cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; - bus-witdh = <4>; + bus-width = <4>; no-1-8-v; status = "okay"; }; @@ -233,7 +233,7 @@ pinctrl-1 = <&pinctrl_usdhc4_100mhz>; pinctrl-2 = <&pinctrl_usdhc4_200mhz>; vmcc-supply = <®_sd4_vmmc>; - bus-witdh = <8>; + bus-width = <8>; no-1-8-v; non-removable; status = "okay"; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi index d81b0078a100feb882703bec5c395dc709305ba8..25b0704c60549bbeb323282729f82d81b08f7430 100644 --- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi @@ -89,6 +89,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; + phy-reset-duration = <10>; /* in msecs */ phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; phy-supply = <&vdd_eth_io_reg>; status = "disabled"; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index f7a951afd28118947249a53df726b4a9245b348f..5a7888581eea916725a5cc09bf561c170e329984 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -1181,27 +1181,27 @@ gpu_opp_table: gpu-opp-table { compatible = "operating-points-v2"; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <950000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <950000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <1000000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1100000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <1200000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <1250000>; }; diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h index e57191fb83de895ae0675966b2b3319410f7ed99..9daa6dfd71e0d9ea816068858737b29536c62f7d 100644 --- a/arch/arm/boot/dts/sama5d2-pinfunc.h +++ b/arch/arm/boot/dts/sama5d2-pinfunc.h @@ -518,7 +518,7 @@ #define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0) #define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 1, 3) #define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 2, 1) -#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 2, 1) +#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 3, 1) #define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 4, 2) #define PIN_PC10 74 #define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0) diff --git a/arch/arm/configs/sa515m-perf_defconfig b/arch/arm/configs/sa515m-perf_defconfig new file mode 120000 index 0000000000000000000000000000000000000000..f15877fab05a30d62d3dc91a19713877c732af1f --- /dev/null +++ b/arch/arm/configs/sa515m-perf_defconfig @@ -0,0 +1 @@ +vendor/sa515m-perf_defconfig \ No newline at end of file diff --git a/arch/arm/configs/sa515m_defconfig b/arch/arm/configs/sa515m_defconfig new file mode 120000 index 0000000000000000000000000000000000000000..16aa13f597709e84147428e406317c4dca14ed79 --- /dev/null +++ b/arch/arm/configs/sa515m_defconfig @@ -0,0 +1 @@ +vendor/sa515m_defconfig \ No newline at end of file diff --git a/arch/arm/configs/sdxprairie-auto-perf_defconfig b/arch/arm/configs/sdxprairie-auto-perf_defconfig deleted file mode 120000 index bea718d54c271c8b3afae172347ec71f59916de5..0000000000000000000000000000000000000000 --- a/arch/arm/configs/sdxprairie-auto-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sdxprairie-auto-perf_defconfig \ No newline at end of file diff --git a/arch/arm/configs/sdxprairie-auto_defconfig b/arch/arm/configs/sdxprairie-auto_defconfig deleted file mode 120000 index 3c219277895bce438555a07e2126a4893e428149..0000000000000000000000000000000000000000 --- a/arch/arm/configs/sdxprairie-auto_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sdxprairie-auto_defconfig \ No newline at end of file diff --git a/arch/arm/configs/vendor/qcs403-perf_defconfig b/arch/arm/configs/vendor/qcs403-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..4c5728f6771ce478bd42c718aaec484e0a558fa4 --- /dev/null +++ b/arch/arm/configs/vendor/qcs403-perf_defconfig @@ -0,0 +1,369 @@ +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_RELAY=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_QCS403=y +# CONFIG_VDSO is not set +CONFIG_SMP=y +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_IPV6_SIT is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +# CONFIG_NF_CONNTRACK_PROCFS is not set +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_LOG_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_LOG_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_EMATCH=y +CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_BT=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 +CONFIG_NTAG_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_QPNP_MISC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_PHYLIB=y +CONFIG_AT803X_PHY=y +CONFIG_PPP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_ASYNC=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_HS=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_QCS405=y +CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_RPM_SMD_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +# CONFIG_USB_HID is not set +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MSM_SNPS_FEMTO_PHY=y +CONFIG_USB_MSM_SSPHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_PARANOID_SD_INIT=y +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_PCA9956B=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_SYNC_FILE=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MDM_DEBUGCC_QCS405=y +CONFIG_CLOCK_CPU_QCS405=y +CONFIG_QCS_CMN_BLK_PLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_SMD=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_TZ_SMMU=y +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_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QTI_MPM=y +CONFIG_PHY_QCOM_UFS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_DAX=y +CONFIG_MSM_TZ_LOG=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_STACKTRACE=y +# CONFIG_FTRACE is not set +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/vendor/qcs403_defconfig b/arch/arm/configs/vendor/qcs403_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..ac217a92deb3bb943ee57d4139b79b3a489c2915 --- /dev/null +++ b/arch/arm/configs/vendor/qcs403_defconfig @@ -0,0 +1,571 @@ +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_QCS403=y +# CONFIG_VDSO is not set +CONFIG_SMP=y +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_HIGHMEM=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_ARP=y +CONFIG_BRIDGE_EBT_IP=y +CONFIG_BRIDGE_EBT_IP6=y +CONFIG_BRIDGE_EBT_ARPREPLY=y +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_BT=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 +CONFIG_NTAG_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +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 +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AT803X_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_DEBUG=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_QCS405=y +CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_RPM_SMD_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_PLATFORM=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MSM_SNPS_FEMTO_PHY=y +CONFIG_USB_MSM_SSPHY=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +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_PCA9956B=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MDM_DEBUGCC_QCS405=y +CONFIG_CLOCK_CPU_QCS405=y +CONFIG_QCS_CMN_BLK_PLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_IOMMU=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_SMD=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_TZ_SMMU=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +# CONFIG_MSM_JTAGV8 is not set +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=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 +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/vendor/qcs405-perf_defconfig b/arch/arm/configs/vendor/qcs405-perf_defconfig index 1ab1d99cd67d0c90b40f0d531f3705f614859992..8042c3000e0d4814feeb01bcb9018a8957e25355 100644 --- a/arch/arm/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm/configs/vendor/qcs405-perf_defconfig @@ -37,6 +37,7 @@ CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_QCS405=y +CONFIG_ARCH_QCS403=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_ARM_PSCI=y diff --git a/arch/arm/configs/vendor/qcs405_defconfig b/arch/arm/configs/vendor/qcs405_defconfig index f8fcf714bd3799eaf8e35315b92dca4f25752c4b..4a06454d869932320026be5c697c4f542de31f21 100644 --- a/arch/arm/configs/vendor/qcs405_defconfig +++ b/arch/arm/configs/vendor/qcs405_defconfig @@ -39,6 +39,7 @@ CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_QCS405=y +CONFIG_ARCH_QCS403=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_ARM_PSCI=y diff --git a/arch/arm/configs/vendor/sdxprairie-auto-perf_defconfig b/arch/arm/configs/vendor/sa515m-perf_defconfig similarity index 98% rename from arch/arm/configs/vendor/sdxprairie-auto-perf_defconfig rename to arch/arm/configs/vendor/sa515m-perf_defconfig index 8dc781b377725514b8ddaa0e227dbb47a61ed3bb..c726917d76cbc79f5cf8aa3de93802946c0a9b3b 100644 --- a/arch/arm/configs/vendor/sdxprairie-auto-perf_defconfig +++ b/arch/arm/configs/vendor/sa515m-perf_defconfig @@ -156,8 +156,12 @@ CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y CONFIG_QRTR=y +CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y +CONFIG_QRTR_MHI_DEV=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y CONFIG_BT=y # CONFIG_BT_BREDR is not set # CONFIG_BT_LE is not set @@ -186,6 +190,7 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_QSEECOM=y +CONFIG_EEPROM_AT24=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -209,6 +214,7 @@ CONFIG_RMNET=y # CONFIG_NET_VENDOR_SMSC is not set # CONFIG_NET_VENDOR_STMICRO is not set CONFIG_AT803X_PHY=y +CONFIG_MICREL_PHY=y CONFIG_PPP=y CONFIG_PPP_ASYNC=y CONFIG_USB_USBNET=y @@ -242,6 +248,8 @@ CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=m CONFIG_SPMI=y CONFIG_SLIMBUS=y +CONFIG_PPS=y +CONFIG_PPS_CLIENT_GPIO=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDXPRAIRIE=y CONFIG_GPIOLIB=y @@ -275,6 +283,7 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_SOC=y +CONFIG_SND_SOC_TLV320AIC3X=y CONFIG_UHID=y CONFIG_HID_APPLE=y CONFIG_HID_ELECOM=y diff --git a/arch/arm/configs/vendor/sdxprairie-auto_defconfig b/arch/arm/configs/vendor/sa515m_defconfig similarity index 98% rename from arch/arm/configs/vendor/sdxprairie-auto_defconfig rename to arch/arm/configs/vendor/sa515m_defconfig index ae512352a79d05725a456274d227a23c47b2420a..5041ddd15f9f816cf81badc2cf20142ca88823b7 100644 --- a/arch/arm/configs/vendor/sdxprairie-auto_defconfig +++ b/arch/arm/configs/vendor/sa515m_defconfig @@ -156,8 +156,12 @@ CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y CONFIG_QRTR=y +CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y +CONFIG_QRTR_MHI_DEV=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y CONFIG_BT=y # CONFIG_BT_BREDR is not set # CONFIG_BT_LE is not set @@ -184,6 +188,7 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_QSEECOM=y +CONFIG_EEPROM_AT24=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -207,6 +212,7 @@ CONFIG_RMNET=y # CONFIG_NET_VENDOR_SMSC is not set # CONFIG_NET_VENDOR_STMICRO is not set CONFIG_AT803X_PHY=y +CONFIG_MICREL_PHY=y CONFIG_PPP=y CONFIG_PPP_ASYNC=y CONFIG_USB_USBNET=y @@ -242,6 +248,8 @@ CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=m CONFIG_SPMI=y CONFIG_SLIMBUS=y +CONFIG_PPS=y +CONFIG_PPS_CLIENT_GPIO=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDXPRAIRIE=y CONFIG_GPIOLIB=y @@ -276,6 +284,7 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_SOC=y +CONFIG_SND_SOC_TLV320AIC3X=y CONFIG_UHID=y CONFIG_HID_APPLE=y CONFIG_HID_ELECOM=y diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index d629857a60fe118494723de80d8b6cba5ce83e5f..ccd851bd5dca7a3d5cc889af41de0f458fc59350 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -156,8 +156,10 @@ CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y CONFIG_QRTR=y +CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y +CONFIG_QRTR_MHI_DEV=y CONFIG_BT=y # CONFIG_BT_BREDR is not set # CONFIG_BT_LE is not set @@ -379,6 +381,9 @@ CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDXPRAIRIE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_QMI_RMNET=y +CONFIG_QCOM_QMI_DFC=y +CONFIG_QCOM_QMI_POWER_COLLAPSE=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 04b5b0310ce40361e6835c92896407a4a1555c25..994ee3ad74b9b818b2e605af00d0c6f5a8b9d437 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -156,8 +156,10 @@ CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y CONFIG_QRTR=y +CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y +CONFIG_QRTR_MHI_DEV=y CONFIG_BT=y # CONFIG_BT_BREDR is not set # CONFIG_BT_LE is not set @@ -384,6 +386,9 @@ CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDXPRAIRIE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_QMI_RMNET=y +CONFIG_QCOM_QMI_DFC=y +CONFIG_QCOM_QMI_POWER_COLLAPSE=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y diff --git a/arch/arm/crypto/sha256-armv4.pl b/arch/arm/crypto/sha256-armv4.pl index fac0533ea633e9803dea6b6ee6a6f019c48c5196..f64e8413ab9a63868630e3c7b5ef8cbe4fa1bed4 100644 --- a/arch/arm/crypto/sha256-armv4.pl +++ b/arch/arm/crypto/sha256-armv4.pl @@ -205,10 +205,11 @@ K256: .global sha256_block_data_order .type sha256_block_data_order,%function sha256_block_data_order: +.Lsha256_block_data_order: #if __ARM_ARCH__<7 sub r3,pc,#8 @ sha256_block_data_order #else - adr r3,sha256_block_data_order + adr r3,.Lsha256_block_data_order #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ldr r12,.LOPENSSL_armcap diff --git a/arch/arm/crypto/sha256-core.S_shipped b/arch/arm/crypto/sha256-core.S_shipped index 555a1a8eec90ae37bbf5d3b0ad6f7fdde1967f81..72c248081d27235edd790564fbf1e8b555f22247 100644 --- a/arch/arm/crypto/sha256-core.S_shipped +++ b/arch/arm/crypto/sha256-core.S_shipped @@ -86,10 +86,11 @@ K256: .global sha256_block_data_order .type sha256_block_data_order,%function sha256_block_data_order: +.Lsha256_block_data_order: #if __ARM_ARCH__<7 sub r3,pc,#8 @ sha256_block_data_order #else - adr r3,sha256_block_data_order + adr r3,.Lsha256_block_data_order #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ldr r12,.LOPENSSL_armcap diff --git a/arch/arm/crypto/sha512-armv4.pl b/arch/arm/crypto/sha512-armv4.pl index a2b11a84435776aca76fc4f479a95468a252964d..5fe336420bcf73d2e8fb7d2c96f4d6b6703c87ba 100644 --- a/arch/arm/crypto/sha512-armv4.pl +++ b/arch/arm/crypto/sha512-armv4.pl @@ -267,10 +267,11 @@ WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) .global sha512_block_data_order .type sha512_block_data_order,%function sha512_block_data_order: +.Lsha512_block_data_order: #if __ARM_ARCH__<7 sub r3,pc,#8 @ sha512_block_data_order #else - adr r3,sha512_block_data_order + adr r3,.Lsha512_block_data_order #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ldr r12,.LOPENSSL_armcap diff --git a/arch/arm/crypto/sha512-core.S_shipped b/arch/arm/crypto/sha512-core.S_shipped index 3694c4d4ca2bcfd8c0b083946c23493c036e348e..de9bd7f55242f63d44c35e03949f6468740372f6 100644 --- a/arch/arm/crypto/sha512-core.S_shipped +++ b/arch/arm/crypto/sha512-core.S_shipped @@ -134,10 +134,11 @@ WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) .global sha512_block_data_order .type sha512_block_data_order,%function sha512_block_data_order: +.Lsha512_block_data_order: #if __ARM_ARCH__<7 sub r3,pc,#8 @ sha512_block_data_order #else - adr r3,sha512_block_data_order + adr r3,.Lsha512_block_data_order #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ldr r12,.LOPENSSL_armcap diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 93260648840847f09ea444832f2d4c99a358513b..c61b1db9e4c947958e9285b03e6f3f9e4f8c17c6 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -401,6 +401,24 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define writesw(p,d,l) __raw_writesw(p,d,l) #define writesl(p,d,l) __raw_writesl(p,d,l) +#define readb_no_log(c) \ + ({ u8 __v = readb_relaxed_no_log(c); __iormb(); __v; }) +#define readw_no_log(c) \ + ({ u16 __v = readw_relaxed_no_log(c); __iormb(); __v; }) +#define readl_no_log(c) \ + ({ u32 __v = readl_relaxed_no_log(c); __iormb(); __v; }) +#define readq_no_log(c) \ + ({ u64 __v = readq_relaxed_no_log(c); __iormb(); __v; }) + +#define writeb_no_log(v, c) \ + ({ __iowmb(); writeb_relaxed_no_log((v), (c)); }) +#define writew_no_log(v, c) \ + ({ __iowmb(); writew_relaxed_no_log((v), (c)); }) +#define writel_no_log(v, c) \ + ({ __iowmb(); writel_relaxed_no_log((v), (c)); }) +#define writeq_no_log(v, c) \ + ({ __iowmb(); writeq_relaxed_no_log((v), (c)); }) + #ifndef __ARMBE__ static inline void memset_io(volatile void __iomem *dst, unsigned c, size_t count) diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c index a50dc00d79a273fac9e5d5c3f8be75f37231f766..d0a05a3bdb9652450ea4a6e1cdc6036c945ab42a 100644 --- a/arch/arm/kernel/patch.c +++ b/arch/arm/kernel/patch.c @@ -16,7 +16,7 @@ struct patch { unsigned int insn; }; -static DEFINE_SPINLOCK(patch_lock); +static DEFINE_RAW_SPINLOCK(patch_lock); static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags) __acquires(&patch_lock) @@ -33,7 +33,7 @@ static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags) return addr; if (flags) - spin_lock_irqsave(&patch_lock, *flags); + raw_spin_lock_irqsave(&patch_lock, *flags); else __acquire(&patch_lock); @@ -48,7 +48,7 @@ static void __kprobes patch_unmap(int fixmap, unsigned long *flags) clear_fixmap(fixmap); if (flags) - spin_unlock_irqrestore(&patch_lock, *flags); + raw_spin_unlock_irqrestore(&patch_lock, *flags); else __release(&patch_lock); } diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c index 53c316f7301e69fcbebbfe5d73bb48664180f5b6..fe4932fda01d7d0bc819c0ca4e6dcedb6b061081 100644 --- a/arch/arm/mach-iop13xx/setup.c +++ b/arch/arm/mach-iop13xx/setup.c @@ -300,7 +300,7 @@ static struct resource iop13xx_adma_2_resources[] = { } }; -static u64 iop13xx_adma_dmamask = DMA_BIT_MASK(64); +static u64 iop13xx_adma_dmamask = DMA_BIT_MASK(32); static struct iop_adma_platform_data iop13xx_adma_0_data = { .hw_id = 0, .pool_size = PAGE_SIZE, @@ -324,7 +324,7 @@ static struct platform_device iop13xx_adma_0_channel = { .resource = iop13xx_adma_0_resources, .dev = { .dma_mask = &iop13xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = (void *) &iop13xx_adma_0_data, }, }; @@ -336,7 +336,7 @@ static struct platform_device iop13xx_adma_1_channel = { .resource = iop13xx_adma_1_resources, .dev = { .dma_mask = &iop13xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = (void *) &iop13xx_adma_1_data, }, }; @@ -348,7 +348,7 @@ static struct platform_device iop13xx_adma_2_channel = { .resource = iop13xx_adma_2_resources, .dev = { .dma_mask = &iop13xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = (void *) &iop13xx_adma_2_data, }, }; diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c index db511ec2b1df6824cb6d3d24659cfebe2428d5ec..116feb6b261eb7b0e08ee7ce248e44682e537898 100644 --- a/arch/arm/mach-iop13xx/tpmi.c +++ b/arch/arm/mach-iop13xx/tpmi.c @@ -152,7 +152,7 @@ static struct resource iop13xx_tpmi_3_resources[] = { } }; -u64 iop13xx_tpmi_mask = DMA_BIT_MASK(64); +u64 iop13xx_tpmi_mask = DMA_BIT_MASK(32); static struct platform_device iop13xx_tpmi_0_device = { .name = "iop-tpmi", .id = 0, @@ -160,7 +160,7 @@ static struct platform_device iop13xx_tpmi_0_device = { .resource = iop13xx_tpmi_0_resources, .dev = { .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; @@ -171,7 +171,7 @@ static struct platform_device iop13xx_tpmi_1_device = { .resource = iop13xx_tpmi_1_resources, .dev = { .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; @@ -182,7 +182,7 @@ static struct platform_device iop13xx_tpmi_2_device = { .resource = iop13xx_tpmi_2_resources, .dev = { .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; @@ -193,7 +193,7 @@ static struct platform_device iop13xx_tpmi_3_device = { .resource = iop13xx_tpmi_3_resources, .dev = { .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index fc17977d52a2b1f814aac518d723f8f75c986534..8b77bab0f1793fff103b2360693f134b1f72b384 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -2,7 +2,7 @@ if ARCH_QCOM menu "QCOM SoC Type" config ARCH_QCS405 - bool "Enable Support for QCS405" + bool "Enable Support for QCS405" select CLKDEV_LOOKUP select HAVE_CLK select HAVE_CLK_PREPARE @@ -37,6 +37,42 @@ config ARCH_QCS405 This enables support for the QCS405 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. +config ARCH_QCS403 + bool "Enable Support for QCS403" + select CLKDEV_LOOKUP + select HAVE_CLK + select HAVE_CLK_PREPARE + select PM_OPP + select SOC_BUS + select MSM_IRQ + select THERMAL_WRITABLE_TRIPS + select ARM_GIC + select ARM_AMBA + select SPARSE_IRQ + select MULTI_IRQ_HANDLER + select HAVE_ARM_ARCH_TIMER + select MAY_HAVE_SPARSE_IRQ + select COMMON_CLK + select QCOM_GDSC + select PINCTRL_MSM + select USE_PINCTRL_IRQ + select MSM_PM if PM + select QMI_ENCDEC + select CPU_FREQ + select CPU_FREQ_MSM + select PM_DEVFREQ + select MSM_DEVFREQ_DEVBW + select DEVFREQ_SIMPLE_DEV + select DEVFREQ_GOV_MSM_BW_HWMON + select MSM_BIMC_BWMON + select MSM_QDSP6V2_CODECS + select MSM_AUDIO_QDSP6V2 if SND_SOC + select MSM_RPM_SMD + select MSM_JTAGV8 if CORESIGHT_ETMV4 + help + This enables support for the QCS403 chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + config ARCH_MSM8X60 bool "Enable support for MSM8X60" select ARCH_SUPPORTS_BIG_ENDIAN diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile index 23af561084b8abc58369834d3f7dbd914ff0042d..27a323e0bee7c30df1f2f848678b415c49c7c4c5 100644 --- a/arch/arm/mach-qcom/Makefile +++ b/arch/arm/mach-qcom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_USE_OF) += board-dt.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_ARCH_QCS405) += board-qcs405.o +obj-$(CONFIG_ARCH_QCS403) += board-qcs403.o obj-$(CONFIG_ARCH_SDXPRAIRIE) += board-sdxprairie.o diff --git a/arch/arm/mach-qcom/board-qcs403.c b/arch/arm/mach-qcom/board-qcs403.c new file mode 100644 index 0000000000000000000000000000000000000000..dec88c6f9742b98fd216212805fdbe7f7736b1fe --- /dev/null +++ b/arch/arm/mach-qcom/board-qcs403.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "board-dt.h" +#include +#include + +static const char *qcs403_dt_match[] __initconst = { + "qcom,qcs403", + "qcom,qcs404", + NULL +}; + +static void __init qcs403_init(void) +{ + board_dt_populate(NULL); +} + +DT_MACHINE_START(QCS403_DT, + "Qualcomm Technologies, Inc. QCS403 (Flattened Device Tree)") + .init_machine = qcs403_init, + .dt_compat = qcs403_dt_match, +MACHINE_END diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 204a63061aa64f3994c6529a505f642eb4a95009..1a4d48a38416983bda13420e2c6f04789dc4aceb 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2718,10 +2718,13 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, if (dev->dma_ops) return; - if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu)) + if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu)) { dma_ops = arm_get_iommu_dma_map_ops(coherent); - else + dev->archdata.dma_ops_setup = true; + } else { dma_ops = arm_get_dma_map_ops(coherent); + dev->archdata.dma_ops_setup = false; + } set_dma_ops(dev, dma_ops); @@ -2731,7 +2734,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, dev->dma_ops = xen_dma_ops; } #endif - dev->archdata.dma_ops_setup = true; } EXPORT_SYMBOL(arch_setup_dma_ops); diff --git a/arch/arm/plat-iop/adma.c b/arch/arm/plat-iop/adma.c index a4d1f8de3b5b23453ee4738723164a5ba8405424..d9612221e4848971f4ea27cf4f5d4c319073e439 100644 --- a/arch/arm/plat-iop/adma.c +++ b/arch/arm/plat-iop/adma.c @@ -143,7 +143,7 @@ struct platform_device iop3xx_dma_0_channel = { .resource = iop3xx_dma_0_resources, .dev = { .dma_mask = &iop3xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = (void *) &iop3xx_dma_0_data, }, }; @@ -155,7 +155,7 @@ struct platform_device iop3xx_dma_1_channel = { .resource = iop3xx_dma_1_resources, .dev = { .dma_mask = &iop3xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = (void *) &iop3xx_dma_1_data, }, }; @@ -167,7 +167,7 @@ struct platform_device iop3xx_aau_channel = { .resource = iop3xx_aau_resources, .dev = { .dma_mask = &iop3xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = (void *) &iop3xx_aau_data, }, }; diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index a2399fd66e97cef3db011508dc73c718c9456bc9..1e970873439cdd9812ba9d6ad974ea150d173b31 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -622,7 +622,7 @@ static struct platform_device orion_xor0_shared = { .resource = orion_xor0_shared_resources, .dev = { .dma_mask = &orion_xor_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &orion_xor0_pdata, }, }; @@ -683,7 +683,7 @@ static struct platform_device orion_xor1_shared = { .resource = orion_xor1_shared_resources, .dev = { .dma_mask = &orion_xor_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(64), + .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &orion_xor1_pdata, }, }; diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index e8229b9fee4a107a8ea180420df98141910b1879..3265b8f860694fefd06bf010e31f4a3fe45e9d4b 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -258,7 +258,7 @@ config S3C_PM_DEBUG_LED_SMDK config SAMSUNG_PM_CHECK bool "S3C2410 PM Suspend Memory CRC" - depends on PM + depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210) select CRC32 help Enable the PM code's memory area checksum over sleep. This option diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 6ce416f15959e32e6591c6491023e3b26eced588..1b524f2c04330b8226f5808b4a9f343ed6d3d0f2 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -186,6 +186,16 @@ config ARCH_QCS405 If you do not wish to build a kernel that runs on this chipset, say 'N' here. +config ARCH_QCS403 + bool "Enable Support for Qualcomm Technologies, Inc. QCS403" + depends on ARCH_QCOM + select COMMON_CLK_QCOM + help + This configuration option enables support to build kernel for + QCS403 SoC. + If you do not wish to build a kernel that runs on this chipset, + say 'N' here. + config ARCH_SDMMAGPIE bool "Enable Support for Qualcomm Technologies, Inc. SDMMAGPIE" depends on ARCH_QCOM diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 1450e40b1bb3250b052c57e6812a8a11dd06f7ac..d2437bdc70159dfa187d77b6374c55ec68d51bca 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -6,27 +6,26 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8916-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8992-bullhead-rev-101.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb -ifeq ($(CONFIG_ARM64),y) -dtb-$(CONFIG_ARCH_QCS405) += qcs405-rumi.dtb \ - qcs405-iot-sku1.dtb \ - qcs405-iot-sku2.dtb \ + +dtb-$(CONFIG_ARCH_QCS403) += qcs403-iot-sku1.dtb \ + qcs403-iot-sku3.dtb \ + qcs403-iot-sku5.dtb \ + qcs401-iot-sku5.dtb \ + qcs404-iot-sku3.dtb \ + qcs404-iot-sku5.dtb \ + qcs404-iot-sku6.dtb + +dtb-$(CONFIG_ARCH_QCS405) += qcs405-iot-sku1.dtb \ + qcs407-iot-sku1.dtb \ qcs405-iot-sku3.dtb \ + qcs407-iot-sku3.dtb \ qcs405-iot-sku4.dtb \ - qcs405-iot-sku5.dtb \ + qcs407-iot-sku4.dtb \ qcs405-iot-sku6.dtb \ - qcs405-iot-sku7.dtb \ - qcs405-iot-sku8.dtb \ - qcs405-iot-sku9.dtb \ - qcs405-iot-sku10.dtb \ - qcs405-iot-sku11.dtb \ + qcs407-iot-sku6.dtb \ + qcs407-iot-sku9.dtb \ qcs405-iot-sku12.dtb \ - qcs401-iot-sku1.dtb -else -dtb-$(CONFIG_ARCH_QCS405) += qcs403-iot-sku1.dtb \ - qcs403-iot-sku2.dtb \ - qcs403-iot-sku3.dtb \ - qcs403-iot-sku4.dtb -endif + qcs407-iot-sku12.dtb ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) dtbo-$(CONFIG_ARCH_SM8150) += \ @@ -101,6 +100,8 @@ endif dtb-$(CONFIG_QTI_GVM) += sa8155-vm.dtb \ sa8155-vm-lv.dtb \ + sa8155-vm-lv-mt.dtb \ + sa8155-vm-la-mt.dtb \ sa6155p-vm.dtb \ sa8195-vm.dtb @@ -244,11 +245,17 @@ endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) dtbo-$(CONFIG_ARCH_ATOLL) += \ - atoll-rumi-overlay.dtbo\ + atoll-idp-overlay.dtbo\ + atoll-qrd-overlay.dtbo\ + atoll-rumi-overlay.dtbo +atoll-idp-overlay.dtbo-base := atoll.dtb +atoll-qrd-overlay.dtbo-base := atoll.dtb atoll-rumi-overlay.dtbo-base := atoll.dtb else -dtb-$(CONFIG_ARCH_ATOLL) += atoll-rumi.dtb +dtb-$(CONFIG_ARCH_ATOLL) += atoll-idp.dtb\ + atoll-qrd.dtb\ + atoll-rumi.dtb endif dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ @@ -256,12 +263,17 @@ dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ sdxprairie-dsda-cdp.dtb \ sdxprairie-mtp.dtb \ sdxprairie-pcie-ep-mtp.dtb \ + sdxprairie-mtp-cpe.dtb \ + sdxprairie-cdp-cpe.dtb \ sdxprairie-cdp-256.dtb \ sdxprairie-mtp-256.dtb \ sdxprairie-mtp-aqc.dtb \ sdxprairie-dsda-mtp.dtb \ sdxprairie-v2-cdp.dtb \ - sdxprairie-v2-mtp.dtb + sdxprairie-v2-mtp.dtb \ + sa515m-ccard.dtb \ + sa515m-ccard-pcie-ep.dtb \ + sa515m-ccard-usb-ep.dtb ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) diff --git a/arch/arm64/boot/dts/qcom/atoll-bus.dtsi b/arch/arm64/boot/dts/qcom/atoll-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..105b298ce10b0d94c93ab3c2004fb27ad009f411 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-bus.dtsi @@ -0,0 +1,1994 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x16E0000 0x15080>, + <0x1700000 0x1F880>, + <0x1500000 0x28000>, + <0x9160000 0x03200>, + <0x9680000 0x3E200>, + <0x1620000 0x4000>, + <0x1740000 0x1C100>, + <0x1620000 0x17080>, + <0x1620000 0x4000>, + <0x1700000 0x1F880>, + <0x9990000 0x1600>, + <0x1620000 0x4000>; + + reg-names = "aggre1_noc-base", "aggre2_noc-base", + "config_noc-base", "dc_noc-base", + "gem_noc-base", "mc_virt-base", + "mmss_noc-base", "system_noc-base", + "ipa_virt-base", "compute_noc-base", + "npu_noc-base", "qup_virt-base"; + + mbox-names = "apps_rsc", "disp_rsc"; + mboxes = <&apps_rsc 0 &disp_rsc 0>; + + /*RSCs*/ + rsc_apps: rsc-apps { + cell-id = ; + label = "apps_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + rsc_disp: rsc-disp { + cell-id = ; + label = "disp_rsc"; + qcom,rsc-dev; + qcom,req_state = <3>; + }; + + /*BCMs*/ + bcm_acv: bcm-acv { + cell-id = ; + label = "ACV"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_alc: bcm-alc { + cell-id = ; + label = "ALC"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mc0: bcm-mc0 { + cell-id = ; + label = "MC0"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh0: bcm-sh0 { + cell-id = ; + label = "SH0"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm0: bcm-mm0 { + cell-id = ; + label = "MM0"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co0: bcm-co0 { + cell-id = ; + label = "CO0"; + qcom,bcm-name = "CO0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ce0: bcm-ce0 { + cell-id = ; + label = "CE0"; + qcom,bcm-name = "CE0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn0: bcm-cn0 { + cell-id = ; + label = "CN0"; + qcom,bcm-name = "CN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm1: bcm-mm1 { + cell-id = ; + label = "MM1"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn1: bcm-cn1 { + cell-id = ; + label = "CN1"; + qcom,bcm-name = "CN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh2: bcm-sh2 { + cell-id = ; + label = "SH2"; + qcom,bcm-name = "SH2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm2: bcm-mm2 { + cell-id = ; + label = "MM2"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co2: bcm-co2 { + cell-id = ; + label = "CO2"; + qcom,bcm-name = "CO2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_qup0: bcm-qup0 { + cell-id = ; + label = "QUP0"; + qcom,bcm-name = "QUP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh3: bcm-sh3 { + cell-id = ; + label = "SH3"; + qcom,bcm-name = "SH3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co3: bcm-co3 { + cell-id = ; + label = "CO3"; + qcom,bcm-name = "CO3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh4: bcm-sh4 { + cell-id = ; + label = "SH4"; + qcom,bcm-name = "SH4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn0: bcm-sn0 { + cell-id = ; + label = "SN0"; + qcom,bcm-name = "SN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn2: bcm-sn2 { + cell-id = ; + label = "SN2"; + qcom,bcm-name = "SN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn4: bcm-sn4 { + cell-id = ; + label = "SN4"; + qcom,bcm-name = "SN4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn7: bcm-sn7 { + cell-id = ; + label = "SN7"; + qcom,bcm-name = "SN7"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn9: bcm-sn9 { + cell-id = ; + label = "SN9"; + qcom,bcm-name = "SN9"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn10: bcm-sn10 { + cell-id = ; + label = "SN10"; + qcom,bcm-name = "SN10"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn12: bcm-sn12 { + cell-id = ; + label = "SN12"; + qcom,bcm-name = "SN12"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_acv_display: bcm-acv_display { + cell-id = ; + label = "ACV_DISPLAY"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_alc_display: bcm-alc_display { + cell-id = ; + label = "ALC_DISPLAY"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mc0_display: bcm-mc0_display { + cell-id = ; + label = "MC0_DISPLAY"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_sh0_display: bcm-sh0_display { + cell-id = ; + label = "SH0_DISPLAY"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm0_display: bcm-mm0_display { + cell-id = ; + label = "MM0_DISPLAY"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm1_display: bcm-mm1_display { + cell-id = ; + label = "MM1_DISPLAY"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm2_display: bcm-mm2_display { + cell-id = ; + label = "MM2_DISPLAY"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + /*Buses*/ + fab_aggre1_noc: fab-aggre1_noc { + cell-id = ; + label = "fab-aggre1_noc"; + qcom,fab-dev; + qcom,base-name = "aggre1_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_aggre2_noc: fab-aggre2_noc { + cell-id = ; + label = "fab-aggre2_noc"; + qcom,fab-dev; + qcom,base-name = "aggre2_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <20480>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_compute_noc: fab-compute_noc { + cell-id = ; + label = "fab-compute_noc"; + qcom,fab-dev; + qcom,base-name = "compute_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <57344>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_dc_noc: fab-dc_noc { + cell-id = ; + label = "fab-dc_noc"; + qcom,fab-dev; + qcom,base-name = "dc_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc: fab-gem_noc { + cell-id = ; + label = "fab-gem_noc"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <176128>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_ipa_virt: fab-ipa_virt { + cell-id = ; + label = "fab-ipa_virt"; + qcom,fab-dev; + qcom,base-name = "ipa_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mc_virt: fab-mc_virt { + cell-id = ; + label = "fab-mc_virt"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mmss_noc: fab-mmss_noc { + cell-id = ; + label = "fab-mmss_noc"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_npu_noc: fab-npu_noc { + cell-id = ; + label = "fab-npu_noc"; + qcom,fab-dev; + qcom,base-name = "npu_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_qup_virt: fab-qup_virt { + cell-id = ; + label = "fab-qup_virt"; + qcom,fab-dev; + qcom,base-name = "qup_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_system_noc: fab-system_noc { + cell-id = ; + label = "fab-system_noc"; + qcom,fab-dev; + qcom,base-name = "system_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <45056>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc_display: fab-gem_noc_display { + cell-id = ; + label = "fab-gem_noc_display"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <176128>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mc_virt_display: fab-mc_virt_display { + cell-id = ; + label = "fab-mc_virt_display"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mmss_noc_display: fab-mmss_noc_display { + cell-id = ; + label = "fab-mmss_noc_display"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + /*Masters*/ + mas_qhm_a1noc_cfg: mas-qhm-a1noc-cfg { + cell-id = ; + label = "mas-qhm-a1noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre1_noc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_qhm_qspi: mas-qhm-qspi { + cell-id = ; + label = "mas-qhm-qspi"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup_0: mas-qhm-qup-0 { + cell-id = ; + label = "mas-qhm-qup-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_emmc: mas-xm-emmc { + cell-id = ; + label = "mas-xm-emmc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg { + cell-id = ; + label = "mas-qhm-a2noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre2_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup_1: mas-qhm-qup-1 { + cell-id = ; + label = "mas-qhm-qup-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_ce0>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qnm_npu: mas-qnm-npu { + cell-id = ; + label = "mas-qnm-npu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <1 3>; + qcom,connections = <&slv_qns_cdsp_gemnoc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co2>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_npu_dsp: mas-qxm-npu-dsp { + cell-id = ; + label = "mas-qxm-npu-dsp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_cdsp_gemnoc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc: mas-qnm-snoc { + cell-id = ; + label = "mas-qnm-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_tlmm_3 &slv_qhs_tlmm_2 + &slv_qhs_camera_cfg &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_qm_cfg &slv_qhs_snoc_cfg + &slv_qhs_qm_mpu_cfg &slv_qhs_glm &slv_qhs_pdm + &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_a2_noc_cfg &slv_qhs_qdss_cfg + &slv_qhs_vsense_ctrl_cfg + &slv_qhs_camera_rt_throttle_cfg + &slv_qhs_npu_dsp_throttle_cfg + &slv_qhs_display_cfg &slv_qhs_qspi + &slv_qhs_display_throttle_cfg &slv_qhs_tlmm_1 + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg + &slv_qhs_display_rt_throttle_cfg + &slv_qhs_ahb2phy2 &slv_qhs_npu_cfg + &slv_qhs_ahb2phy0 &slv_qhs_gpuss_cfg + &slv_qhs_boot_rom &slv_qhs_venus_cfg + &slv_qhs_ipa &slv_qhs_security + &slv_qhs_aop &slv_qhs_imem_cfg + &slv_qhs_mss_cfg &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_venus_throttle_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_npu_dma_throttle_cfg &slv_qhs_emmc_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_cpr_mx &slv_qhs_qup0 + &slv_qhs_qup1 &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_xm_qdss_dap: mas-xm-qdss-dap { + cell-id = ; + label = "mas-xm-qdss-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_tlmm_3 &slv_qhs_tlmm_2 + &slv_qhs_camera_cfg &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_qm_cfg &slv_qhs_snoc_cfg + &slv_qhs_qm_mpu_cfg &slv_qhs_glm &slv_qhs_pdm + &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_a2_noc_cfg &slv_qhs_qdss_cfg + &slv_qhs_vsense_ctrl_cfg + &slv_qhs_camera_rt_throttle_cfg + &slv_qhs_npu_dsp_throttle_cfg + &slv_qhs_display_cfg &slv_qhs_qspi + &slv_qhs_display_throttle_cfg &slv_qhs_tlmm_1 + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg + &slv_qhs_display_rt_throttle_cfg + &slv_qhs_ahb2phy2 &slv_qhs_npu_cfg + &slv_qhs_ahb2phy0 &slv_qhs_gpuss_cfg + &slv_qhs_boot_rom &slv_qhs_venus_cfg + &slv_qhs_ipa &slv_qhs_security + &slv_qhs_aop &slv_qhs_imem_cfg + &slv_qhs_mss_cfg &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_venus_throttle_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_npu_dma_throttle_cfg &slv_qhs_emmc_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_cpr_mx &slv_qhs_qup0 + &slv_qhs_qup1 &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qhm_cnoc_dc_noc: mas-qhm-cnoc-dc-noc { + cell-id = ; + label = "mas-qhm-cnoc-dc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_llcc &slv_qhs_gemnoc>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + mas_acm_apps: mas-acm-apps { + cell-id = ; + label = "mas-acm-apps"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <96 98>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh4>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_acm_sys_tcu: mas-acm-sys-tcu { + cell-id = ; + label = "mas-acm-sys-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <384>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh2>; + qcom,ap-owned; + qcom,prio = <6>; + }; + + mas_qhm_gemnoc_cfg: mas-qhm-gemnoc-cfg { + cell-id = ; + label = "mas-qhm-gemnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_gemnoc + &slv_qhs_mdsp_ms_mpu_cfg>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + mas_qnm_cmpnoc: mas-qnm-cmpnoc { + cell-id = ; + label = "mas-qnm-cmpnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <64>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { + cell-id = ; + label = "mas-qnm-mnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <128>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { + cell-id = ; + label = "mas-qnm-mnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <320>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <192>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc_sf: mas-qnm-snoc-sf { + cell-id = ; + label = "mas-qnm-snoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <160>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_gpu: mas-qxm-gpu { + cell-id = ; + label = "mas-qxm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <288 289>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_ipa_core_master: mas-ipa-core-master { + cell-id = ; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ipa_core_slave>; + qcom,bus-dev = <&fab_ipa_virt>; + }; + + mas_llcc_mc: mas-llcc-mc { + cell-id = ; + label = "mas-llcc-mc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_mc_virt>; + }; + + mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { + cell-id = ; + label = "mas-qhm-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_hf: mas-qxm-camnoc-hf { + cell-id = ; + label = "mas-qxm-camnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <1 2>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { + cell-id = ; + label = "mas-qxm-camnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_rot: mas-qxm-rot { + cell-id = ; + label = "mas-qxm-rot"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus0: mas-qxm-venus0 { + cell-id = ; + label = "mas-qxm-venus0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus_arm9: mas-qxm-venus-arm9 { + cell-id = ; + label = "mas-qxm-venus-arm9"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <5>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_amm_npu_sys: mas-amm-npu-sys { + cell-id = ; + label = "mas-amm-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_npu_sys>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qhm_npu_cfg: mas-qhm-npu-cfg { + cell-id = ; + label = "mas-qhm-npu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_noc &slv_qhs_isense + &slv_qhs_llm &slv_qhs_dma_bwmon &slv_qhs_cp + &slv_qhs_tcm &slv_qhs_cal_dp0 + &slv_qhs_dpm>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qup_core_master_0: mas-qup-core-master-0 { + cell-id = ; + label = "mas-qup-core-master-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup_core_slave_0>; + qcom,bus-dev = <&fab_qup_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qup_core_master_1: mas-qup-core-master-1 { + cell-id = ; + label = "mas-qup-core-master-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup_core_slave_1>; + qcom,bus-dev = <&fab_qup_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { + cell-id = ; + label = "mas-qhm-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qnm_aggre1_noc: mas-qnm-aggre1-noc { + cell-id = ; + label = "mas-qnm-aggre1-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf &slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss &slv_qns_cnoc + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn7>; + }; + + mas_qnm_aggre2_noc: mas-qnm-aggre2-noc { + cell-id = ; + label = "mas-qnm-aggre2-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf &slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn9>; + }; + + mas_qnm_gemnoc: mas-qnm-gemnoc { + cell-id = ; + label = "mas-qnm-gemnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn12>; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_gemnoc_gc &slv_qxs_imem>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn2>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display { + cell-id = ; + label = "mas-qnm-mnoc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <128>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display { + cell-id = ; + label = "mas-qnm-mnoc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <320>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_llcc_mc_display: mas-llcc-mc_display { + cell-id = ; + label = "mas-llcc-mc_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi_display>; + qcom,bus-dev = <&fab_mc_virt_display>; + }; + + mas_qxm_mdp0_display: mas-qxm-mdp0_display { + cell-id = ; + label = "mas-qxm-mdp0_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_rot_display: mas-qxm-rot_display { + cell-id = ; + label = "mas-qxm-rot_display"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_mem_noc_sf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + /*Slaves*/ + slv_qns_a1noc_snoc:slv-qns-a1noc-snoc { + cell-id = ; + label = "slv-qns-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_aggre1_noc>; + }; + + slv_srvc_aggre1_noc:slv-srvc-aggre1-noc { + cell-id = ; + label = "slv-srvc-aggre1-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + slv_qns_a2noc_snoc:slv-qns-a2noc-snoc { + cell-id = ; + label = "slv-qns-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_aggre2_noc>; + }; + + slv_srvc_aggre2_noc:slv-srvc-aggre2-noc { + cell-id = ; + label = "slv-srvc-aggre2-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + slv_qns_cdsp_gemnoc:slv-qns-cdsp-gemnoc { + cell-id = ; + label = "slv-qns-cdsp-gemnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,connections = <&mas_qnm_cmpnoc>; + qcom,bcms = <&bcm_co0>; + }; + + slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg { + cell-id = ; + label = "slv-qhs-a1-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a1noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_a2_noc_cfg:slv-qhs-a2-noc-cfg { + cell-id = ; + label = "slv-qhs-a2-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a2noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy0:slv-qhs-ahb2phy0 { + cell-id = ; + label = "slv-qhs-ahb2phy0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy2:slv-qhs-ahb2phy2 { + cell-id = ; + label = "slv-qhs-ahb2phy2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_aop:slv-qhs-aop { + cell-id = ; + label = "slv-qhs-aop"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_aoss:slv-qhs-aoss { + cell-id = ; + label = "slv-qhs-aoss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_boot_rom:slv-qhs-boot-rom { + cell-id = ; + label = "slv-qhs-boot-rom"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_cfg:slv-qhs-camera-cfg { + cell-id = ; + label = "slv-qhs-camera-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_nrt_throttle_cfg:slv-qhs-camera-nrt-thrott-cfg { + cell-id = ; + label = "slv-qhs-camera-nrt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_rt_throttle_cfg:slv-qhs-camera-rt-throttle-cfg { + cell-id = ; + label = "slv-qhs-camera-rt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_cx:slv-qhs-cpr-cx { + cell-id = ; + label = "slv-qhs-cpr-cx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_mx:slv-qhs-cpr-mx { + cell-id = ; + label = "slv-qhs-cpr-mx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_dcc_cfg:slv-qhs-dcc-cfg { + cell-id = ; + label = "slv-qhs-dcc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ddrss_cfg:slv-qhs-ddrss-cfg { + cell-id = ; + label = "slv-qhs-ddrss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cnoc_dc_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_cfg:slv-qhs-display-cfg { + cell-id = ; + label = "slv-qhs-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_rt_throttle_cfg:slv-qhs-display-rt-throt-cfg { + cell-id = ; + label = "slv-qhs-display-rt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_throttle_cfg:slv-qhs-display-throttle-cfg { + cell-id = ; + label = "slv-qhs-display-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_emmc_cfg:slv-qhs-emmc-cfg { + cell-id = ; + label = "slv-qhs-emmc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_glm:slv-qhs-glm { + cell-id = ; + label = "slv-qhs-glm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg { + cell-id = ; + label = "slv-qhs-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg { + cell-id = ; + label = "slv-qhs-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_mnoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mss_cfg:slv-qhs-mss-cfg { + cell-id = ; + label = "slv-qhs-mss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_npu_cfg:slv-qhs-npu-cfg { + cell-id = ; + label = "slv-qhs-npu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_npu_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_npu_dma_throttle_cfg:slv-qhs-npu-dma-throttle-cfg { + cell-id = ; + label = "slv-qhs-npu-dma-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_npu_dsp_throttle_cfg:slv-qhs-npu-dsp-throttle-cfg { + cell-id = ; + label = "slv-qhs-npu-dsp-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qm_cfg:slv-qhs-qm-cfg { + cell-id = ; + label = "slv-qhs-qm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qm_mpu_cfg:slv-qhs-qm-mpu-cfg { + cell-id = ; + label = "slv-qhs-qm-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qspi:slv-qhs-qspi { + cell-id = ; + label = "slv-qhs-qspi"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_qup0:slv-qhs-qup0 { + cell-id = ; + label = "slv-qhs-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup1:slv-qhs-qup1 { + cell-id = ; + label = "slv-qhs-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_security:slv-qhs-security { + cell-id = ; + label = "slv-qhs-security"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_snoc_cfg:slv-qhs-snoc-cfg { + cell-id = ; + label = "slv-qhs-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_snoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_1:slv-qhs-tlmm-1 { + cell-id = ; + label = "slv-qhs-tlmm-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_2:slv-qhs-tlmm-2 { + cell-id = ; + label = "slv-qhs-tlmm-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_3:slv-qhs-tlmm-3 { + cell-id = ; + label = "slv-qhs-tlmm-3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg { + cell-id = ; + label = "slv-qhs-ufs-mem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_usb3_0:slv-qhs-usb3-0 { + cell-id = ; + label = "slv-qhs-usb3-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_throttle_cfg:slv-qhs-venus-throttle-cfg { + cell-id = ; + label = "slv-qhs-venus-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gemnoc:slv-qhs-gemnoc { + cell-id = ; + label = "slv-qhs-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + qcom,connections = <&mas_qhm_gemnoc_cfg>; + }; + + slv_qhs_llcc:slv-qhs-llcc { + cell-id = ; + label = "slv-qhs-llcc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + slv_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mdsp-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_qns_gem_noc_snoc:slv-qns-gem-noc-snoc { + cell-id = ; + label = "slv-qns-gem-noc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_qnm_gemnoc>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_srvc_gemnoc:slv-srvc-gemnoc { + cell-id = ; + label = "slv-srvc-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_ipa_virt>; + qcom,bcms = <&bcm_ip0>; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_mc0>, <&bcm_acv>; + }; + + slv_qns_mem_noc_hf:slv-qns-mem-noc-hf { + cell-id = ; + label = "slv-qns-mem-noc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_hf>; + qcom,bcms = <&bcm_mm0>; + }; + + slv_qns_mem_noc_sf:slv-qns-mem-noc-sf { + cell-id = ; + label = "slv-qns-mem-noc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_sf>; + qcom,bcms = <&bcm_mm2>; + }; + + slv_srvc_mnoc:slv-srvc-mnoc { + cell-id = ; + label = "slv-srvc-mnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + slv_qhs_cal_dp0:slv-qhs-cal-dp0 { + cell-id = ; + label = "slv-qhs-cal-dp0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_cp:slv-qhs-cp { + cell-id = ; + label = "slv-qhs-cp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dma_bwmon:slv-qhs-dma-bwmon { + cell-id = ; + label = "slv-qhs-dma-bwmon"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dpm:slv-qhs-dpm { + cell-id = ; + label = "slv-qhs-dpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_isense:slv-qhs-isense { + cell-id = ; + label = "slv-qhs-isense"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_llm:slv-qhs-llm { + cell-id = ; + label = "slv-qhs-llm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_tcm:slv-qhs-tcm { + cell-id = ; + label = "slv-qhs-tcm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qns_npu_sys:slv-qns-npu-sys { + cell-id = ; + label = "slv-qns-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_srvc_noc:slv-srvc-noc { + cell-id = ; + label = "slv-srvc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qup_core_slave_0:slv-qup-core-slave-0 { + cell-id = ; + label = "slv-qup-core-slave-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_qup_virt>; + }; + + slv_qup_core_slave_1:slv-qup-core-slave-1 { + cell-id = ; + label = "slv-qup-core-slave-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_qup_virt>; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_cnoc:slv-qns-cnoc { + cell-id = ; + label = "slv-qns-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc>; + }; + + slv_qns_gemnoc_gc:slv-qns-gemnoc-gc { + cell-id = ; + label = "slv-qns-gemnoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_gc>; + qcom,bcms = <&bcm_sn2>; + }; + + slv_qns_gemnoc_sf:slv-qns-gemnoc-sf { + cell-id = ; + label = "slv-qns-gemnoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_sf>; + qcom,bcms = <&bcm_sn0>; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn1>; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_llcc_display:slv-qns-llcc_display { + cell-id = ; + label = "slv-qns-llcc_display"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc_display>; + qcom,connections = <&mas_llcc_mc_display>; + qcom,bcms = <&bcm_sh0_display>; + }; + + slv_ebi_display:slv-ebi_display { + cell-id = ; + label = "slv-ebi_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mc_virt_display>; + qcom,bcms = <&bcm_mc0_display>, <&bcm_acv_display>; + }; + + slv_qns_mem_noc_hf_display:slv-qns-mem-noc-hf_display { + cell-id = ; + label = "slv-qns-mem-noc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_hf_display>; + qcom,bcms = <&bcm_mm0_display>; + }; + + slv_qns_mem_noc_sf_display:slv-qns-mem-noc-sf_display { + cell-id = ; + label = "slv-qns-mem-noc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_sf_display>; + qcom,bcms = <&bcm_mm2_display>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-camera.dtsi b/arch/arm64/boot/dts/qcom/atoll-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..05665defb5b28381d201eb418f542ffdf4816af4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-camera.dtsi @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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"; + }; + + 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 0xd80 0x20>, + <&apps_smmu 0xda0 0x20>; + 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 0x0ce2 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 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + 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 = <0x10A00000>; + 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 = <0x10B11000>; + iova-region-len = <0xCF4EF000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 64K */ + iova-region-name = "qdss"; + iova-region-start = <0x10B00000>; + 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 0x0d60 0x0>, + <&apps_smmu 0x0d61 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 = <0x150110>; /* Titan v150 v1.1.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,cam-cx-ipeak = <&cx_ipeak_lm 2>; + 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", "csiphy3", + "csid0", "csid1", "csid2", "cci0", + "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_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "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-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + icp_pc_en; + 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"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; + 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 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; + 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 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + 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 469 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 270000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 480000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + ppi-enable; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife", "cam_camnoc"; + reg = <0xacaf000 0x4000>, + <0xac42000 0x5000>; + reg-cam-base = <0xaf000 0x42000>; + 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 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "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 270000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 480000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + ppi-enable; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife", "cam_camnoc"; + reg = <0xacb6000 0x4000>, + <0xac42000 0x5000>; + reg-cam-base = <0xb6000 0x42000>; + 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 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "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 473 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 270000000 0 0 0 360000000 0>, + <0 0 0 0 0 0 480000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + ppi-enable; + 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 472 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 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + 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 600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "turbo"; + 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 600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "turbo"; + status = "ok"; + }; + + cam_ppi0: qcom,ppi0@ace0000 { + cell-index = <0>; + compatible = "qcom,ppi170"; + reg-names = "ppi"; + reg = <0xace0000 0x200>; + reg-cam-base = <0xe0000>; + interrupt-names = "ppi"; + interrupts = <0 170 0>; + clocks = <&clock_camcc CAM_CC_CSIPHY0_CLK>; + clock-names = "csiphy0_clk"; + status = "ok"; + }; + + cam_ppi1: qcom,ppi0@ace0200 { + cell-index = <1>; + compatible = "qcom,ppi170"; + reg-names = "ppi"; + reg = <0xace0200 0x200>; + reg-cam-base = <0xe0200>; + interrupt-names = "ppi"; + interrupts = <0 171 0>; + clocks = <&clock_camcc CAM_CC_CSIPHY1_CLK>; + clock-names = "csiphy1_clk"; + status = "ok"; + }; + + cam_ppi2: qcom,ppi0@ace0400 { + cell-index = <2>; + compatible = "qcom,ppi170"; + reg-names = "ppi"; + reg = <0xace0400 0x200>; + reg-cam-base = <0xe0400>; + interrupt-names = "ppi"; + interrupts = <0 172 0>; + clocks = <&clock_camcc CAM_CC_CSIPHY2_CLK>; + clock-names = "csiphy2_clk"; + status = "ok"; + }; + + cam_ppi3: qcom,ppi0@ace0600 { + cell-index = <3>; + compatible = "qcom,ppi170"; + reg-names = "ppi"; + reg = <0xace0600 0x200>; + reg-cam-base = <0xe00600>; + interrupt-names = "ppi"; + interrupts = <0 173 0>; + clocks = <&clock_camcc CAM_CC_CSIPHY3_CLK>; + clock-names = "csiphy3_clk"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-coresight.dtsi b/arch/arm64/boot/dts/qcom/atoll-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..30469db9e54b534f7a3a3b9a3c69c51cf95efd8e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-coresight.dtsi @@ -0,0 +1,2979 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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>; + }; + + audio_etm0: audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-audio-etm0"; + + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_audio_etm0>; + }; + }; + }; + + tpdm_lpass_lpi: tpdm@6b26000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-lpass-lpi"; + qcom,dummy-source; + + port { + tpdm_lpss_lpi_out_funnel_swao: endpoint { + remote-endpoint = <&funnel_swao_in_tpdm_lpass_lpi>; + }; + }; + }; + + tpdm_swao_0: tpdm@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b09000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_swao_0_out_tpda_swao0: endpoint { + remote-endpoint = + <&tpda_swao0_in_tpdm_swao_0>; + }; + }; + }; + + tpdm_swao_1: tpdm@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b0a000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_swao_1_out_tpda_swao1: endpoint { + remote-endpoint = + <&tpda_swao1_in_tpdm_swao_1>; + }; + }; + }; + + tpdm_vsense: tpdm@6834000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6834000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_vsense_out_tpda21: endpoint { + remote-endpoint = + <&tpda21_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@6870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6870000 0x1000>; + reg-names = "tpdm-base"; + + qcom,hw-enable-check; + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dcc_out_tpda22: endpoint { + remote-endpoint = + <&tpda22_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_tpda23: endpoint { + remote-endpoint = + <&tpda23_in_tpdm_prng>; + }; + }; + }; + + 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_tpda24: endpoint { + remote-endpoint = + <&tpda24_in_tpdm_qm>; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6844000 0x1000>; + reg-names = "tpdm-base"; + + qcom,msr-fix-req; + coresight-name = "coresight-tpdm-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_lpass_out_funnel_lpass: endpoint { + remote-endpoint = + <&funnel_lpass_in_tpdm_lpass>; + }; + }; + }; + + tpdm_npu: tpdm@6c47000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c47000 0x1000>; + reg-names = "tpdm-base"; + status = "disabled"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_npu_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_tpdm_npu>; + }; + }; + }; + + tpdm_npu_llm: tpdm@6c40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c40000 0x1000>; + reg-names = "tpdm-base"; + + status = "disabled"; + coresight-name = "coresight-tpdm-npu-llm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_npu_llm_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_tpdm_npu_llm>; + }; + }; + }; + + tpdm_npu_dpm: tpdm@6c41000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c41000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu-dpm"; + + status = "disabled"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_npu_dpm_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_tpdm_npu_dpm>; + }; + }; + }; + + npu_etm0: npu_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-npu-etm0"; + + qcom,inst-id = <14>; + + port { + npu_etm0_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_npu_etm0>; + }; + }; + }; + + tpdm_mdss: tpdm@6c60000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c60000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mdss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_mdss_out_funnel_dlnt: endpoint { + remote-endpoint = + <&funnel_dlnt_in_tpdm_mdss>; + }; + }; + }; + + tpdm_dl_north: tpdm@6ac0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6ac0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dl_north_out_funnel_dlnt: endpoint { + remote-endpoint = + <&funnel_dlnt_in_tpdm_dl_north>; + }; + }; + }; + + tpdm_nav: tpdm@6842000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6842000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-nav"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_nav_out_tpda_nav0: endpoint { + remote-endpoint = + <&tpda_nav0_in_tpdm_nav>; + }; + }; + }; + + modem_etm0: modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm0"; + + qcom,inst-id = <11>; + + port { + modem_etm0_out_funnel_dlnt: endpoint { + remote-endpoint = + <&funnel_dlnt_in_modem_etm0>; + }; + }; + }; + + tpdm_modem_0: tpdm@6800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6800000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_modem_0_out_tpda_modem0: endpoint { + remote-endpoint = + <&tpda_modem0_in_tpdm_modem_0>; + }; + }; + }; + + tpdm_modem_1: tpdm@6804000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6804000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_modem_1_out_tpda_modem1: endpoint { + remote-endpoint = + <&tpda_modem1_in_tpdm_modem_1>; + }; + }; + }; + + tpdm_dlct: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dlct"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dlct_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_tpdm_dlct>; + }; + }; + }; + + 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_dl_center16: endpoint { + remote-endpoint = + <&tpda_dl_center16_in_tpdm_pimem>; + }; + }; + }; + + tpdm_gpu: tpdm@6940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6940000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gpu"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_gpu_out_funnel_gpu: endpoint { + remote-endpoint = + <&funnel_gpu_in_tpdm_gpu>; + }; + }; + }; + + tpdm_ddr: tpdm@6f80000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6f80000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + qcom,msr-fix-req; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_ddr_out_funnel_ddr0: endpoint { + remote-endpoint = + <&funnel_ddr0_in_tpdm_ddr>; + }; + }; + }; + + tpdm_turing: tpdm@6980000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + tpdm_turing_llm: tpdm@6981000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6981000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing-llm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_turing_llm_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing_llm>; + }; + }; + }; + + turing_etm0: turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-turing-etm0"; + + qcom,inst-id = <13>; + + port { + turing_etm0_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_turing_etm0>; + }; + }; + }; + + tpdm_wcss: tpdm@69a4000 { + 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>; + }; + }; + }; + + etm0: tpdm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + qcom,tupwr-disable; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: tpdm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + qcom,tupwr-disable; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: tpdm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + qcom,tupwr-disable; + 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: tpdm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + qcom,tupwr-disable; + 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: tpdm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + coresight-name = "coresight-etm4"; + + qcom,tupwr-disable; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: tpdm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + coresight-name = "coresight-etm5"; + + qcom,tupwr-disable; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: tpdm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + coresight-name = "coresight-etm6"; + + qcom,tupwr-disable; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: tpdm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + coresight-name = "coresight-etm7"; + + qcom,tupwr-disable; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm7>; + }; + }; + }; + + 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_olc0: endpoint { + remote-endpoint = + <&tpda_olc0_in_tpdm_olc>; + }; + }; + }; + + 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_silver0: endpoint { + remote-endpoint = + <&tpda_llm_silver0_in_tpdm_llm_silver>; + }; + }; + }; + + 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_gold0: endpoint { + remote-endpoint = + <&tpda_llm_gold0_in_tpdm_llm_gold>; + }; + }; + }; + + 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_apss0: endpoint { + remote-endpoint = + <&tpda_apss0_in_tpdm_apss>; + }; + }; + }; + + funnel_lpass: funnel@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6846000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_lpass_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_funnel_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_lpass_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_lpass>; + }; + }; + + }; + }; + + funnel_npu: funnel@6c44000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6c44000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-npu"; + + status = "disabled"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_npu_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_funnel_npu>; + }; + }; + + port@1 { + reg = <0>; + funnel_npu_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_funnel_npu>; + }; + }; + + port@2 { + reg = <1>; + funnel_npu_in_tpdm_npu_llm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_llm_out_funnel_npu>; + }; + }; + + port@3 { + reg = <2>; + funnel_npu_in_tpdm_npu_dpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_dpm_out_funnel_npu>; + }; + }; + + port@4 { + reg = <3>; + funnel_npu_in_npu_etm0: endpoint { + slave-mode; + remote-endpoint = + <&npu_etm0_out_funnel_npu>; + }; + }; + + }; + }; + + tpda_nav: tpda@6843000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6843000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-nav"; + qcom,tpda-atid = <68>; + 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_nav_out_funnel_dlnt: endpoint { + remote-endpoint = + <&funnel_dlnt_in_tpda_nav>; + }; + }; + + port@1 { + reg = <0>; + tpda_nav0_in_tpdm_nav: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_nav_out_tpda_nav0>; + }; + }; + + }; + }; + + tpda_modem0: tpda@6801000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6801000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem0"; + 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_modem0_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem0>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem0_in_tpdm_modem_0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_0_out_tpda_modem0>; + }; + }; + + }; + }; + + tpda_modem1: tpda@6803000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6803000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem1"; + qcom,tpda-atid = <98>; + 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_modem1_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem1>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem1_in_tpdm_modem_1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_1_out_tpda_modem1>; + }; + }; + + }; + }; + + funnel_modem: funnel@6802000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6802000 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_dlnt: endpoint { + remote-endpoint = + <&funnel_dlnt_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem0: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem0_out_funnel_modem>; + }; + }; + + port@2 { + reg = <1>; + funnel_modem_in_tpda_modem1: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem1_out_funnel_modem>; + }; + }; + + }; + }; + + funnel_dlnt: funnel@6ac5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6ac5000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlnt"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dlnt_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_funnel_dlnt>; + }; + }; + + port@1 { + reg = <0>; + funnel_dlnt_in_tpdm_mdss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mdss_out_funnel_dlnt>; + }; + }; + + port@2 { + reg = <1>; + funnel_dlnt_in_tpdm_dl_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_north_out_funnel_dlnt>; + }; + }; + + port@3 { + reg = <2>; + funnel_dlnt_in_tpda_nav: endpoint { + slave-mode; + remote-endpoint = + <&tpda_nav_out_funnel_dlnt>; + }; + }; + + port@4 { + reg = <5>; + funnel_dlnt_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_dlnt>; + }; + }; + + port@5 { + reg = <6>; + funnel_dlnt_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_dlnt>; + }; + }; + + }; + }; + + funnel_dlct0: funnel@6c2d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6c2d000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlct0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dlct0_out_tpda2: endpoint { + remote-endpoint = + <&tpda2_in_funnel_dlct0>; + source = <&tpdm_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_dlct0_out_tpda11: endpoint { + remote-endpoint = + <&tpda11_in_funnel_dlct0>; + source = <&tpdm_npu>; + }; + }; + + port@2 { + reg = <0>; + funnel_dlct0_out_tpda12: endpoint { + remote-endpoint = + <&tpda12_in_funnel_dlct0>; + source = <&tpdm_npu_llm>; + }; + }; + + port@3 { + reg = <0>; + funnel_dlct0_out_tpda13: endpoint { + remote-endpoint = + <&tpda13_in_funnel_dlct0>; + source = <&tpdm_npu_dpm>; + }; + }; + + port@4 { + reg = <0>; + funnel_dlct0_out_tpda14: endpoint { + remote-endpoint = + <&tpda14_in_funnel_dlct0>; + source = <&tpdm_mdss>; + }; + }; + + port@5 { + reg = <0>; + funnel_dlct0_out_tpda15: endpoint { + remote-endpoint = + <&tpda15_in_funnel_dlct0>; + source = <&tpdm_dl_north>; + }; + }; + + port@6 { + reg = <0>; + funnel_dlct0_out_tpda19: endpoint { + remote-endpoint = + <&tpda19_in_funnel_dlct0>; + source = <&tpdm_dlct>; + }; + }; + + port@7 { + reg = <0>; + funnel_dlct0_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_dlct0>; + }; + }; + + port@8 { + reg = <0>; + funnel_dlct0_in_funnel_lpass: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_out_funnel_dlct0>; + }; + }; + + port@9 { + reg = <4>; + funnel_dlct0_in_funnel_npu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_npu_out_funnel_dlct0>; + }; + }; + + port@10 { + reg = <5>; + funnel_dlct0_in_funnel_dlnt: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlnt_out_funnel_dlct0>; + }; + }; + + port@11 { + reg = <6>; + funnel_dlct0_in_tpdm_dlct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct_out_funnel_dlct0>; + }; + }; + + }; + }; + + funnel_gpu: funnel@6944000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6944000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gpu"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_gpu_out_tpda_dl_center: endpoint { + remote-endpoint = + <&tpda_dl_center_in_funnel_gpu>; + }; + }; + + port@1 { + reg = <0>; + funnel_gpu_in_tpdm_gpu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gpu_out_funnel_gpu>; + }; + }; + + }; + }; + + funnel_ddr0: funnel@6f85000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6f85000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_ddr0_out_tpda_dl_center: endpoint { + remote-endpoint = + <&tpda_dl_center_in_funnel_ddr0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr0>; + }; + }; + + }; + }; + + funnel_turing: funnel@6983000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6983000 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_dl_center5: endpoint { + remote-endpoint = + <&tpda_dl_center5_in_funnel_turing>; + source = <&tpdm_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_out_tpda_dl_center6: endpoint { + remote-endpoint = + <&tpda_dl_center6_in_funnel_turing>; + source = <&tpdm_turing_llm>; + }; + }; + + port@2 { + reg = <0>; + funnel_turing_out_funnel_dlct1: endpoint { + remote-endpoint = + <&funnel_dlct1_in_funnel_turing>; + }; + }; + + port@3 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + + port@4 { + reg = <1>; + funnel_turing_in_tpdm_turing_llm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_llm_out_funnel_turing>; + }; + }; + + port@5 { + reg = <2>; + funnel_turing_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing>; + }; + }; + + }; + }; + + tpda_dl_center: tpda@6c38000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6c38000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-dl-center"; + qcom,tpda-atid = <78>; + qcom,dsb-elem-size = <0 32>, + <3 32>, + <5 32>, + <16 32>; + qcom,cmb-elem-size = <3 32>, + <6 32>, + <16 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_dl_center_out_funnel_dlct1: endpoint { + remote-endpoint = + <&funnel_dlct1_in_tpda_dl_center>; + }; + }; + + port@1 { + reg = <16>; + tpda_dl_center16_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda_dl_center16>; + }; + }; + + port@2 { + reg = <0>; + tpda_dl_center_in_funnel_gpu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gpu_out_tpda_dl_center>; + }; + }; + + port@3 { + reg = <3>; + tpda_dl_center_in_funnel_ddr0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr0_out_tpda_dl_center>; + }; + }; + + port@4 { + reg = <5>; + tpda_dl_center5_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda_dl_center5>; + }; + }; + + port@5 { + reg = <6>; + tpda_dl_center6_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda_dl_center6>; + }; + }; + + }; + }; + + funnel_dlct1: funnel@6c39000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6c39000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlct1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dlct1_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_dlct1>; + }; + }; + + port@1 { + reg = <0>; + funnel_dlct1_in_tpda_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&tpda_dl_center_out_funnel_dlct1>; + }; + }; + + port@2 { + reg = <4>; + funnel_dlct1_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_funnel_dlct1>; + }; + }; + + }; + }; + + 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_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_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>; + }; + }; + + }; + }; + + 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_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_olc>; + }; + }; + + port@1 { + reg = <0>; + tpda_olc0_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc0>; + }; + }; + + }; + }; + + 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_silver_out_funnel_apss_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver0_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver0>; + }; + }; + + }; + }; + + 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_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold0_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold0>; + }; + }; + + }; + }; + + 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_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss0_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss0>; + }; + }; + + }; + }; + + funnel_apss_merge: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merge"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss_merge_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merge>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merge_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merge>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merge_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merge>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merge_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_silver_out_funnel_apss_merge>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merge_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merge>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merge_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merge>; + }; + }; + + }; + }; + + 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 = <16 32>, + <24 32>, + <25 32>; + qcom,tc-elem-size = <16 32>, + <25 32>; + qcom,dsb-elem-size = <2 32>, + <11 32>, + <14 32>, + <15 32>, + <19 32>, + <24 32>; + qcom,cmb-elem-size = <11 32>, + <12 32>, + <13 64>, + <14 32>, + <21 32>, + <22 32>, + <23 32>; + + 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 = <21>; + tpda21_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda21>; + }; + }; + + port@2 { + reg = <22>; + tpda22_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda22>; + }; + }; + + port@3 { + reg = <23>; + tpda23_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda23>; + }; + }; + + port@4 { + reg = <24>; + tpda24_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda24>; + }; + }; + + port@5 { + reg = <2>; + tpda2_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda2>; + }; + }; + + port@6 { + reg = <11>; + tpda11_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda11>; + }; + }; + + port@7 { + reg = <12>; + tpda12_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda12>; + }; + }; + + port@8 { + reg = <13>; + tpda13_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda13>; + }; + }; + + port@9 { + reg = <14>; + tpda14_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda14>; + }; + }; + + port@10 { + reg = <15>; + tpda15_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda15>; + }; + }; + + port@11 { + reg = <19>; + tpda19_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda19>; + }; + }; + + }; + }; + + 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_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_funnel_qatb>; + }; + }; + + }; + }; + + funnel_in0: funnel@6041000 { + 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_merge: endpoint { + remote-endpoint = + <&funnel_merge_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = + <&stm_out_funnel_in0>; + }; + }; + + }; + }; + + 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_merge: endpoint { + remote-endpoint = + <&funnel_merge_in_funnel_in1>; + }; + }; + + port@1 { + reg = <1>; + funnel_in1_in_funnel_dlct1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct1_out_funnel_in1>; + }; + }; + + port@2 { + reg = <2>; + funnel_in1_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_in1>; + }; + }; + + port@3 { + reg = <4>; + funnel_in1_in_funnel_apss_merge: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merge_out_funnel_in1>; + }; + }; + + }; + }; + + funnel_merge: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merge"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_merge_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_funnel_merge>; + }; + }; + + port@1 { + reg = <0>; + funnel_merge_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merge>; + }; + }; + + port@2 { + reg = <1>; + funnel_merge_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merge>; + }; + }; + + }; + }; + + tpda_swao: tpda@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b08000 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_swao0_in_tpdm_swao_0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao_0_out_tpda_swao0>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao1_in_tpdm_swao_1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao_1_out_tpda_swao1>; + }; + }; + + }; + }; + + funnel_swao: funnel@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6b04000 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: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_swao>; + }; + }; + + port@1 { + reg = <5>; + funnel_swao_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <5>; + funnel_swao_in_tpdm_lpass_lpi: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpss_lpi_out_funnel_swao>; + }; + }; + + port@3 { + reg = <6>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint = + <&tpda_swao_out_funnel_swao>; + }; + }; + + port@4 { + reg = <7>; + funnel_swao_in_funnel_merge: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merge_out_funnel_swao>; + }; + }; + + }; + }; + + tmc_etf: tmc@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + reg = <0x6b05000 0x1000>; + reg-names = "tmc-base"; + + coresight-csr = <&csr>; + coresight-name = "coresight-tmc-etf"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etf_out_replicator_swao: endpoint { + remote-endpoint = + <&replicator_swao_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint = + <&funnel_swao_out_tmc_etf>; + }; + }; + + }; + }; + + replicator_swao: replicator@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + reg = <0x6b06000 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>; + port@0 { + reg = <0>; + replicator_swao_out_replicator_qdss: endpoint { + remote-endpoint = + <&replicator_qdss_in_replicator_swao>; + }; + }; + + port@1 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&eud_in_replicator_swao>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator_swao>; + }; + }; + + }; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + replicator_qdss_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator_qdss>; + }; + }; + + port@1 { + reg = <0>; + replicator_qdss_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_replicator_qdss>; + }; + }; + + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + iommus = <&apps_smmu 0x04a0 0x20>, + <&apps_smmu 0x0480 0x20>; + + coresight-ctis = <&cti0 &cti0>; + coresight-csr = <&csr>; + coresight-name = "coresight-tmc-etr"; + arm,buffer-size = <0x400000>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator_qdss: endpoint { + slave-mode; + remote-endpoint = + <&replicator_qdss_out_tmc_etr>; + }; + }; + }; + + cti_apss_cti0: 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"; + }; + + cti_apss_cti1: 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"; + }; + + cti_apss_cti2: 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: 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"; + }; + + 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"; + }; + + 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"; + + qcom,cti-gpio-trigout = <4>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; + }; + + 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"; + }; + + cti_mss: cti@680b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x680b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss_q6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_venus: cti@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6830000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-arm9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_dl_cti: cti@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6845000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_isdb_cti: cti@6941000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6941000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-gpu_isdb_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_cortex_m3: cti@6942000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6942000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-gpu_cortex_m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_dl_cti: cti@6982000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6982000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_q6_cti: cti@698b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x698b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_q6_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti0: cti@6ac1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6ac1000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlnt_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti1: cti@6ac2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6ac2000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlnt_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti2: cti@6ac3000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6ac3000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlnt_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti3: cti@6ac4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6ac4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlnt_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti0: cti@6b00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b00000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti1: cti@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b01000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti2: cti@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti3: cti@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b0e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b0e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cortex_m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_lpi_cti: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + + coresight-name = "coresight-cti-lpass_lpi_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_q6_cti: cti@6b2B000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b2B000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-lpass_q6_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti0: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti1: cti@6C2b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6C2b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti2: cti@6c2c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct0_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl_cti_0: cti@6c42000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c42000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl_cti_1: cti@6C43000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6C43000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_q6_cti: cti@6C4b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6C4b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_q6_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_sierra_a6_cti: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-sierra_a6_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mdss_dl_cti: cti@6c61000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c61000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mdss_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_0_cti_0: cti@6f82000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6f82000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_0_cti_1: cti@6f83000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6f83000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_0_cti_2: cti@6f84000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6f84000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_1_cti_0: cti@6f90000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6f90000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_1_cti_1: cti@6f91000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6f91000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_1_cti_2: cti@6f92000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6f92000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_olc: cti@7831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7831000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_apss: cti@7861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7861000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dl-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + 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>; + }; + }; + + }; + + swao_csr: csr@6b0c000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0c000 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>; + }; + + hwevent { + compatible = "qcom,coresight-hwevent"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + 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>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-idp-overlay.dts b/arch/arm64/boot/dts/qcom/atoll-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..46b35d146ce3348efbaadff662cb5200d4f9407b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-idp-overlay.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "atoll-idp.dtsi" + +/ { + model = "IDP"; + compatible = "qcom,atoll-idp", "qcom,atoll", "qcom,idp"; + qcom,msm-id = <407 0x0>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-idp.dts b/arch/arm64/boot/dts/qcom/atoll-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ff2b4c4266c9773d0f85bfafd0b176516a7d3a94 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "atoll.dtsi" +#include "atoll-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. ATOLL PM6150 IDP"; + compatible = "qcom,atoll-idp", "qcom,atoll", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-idp.dtsi b/arch/arm64/boot/dts/qcom/atoll-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a2bfa96448c05ab235b129fb6ca2d8cb7f72364d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-idp.dtsi @@ -0,0 +1,115 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { +}; + +&pm6150l_vadc { + pinctrl-0 = <&camera_flash_therm_default &tof_therm_default>; + + pa_therm1 { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + tof_therm { + reg = ; + label = "tof_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm6150l_gpios { + tof_therm { + tof_therm_default: tof_therm_default { + pins = "gpio7"; + bias-high-impedance; + }; + }; +}; + +&pm6150l_adc_tm { + io-channels = <&pm6150l_vadc ADC_AMUX_THM1_PU2>, + <&pm6150l_vadc ADC_AMUX_THM2_PU2>, + <&pm6150l_vadc ADC_AMUX_THM3_PU2>, + <&pm6150l_vadc ADC_GPIO1_PU2>; + + pa_therm1 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&usb0 { + extcon = <&pm6150_pdphy>, <&pm6150_charger>; +}; + +&usb_qmp_dp_phy { + extcon = <&pm6150_pdphy>; +}; + +&spmi_bus { + qcom,pm6150l@4 { + pm6150l_adc_tm_iio: adc_tm@3400 { + compatible = "qcom,adc-tm5-iio"; + reg = <0x3400 0x100>; + #thermal-sensor-cells = <1>; + io-channels = <&pm6150l_vadc ADC_GPIO3_PU2>; + + tof_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + }; + }; +}; + +&thermal_zones { + pa-therm1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + tof-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm_iio ADC_GPIO3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-ion.dtsi b/arch/arm64/boot/dts/qcom/atoll-ion.dtsi index 2966fd20d2357c1471370d121aa2f424f9aa06b0..533574d8ff0406a3f55b2c5397db5e64fd00277c 100644 --- a/arch/arm64/boot/dts/qcom/atoll-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-ion.dtsi @@ -27,9 +27,30 @@ qcom,ion-heap-type = "DMA"; }; + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + qcom,ion-heap@9 { reg = <9>; qcom,ion-heap-type = "SYSTEM_SECURE"; }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@14 { /* SECURE CARVEOUT HEAP */ + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + cdsp { + memory-region = <&cdsp_sec_mem>; + token = <0x20000000>; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi index 12ce68f4d3cafe83bac4ee08f3516594cb854371..93cb2fda4f8ac70fc38ced29e3d0e1e6b5060e8f 100644 --- a/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-pinctrl.dtsi @@ -20,5 +20,892 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio69"; + function = "gpio"; + }; + + config { + pins = "gpio69"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio69"; + function = "gpio"; + }; + + config { + pins = "gpio69"; + drive-strength = <2>; + bias-disable; + }; + }; + + trigout_a: trigout_a { + mux { + pins = "gpio72"; + function = "qdss_cti"; + }; + + config { + pins = "gpio72"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio34", "gpio35", + "gpio36", "gpio37"; + function = "qup00"; + }; + + config { + pins = "gpio34", "gpio35", + "gpio36", "gpio37"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio34", "gpio35", + "gpio36", "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio34", "gpio35", + "gpio36", "gpio37"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "qup01"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se3_spi_pins: qupv3_se3_spi_pins { + qupv3_se3_spi_active: qupv3_se3_spi_active { + mux { + pins = "gpio38", "gpio39", + "gpio40 ", "gpio41"; + function = "qup03"; + }; + + config { + pins = "gpio38", "gpio39", + "gpio40 ", "gpio41"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se3_spi_sleep: qupv3_se3_spi_sleep { + mux { + pins = "gpio38", "gpio39", + "gpio40 ", "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39", + "gpio40 ", "gpio41"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio25", "gpio26", + "gpio27", "gpio28"; + function = "qup05"; + }; + + config { + pins = "gpio25", "gpio26", + "gpio27", "gpio28"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio25", "gpio26", + "gpio27", "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio25", "gpio26", + "gpio27", "gpio28"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio34", "gpio35"; + function = "qup00"; + }; + + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio34", "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup01"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio15", "gpio16"; + function = "qup02"; + }; + + config { + pins = "gpio15", "gpio16"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio15", "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio15", "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se3_i2c_pins: qupv3_se3_i2c_pins { + qupv3_se3_i2c_active: qupv3_se3_i2c_active { + mux { + pins = "gpio38", "gpio39"; + function = "qup03"; + }; + + config { + pins = "gpio38", "gpio39"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep { + mux { + pins = "gpio38", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { + qupv3_se4_i2c_active: qupv3_se4_i2c_active { + mux { + pins = "gpio115", "gpio116"; + function = "qup04"; + }; + + config { + pins = "gpio115", "gpio116"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep { + mux { + pins = "gpio115", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio115", "gpio116"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio25", "gpio26"; + function = "qup05"; + }; + + config { + pins = "gpio25", "gpio26"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio25", "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio25", "gpio26"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se3_4uart_pins: qupv3_se3_4uart_pins { + qupv3_se3_default_ctsrtsrx: + qupv3_se3_default_ctsrtsrx { + mux { + pins = "gpio38", "gpio39", + "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39", + "gpio41"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se3_default_tx: qupv3_se3_default_tx { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se3_ctsrx: qupv3_se3_ctsrx { + mux { + pins = "gpio38", "gpio41"; + function = "qup03"; + }; + + config { + pins = "gpio38", "gpio41"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_rts: qupv3_se3_rts { + mux { + pins = "gpio39"; + function = "qup03"; + }; + + config { + pins = "gpio39"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se3_tx: qupv3_se3_tx { + mux { + pins = "gpio40"; + function = "qup03"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio59", "gpio60", + "gpio61", "gpio62"; + function = "qup10"; + }; + + config { + pins = "gpio59", "gpio60", + "gpio61", "gpio62"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio59", "gpio60", + "gpio61", "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio59", "gpio60", + "gpio61", "gpio62"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se8_spi_pins: qupv3_se8_spi_pins { + qupv3_se8_spi_active: qupv3_se8_spi_active { + mux { + pins = "gpio42", "gpio43", + "gpio44", "gpio45"; + function = "qup12"; + }; + + config { + pins = "gpio42", "gpio43", + "gpio44", "gpio45"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se8_spi_sleep: qupv3_se8_spi_sleep { + mux { + pins = "gpio42", "gpio43", + "gpio44", "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio42", "gpio43", + "gpio44", "gpio45"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se10_spi_pins: qupv3_se10_spi_pins { + qupv3_se10_spi_active: qupv3_se10_spi_active { + mux { + pins = "gpio86", "gpio87", + "gpio88 ", "gpio89"; + function = "qup14"; + }; + + config { + pins = "gpio86", "gpio87", + "gpio88 ", "gpio89"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se10_spi_sleep: qupv3_se10_spi_sleep { + mux { + pins = "gpio86", "gpio87", + "gpio88 ", "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio86", "gpio87", + "gpio88 ", "gpio89"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se11_spi_pins: qupv3_se11_spi_pins { + qupv3_se11_spi_active: qupv3_se11_spi_active { + mux { + pins = "gpio53", "gpio54", + "gpio55", "gpio56"; + function = "qup15"; + }; + + config { + pins = "gpio53", "gpio54", + "gpio55", "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se11_spi_sleep: qupv3_se11_spi_sleep { + mux { + pins = "gpio53", "gpio54", + "gpio55", "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54", + "gpio55", "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio59", "gpio60"; + function = "qup10"; + }; + + config { + pins = "gpio59", "gpio60"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio59", "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio59", "gpio60"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup11"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se8_i2c_pins: qupv3_se8_i2c_pins { + qupv3_se8_i2c_active: qupv3_se8_i2c_active { + mux { + pins = "gpio42", "gpio43"; + function = "qup12"; + }; + + config { + pins = "gpio42", "gpio43"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep { + mux { + pins = "gpio42", "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio42", "gpio43"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se9_i2c_pins: qupv3_se9_i2c_pins { + qupv3_se9_i2c_active: qupv3_se9_i2c_active { + mux { + pins = "gpio46", "gpio47"; + function = "qup13"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep { + mux { + pins = "gpio46", "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se10_i2c_pins: qupv3_se10_i2c_pins { + qupv3_se10_i2c_active: qupv3_se10_i2c_active { + mux { + pins = "gpio86", "gpio87"; + function = "qup14"; + }; + + config { + pins = "gpio86", "gpio87"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep { + mux { + pins = "gpio86", "gpio87"; + function = "gpio"; + }; + + config { + pins = "gpio86", "gpio87"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se11_i2c_pins: qupv3_se11_i2c_pins { + qupv3_se11_i2c_active: qupv3_se11_i2c_active { + mux { + pins = "gpio53", "gpio54"; + function = "qup15"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep { + mux { + pins = "gpio53", "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se8_2uart_pins: qupv3_se8_2uart_pins { + qupv3_se8_2uart_active: qupv3_se8_2uart_active { + mux { + pins = "gpio44", "gpio45"; + function = "qup12"; + }; + + config { + pins = "gpio44", "gpio45"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_2uart_sleep: qupv3_se8_2uart_sleep { + mux { + pins = "gpio44", "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio44", "gpio45"; + drive-strength = <2>; + bias-disable; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/atoll-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/atoll-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a041d8a82236a484e08392e369a619acf35994df --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-qrd-overlay.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "atoll-qrd.dtsi" + +/ { + model = "QRD"; + compatible = "qcom,atoll-qrd", "qcom,atoll", "qcom,qrd"; + qcom,msm-id = <407 0x0>; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-qrd.dts b/arch/arm64/boot/dts/qcom/atoll-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..9a61533fdfec925be9bd19d5c7d83ad8cc1301ac --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-qrd.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "atoll.dtsi" +#include "atoll-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. ATOLL PM6150 QRD"; + compatible = "qcom,atoll-qrd", "qcom,atoll", "qcom,qrd"; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi b/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9132ac26e6354461fb6b3f91561bdbc18d50fbf6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-qrd.dtsi @@ -0,0 +1,14 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 { +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-qupv3.dtsi b/arch/arm64/boot/dts/qcom/atoll-qupv3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a5075a5bc40b3528b805a40e77efb18a2ea56072 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-qupv3.dtsi @@ -0,0 +1,561 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + /* QUPv3 North Instances + * North 0 : SE 0 + * North 1 : SE 1 + * North 2 : SE 2 + * North 3 : SE 3 + * North 4 : SE 4 + * North 5 : SE 5 + */ + + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + qcom,iommu-s1-bypass; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x43 0x0>; + }; + }; + + /* GPI */ + gpi_dma0: qcom,gpi-dma@800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, + <0 252 0>, <0 253 0>; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x1f>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x56 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,gpi-ee-offset = <0x10000>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; + }; + + /* SPI */ + qupv3_se0_spi: spi@880000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x880000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se1_spi: spi@884000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x884000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_spi_active>; + pinctrl-1 = <&qupv3_se1_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se3_spi: spi@88c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x88c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_spi_active>; + pinctrl-1 = <&qupv3_se3_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 3 1 64 0>, + <&gpi_dma0 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se5_spi: spi@894000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x894000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_spi_active>; + pinctrl-1 = <&qupv3_se5_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* I2C */ + qupv3_se0_i2c: i2c@880000 { + compatible = "qcom,i2c-geni"; + reg = <0x880000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se1_i2c: i2c@884000 { + compatible = "qcom,i2c-geni"; + reg = <0x884000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@888000 { + compatible = "qcom,i2c-geni"; + reg = <0x888000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se3_i2c: i2c@88c000 { + compatible = "qcom,i2c-geni"; + reg = <0x88c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 3 3 64 0>, + <&gpi_dma0 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_i2c_active>; + pinctrl-1 = <&qupv3_se3_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se4_i2c: i2c@890000 { + compatible = "qcom,i2c-geni"; + reg = <0x890000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 4 3 64 0>, + <&gpi_dma0 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_i2c_active>; + pinctrl-1 = <&qupv3_se4_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se5_i2c: i2c@894000 { + compatible = "qcom,i2c-geni"; + reg = <0x894000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 5 3 64 0>, + <&gpi_dma0 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_i2c_active>; + pinctrl-1 = <&qupv3_se5_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* HSUART: BT used instance */ + qupv3_se3_4uart: qcom,qup_uart@88c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x88c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "active", "sleep"; + pinctrl-0 = <&qupv3_se3_default_ctsrtsrx>, + <&qupv3_se3_default_tx>; + pinctrl-1 = <&qupv3_se3_ctsrx>, <&qupv3_se3_rts>, + <&qupv3_se3_tx>; + pinctrl-2 = <&qupv3_se3_ctsrx>, <&qupv3_se3_rts>, + <&qupv3_se3_tx>; + interrupts-extended = <&intc GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 41 IRQ_TYPE_LEVEL_HIGH>; + qcom,wrapper-core = <&qupv3_0>; + qcom,wakeup-byte = <0xFD>; + status = "disabled"; + }; + + /* QUPv3 South Instances + * South 0 : SE 6 + * South 1 : SE 7 + * South 2 : SE 8 + * South 3 : SE 9 + * South 4 : SE 10 + * South 5 : SE 11 + */ + + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + qcom,iommu-s1-bypass; + + iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x4c3 0x0>; + }; + }; + + /* GPI */ + gpi_dma1: qcom,gpi-dma@a00000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0xa00000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 646 0>, <0 647 0>, <0 648 0>, <0 649 0>, + <0 650 0>, <0 651 0>, <0 652 0>, <0 653 0>, + <0 654 0>, <0 655 0>; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x3f>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x4d6 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,gpi-ee-offset = <0x10000>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; + }; + + /* SPI */ + qupv3_se6_spi: spi@a80000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa80000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_spi_active>; + pinctrl-1 = <&qupv3_se6_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se8_spi: spi@a88000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa88000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_spi_active>; + pinctrl-1 = <&qupv3_se8_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 2 1 64 0>, + <&gpi_dma1 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se10_spi: spi@a90000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_spi_active>; + pinctrl-1 = <&qupv3_se10_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 4 1 64 0>, + <&gpi_dma1 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se11_spi: spi@a94000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa94000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_spi_active>; + pinctrl-1 = <&qupv3_se11_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 5 1 64 0>, + <&gpi_dma1 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* I2C */ + qupv3_se6_i2c: i2c@a80000 { + compatible = "qcom,i2c-geni"; + reg = <0xa80000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i2c_active>; + pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se7_i2c: i2c@a84000 { + compatible = "qcom,i2c-geni"; + reg = <0xa84000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_i2c_active>; + pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se8_i2c: i2c@a88000 { + compatible = "qcom,i2c-geni"; + reg = <0xa88000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_i2c_active>; + pinctrl-1 = <&qupv3_se8_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se9_i2c: i2c@a8c000 { + compatible = "qcom,i2c-geni"; + reg = <0xa8c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 3 3 64 0>, + <&gpi_dma1 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_i2c_active>; + pinctrl-1 = <&qupv3_se9_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se10_i2c: i2c@a90000 { + compatible = "qcom,i2c-geni"; + reg = <0xa90000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 4 3 64 0>, + <&gpi_dma1 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_i2c_active>; + pinctrl-1 = <&qupv3_se10_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se11_i2c: i2c@a94000 { + compatible = "qcom,i2c-geni"; + reg = <0xa94000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 5 3 64 0>, + <&gpi_dma1 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_i2c_active>; + pinctrl-1 = <&qupv3_se11_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se8_2uart: qcom,qup_uart@a88000 { + compatible = "qcom,msm-geni-console"; + reg = <0xa88000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_2uart_active>; + pinctrl-1 = <&qupv3_se8_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-regulator.dtsi b/arch/arm64/boot/dts/qcom/atoll-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3106ced89fc1d5a15f47f845dd796901f5d6b18c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-regulator.dtsi @@ -0,0 +1,853 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pm6150l-s1-level-parent-supply = <&VDD_MX_LEVEL>; + pm6150l-s1-level_ao-parent-supply = <&VDD_MX_LEVEL_AO>; + VDD_CX_LEVEL: + S1C_LEVEL: + pm6150l_s1_level: regulator-pm6150l-s1-level { + regulator-name = "pm6150l_s1_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_LEVEL_AO: + S1C_LEVEL_AO: + pm6150l_s1_level_ao: regulator-pm6150l-s1-level-ao { + regulator-name = "pm6150l_s1_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "gfx.lvl"; + VDD_GFX_LEVEL: + S2A_LEVEL: + pm6150_s2_level: regulator-pm6150-s2-level { + regulator-name = "pm6150_s2_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + VDD_MX_LEVEL: + S3A_LEVEL: + pm6150_s3_level: regulator-pm6150-s3-level { + regulator-name = "pm6150_s3_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + + VDD_MX_LEVEL_AO: + S3A_LEVEL_AO: + pm6150_s3_level_ao: regulator-pm6150-s3-level-ao { + regulator-name = "pm6150_s3_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MX_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa1"; + S1A: + pm6150_s1: regulator-pm6150-s1 { + regulator-name = "pm6150_s1"; + qcom,set = ; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <1128000>; + }; + }; + + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa4"; + S4A: + pm6150_s4: regulator-pm6150-s4 { + regulator-name = "pm6150_s4"; + qcom,set = ; + regulator-min-microvolt = <824000>; + regulator-max-microvolt = <1120000>; + qcom,init-voltage = <824000>; + }; + }; + + rpmh-regulator-smpa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa5"; + S5A: + pm6150_s5: regulator-pm6150-s5 { + regulator-name = "pm6150_s5"; + qcom,set = ; + regulator-min-microvolt = <1744000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1744000>; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L1A: + pm6150_l1: regulator-pm6150-l1 { + regulator-name = "pm6150_l1"; + qcom,set = ; + regulator-min-microvolt = <1178000>; + regulator-max-microvolt = <1256000>; + qcom,init-voltage = <1178000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2A: + pm6150_l2: regulator-pm6150-l2 { + regulator-name = "pm6150_l2"; + qcom,set = ; + regulator-min-microvolt = <944000>; + regulator-max-microvolt = <1056000>; + qcom,init-voltage = <944000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3A: + pm6150_l3: regulator-pm6150-l3 { + regulator-name = "pm6150_l3"; + qcom,set = ; + regulator-min-microvolt = <968000>; + regulator-max-microvolt = <1064000>; + qcom,init-voltage = <968000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L4A: + pm6150_l4: regulator-pm6150-l4 { + regulator-name = "pm6150_l4"; + qcom,set = ; + regulator-min-microvolt = <824000>; + regulator-max-microvolt = <928000>; + qcom,init-voltage = <824000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5A: + pm6150_l5: regulator-pm6150-l5 { + regulator-name = "pm6150_l5"; + qcom,set = ; + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <2496000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L6A: + pm6150_l6: regulator-pm6150-l6 { + regulator-name = "pm6150_l6"; + qcom,set = ; + regulator-min-microvolt = <568000>; + regulator-max-microvolt = <648000>; + qcom,init-voltage = <568000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lmx.lvl"; + L7A_LEVEL: + pm6150_l7_level: regulator-pm6150-l7-level { + regulator-name = "pm6150_l7_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lcx.lvl"; + L8A_LEVEL: + pm6150_l8_level: regulator-pm6150-l8-level { + regulator-name = "pm6150_l8_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L9A: + pm6150_l9: regulator-pm6150-l9 { + regulator-name = "pm6150_l9"; + qcom,set = ; + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <488000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10A: + pm6150_l10: regulator-pm6150-l10 { + regulator-name = "pm6150_l10"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1832000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11A: + pm6150_l11: regulator-pm6150-l11 { + regulator-name = "pm6150_l11"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12A: + pm6150_l12: regulator-pm6150-l12 { + regulator-name = "pm6150_l12"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1952000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L13A: + pm6150_l13: regulator-pm6150-l13 { + regulator-name = "pm6150_l13"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L14A: + pm6150_l14: regulator-pm6150-l14 { + regulator-name = "pm6150_l14"; + qcom,set = ; + regulator-min-microvolt = <1728000>; + regulator-max-microvolt = <1832000>; + qcom,init-voltage = <1728000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L15A: + pm6150_l15: regulator-pm6150-l15 { + regulator-name = "pm6150_l15"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L16A: + pm6150_l16: regulator-pm6150-l16 { + regulator-name = "pm6150_l16"; + qcom,set = ; + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2496000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L17A: + pm6150_l17: regulator-pm6150-l17 { + regulator-name = "pm6150_l17"; + qcom,set = ; + regulator-min-microvolt = <2920000>; + regulator-max-microvolt = <3232000>; + qcom,init-voltage = <2920000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa18 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L18A: + pm6150_l18: regulator-pm6150-l18 { + regulator-name = "pm6150_l18"; + qcom,set = ; + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2496000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoa19 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa19"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L19A: + pm6150_l19: regulator-pm6150-l19 { + regulator-name = "pm6150_l19"; + qcom,set = ; + regulator-min-microvolt = <2696000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2696000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-msslvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mss.lvl"; + VDD_MSS_LEVEL: + S7C_LEVEL: + pm6150l_s7_level: regulator-pm6150l-s7-level { + regulator-name = "pm6150l_s7_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-smpc8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc8"; + S8C: + pm6150l_s8: regulator-pm6150l-s8 { + regulator-name = "pm6150l_s8"; + qcom,set = ; + regulator-min-microvolt = <1120000>; + regulator-max-microvolt = <1408000>; + qcom,init-voltage = <1120000>; + }; + }; + + rpmh-regulator-ldoc1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L1C: + pm6150l_l1: regulator-pm6150l-l1 { + regulator-name = "pm6150l_l1"; + qcom,set = ; + regulator-min-microvolt = <1616000>; + regulator-max-microvolt = <1984000>; + qcom,init-voltage = <1616000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2C: + pm6150l_l2: regulator-pm6150l-l2 { + regulator-name = "pm6150l_l2"; + qcom,set = ; + regulator-min-microvolt = <1168000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1168000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3C: + pm6150l_l3: regulator-pm6150l-l3 { + regulator-name = "pm6150l_l3"; + qcom,set = ; + regulator-min-microvolt = <1144000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1144000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L4C: + pm6150l_l4: regulator-pm6150l-l4 { + regulator-name = "pm6150l_l4"; + qcom,set = ; + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <1648000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5C: + pm6150l_l5: regulator-pm6150l-l5 { + regulator-name = "pm6150l_l5"; + qcom,set = ; + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <1648000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L6C: + pm6150l_l6: regulator-pm6150l-l6 { + regulator-name = "pm6150l_l6"; + qcom,set = ; + regulator-min-microvolt = <2696000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2696000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7C: + pm6150l_l7: regulator-pm6150l-l7 { + regulator-name = "pm6150l_l7"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L8C: + pm6150l_l8: regulator-pm6150l-l8 { + regulator-name = "pm6150l_l8"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L9C: + pm6150l_l9: regulator-pm6150l-l9 { + regulator-name = "pm6150l_l9"; + qcom,set = ; + regulator-min-microvolt = <2952000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2952000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10C: + pm6150l_l10: regulator-pm6150l-l10 { + regulator-name = "pm6150l_l10"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3400000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-ldoc11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11C: + pm6150l_l11: regulator-pm6150l-l11 { + regulator-name = "pm6150l_l11"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3400000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = + ; + }; + }; + + rpmh-regulator-bobc1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "bobc1"; + qcom,regulator-type = "pmic5-bob"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + qcom,send-defaults; + BOB: + pm6150l_bob: regulator-pm6150l-bob { + regulator-name = "pm6150l_bob"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = + ; + }; + + BOB_AO: + pm6150l_bob_ao: regulator-pm6150l-bob_ao { + regulator-name = "pm6150l_bob_ao"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = + ; + }; + }; + + refgen: refgen-regulator@88e7000 { + compatible = "qcom,refgen-regulator"; + reg = <0x88e7000 0x60>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + proxy-supply = <&refgen>; + qcom,proxy-consumer-enable; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-rumi.dtsi b/arch/arm64/boot/dts/qcom/atoll-rumi.dtsi index 84e7518cf79b930d42452a9baed0c3a98ca26131..4ac010263b7213ae0966d356bdc6e5d1a88b2a2f 100644 --- a/arch/arm64/boot/dts/qcom/atoll-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-rumi.dtsi @@ -20,7 +20,146 @@ clock-frequency = <1000000>; }; + usb_emu_phy: usb_emu_phy@a720000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x0a720000 0x9500>, + <0x0a6f8800 0x100>; + reg-names = "base", "qcratch_base"; + + qcom,emu-init-seq = <0xfff0 0x4 + 0xfff3 0x4 + 0x40 0x4 + 0xfff3 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + wdog: qcom,wdt@17c10000{ status = "disabled"; }; + + disp_rsc: mailbox@af20000 { + status = "disabled"; + }; +}; + +&sdhc_1 { + vdd-supply = <&pm6150_l19>; + 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>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm6150l_l9>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm6150l_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qrbtc-sdm845"; + + vdda-phy-supply = <&pm6150_l4>; /* 0.88v */ + vdda-pll-supply = <&pm6150l_l3>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + limit-tx-hs-gear = <1>; + limit-rx-hs-gear = <1>; + scsi-cmd-timeout = <300000>; + + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm6150_l19>; + vccq2-supply = <&pm6150_l12>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm6150l_l3>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1200000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + + + qcom,disable-lpm; + rpm-level = <0>; + spm-level = <0>; + status = "ok"; +}; + +&thermal_zones { + /delete-node/ aoss-0-lowf; +}; + +&usb0 { + dwc3@a600000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; + qcom,usbbam@a704000 { + status = "disabled"; + }; +}; + +&qusb_phy0 { + status = "disabled"; +}; + +&usb_qmp_dp_phy { + status = "disabled"; +}; + +&pm6150_pdphy { + status = "disabled"; +}; + +&qupv3_se9_i2c { + status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/atoll-thermal.dtsi b/arch/arm64/boot/dts/qcom/atoll-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fdd8d09839fb8da2529601cb7099762dd176d982 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-thermal.dtsi @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&clock_cpucc { + #address-cells = <1>; + #size-cells = <1>; + lmh_dcvs0: qcom,limits-dcvs@18358800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + reg = <0x18358800 0x1000>, + <0x18323000 0x1000>; + #thermal-sensor-cells = <0>; + }; + + lmh_dcvs1: qcom,limits-dcvs@18350800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + reg = <0x18350800 0x1000>, + <0x18325800 0x1000>; + #thermal-sensor-cells = <0>; + }; +}; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + aoss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-4-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-5-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cwlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + audio-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + ddr-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + q6-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-dsp-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + npu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 8>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 9>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + chg-skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + nvm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150_adc_tm ADC_GPIO1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + sdm-skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150_adc_tm ADC_GPIO2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_GPIO1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-max-step { + polling-delay-passive = <10>; + polling-delay = <100>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gpu_trip: gpu-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev { + trip = <&gpu_trip>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu-0-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + silver-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + cpu-1-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gold-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + cpu-0-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + cpu0_config: cpu0-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&cpu0_config>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-0-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + cpu1_config: cpu1-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu1_cdev { + trip = <&cpu1_config>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-0-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + cpu2_config: cpu2-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu2_cdev { + trip = <&cpu2_config>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-0-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + trips { + cpu3_config: cpu3-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu3_cdev { + trip = <&cpu3_config>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-0-4-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + trips { + cpu4_config: cpu4-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu4_cdev { + trip = <&cpu4_config>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-0-5-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + trips { + cpu5_config: cpu5-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu5_cdev { + trip = <&cpu5_config>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-1-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + trips { + cpu6_0_config: cpu6-0-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu6_cdev { + trip = <&cpu6_0_config>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-1-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + trips { + cpu6_1_config: cpu6-1-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu6_cdev { + trip = <&cpu6_1_config>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-1-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 11>; + wake-capable-sensor; + trips { + cpu7_0_config: cpu7-0-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu7_cdev { + trip = <&cpu7_0_config>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu-1-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 12>; + wake-capable-sensor; + trips { + cpu7_1_config: cpu7-1-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + cpu7_cdev { + trip = <&cpu7_1_config>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + aoss-0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + trips { + aoss0_trip: aoss0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU0 2 2>; + }; + cpu1_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU6 4 4>; + }; + gpu_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + cx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-usb.dtsi b/arch/arm64/boot/dts/qcom/atoll-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..83e4a9ea0512c011529b4040eb832b7e28dc3a30 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-usb.dtsi @@ -0,0 +1,373 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + usb0: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x540 0x0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 489 0>, <0 130 0>, <0 486 0>, <0 488 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + USB3_GDSC-supply = <&usb30_prim_gdsc>; + dpdm-supply = <&qusb_phy0>; + qcom,use-pdc-interrupts; + + clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&clock_gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,gsi-disable-io-coherency; + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,pm-qos-latency = <62>; + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + , + + /* min vote */ + , + , + ; + + qcom,default-bus-vote = <2>; /* use svs bus voting */ + dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xcd00>; + interrupts = <0 133 0>; + usb-phy = <&qusb_phy0>, <&usb_qmp_dp_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <0>; + tx-fifo-resize; + maximum-speed = "super-speed"; + dr_mode = "otg"; + }; + + qcom,usbbam@a704000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xa704000 0x17000>; + interrupts = <0 132 0>; + + qcom,usb-bam-fifo-baseaddr = <0x146a6000>; + qcom,usb-bam-num-pipes = <4>; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x6064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + }; + + /* Primary USB port related QUSB2 PHY */ + qusb_phy0: qusb@88e2000 { + compatible = "qcom,qusb2phy-v2"; + reg = <0x088e2000 0x400>, + <0x00780200 0x4>, + <0x088e7014 0x4>; + reg-names = "qusb_phy_base", "efuse_addr", + "refgen_north_bg_reg_addr"; + + qcom,efuse-bit-pos = <25>; + qcom,efuse-num-bits = <3>; + vdd-supply = <&pm6150_l4>; + vdda18-supply = <&pm6150_l11>; + vdda33-supply = <&pm6150_l17>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x27c /* QUSB2PHY_DEBUG_CTRL1 */ + 0x280 /* QUSB2PHY_DEBUG_CTRL2 */ + 0x2a0>; /* QUSB2PHY_STAT5 */ + + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x22 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x30 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + qcom,qusb-phy-host-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x22 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x30 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + phy_type= "utmi"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "ref_clk_src", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + /* Primary USB port related QMP USB DP Combo PHY */ + usb_qmp_dp_phy: ssphy@88e8000 { + compatible = "qcom,usb-ssphy-qmp-dp-combo"; + reg = <0x88e8000 0x3000>; + reg-names = "qmp_phy_base"; + vdd-supply = <&pm6150_l4>; + qcom,vdd-voltage-level = <0 880000 880000>; + core-supply = <&pm6150l_l3>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&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_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&clock_gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "global_phy_reset", "phy_reset"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x1b2f 0x0>; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/atoll-vidc.dtsi b/arch/arm64/boot/dts/qcom/atoll-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ec3b77ba77f218a661d49d5481c29fc5dfaaf168 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/atoll-vidc.dtsi @@ -0,0 +1,106 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + msm_vidc: qcom,vidc@aa00000 { + compatible = "qcom,msm-vidc", "qcom,atoll-vidc"; + status = "ok"; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + venus-supply = <&venus_gdsc>; + venus-core0-supply = <&vcodec0_gdsc>; + + /* Clocks */ + clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk"; + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>; + qcom,proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "core0_clk", "core0_bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>; + qcom,allowed-clock-rates = <150000000 270000000 340000000 + 434000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "vidc-ar50-ddr"; + qcom,bus-range-kbps = <1000 2128000>; + }; + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0xC00 0x60>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x6f800000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0xC21 0x4>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0xC23 0x0>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0xC04 0x60>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/atoll.dtsi b/arch/arm64/boot/dts/qcom/atoll.dtsi index b8d80771d662999841c6320a6b2565dc23e1e1e6..905382c0f295fd3a777520ce652298ba370a255f 100644 --- a/arch/arm64/boot/dts/qcom/atoll.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll.dtsi @@ -13,6 +13,7 @@ #include "skeleton64.dtsi" #include #include +#include #include #include #include @@ -30,6 +31,13 @@ qcom,msm-id = <407 0x0>; interrupt-parent = <&pdc>; + aliases { + serial0 = &qupv3_se8_2uart; + sdhc1 = &sdhc_1; /* eMMC */ + sdhc2 = &sdhc_2; /* SD Card */ + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + }; + cpus { #address-cells = <2>; #size-cells = <0>; @@ -44,6 +52,8 @@ d-cache-size = <0x8000>; i-cache-size = <0x8000>; next-level-cache = <&L2_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; L2_0: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x10000>; @@ -82,6 +92,8 @@ d-cache-size = <0x8000>; i-cache-size = <0x8000>; next-level-cache = <&L2_100>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; L2_100: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x10000>; @@ -115,6 +127,8 @@ d-cache-size = <0x8000>; i-cache-size = <0x8000>; next-level-cache = <&L2_200>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; L2_200: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x10000>; @@ -147,6 +161,8 @@ d-cache-size = <0x8000>; i-cache-size = <0x8000>; next-level-cache = <&L2_300>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; L2_300: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x10000>; @@ -179,6 +195,8 @@ d-cache-size = <0x8000>; i-cache-size = <0x8000>; next-level-cache = <&L2_400>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; L2_400: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x10000>; @@ -211,6 +229,8 @@ d-cache-size = <0x8000>; i-cache-size = <0x8000>; next-level-cache = <&L2_500>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; L2_500: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x10000>; @@ -243,6 +263,8 @@ d-cache-size = <0x10000>; i-cache-size = <0x10000>; next-level-cache = <&L2_600>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; L2_600: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -284,6 +306,8 @@ d-cache-size = <0x10000>; i-cache-size = <0x10000>; next-level-cache = <&L2_700>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; L2_700: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -444,6 +468,27 @@ method = "smc"; }; + 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/7c4000.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + reserved_memory: reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -482,61 +527,61 @@ pil_camera_mem: camera_region@8e000000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8e000000 0 0x500000>; + reg = <0 0x8e400000 0 0x500000>; }; pil_modem_mem: modem_region@86000000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x86000000 0 0x8000000>; + reg = <0 0x86000000 0 0x8400000>; }; pil_video_mem: pil_video_region@8ea00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8ea00000 0 0x500000>; + reg = <0 0x8ee00000 0 0x500000>; }; pil_cdsp_mem: cdsp_regions@8ef00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8ef00000 0 0x1e00000>; + reg = <0 0x8f300000 0 0x1e00000>; }; pil_adsp_mem: pil_adsp_region@90d00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x90d00000 0 0x2800000>; + reg = <0 0x91100000 0 0x2800000>; }; wlan_fw_mem: wlan_fw_region@93500000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93500000 0 0x200000>; + reg = <0 0x93900000 0 0x200000>; }; npu_mem: npu_region@8e500000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8e500000 0 0x500000>; + reg = <0 0x8e900000 0 0x500000>; }; pil_ipa_fw_mem: ipa_fw_region@93700000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93700000 0 0x10000>; + reg = <0 0x93b00000 0 0x10000>; }; pil_ipa_gsi_mem: ipa_gsi_region@93710000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93710000 0 0x5000>; + reg = <0 0x93b10000 0 0x5000>; }; pil_gpu_mem: gpu_region@93715000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93715000 0 0x2000>; + reg = <0 0x93b15000 0 0x2000>; }; qseecom_mem: qseecom_region@9e000000 { @@ -545,11 +590,41 @@ reg = <0 0x9e000000 0 0x1400000>; }; + qseecom_ta_mem: qseecom_ta_region@0 { + compatible = "shared-dma-pool"; + reusable; + alignment = <0x400000>; + size = <0x1000000>; + }; + cdsp_sec_mem: cdsp_sec_regions@0x9f400000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x9f400000 0 0xc00000>; + reg = <0 0x9f400000 0 0x1e00000>; + }; + + secure_display_memory: secure_display_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x8c00000>; }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x800000>; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + reusable; + size = <0 0x2400000>; + }; + /* global autoconfigured region for contiguous allocations */ linux,cma { compatible = "shared-dma-pool"; @@ -670,6 +745,94 @@ interrupts = ; }; + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + qcom,msm-imem@146aa000 { compatible = "qcom,msm-imem"; reg = <0x146aa000 0x1000>; @@ -713,6 +876,14 @@ }; }; + dcc: dcc_v2@10a2000 { + compatible = "qcom,dcc-v2"; + reg = <0x10a2000 0x1000>, + <0x10ae000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + dcc-ram-offset = <0x6000>; + }; + restart@c264000 { compatible = "qcom,pshold"; reg = <0xc264000 0x4>, @@ -720,11 +891,161 @@ reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; + qcom_seecom: qseecom@82200000 { + compatible = "qcom,qseecom"; + reg = <0x82200000 0x2200000>; + 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@82200000 { + compatible = "qcom,smcinvoke"; + reg = <0x82200000 0x2200000>; + reg-names = "secapp-region"; + }; + + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + + qcom_tzlog: tz-log@146aa720 { + compatible = "qcom,tz-log"; + reg = <0x146aa720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + 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"; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + 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 0x0424 0x0011>, + <&apps_smmu 0x0434 0x0011>; + }; + + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + 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 0x0426 0x0011>, + <&apps_smmu 0x0436 0x0011>; + }; + qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; }; + ufs_ice: ufsice@1d90000 { + compatible = "qcom,ice"; + reg = <0x1d90000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_phy_gdsc>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 757 0 0>, /* No vote */ + <1 757 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + + sdcc1_ice: sdcc1ice@7c8000{ + compatible = "qcom,ice"; + reg = <0x7c8000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ice_core_clk_src", "ice_core_clk", + "bus_clk", "iface_clk"; + clocks = <&clock_gcc GCC_SDCC1_ICE_CORE_CLK_SRC>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>, + <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>; + qcom,op-freq-hz = <300000000>, <0>, <0>, <0>; + qcom,msm-bus,name = "sdcc_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 608 0 0>, /* No vote */ + <1 608 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "sdcc"; + }; + wdog: qcom,wdt@17c10000{ compatible = "qcom,msm-watchdog"; reg = <0x17c10000 0x1000>; @@ -739,6 +1060,20 @@ 0x10100 0x10100 0x25900 0x25900>; }; + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x88e0000 0x2000>, + <0x88e2000 0x1000>; + reg-names = "eud_base", "eud_mode_mgr2"; + qcom,secure-eud-en; + qcom,eud-clock-vote-req; + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "eud_ahb2phy_clk"; + status = "ok"; + }; + qcom,chd_sliver { compatible = "qcom,core-hang-detect"; label = "silver"; @@ -780,6 +1115,218 @@ qcom,guard-memory; }; + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x4080000 0x100>; + + qcom,firmware-name = "modem"; + memory-region = <&pil_modem_mem>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,pas-id = <4>; + qcom,smem-id = <421>; + qcom,signal-aop; + qcom,minidump-id = <3>; + qcom,complete-ramdump; + + /* Inputs from mss */ + interrupts-extended = <&pdc GIC_SPI 266 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 0 IRQ_TYPE_NONE>, + <&modem_smp2p_in 1 IRQ_TYPE_NONE>, + <&modem_smp2p_in 2 IRQ_TYPE_NONE>, + <&modem_smp2p_in 3 IRQ_TYPE_NONE>, + <&modem_smp2p_in 7 IRQ_TYPE_NONE>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack", + "qcom,shutdown-ack"; + /* Outputs to mss */ + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "mss-pil"; + }; + + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&pil_cdsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + + /* Inputs from turing */ + interrupts-extended = <&pdc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; + }; + + 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 0x1401 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1402 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1403 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1404 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1405 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1406 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1407 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1408 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1409 0x20>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1003 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1004 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1005 0x0>; + shared-cb = <5>; + dma-coherent; + }; + }; + + qcom,lpass@62400000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x62400000 0x00100>; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + + /* Inputs from lpass */ + interrupts-extended = <&pdc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack"; + + /* Outputs to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; + }; + qcom,llcc@9200000 { compatible = "qcom,llcc-core", "syscon", "simple-mfd"; reg = <0x9200000 0x450000>; @@ -961,6 +1508,61 @@ }; }; + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xe4>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + etf_swao { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf1>; + }; + + etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + etfswao_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + + etf_lpass { + qcom,dump-size = <0x4000>; + qcom,dump-id = <0xf4>; + }; + + etflpass_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x104>; + }; + }; + clock_rpmh: qcom,rpmh { compatible = "qcom,dummycc"; clock-output-names = "rpm_clocks"; @@ -1015,6 +1617,17 @@ #reset-cells = <1>; }; + clock_cpucc: qcom,cpucc@18321000 { + compatible = "qcom,clk-cpu-osm-atoll"; + reg = <0x18321000 0x1400>, + <0x18323000 0x1400>, + <0x18325800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", + "osm_perfcl_base"; + #clock-cells = <1>; + status = "disabled"; + }; + tcsr_mutex_block: syscon@01F40000 { compatible = "syscon"; reg = <0x01F40000 0x20000>; @@ -1540,7 +2153,6 @@ ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x0440 0x0>; qcom,iova-mapping = <0x20000000 0x40000000>; /* modem tables in IMEM */ @@ -1549,7 +2161,6 @@ ipa_smmu_wlan: ipa_smmu_wlan { compatible = "qcom,ipa-smmu-wlan-cb"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x0441 0x0>; /* ipa-uc ram */ qcom,additional-mapping = <0x1e60000 0x1e60000 0x80000>; @@ -1557,7 +2168,6 @@ ipa_smmu_uc: ipa_smmu_uc { compatible = "qcom,ipa-smmu-uc-cb"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x0442 0x0>; qcom,iova-mapping = <0x40400000 0x1fc00000>; }; @@ -1583,6 +2193,176 @@ ; }; + sdhc_1: sdhci@7c4000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>; + reg-names = "hc_mem", "cmdq_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + sdhc-msm-crypto = <&sdcc1_ice>; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,ice-clk-rates = <300000000 100000000>; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x000F642C 0x0 0x0 0x00010800 0x80040868>; + + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 202000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 202000000>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642C 0x0 0x0 0x00010800 0x80040868>; + + status = "disabled"; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + reg = <0x1d87000 0xddc>; /* PHY regs */ + reg-names = "phy_mem"; + #phy-cells = <0>; + + lanes-per-direction = <1>; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_PHY_AUX_CLK>; + + status = "disabled"; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x3000>; + interrupts = <0 265 0>; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; + + lanes-per-direction = <1>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + spm-level = <5>; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk"; + clocks = + <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x3f 0xC0>; + qcom,pm-qos-cpu-group-latency-us = <67 67>; + qcom,pm-qos-default-cpu = <0>; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&clock_gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + non-removable; + + status = "disabled"; + }; + disp_rsc: mailbox@af20000 { compatible = "qcom,tcs-drv"; label = "display_rsc"; @@ -1592,7 +2372,7 @@ qcom,drv-id = <0>; qcom,tcs-config = , , - , + , ; }; @@ -1605,11 +2385,89 @@ compatible = "qcom,cmd-db"; reg = <0xc3f000c 8>; }; + + thermal_zones: thermal-zones {}; + + tsens0: tsens@c222000 { + compatible = "qcom,tsens24xx"; + reg = <0xc222000 0x8>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 506 0>, <0 508 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: tsens@c223000 { + compatible = "qcom,tsens24xx"; + reg = <0xc223000 0x8>, + <0xc265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 507 0>, <0 509 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + qcom,venus@aae0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xaae0000 0x4000>; + + vdd-supply = <&venus_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; + clock-names = "core_clk", "iface_clk", "bus_clk"; + qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk"; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + }; + + slim_aud: slim@62ec0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x62ec0000 0x2c000>, + <0x62e84000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = , + ; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x700000>; + qcom,ea-pc = <0x340>; + qcom,iommu-s1-bypass; + status = "ok"; + + iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1026 0x0>, + <&apps_smmu 0x102f 0x0>, + <&apps_smmu 0x1030 0x1>; + }; + }; }; #include "atoll-gdsc.dtsi" #include "atoll-ion.dtsi" -#include "msm-arm-smmu-sdmatoll.dtsi" +#include "msm-arm-smmu-atoll.dtsi" +#include "atoll-qupv3.dtsi" +#include "sdmmagpie-gpu.dtsi" +#include "atoll-bus.dtsi" + +&msm_gpu { + /delete-property/qcom,gpu-speed-bin; +}; &ufs_phy_gdsc { status = "ok"; @@ -1671,6 +2529,251 @@ status = "ok"; }; +&qupv3_se8_2uart { + status = "ok"; +}; + +#include "pm6150.dtsi" +#include "pm6150l.dtsi" #include "atoll-pinctrl.dtsi" #include "atoll-pm.dtsi" -#include "atoll-stub-regulator.dtsi" +#include "atoll-coresight.dtsi" +#include "atoll-regulator.dtsi" +#include "atoll-usb.dtsi" +#include "atoll-vidc.dtsi" + +&pm6150_vadc { + pinctrl-names = "default"; + pinctrl-0 = <&nvm_therm_default &sdm_skin_therm_default>; + + chg_skin_therm { + reg = ; + label = "chg_skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + conn_therm { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + nvm_therm { + reg = ; + label = "nvm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + sdm_skin_therm { + reg = ; + label = "sdm_skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm6150_gpios { + nvm_therm { + nvm_therm_default: nvm_therm_default { + pins = "gpio1"; + bias-high-impedance; + }; + }; + + sdm_skin_therm { + sdm_skin_therm_default: sdm_skin_therm_default { + pins = "gpio8"; + bias-high-impedance; + }; + }; +}; + +&pm6150_adc_tm { + io-channels = <&pm6150_vadc ADC_XO_THERM_PU2>, + <&pm6150_vadc ADC_AMUX_THM1_PU2>, + <&pm6150_vadc ADC_GPIO1_PU2>, + <&pm6150_vadc ADC_GPIO2_PU2>; + + /* Channel nodes */ + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + chg_skin_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + nvm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + sdm_skin_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm6150l_vadc { + pinctrl-names = "default"; + pinctrl-0 = <&camera_flash_therm_default>; + + quiet_therm { + reg = ; + label = "quiet_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm0 { + reg = ; + label = "pa_therm0"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + camera_flash_therm { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm6150l_gpios { + camera_flash_therm { + camera_flash_therm_default: camera_flash_therm_default { + pins = "gpio5"; + bias-high-impedance; + }; + }; +}; + +&pm6150l_adc_tm { + io-channels = <&pm6150l_vadc ADC_AMUX_THM1_PU2>, + <&pm6150l_vadc ADC_AMUX_THM2_PU2>, + <&pm6150l_vadc ADC_GPIO1_PU2>; + + /* Channel nodes */ + quiet_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm0 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + camera_flash_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +#include "atoll-thermal.dtsi" + + +&qupv3_se9_i2c { + status = "ok"; + #include "pm8008.dtsi" +}; + +&tlmm { + pm8008_active: pm8008_active { + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + bias-pull-up; + output-high; + drive-strength = <2>; + }; + }; +}; + +&pm8008_gpios { + gpio1_active { + pm8008_gpio1_active: pm8008_gpio1_active { + pins = "gpio1"; + function = "normal"; + power-source = <1>; + bias-disable; + input-enable; + }; + }; +}; + +&pm8008_chip { + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_active>; +}; + +&pm8008_regulators { + vdd_l1_l2-supply = <&S8C>; + vdd_l3_l4-supply = <&BOB>; + vdd_l5-supply = <&S5A>; + vdd_l6-supply = <&BOB>; + vdd_l7-supply = <&BOB>; +}; + +&pm8008_9 { + /* GPIO1 pinctrl config */ + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_gpio1_active>; +}; + +&L1P { + regulator-max-microvolt = <1104000>; + qcom,min-dropout-voltage = <225000>; +}; + +&L2P { + regulator-max-microvolt = <1200000>; + qcom,min-dropout-voltage = <75000>; +}; + +&L3P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <200000>; +}; + +&L4P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <200000>; +}; + +&L5P { + regulator-max-microvolt = <1800000>; + qcom,min-dropout-voltage = <200000>; +}; + +&L6P { + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <300000>; +}; + diff --git a/arch/arm64/boot/dts/qcom/dm-verity-boot.dtsi b/arch/arm64/boot/dts/qcom/dm-verity-boot.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3aee6a4295f9bb1a5715b0526aed9d06137b812d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dm-verity-boot.dtsi @@ -0,0 +1,28 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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. + */ +dm_verity { + dmname="disabled"; + version="1"; + data_device="/dev/sda6"; + hash_device="/dev/sda6"; + data_block_size="4096"; + hash_block_size="4096"; + number_of_data_blocks="262144"; + hash_start_block="262145"; + algorithm="sha256"; + // root hash: 64 bytes long + digest= + "b0fe12d7da6e23a1e19b5a69252c7aaf7b249191eb13bba3f566d630b3f2828a"; + salt="a2df040e00f02c3b2a19e90e5aa76fe1a303f4e08584aaf40e87f088a32b7709"; + // restart_on_corruption ignore_corruption ignore_zero_blocks + opt="restart_on_corruption"; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-1080p.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-1080p.dtsi index 0d518a6901eb7dbc8b58dbed15530f33318391b7..9347de7ecc7af7b6181ca18d50e5594a0dfe266c 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-1080p.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-1080p.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This 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,6 @@ qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x24>; qcom,mdss-dsi-force-clock-lane-hs; - qcom,mdss-dsi-ext-bridge-mode; qcom,mdss-dsi-display-timings { timing@0{ diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-hdmi-1080p.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-hdmi-1080p.dtsi index 3d3362a4fcd95115871695de3c8c208de4e53174..ed9398f1cae62e889b92c56851e1b7196a778409 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-hdmi-1080p.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-ext-bridge-hdmi-1080p.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This 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,6 @@ qcom,mdss-dsi-t-clk-post = <0x18>; qcom,mdss-dsi-t-clk-pre = <0x1b>; qcom,mdss-dsi-force-clock-lane-hs; - qcom,mdss-dsi-ext-bridge-mode; qcom,mdss-dsi-display-timings { timing@0{ diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmatoll.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-atoll.dtsi similarity index 73% rename from arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmatoll.dtsi rename to arch/arm64/boot/dts/qcom/msm-arm-smmu-atoll.dtsi index d96746cce5cd20d7c876d5742d85cf6055ac8090..e92bc4caf0a779bf5f04b5b18e7e9e5b2211c938 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmatoll.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-atoll.dtsi @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ #include +#include &soc { kgsl_smmu: arm,smmu-kgsl@5040000 { @@ -36,6 +37,20 @@ ; clock-names = "gcc_gpu_memnoc_gfx_clk"; clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + + attach-impl-defs = + <0x6000 0x2378>, + <0x6060 0x1055>, + <0x678c 0x8>, + <0x6794 0x28>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x11000>, + <0x6930 0x800>, + <0x6960 0xffffffff>, + <0x6b64 0x1a5551>, + <0x6b68 0x9a82a382>; }; apps_smmu: apps-smmu@0x15000000 { @@ -138,6 +153,17 @@ <0x15182200 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x0 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; }; anoc_2_tbu: anoc_2_tbu@0x15189000 { @@ -146,6 +172,17 @@ <0x15182208 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x400 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; }; mnoc_hf_0_tbu: mnoc_hf_0_tbu@0x1518d000 { @@ -156,6 +193,17 @@ qcom,stream-id-range = <0x800 0x400>; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>; + qcom,msm-bus,name = "mnoc_hf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; }; mnoc_sf_0_tbu: mnoc_sf_0_tbu@0x15191000 { @@ -166,6 +214,17 @@ qcom,stream-id-range = <0xc00 0x400>; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; + qcom,msm-bus,name = "mnoc_sf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; }; lpass_noc_tbu: lpass_noc_tbu@0x15195000 { @@ -174,6 +233,17 @@ <0x15182220 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1000 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; }; compute_dsp_0_tbu: compute_dsp_0_tbu@0x15199000 { @@ -183,6 +253,17 @@ reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1400 0x400>; /* No GDSC */ + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; }; }; @@ -202,3 +283,13 @@ dma-coherent; }; }; + +&apps_smmu { + qcom,actlr = + /* HF_0 and SF_0 TBUs: +3 deep PF */ + <0x800 0x7ff 0x103>, + + /* NPU SIDs: +3 deep PF */ + <0x1460 0x1f 0x303>, + <0x1480 0x1f 0x303>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi index 6fab5f53ea615c34427f7d886ea7c26ccf224aea..bd1f37554f7e96f83f017702d7dc87afaa8e52a4 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi @@ -28,7 +28,6 @@ #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; - qcom,deferred-regulator-disable-delay = <80>; clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, <&clock_gcc GCC_GPU_SNOC_DVM_GFX_CLK>, <&clock_gpucc GPU_CC_AHB_CLK>, diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi index 087aa21910cef20496cab5afb963124f840994b5..e198ed897b557dc3b50109045e7611491c1800de 100644 --- a/arch/arm64/boot/dts/qcom/pm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -449,15 +449,11 @@ compatible = "qcom,bcl-v5"; reg = <0x1d00 0x100>; interrupts = <0x0 0x1d 0x0 IRQ_TYPE_NONE>, - <0x0 0x1d 0x1 IRQ_TYPE_NONE>, - <0x0 0x1d 0x0 IRQ_TYPE_NONE>, <0x0 0x1d 0x1 IRQ_TYPE_NONE>, <0x0 0x1d 0x2 IRQ_TYPE_NONE>; - interrupt-names = "bcl-ibat-lvl0", - "bcl-ibat-lvl1", - "bcl-vbat-lvl0", - "bcl-vbat-lvl1", - "bcl-vbat-lvl2"; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; #thermal-sensor-cells = <1>; }; @@ -564,7 +560,7 @@ }; pm6150-ibat-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "step_wise"; thermal-sensors = <&pm6150_bcl 0>; @@ -596,7 +592,7 @@ }; pm6150-vbat-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm6150_bcl 2>; @@ -646,6 +642,54 @@ }; }; + pm6150-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150_bcl 5>; + wake-capable-sensor; + + trips { + bcl_lvl0: bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm6150-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150_bcl 6>; + wake-capable-sensor; + + trips { + bcl_lvl1: bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm6150-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150_bcl 7>; + wake-capable-sensor; + + trips { + bcl_lvl2: bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + soc { polling-delay-passive = <100>; polling-delay = <0>; diff --git a/arch/arm64/boot/dts/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi index 64672673a4f92df43b205cc4bb59bf1d12c8848e..17f0a5dfb704a008dfbd2b9182b3edc6924b0d76 100644 --- a/arch/arm64/boot/dts/qcom/pm6150l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi @@ -46,9 +46,9 @@ interrupts = <0x4 0x3d 0x0 IRQ_TYPE_NONE>, <0x4 0x3d 0x1 IRQ_TYPE_NONE>, <0x4 0x3d 0x2 IRQ_TYPE_NONE>; - interrupt-names = "bcl-vbat-lvl0", - "bcl-vbat-lvl1", - "bcl-vbat-lvl2"; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; #thermal-sensor-cells = <1>; }; @@ -511,4 +511,52 @@ }; }; }; + + pm6150l-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_bcl 5>; + wake-capable-sensor; + + trips { + l_bcl_lvl0: l-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm6150l-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_bcl 6>; + wake-capable-sensor; + + trips { + l_bcl_lvl1: l-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm6150l-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_bcl 7>; + wake-capable-sensor; + + trips { + l_bcl_lvl2: l-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/pm6155-vm.dtsi b/arch/arm64/boot/dts/qcom/pm6155-vm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d7a5b9672d14c326d6fac26c2c49c5918a9f77fc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm6155-vm.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&spmi_bus { + qcom,pm6155@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm6155_1_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm6155_1_gpio1", "pm6155_1_gpio2", + "pm6155_1_gpio3", "pm6155_1_gpio4", + "pm6155_1_gpio5", "pm6155_1_gpio6", + "pm6155_1_gpio7", "pm6155_1_gpio8", + "pm6155_1_gpio9", "pm6155_1_gpio10"; + gpio-controller; + #gpio-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8150-vm.dtsi b/arch/arm64/boot/dts/qcom/pm8150-vm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6c5a21a6e7f347c9d4ed9bd4d88cec464c7d7548 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8150-vm.dtsi @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&spmi_bus { + qcom,pm8150@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8150_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150_gpio1", "pm8150_gpio3", + "pm8150_gpio4", "pm8150_gpio6", + "pm8150_gpio9", "pm8150_gpio10"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <2 5 7 8>; + }; + }; +}; + +&pm8150_gpios { + key_home { + key_home_default: key_home_default { + pins = "gpio1"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + storage_sd_detect { + storage_cd_default: storage_cd_default { + pins = "gpio4"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi index 6e5d35a6e67c89ef33250e563fb42eb44861cb1e..e1ff572b262d5608fc70a5c1e8b8bea9a72edca9 100644 --- a/arch/arm64/boot/dts/qcom/pm8150b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi @@ -55,6 +55,11 @@ clock-names = "xo"; }; + pm8150b_pbs1: qcom,pbs@7200 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7200 0x100>; + }; + pm8150b_qnovo: qcom,sdam-qnovo@b000 { compatible = "qcom,qpnp-qnovo5"; reg = <0xb000 0x100>; @@ -360,15 +365,11 @@ compatible = "qcom,bcl-v5"; reg = <0x1d00 0x100>; interrupts = <0x2 0x1d 0x0 IRQ_TYPE_NONE>, - <0x2 0x1d 0x1 IRQ_TYPE_NONE>, - <0x2 0x1d 0x0 IRQ_TYPE_NONE>, <0x2 0x1d 0x1 IRQ_TYPE_NONE>, <0x2 0x1d 0x2 IRQ_TYPE_NONE>; - interrupt-names = "bcl-ibat-lvl0", - "bcl-ibat-lvl1", - "bcl-vbat-lvl0", - "bcl-vbat-lvl1", - "bcl-vbat-lvl2"; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; #thermal-sensor-cells = <1>; }; @@ -382,6 +383,7 @@ #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pm8150b_revid>; + qcom,pmic-pbs = <&pm8150b_pbs1>; status = "okay"; qcom,fg-batt-soc@4000 { @@ -597,7 +599,7 @@ }; pm8150b-ibat-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "step_wise"; thermal-sensors = <&pm8150b_bcl 0>; @@ -613,7 +615,7 @@ }; pm8150b-ibat-lvl1 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "step_wise"; thermal-sensors = <&pm8150b_bcl 1>; @@ -629,7 +631,7 @@ }; pm8150b-vbat-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm8150b_bcl 2>; @@ -646,7 +648,7 @@ }; pm8150b-vbat-lvl1 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm8150b_bcl 3>; @@ -663,7 +665,7 @@ }; pm8150b-vbat-lvl2 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm8150b_bcl 4>; @@ -679,6 +681,54 @@ }; }; + pm8150b-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 5>; + wake-capable-sensor; + + trips { + b_bcl_lvl0: b-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150b-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 6>; + wake-capable-sensor; + + trips { + b_bcl_lvl1: b-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150b-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 7>; + wake-capable-sensor; + + trips { + b_bcl_lvl2: b-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + soc { polling-delay-passive = <100>; polling-delay = <0>; diff --git a/arch/arm64/boot/dts/qcom/pm8150l.dtsi b/arch/arm64/boot/dts/qcom/pm8150l.dtsi index 8a9fccafda971e9e2ddbb45d9d7b34b66f84926c..3586af695f4f93bef0a041856fa04dcdd87c6d6c 100644 --- a/arch/arm64/boot/dts/qcom/pm8150l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150l.dtsi @@ -117,9 +117,9 @@ interrupts = <0x4 0x3d 0x0 IRQ_TYPE_NONE>, <0x4 0x3d 0x1 IRQ_TYPE_NONE>, <0x4 0x3d 0x2 IRQ_TYPE_NONE>; - interrupt-names = "bcl-vbat-lvl0", - "bcl-vbat-lvl1", - "bcl-vbat-lvl2"; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; #thermal-sensor-cells = <1>; }; @@ -400,6 +400,9 @@ }; pm8150a_amoled: qcom,amoled { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,qpnp-amoled-regulator"; status = "disabled"; @@ -461,7 +464,7 @@ }; pm8150l-vph-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm8150l_bcl 2>; @@ -478,7 +481,7 @@ }; pm8150l-vph-lvl1 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm8150l_bcl 3>; @@ -495,7 +498,7 @@ }; pm8150l-vph-lvl2 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm8150l_bcl 4>; @@ -510,4 +513,52 @@ }; }; }; + + pm8150l-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_bcl 5>; + wake-capable-sensor; + + trips { + l_bcl_lvl0: l-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150l-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_bcl 6>; + wake-capable-sensor; + + trips { + l_bcl_lvl1: l-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150l-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_bcl 7>; + wake-capable-sensor; + + trips { + l_bcl_lvl2: l-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/pm8195.dtsi b/arch/arm64/boot/dts/qcom/pm8195.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..51036638acb1ae1e17c6e7e65a16c2407767a2b6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8195.dtsi @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&spmi_bus { + qcom,pm8195@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8195_1_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + + qcom,pon_2 { + qcom,pon-type = ; + qcom,pull-up; + linux,code = ; + }; + }; + + pm8195_1_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x200>; + #clock-cells = <1>; + qcom,num-clkdivs = <2>; + clock-output-names = "pm8195_1_div_clk1", + "pm8195_1_div_clk2"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm8195_1_rtc: qcom,pm8195_1_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8195_1_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + qcom,pm8195_1_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + + pm8195_1_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8195_1_gpio1", "pm8195_1_gpio2", + "pm8195_1_gpio3", "pm8195_1_gpio4", + "pm8195_1_gpio5", "pm8195_1_gpio6", + "pm8195_1_gpio7", "pm8195_1_gpio8", + "pm8195_1_gpio9", "pm8195_1_gpio10"; + gpio-controller; + #gpio-cells = <2>; + }; + + pm8195_1_sdam_2: sdam@b100 { + compatible = "qcom,spmi-sdam"; + reg = <0xb100 0x100>; + }; + + }; + + qcom,pm8195@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + }; + + /* below definitions are for the second instance of pm8195 */ + qcom,pm8195@4 { + compatible = "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm8195_2_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x200>; + #clock-cells = <1>; + qcom,num-clkdivs = <2>; + clock-output-names = "pm8195_2_div_clk1", + "pm8195_2_div_clk2"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm8195_2_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>, + <0x4 0xc1 0 IRQ_TYPE_NONE>, + <0x4 0xc2 0 IRQ_TYPE_NONE>, + <0x4 0xc3 0 IRQ_TYPE_NONE>, + <0x4 0xc4 0 IRQ_TYPE_NONE>, + <0x4 0xc5 0 IRQ_TYPE_NONE>, + <0x4 0xc6 0 IRQ_TYPE_NONE>, + <0x4 0xc7 0 IRQ_TYPE_NONE>, + <0x4 0xc8 0 IRQ_TYPE_NONE>, + <0x4 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8195_2_gpio1", "pm8195_2_gpio2", + "pm8195_2_gpio3", "pm8195_2_gpio4", + "pm8195_2_gpio5", "pm8195_2_gpio6", + "pm8195_2_gpio7", "pm8195_2_gpio8", + "pm8195_2_gpio9", "pm8195_2_gpio10"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + qcom,pm8195@5 { + compatible ="qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + }; + + /* below definitions are for the third instance of pm8195 */ + qcom,pm8195@8 { + compatible = "qcom,spmi-pmic"; + reg = <0x8 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm8195_3_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x200>; + #clock-cells = <1>; + qcom,num-clkdivs = <2>; + clock-output-names = "pm8195_3_div_clk1", + "pm8195_3_div_clk2"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm8195_3_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x8 0xc0 0 IRQ_TYPE_NONE>, + <0x8 0xc1 0 IRQ_TYPE_NONE>, + <0x8 0xc2 0 IRQ_TYPE_NONE>, + <0x8 0xc3 0 IRQ_TYPE_NONE>, + <0x8 0xc4 0 IRQ_TYPE_NONE>, + <0x8 0xc5 0 IRQ_TYPE_NONE>, + <0x8 0xc6 0 IRQ_TYPE_NONE>, + <0x8 0xc7 0 IRQ_TYPE_NONE>, + <0x8 0xc8 0 IRQ_TYPE_NONE>, + <0x8 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8195_3_gpio1", "pm8195_3_gpio2", + "pm8195_3_gpio3", "pm8195_3_gpio4", + "pm8195_3_gpio5", "pm8195_3_gpio6", + "pm8195_3_gpio7", "pm8195_3_gpio8", + "pm8195_3_gpio9", "pm8195_3_gpio10"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + qcom,pm8195@9 { + compatible ="qcom,spmi-pmic"; + reg = <0x9 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +/* PMIC GPIO pin control configurations */ +&pm8195_1_gpios { + storage_sd_detect { + storage_cd_default: storage_cd_default { + pins = "gpio4"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index f97fe75e7fe01979ed2e95ff0c28338d3321de14..41ddd00c89e192871dbcb61e3de57bf32acb095c 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -394,15 +394,11 @@ compatible = "qcom,bcl-v5"; reg = <0x3d00 0x100>; interrupts = <0x2 0x3d 0x0 IRQ_TYPE_NONE>, - <0x2 0x3d 0x1 IRQ_TYPE_NONE>, - <0x2 0x3d 0x0 IRQ_TYPE_NONE>, <0x2 0x3d 0x1 IRQ_TYPE_NONE>, <0x2 0x3d 0x2 IRQ_TYPE_NONE>; - interrupt-names = "bcl-ibat-lvl0", - "bcl-ibat-lvl1", - "bcl-vbat-lvl0", - "bcl-vbat-lvl1", - "bcl-vbat-lvl2"; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; qcom,ibat-use-qg-adc-5a; #thermal-sensor-cells = <1>; }; @@ -636,7 +632,7 @@ }; pmi632-ibat-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "step_wise"; thermal-sensors = <&bcl_sensor 0>; @@ -652,7 +648,7 @@ }; pmi632-ibat-lvl1 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "step_wise"; thermal-sensors = <&bcl_sensor 1>; @@ -668,7 +664,7 @@ }; pmi632-vbat-lvl0 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&bcl_sensor 2>; @@ -685,7 +681,7 @@ }; pmi632-vbat-lvl1 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&bcl_sensor 3>; @@ -702,7 +698,7 @@ }; pmi632-vbat-lvl2 { - polling-delay-passive = <100>; + polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&bcl_sensor 4>; @@ -718,6 +714,54 @@ }; }; + pmi632-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 5>; + wake-capable-sensor; + + trips { + bcl_lvl0: bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pmi632-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 6>; + wake-capable-sensor; + + trips { + bcl_lvl1: bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pmi632-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 7>; + wake-capable-sensor; + + trips { + bcl_lvl2: bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + soc { polling-delay-passive = <100>; polling-delay = <0>; diff --git a/arch/arm64/boot/dts/qcom/qcs401-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs401-iot-sku5.dts new file mode 100644 index 0000000000000000000000000000000000000000..b3f3c128abcd2ccbeec83d529fdbb705b33b9832 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs401-iot-sku5.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs403.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-pinctrl.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS401 sEVB/SLT IOT"; + compatible = "qcom,qcs401-iot", "qcom,qcs401", "qcom,iot"; + qcom,board-id = <0x010020 0x2>; +}; +#include "qcs405-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs401.dtsi b/arch/arm64/boot/dts/qcom/qcs401.dtsi index abf0c5893a2b0948998d66a7d9e1950a075895f6..06387ed9e2e36e92a1501349e5e653a6ad059a62 100644 --- a/arch/arm64/boot/dts/qcom/qcs401.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs401.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ -#include "qcs405.dtsi" +#include "qcs403.dtsi" / { model = "Qualcomm Technologies, Inc. QCS401"; @@ -20,29 +20,5 @@ }; &soc { - /delete-node/ qcom,msm-cpufreq; - - msm_cpufreq: qcom,msm-cpufreq { - compatible = "qcom,msm-cpufreq"; - clock-names = "cpu0_clk"; - clocks = <&clock_cpu APCS_MUX_CLK>; - - qcom,cpufreq-table = - < 1094400 >, - < 1248000 >, - < 1401600 >; - }; - - /delete-node/ qcom,cpu0-computemon; - - cpu0_computemon: qcom,cpu0-computemon { - compatible = "qcom,arm-cpu-mon"; - qcom,cpulist = <&CPU0 &CPU1>; - qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; - qcom,core-dev-table = - < 1094400 MHZ_TO_MBPS( 297, 8) >, - < 1248000 MHZ_TO_MBPS( 597, 8) >, - < 1401600 MHZ_TO_MBPS( 710, 8) >; - }; + /delete-node/ qcom,turing@800000; }; - diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts index bcf65cf5aa3e94b7554c98887bc028dda27b06db..34de78d0baf63603059aba229f17836d3289ceea 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,61 +22,6 @@ compatible = "qcom,qcs403-iot", "qcom,qcs403", "qcom,iot"; qcom,board-id = <0x010020 0x3>; - cpus { - /delete-node/ cpu@102; - /delete-node/ cpu@103; - - cpu-map { - cluster0 { - /delete-node/ core2; - /delete-node/ core3; - }; - }; - }; -}; - -&soc { - cpuss_dump { - /delete-node/ qcom,l1_i_cache102; - /delete-node/ qcom,l1_i_cache103; - /delete-node/ qcom,l1_d_cache102; - /delete-node/ qcom,l1_d_cache103; - }; - - qcom,spm@b012000 { - qcom,cpu-vctl-list = <&CPU0 &CPU1>; - }; - - qcom,lpm-levels { - qcom,pm-cluster@0{ - qcom,pm-cpu { - qcom,cpu = <&CPU0 &CPU1>; - }; - }; - }; - - /delete-node/ cti@61ba000; - /delete-node/ cti@61bb000; - /delete-node/ etm@61be000; - /delete-node/ etm@61bf000; - funnel@61a1000 { - ports { - /delete-node/ port@3; - /delete-node/ port@4; - }; - }; -}; - -&thermal_zones { - cpuss-max-step { - cooling-maps { - /delete-node/ cpu2_cdev; - /delete-node/ cpu3_cdev; - }; - }; - - /delete-node/ cpuss-2-step; - /delete-node/ cpuss-3-step; }; &qnand_1 { diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts index 4220f8e48ef5517024aff632b9d44400a97245dc..c782e1d43ca48d6845ac06ada852f6b4e73a7069 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts @@ -22,61 +22,6 @@ compatible = "qcom,qcs403-iot", "qcom,qcs403", "qcom,iot"; qcom,board-id = <0x010015 0x0>; - cpus { - /delete-node/ cpu@102; - /delete-node/ cpu@103; - - cpu-map { - cluster0 { - /delete-node/ core2; - /delete-node/ core3; - }; - }; - }; -}; - -&soc { - cpuss_dump { - /delete-node/ qcom,l1_i_cache102; - /delete-node/ qcom,l1_i_cache103; - /delete-node/ qcom,l1_d_cache102; - /delete-node/ qcom,l1_d_cache103; - }; - - qcom,spm@b012000 { - qcom,cpu-vctl-list = <&CPU0 &CPU1>; - }; - - qcom,lpm-levels { - qcom,pm-cluster@0{ - qcom,pm-cpu { - qcom,cpu = <&CPU0 &CPU1>; - }; - }; - }; - - /delete-node/ cti@61ba000; - /delete-node/ cti@61bb000; - /delete-node/ etm@61be000; - /delete-node/ etm@61bf000; - funnel@61a1000 { - ports { - /delete-node/ port@3; - /delete-node/ port@4; - }; - }; -}; - -&thermal_zones { - cpuss-max-step { - cooling-maps { - /delete-node/ cpu2_cdev; - /delete-node/ cpu3_cdev; - }; - }; - - /delete-node/ cpuss-2-step; - /delete-node/ cpuss-3-step; }; #include "qcs405-mdss-panels.dtsi" diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts index 637d94ce2e505441fc42a4360b7c3e1aa0a7b19f..7497da5aad38bd95af18ff016118a0cfba63ab62 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts @@ -22,50 +22,9 @@ compatible = "qcom,qcs403-iot", "qcom,qcs403", "qcom,iot"; qcom,board-id = <0x010020 0x4>; - cpus { - /delete-node/ cpu@102; - /delete-node/ cpu@103; - - cpu-map { - cluster0 { - /delete-node/ core2; - /delete-node/ core3; - }; - }; - }; }; &soc { - cpuss_dump { - /delete-node/ qcom,l1_i_cache102; - /delete-node/ qcom,l1_i_cache103; - /delete-node/ qcom,l1_d_cache102; - /delete-node/ qcom,l1_d_cache103; - }; - - qcom,spm@b012000 { - qcom,cpu-vctl-list = <&CPU0 &CPU1>; - }; - - qcom,lpm-levels { - qcom,pm-cluster@0{ - qcom,pm-cpu { - qcom,cpu = <&CPU0 &CPU1>; - }; - }; - }; - - /delete-node/ cti@61ba000; - /delete-node/ cti@61bb000; - /delete-node/ etm@61be000; - /delete-node/ etm@61bf000; - funnel@61a1000 { - ports { - /delete-node/ port@3; - /delete-node/ port@4; - }; - }; - spi@78b5000 { status = "ok"; spi@0 { @@ -82,18 +41,6 @@ }; }; -&thermal_zones { - cpuss-max-step { - cooling-maps { - /delete-node/ cpu2_cdev; - /delete-node/ cpu3_cdev; - }; - }; - - /delete-node/ cpuss-2-step; - /delete-node/ cpuss-3-step; -}; - &qnand_1 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku4.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku4.dts index 77ac0f29bb32457f6fd477e4e589094130b8ab65..bbc81eb229edd906521b2e04cf6676c996bd8142 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku4.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku4.dts @@ -22,50 +22,9 @@ compatible = "qcom,qcs403-iot", "qcom,qcs403", "qcom,iot"; qcom,board-id = <0x010020 0x5>; - cpus { - /delete-node/ cpu@102; - /delete-node/ cpu@103; - - cpu-map { - cluster0 { - /delete-node/ core2; - /delete-node/ core3; - }; - }; - }; }; &soc { - cpuss_dump { - /delete-node/ qcom,l1_i_cache102; - /delete-node/ qcom,l1_i_cache103; - /delete-node/ qcom,l1_d_cache102; - /delete-node/ qcom,l1_d_cache103; - }; - - qcom,spm@b012000 { - qcom,cpu-vctl-list = <&CPU0 &CPU1>; - }; - - qcom,lpm-levels { - qcom,pm-cluster@0{ - qcom,pm-cpu { - qcom,cpu = <&CPU0 &CPU1>; - }; - }; - }; - - /delete-node/ cti@61ba000; - /delete-node/ cti@61bb000; - /delete-node/ etm@61be000; - /delete-node/ etm@61bf000; - funnel@61a1000 { - ports { - /delete-node/ port@3; - /delete-node/ port@4; - }; - }; - gpio_keys { vol_mute { gpios = <&tlmm 19 GPIO_ACTIVE_LOW>; @@ -73,18 +32,6 @@ }; }; -&thermal_zones { - cpuss-max-step { - cooling-maps { - /delete-node/ cpu2_cdev; - /delete-node/ cpu3_cdev; - }; - }; - - /delete-node/ cpuss-2-step; - /delete-node/ cpuss-3-step; -}; - &qnand_1 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku5.dts new file mode 100644 index 0000000000000000000000000000000000000000..f1242404ca817b94e4290f93305a41ac3e99b563 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku5.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs403.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-pinctrl.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS403 sEVB/SLT IOT"; + compatible = "qcom,qcs403-iot", "qcom,qcs403", "qcom,iot"; + qcom,board-id = <0x010020 0x2>; +}; +#include "qcs405-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs403.dtsi b/arch/arm64/boot/dts/qcom/qcs403.dtsi index c5058cbaec53a2d25ed63db85be5fc89badfebe5..70f1c135f7db0b83162d38a4ad70d8b5f4cc5e4a 100644 --- a/arch/arm64/boot/dts/qcom/qcs403.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs403.dtsi @@ -17,20 +17,48 @@ model = "Qualcomm Technologies, Inc. QCS403"; qcom,msm-name = "QCS403"; qcom,msm-id = <373 0x0>; + + cpus { + /delete-node/ cpu@102; + /delete-node/ cpu@103; + cpu-map { + cluster0 { + /delete-node/ core2; + /delete-node/ core3; + }; + }; + }; + }; &soc { - /delete-node/ qcom,msm-cpufreq; - msm_cpufreq: qcom,msm-cpufreq { - compatible = "qcom,msm-cpufreq"; - clock-names = "cpu0_clk"; - clocks = <&clock_cpu APCS_MUX_CLK>; + cpuss_dump { + /delete-node/ qcom,l1_i_cache102; + /delete-node/ qcom,l1_i_cache103; + /delete-node/ qcom,l1_d_cache102; + /delete-node/ qcom,l1_d_cache103; + }; + qcom,spm@b012000 { + qcom,cpu-vctl-list = <&CPU0 &CPU1>; + }; + qcom,lpm-levels { + qcom,pm-cluster@0{ + qcom,pm-cpu { + qcom,cpu = <&CPU0 &CPU1>; + }; + }; + }; + /delete-node/ cti@61ba000; + /delete-node/ cti@61bb000; + /delete-node/ etm@61be000; + /delete-node/ etm@61bf000; - qcom,cpufreq-table = - < 1094400 >, - < 1248000 >, - < 1401600 >; + funnel@61a1000 { + ports { + /delete-node/ port@3; + /delete-node/ port@4; + }; }; /delete-node/ qcom,cpu0-computemon; @@ -46,6 +74,17 @@ }; }; +&thermal_zones { + cpuss-max-step { + cooling-maps { + /delete-node/ cpu2_cdev; + /delete-node/ cpu3_cdev; + }; + }; + /delete-node/ cpuss-2-step; + /delete-node/ cpuss-3-step; +}; + &adsp_fw_mem { reg = <0x0 0x87400000 0x0 0x1200000>; }; diff --git a/arch/arm64/boot/dts/qcom/qcs404-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs404-iot-sku3.dts new file mode 100644 index 0000000000000000000000000000000000000000..227e63721fe99482f631398f00b774b5f8a044ef --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs404-iot-sku3.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs404.dtsi" +#include "qcs405-wsa-audio-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS404 SSRD IOT"; + compatible = "qcom,qcs404-iot", "qcom,qcs404", "qcom,iot"; + qcom,board-id = <0x010020 0x4>; + +}; + +&soc { + spi@78b5000 { + status = "ok"; + spi@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; + + gpio_keys { + vol_mute { + gpios = <&tlmm 19 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&qnand_1 { + status = "ok"; +}; + +&soc { + usb2_extcon: usb2_extcon { + compatible = "linux,extcon-usb-gpio"; + vbus-gpio = <&tlmm 27 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_ssrd_det_default>; + }; +}; + +&usb2s { + extcon = <&usb2_extcon>; +}; + +&usb3 { + status = "disabled"; +}; + +&usb_ss_phy { + status = "ok"; + qcom,keep-powerdown; +}; + +&usb2_phy1 { + status = "disabled"; +}; + +&tlmm { + evb_tlmm_gpio_key{ + tlmm_gpio_key_active: tlmm_gpio_key_active { + mux { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + + config { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + }; + + tlmm_gpio_key_suspend: tlmm_gpio_key_suspend { + mux { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + + config { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs404-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs404-iot-sku5.dts new file mode 100644 index 0000000000000000000000000000000000000000..c76b41fc2d37231b569127ed04d530ffb539ce83 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs404-iot-sku5.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs404.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-pinctrl.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS404 sEVB/SLT IOT"; + compatible = "qcom,qcs404-iot", "qcom,qcs404", "qcom,iot"; + qcom,board-id = <0x010020 0x2>; +}; +#include "qcs405-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs404-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs404-iot-sku6.dts new file mode 100644 index 0000000000000000000000000000000000000000..79f4044606e5b4e8b8c8212bd4168a2e0785776f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs404-iot-sku6.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs404.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS404 QCS404 1 CSRA"; + compatible = "qcom,qcs404-iot", "qcom,qcs404", "qcom,iot"; + qcom,board-id = <0x020020 0x4>; + +}; + +&qnand_1 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bcf08143cbae89d48d9661a5a2436a449b12e99c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs405.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS404"; + qcom,msm-name = "QCS404"; + qcom,msm-id = <410 0x0>; + +}; + +&adsp_fw_mem { + reg = <0x0 0x87400000 0x0 0x1200000>; +}; + +&reserved_mem { + linux,cma { + size = <0 0x400000>; + }; +}; + +&qcom_seecom { + /delete-property/ qcom,appsbl-qseecom-support; +}; 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 742270e49394d8767ffadb47e69c569cc43caff5..408285b6c756b06241c341568b9fa45c96765c31 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi @@ -43,6 +43,26 @@ pinctrl-1 = <&cdc_dmic67_clk_sleep &cdc_dmic67_data_sleep>; qcom,lpi-gpios; }; + + pri_mi2s_gpios: pri_mi2s_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_sck_active &pri_mi2s_ws_active + &pri_mi2s_sd0_active>; + pinctrl-1 = <&pri_mi2s_sck_sleep &pri_mi2s_ws_sleep + &pri_mi2s_sd0_sleep>; + }; + + sec_mi2s_gpios: sec_mi2s_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_mi2s_sck_active &sec_mi2s_ws_active + &sec_mi2s_sd0_active &sec_mi2s_sd1_active + &sec_mi2s_sd2_active &sec_mi2s_sd3_active>; + pinctrl-1 = <&sec_mi2s_sck_sleep &sec_mi2s_ws_sleep + &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep + &sec_mi2s_sd2_sleep &sec_mi2s_sd3_sleep>; + }; }; &q6core { @@ -68,6 +88,8 @@ qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; + qcom,pri-mi2s-gpios = <&pri_mi2s_gpios>; + qcom,sec-mi2s-gpios = <&sec_mi2s_gpios>; qcom,audio-routing = "RX_BIAS", "MCLK", "lineout booster", "LINEOUT1", @@ -98,12 +120,7 @@ "VA MIC BIAS1", "Digital Mic7", "CSRA_12 IN", "PRI_MI2S_RX"; pinctrl-names = "default"; - pinctrl-0 = <&spdifrx_opt_default - &pri_mi2s_sck_active &pri_mi2s_ws_active - &pri_mi2s_sd0_active - &sec_mi2s_sck_active &sec_mi2s_ws_active - &sec_mi2s_sd0_active &sec_mi2s_sd1_active - &sec_mi2s_sd2_active &sec_mi2s_sd3_active>; + pinctrl-0 = <&spdifrx_opt_default>; }; &dai_mi2s0 { 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 2818f5f0b17d37480da8da20e1d4abb5539ceae1..44b10697db35f74e5bcf4a0e2a8750cd412ffc25 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi @@ -43,6 +43,30 @@ pinctrl-1 = <&cdc_dmic67_clk_sleep &cdc_dmic67_data_sleep>; qcom,lpi-gpios; }; + + pri_mi2s_gpios: pri_mi2s_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_sck_active &pri_mi2s_ws_active + &pri_mi2s_sd0_active &pri_mi2s_sd1_active + &pri_mi2s_sd2_active &pri_mi2s_sd3_active + &pri_mi2s_sd4_active &pri_mi2s_sd5_active>; + pinctrl-1 = <&pri_mi2s_sck_sleep &pri_mi2s_ws_sleep + &pri_mi2s_sd0_sleep &pri_mi2s_sd1_sleep + &pri_mi2s_sd2_sleep &pri_mi2s_sd3_sleep + &pri_mi2s_sd4_sleep &pri_mi2s_sd5_sleep>; + }; + + sec_mi2s_gpios: sec_mi2s_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_mi2s_sck_active &sec_mi2s_ws_active + &sec_mi2s_sd0_active &sec_mi2s_sd1_active + &sec_mi2s_sd2_active &sec_mi2s_sd3_active>; + pinctrl-1 = <&sec_mi2s_sck_sleep &sec_mi2s_ws_sleep + &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep + &sec_mi2s_sd2_sleep &sec_mi2s_sd3_sleep>; + }; }; &q6core { @@ -71,6 +95,8 @@ qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; + qcom,pri-mi2s-gpios = <&pri_mi2s_gpios>; + qcom,sec-mi2s-gpios = <&sec_mi2s_gpios>; qcom,audio-routing = "RX_BIAS", "MCLK", "lineout booster", "LINEOUT1", @@ -106,14 +132,7 @@ "CSRA_9A IN", "PRI_MI2S_RX", "CSRA_BC IN", "PRI_MI2S_RX"; pinctrl-names = "default"; - pinctrl-0 = <&spdifrx_opt_default - &pri_mi2s_sck_active &pri_mi2s_ws_active - &pri_mi2s_sd0_active &pri_mi2s_sd1_active - &pri_mi2s_sd2_active &pri_mi2s_sd3_active - &pri_mi2s_sd4_active &pri_mi2s_sd5_active - &sec_mi2s_sck_active &sec_mi2s_ws_active - &sec_mi2s_sd0_active &sec_mi2s_sd1_active - &sec_mi2s_sd2_active &sec_mi2s_sd3_active>; + pinctrl-0 = <&spdifrx_opt_default>; }; &dai_mi2s0 { diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi index 1e753a38e799d71a14d36c82ead83c7d02e38978..1138390a012ca8f8cc5979a7861183cb09e64c6b 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi @@ -43,6 +43,32 @@ pinctrl-1 = <&cdc_dmic67_clk_sleep &cdc_dmic67_data_sleep>; qcom,lpi-gpios; }; + + pri_mi2s_gpios: pri_mi2s_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_sck_active &pri_mi2s_ws_active + &pri_mi2s_sd0_active &pri_mi2s_sd1_active + &pri_mi2s_sd2_active &pri_mi2s_sd3_active + &pri_mi2s_sd4_active &pri_mi2s_sd5_active + &pri_mi2s_sd6_active &pri_mi2s_sd7_active>; + pinctrl-1 = <&pri_mi2s_sck_sleep &pri_mi2s_ws_sleep + &pri_mi2s_sd0_sleep &pri_mi2s_sd1_sleep + &pri_mi2s_sd2_sleep &pri_mi2s_sd3_sleep + &pri_mi2s_sd4_sleep &pri_mi2s_sd5_sleep + &pri_mi2s_sd6_sleep &pri_mi2s_sd7_sleep>; + }; + + sec_mi2s_gpios: sec_mi2s_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_mi2s_sck_active &sec_mi2s_ws_active + &sec_mi2s_sd0_active &sec_mi2s_sd1_active + &sec_mi2s_sd2_active &sec_mi2s_sd3_active>; + pinctrl-1 = <&sec_mi2s_sck_sleep &sec_mi2s_ws_sleep + &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep + &sec_mi2s_sd2_sleep &sec_mi2s_sd3_sleep>; + }; }; &q6core { @@ -72,6 +98,8 @@ qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; + qcom,pri-mi2s-gpios = <&pri_mi2s_gpios>; + qcom,sec-mi2s-gpios = <&sec_mi2s_gpios>; qcom,audio-routing = "RX_BIAS", "MCLK", "lineout booster", "LINEOUT1", @@ -109,15 +137,7 @@ "CSRA_DE IN", "PRI_MI2S_RX", "CSRA_F0 IN", "PRI_MI2S_RX"; pinctrl-names = "default"; - pinctrl-0 = <&spdifrx_opt_default - &pri_mi2s_sck_active &pri_mi2s_ws_active - &pri_mi2s_sd0_active &pri_mi2s_sd1_active - &pri_mi2s_sd2_active &pri_mi2s_sd3_active - &pri_mi2s_sd4_active &pri_mi2s_sd5_active - &pri_mi2s_sd6_active &pri_mi2s_sd7_active - &sec_mi2s_sck_active &sec_mi2s_ws_active - &sec_mi2s_sd0_active &sec_mi2s_sd1_active - &sec_mi2s_sd2_active &sec_mi2s_sd3_active>; + pinctrl-0 = <&spdifrx_opt_default>; }; &dai_mi2s0 { diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts index 227b8e7033770567291fef59da01b774262ddb63..dddd2f01b5d1b7de80a41b476ed44a9bc5765871 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -60,4 +60,13 @@ spi-max-frequency = <50000000>; }; }; + + gpio_keys { + /delete-node/ vol_mute; + }; +}; + +&pcie0 { + pinctrl-0 = <&pcie0_perst_default &pcie0_wake_default>; + wake-gpio = <&tlmm 21 0>; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi b/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi index aa18e3b0ddd7de195f790d403533cf3000460088..6980899b38bafa3659a0cb968c8d0c1fa925642a 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi @@ -11,10 +11,6 @@ * GNU General Public License for more details. */ -&va_macro { - qcom,va-dmic-sample-rate = <2400000>; -}; - &i2c_2 { status = "ok"; qcom,clk-freq-out = <100000>; diff --git a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi index bda2e511a766e425195d53c0e35edba1725bebdd..b8fbb572f0239a9dd8afdb18e36e90a424a1ed47 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi @@ -65,10 +65,9 @@ 0x0044 0x00 0x0>; pinctrl-names = "default"; - pinctrl-0 = <&pcie0_perst_default &pcie0_wake_default>; + pinctrl-0 = <&pcie0_perst_default>; perst-gpio = <&tlmm 43 0>; - wake-gpio = <&tlmm 21 0>; vreg-1.8-supply = <&pms405_l5>; vreg-0.9-supply = <&pms405_l3>; @@ -115,6 +114,13 @@ clock-output-names = "pcie_0_pipe_clk"; resets = <&clock_gcc GCC_PCIEPHY_0_PHY_BCR>; reset-names = "pcie_0_phy_reset"; + + pcie_rc0: pcie_rc0 { + #address-cells = <5>; + #size-cells = <0>; + reg = <0 0 0 0 0>; + pci-ids = "17cb:1000"; + }; }; pcie0_msi: qcom,pcie0_msi@a0000000 { diff --git a/arch/arm64/boot/dts/qcom/qcs405-va-bolero.dtsi b/arch/arm64/boot/dts/qcom/qcs405-va-bolero.dtsi index 766714c24e6fc23550be0ead14fcc17b9b1e4f44..7b5fa64c4e441b3e3c6749abc8efab0eb860b060 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-va-bolero.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-va-bolero.dtsi @@ -19,7 +19,7 @@ va-vdd-micb-supply = <&pms405_l7>; qcom,va-vdd-micb-voltage = <1800000 1800000>; qcom,va-vdd-micb-current = <9000>; - qcom,va-dmic-sample-rate = <600000>; + qcom,va-dmic-sample-rate = <2400000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 47fdcb141b612dbc784218c60b0aadcb9ed4b773..c58da349d3b346de041fd04fd87bd6f66e0f75f3 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -1311,13 +1311,19 @@ /* VDD is an external regulator eLDO5 */ vdd-io-supply = <&pms405_l11>; - qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-voltage-level = <1800000 1800000>; qcom,vdd-io-current-level = <0 24200>; + qcom,core_3_0v_support; + qcom,nonremovable; + pinctrl-names = "active", "sleep"; pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + /delete-property/ qcom,devfreq,freq-table; + /delete-property/ cd-gpios; + status = "ok"; }; @@ -1354,7 +1360,8 @@ qcom,cpufreq-table = < 1094400 >, - < 1248000 >; + < 1248000 >, + < 1401600 >; }; ddr_bw_opp_table: ddr-bw-opp-table { @@ -1395,7 +1402,8 @@ qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; qcom,core-dev-table = < 1094400 MHZ_TO_MBPS( 297, 8) >, - < 1248000 MHZ_TO_MBPS( 597, 8) >; + < 1248000 MHZ_TO_MBPS( 597, 8) >, + < 1401600 MHZ_TO_MBPS( 710, 8) >; }; emac_hw: qcom,emac@07A80000 { @@ -1509,6 +1517,26 @@ qcom,smmu-s1-bypass; qcom,hyp_disabled; }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + **/ + vdd-wlan-io-supply = <&pms405_l5>; + qcom,cap-tsf-gpio = <&tlmm 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; }; #include "qcs405-gdsc.dtsi" diff --git a/arch/arm64/boot/dts/qcom/qcs407-iot-sku1.dts b/arch/arm64/boot/dts/qcom/qcs407-iot-sku1.dts new file mode 100644 index 0000000000000000000000000000000000000000..34039bc1f83bc653b7173d5fd4e364bf0210d243 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407-iot-sku1.dts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs407.dtsi" +#include "qcs405-wsa-audio-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407 EVB1 1000 IOT"; + compatible = "qcom,qcs407-iot", "qcom,qcs407", "qcom,iot"; + qcom,board-id = <0x010020 0>; +}; + +&i2c_5 { + status = "ok"; +}; + +&smb1351_otg_supply { + status = "ok"; +}; + +&usb2_phy0 { + qcom,snps-hs-phy-init-seq = + <0xc0 0x01 0>, + <0xe8 0x0d 0>, + <0x74 0x12 0>, + <0x98 0x63 0>, + <0x9c 0x83 0>, + <0xa0 0x1d 0>, + <0xa4 0x03 0>, + <0x8c 0x23 0>, + <0x78 0x08 0>, + <0x7c 0xdc 0>, + <0x90 0xe0 20>, + <0x74 0x10 0>, + <0x90 0x60 0>, + <0xffffffff 0xffffffff 0>; +}; + +&usb2s { + extcon = <&smb1351_otg_supply>; + vbus_dwc3-supply = <&smb1351_otg_supply>; +}; + +&soc { + gpio_keys { + vol_mute { + gpios = <&tlmm 19 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&tlmm { + evb_tlmm_gpio_key{ + tlmm_gpio_key_active: tlmm_gpio_key_active { + mux { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + + config { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + }; + + tlmm_gpio_key_suspend: tlmm_gpio_key_suspend { + mux { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + + config { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs407-iot-sku12.dts b/arch/arm64/boot/dts/qcom/qcs407-iot-sku12.dts new file mode 100644 index 0000000000000000000000000000000000000000..dbaf21baa7c1fcb847b6a9f1c0c7a2a6cf3f2c3e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407-iot-sku12.dts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs407.dtsi" +#include "qcs405-csra8-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-linear-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407 EVB1 4K/CSRA8 SPI/LiN"; + compatible = "qcom,qcs407-iot", "qcom,qcs407", "qcom,iot"; + qcom,board-id = <0x080020 0x1>; +}; + +&soc { + spi@78b5000 { + status = "ok"; + spi@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs407-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs407-iot-sku3.dts new file mode 100644 index 0000000000000000000000000000000000000000..27e1f9d640f26b1c05948a9b18a1f2afc5a4b039 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407-iot-sku3.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs407.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-pinctrl.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407 sEVB/SLT IOT"; + compatible = "qcom,qcs407-iot", "qcom,qcs407", "qcom,iot"; + qcom,board-id = <0x010020 0x2>; +}; +#include "qcs405-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs407-iot-sku4.dts b/arch/arm64/boot/dts/qcom/qcs407-iot-sku4.dts new file mode 100644 index 0000000000000000000000000000000000000000..18c434306d6a52fd3cc80adef83ea8f245442288 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407-iot-sku4.dts @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs407.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407 EVB1 4000 DSI IOT"; + compatible = "qcom,qcs407-iot", "qcom,qcs407", "qcom,iot"; + qcom,board-id = <0x020020 0x1>; +}; + +#include "qcs405-mdss-panels.dtsi" + +&mdss_hdmi_tx { + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", + "hdmi_active", "hdmi_sleep"; + pinctrl-0 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; + pinctrl-1 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_active &mdss_hdmi_cec_suspend>; + pinctrl-2 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_cec_active &mdss_hdmi_ddc_suspend>; + pinctrl-3 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_active &mdss_hdmi_cec_active>; + pinctrl-4 = <&mdss_hdmi_5v_suspend &mdss_hdmi_hpd_suspend + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&i2c_5 { /* BLSP (NTAG) */ + status = "ok"; + nq@55 { + status = "ok"; + }; +}; + +&soc { + spi@78b5000 { + status = "ok"; + spi@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs407-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs407-iot-sku6.dts new file mode 100644 index 0000000000000000000000000000000000000000..46d06b57b1817af1a32a44eb5ec7c2e7d032571d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407-iot-sku6.dts @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs407.dtsi" +#include "qcs405-csra1-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407 EVB1 4000 CSRA1 IOT"; + compatible = "qcom,qcs407-iot", "qcom,qcs407", "qcom,iot"; + qcom,board-id = <0x040020 0x1>; +}; + +#include "qcs405-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&soc { + spi@78b5000 { + status = "ok"; + spi@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs407-iot-sku9.dts b/arch/arm64/boot/dts/qcom/qcs407-iot-sku9.dts new file mode 100644 index 0000000000000000000000000000000000000000..ffb93e7e053c90904a5de4865d12331d6377f804 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407-iot-sku9.dts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs407.dtsi" +#include "qcs405-audio-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" +#include "qcs405-pinctrl.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407 RCM IOT"; + compatible = "qcom,qcs407-iot", "qcom,qcs407", "qcom,iot"; + qcom,board-id = <0x010015 0x0>; +}; + +#include "qcs405-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 41 0>; + qcom,platform-reset-gpio = <&tlmm 39 0>; + qcom,platform-bklight-en-gpio = <&tlmm 48 0>; +}; + +&dsi_hx8394d_720_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_tlmm_gpio"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&smb1351_otg_supply { + status = "disabled"; +}; + +&usb3 { + status = "disabled"; +}; + +&usb_ss_phy { + status = "ok"; + qcom,keep-powerdown; +}; + +&usb2_phy1 { + status = "disabled"; +}; + +&emac_hw { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs407.dtsi b/arch/arm64/boot/dts/qcom/qcs407.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..aeb7d3071d6cf1642e9198929d8293d1a812ac0f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs407.dtsi @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qcs405.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS407"; + qcom,msm-name = "QCS407"; + qcom,msm-id = <411 0x0>; + +}; diff --git a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi index 3d0c30f8c254b7a8a864561f32d7830b1a4f4519..16a4bca74ffa45526299be77d2e83aacc620b081 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi @@ -30,6 +30,10 @@ #include "smb1390.dtsi" }; +&fsa4480 { + status = "disabled"; +}; + &pm6150l_gpios { key_vol_up { key_vol_up_default: key_vol_up_default { @@ -322,13 +326,16 @@ regulator-max-microvolt = <2912000>; }; -&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>; +&sde_dp { + status="disabled"; +}; + +&mdss_dp_pll { + status="disabled"; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dsi>; }; &qupv3_se1_i2c { @@ -406,6 +413,9 @@ }; }; +&dsi_ext_bridge_hdmi_1080p { + qcom,mdss-dsi-ext-bridge = <0>; +}; &soc { ext_dsi_bridge_display: qcom,dsi-display@50 { diff --git a/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi b/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bbe8e8e6f225778d88006d3147585d1627cf3a4e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/ { + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; + }; + + soc: soc { }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x2000000>; + linux,cma-default; + }; + + qseecom_mem: qseecom_region@0x9e400000 { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1400000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + }; + }; + + 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/vdevs/1c0f0000.virtio_blk/vdc"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + }; + }; + }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + virtual-interrupt-parent = "gic"; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + clock_gcc: qcom,gcc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_rpmh: qcom,rpmh { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; + + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; + + hab: qcom,hab { + compatible = "qcom,hab"; + vmid = <2>; + + mmidgrp100: mmidgrp100 { + grp-start-id = <100>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp200: mmidgrp200 { + grp-start-id = <200>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp300: mmidgrp300 { + grp-start-id = <300>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp400: mmidgrp400 { + grp-start-id = <400>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp500: mmidgrp500 { + grp-start-id = <500>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp600: mmidgrp600 { + grp-start-id = <600>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp700: mmidgrp700 { + grp-start-id = <700>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp800: mmidgrp800 { + grp-start-id = <800>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp900: mmidgrp900 { + grp-start-id = <900>; + role = "fe"; + remote-vmids = <0>; + }; + + mmidgrp1000: mmidgrp1000 { + grp-start-id = <1000>; + role = "fe"; + remote-vmids = <0>; + }; + }; + + sde_kms_hyp: qcom,sde_kms_hyp@ae00000 { + compatible = "qcom,sde-kms-hyp"; + qcom,client-id = "7815"; + }; + + wdog: qcom,wdt@17c10000{ + compatible = "qcom,msm-watchdog"; + reg = <0x17c10000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 0 0>, <0 1 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + qcom,scandump-sizes = <0x10100 0x10100 0x10100 0x10100 + 0x18100 0x18100 0x18100 0x18100>; + }; + + qcom,msm-imem@14680000 { + compatible = "qcom,msm-imem"; + reg = <0x14680000 0x1000>; + ranges = <0x0 0x14680000 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>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + 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>; + }; + }; + + vm_restart: restart { + compatible = "qcom,vm-restart"; + status = "ok"; + }; + + spmi_bus: qcom,spmi { + compatible = "qcom,viospmi-pmic-arb"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + viospmi: virtio-spmi@1c800000 { + compatible = "virtio,mmio"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1c800000 0x1100>; + interrupts = ; + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts new file mode 100644 index 0000000000000000000000000000000000000000..0d95e1540cf402b9560638ecabbdc7874dc16578 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts @@ -0,0 +1,50 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD PCIE-EP"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 1>, <25 0x101>; +}; + +&restart_pshold { + qcom,force-warm-reboot; +}; + +&cnss_qca6390 { + status = "disabled"; +}; + +&ipa_hw { + qcom,use-ipa-in-mhi-mode; +}; + +&pcie0 { + status = "disabled"; +}; + +&pcie_ep { + status = "ok"; +}; + +&mhi_device { + status = "ok"; +}; + +&mhi_net_device { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts new file mode 100644 index 0000000000000000000000000000000000000000..14c0248a591e517b9b4edec7455cb5943266e2d9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD USB-EP"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 2>, <25 0x102>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard.dts new file mode 100644 index 0000000000000000000000000000000000000000..1fc00a911c001c5d0cff2545a21cdb6b53f6c35a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 0>, <25 0x100>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ee1e7cc77def16cff5edd14c8628148868352cc7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi @@ -0,0 +1,203 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sdxprairie.dtsi" +#include "sdxprairie-mtp.dtsi" + +&soc { + /delete-node/ qcom,battery-data; + + codec_vreg: regulator-codec-tlv320aic3x { + compatible = "regulator-fixed"; + regulator-name = "codec_vreg"; + startup-delay-us = <100>; + gpio = <&tlmm 23 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + snd_tlv3x: sound-auto { + compatible = "qcom,sdx-asoc-snd-auto"; + qcom,model = "sdx-auto-i2s-snd-card"; + qcom,prim_mi2s_aux_master = <&prim_master>; + qcom,prim_mi2s_aux_slave = <&prim_slave>; + qcom,sec_mi2s_aux_master = <&sec_master>; + qcom,sec_mi2s_aux_slave = <&sec_slave>; + + pinctrl-names = "default"; + pinctrl-0 = <&a2b_cdc_sel_default>, <&i2s_mclk_active>; + + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&hostless>, <&afe>, <&routing>, + <&pcm_dtmf>, <&host_pcm>, <&compress>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-voip-dsp", "msm-pcm-voice", + "msm-pcm-loopback", "msm-pcm-hostless", + "msm-pcm-afe", "msm-pcm-routing", + "msm-pcm-dtmf", "msm-voice-host-pcm", + "msm-compress-dsp"; + asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>, + <&dtmf_tx>, + <&rx_capture_tx>, <&rx_playback_rx>, + <&tx_capture_tx>, <&tx_playback_rx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_sec_auxpcm>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", + "msm-dai-stub-dev.6", "msm-dai-stub-dev.7", + "msm-dai-stub-dev.8", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-auxpcm.2"; + asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; + asoc-codec-names = "tlv320aic3x-codec", "msm-stub-codec.1"; + }; + + pps { + compatible = "pps-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pps>; + gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +}; + +/* delete pm8150b nodes */ +&thermal_zones { + /delete-node/ pm8150b-wp-therm; + /delete-node/ pm8150b_tz; + /delete-node/ pm8150b-ibat-lvl0; + /delete-node/ pm8150b-ibat-lvl1; + /delete-node/ pm8150b-vbat-lvl0; + /delete-node/ pm8150b-vbat-lvl1; + /delete-node/ pm8150b-vbat-lvl2; + /delete-node/ pm8150b-bcl-lvl0; + /delete-node/ pm8150b-bcl-lvl1; + /delete-node/ pm8150b-bcl-lvl2; + /delete-node/ soc; +}; + +&usb { + extcon = <&vbus_detect>; +}; + +&spmi_bus { + /delete-node/ qpnp,fg; + /delete-node/ bcl@1d00; + /delete-node/ qcom,usb-pdphy@1700; + /delete-node/ qcom,qpnp-smb5; + /delete-node/ adc_tm@3500; + /delete-node/ vadc@3100; + /delete-node/ qcom,pm8150b@2; + /delete-node/ qcom,pm8150b@3; +}; + +&qnand_1 { + status = "ok"; +}; + +&blsp1_uart2b_hs { + status = "okay"; +}; + +&vbus_detect { + status = "okay"; +}; + +&snd_934x { + status = "disabled"; +}; + +&wcd9xxx_intc { + status = "disabled"; +}; + +&clock_audio_up { + status = "disabled"; +}; + +&wcd_rst_gpio { + status = "disabled"; +}; + + +&wcd934x_cdc { + status = "disabled"; +}; + +&spi_2 { + status = "okay"; + + can-controller@0 { + compatible = "qcom,nxp,mpc5746c"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <88 0>; + spi-max-frequency = <5000000>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <2>; + qcom,bits-per-word = <8>; + qcom,support-can-fd; + }; +}; + +&i2c_3 { + tlv320aic3x_codec: tlv320aic3x@18 { + compatible = "ti,tlv320aic3x"; + reg = <0x18>; + gpio-reset = <&tlmm 92 0>; + reset-inverted; + AVDD-supply = <&codec_vreg>; + IOVDD-supply = <&codec_vreg>; + ai3x-ocmv = <1>; + }; + + eeprom@52 { + compatible = "atmel,24c128"; + reg = <0x52>; + pagesize = <32>; + }; +}; + +&i2c_4 { + status = "okay"; +}; + +&emac_hw { + /delete-property/ vreg_rgmii-supply; + pinctrl-names = "default"; + pinctrl-0 = <&vreg_rgmii_off_default>; + qcom,phy-reset-delay-msecs = <10>; +}; + +&vreg_rgmii_io_pads { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; + +&cnss_qca6390 { + vdd-wlan-ctrl1-supply = <&vreg_conn_pa>; + vdd-wlan-aon-supply = <&pmxprairie_s3>; + vdd-wlan-rfa1-supply = <&pmxprairie_s2>; + vdd-wlan-rfa3-supply = <&pmxprairie_s4>; + qcom,vdd-wlan-ctrl1-info = <0 0 0 0>; + qcom,vdd-wlan-aon-info = <950000 950000 0 0>; + qcom,vdd-wlan-rfa1-info = <1350000 1350000 0 0>; + qcom,vdd-wlan-rfa3-info = <1904000 1904000 450000 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi index d0ebb604d858a3c0234963897dbd5c0aea986d40..e86b8deb8f5764c6d3e69632ead18eabc783fed2 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi @@ -11,7 +11,11 @@ */ #include #include +#include "sa6155-cnss.dtsi" +&bluetooth_ext { + status = "ok"; +}; &qupv3_se6_spi { status = "ok"; @@ -38,6 +42,62 @@ status = "disabled"; }; }; + + ss5_pwr_ctrl0 { + compatible = "gnss_sirf"; + pinctrl-0 = <&ss5_pwr_ctrl_rst_on>; + ssVreset-gpio = <&tlmm 87 1>; + ssVonoff-gpio = <&tlmm 18 1>; + }; + + hsi2s: qcom,hsi2s { + compatible = "qcom,sa6155-hsi2s", "qcom,hsi2s"; + number-of-interfaces = <2>; + reg = <0x1B40000 0x28000>; + reg-names = "lpa_if"; + interrupts = ; + clocks = <&clock_gcc GCC_SDR_CORE_CLK>, + <&clock_gcc GCC_SDR_WR0_MEM_CLK>, + <&clock_gcc GCC_SDR_WR1_MEM_CLK>, + <&clock_gcc GCC_SDR_WR2_MEM_CLK>, + <&clock_gcc GCC_SDR_CSR_HCLK>; + clock-names = "core_clk", "wr0_mem_clk", + "wr1_mem_clk", "wr2_mem_clk", + "csr_hclk"; + bit-clock-hz = <20000000>; + interrupt-interval-ms = <10>; + + sdr0: qcom,hs0_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs0_i2s_sck_active &hs0_i2s_data0_active + &hs0_i2s_data1_active>; + pinctrl-1 = <&hs0_i2s_sck_sleep &hs0_i2s_data0_sleep + &hs0_i2s_data1_sleep>; + clocks = <&clock_gcc GCC_SDR_PRI_MI2S_CLK>; + clock-names = "pri_mi2s_clk"; + iommus = <&apps_smmu 0x035C 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + + sdr1: qcom,hs1_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs1_i2s_sck_active &hs1_i2s_data0_active + &hs1_i2s_data1_active>; + pinctrl-1 = <&hs1_i2s_sck_sleep &hs1_i2s_data0_sleep + &hs1_i2s_data1_sleep>; + clocks = <&clock_gcc GCC_SDR_SEC_MI2S_CLK>; + clock-names = "sec_mi2s_clk"; + iommus = <&apps_smmu 0x035D 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + }; + emac_hw: qcom,emac@20000 { compatible = "qcom,emac-dwc-eqos"; qcom,arm-smmu; @@ -120,9 +180,6 @@ }; }; - bluetooth_ext: bt_qca6174 { - status = "ok"; - }; }; &ufsphy_mem { @@ -203,6 +260,10 @@ status = "ok"; }; +&qupv3_se4_2uart { + status = "ok"; +}; + &qupv3_se7_4uart { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi index a1342376bdff3693fb9d92c1d1a735a8a78df7f3..be1b682abcfc64792e49de992dbc1770d4591f8b 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -11,7 +11,11 @@ */ #include #include +#include "sa6155-cnss.dtsi" +&bluetooth_ext { + status = "ok"; +}; &qupv3_se6_spi { status = "ok"; @@ -38,6 +42,55 @@ status = "disabled"; }; }; + + hsi2s: qcom,hsi2s { + compatible = "qcom,sa6155-hsi2s", "qcom,hsi2s"; + number-of-interfaces = <2>; + reg = <0x1B40000 0x28000>; + reg-names = "lpa_if"; + interrupts = ; + clocks = <&clock_gcc GCC_SDR_CORE_CLK>, + <&clock_gcc GCC_SDR_WR0_MEM_CLK>, + <&clock_gcc GCC_SDR_WR1_MEM_CLK>, + <&clock_gcc GCC_SDR_WR2_MEM_CLK>, + <&clock_gcc GCC_SDR_CSR_HCLK>; + clock-names = "core_clk", "wr0_mem_clk", + "wr1_mem_clk", "wr2_mem_clk", + "csr_hclk"; + bit-clock-hz = <20000000>; + interrupt-interval-ms = <10>; + + sdr0: qcom,hs0_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs0_i2s_sck_active &hs0_i2s_data0_active + &hs0_i2s_data1_active>; + pinctrl-1 = <&hs0_i2s_sck_sleep &hs0_i2s_data0_sleep + &hs0_i2s_data1_sleep>; + clocks = <&clock_gcc GCC_SDR_PRI_MI2S_CLK>; + clock-names = "pri_mi2s_clk"; + iommus = <&apps_smmu 0x035C 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + + sdr1: qcom,hs1_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs1_i2s_sck_active &hs1_i2s_data0_active + &hs1_i2s_data1_active>; + pinctrl-1 = <&hs1_i2s_sck_sleep &hs1_i2s_data0_sleep + &hs1_i2s_data1_sleep>; + clocks = <&clock_gcc GCC_SDR_SEC_MI2S_CLK>; + clock-names = "sec_mi2s_clk"; + iommus = <&apps_smmu 0x035D 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + }; + emac_hw: qcom,emac@20000 { compatible = "qcom,emac-dwc-eqos"; qcom,arm-smmu; @@ -120,9 +173,6 @@ }; }; - bluetooth_ext: bt_qca6174 { - status = "ok"; - }; }; &ufsphy_mem { diff --git a/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi b/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi index 096142eabf92bad1974729fbdcb58fc4a0bff28e..ccff6e021534922afb807e57b2d4d4c68247a6fc 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi @@ -13,7 +13,7 @@ #include "sm6150-lpi.dtsi" &soc { - qcom,msm-dai-tdm-pri-rx { + tdm_pri_rx: qcom,msm-dai-tdm-pri-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37120>; qcom,msm-cpudai-tdm-group-num-ports = <4>; @@ -51,7 +51,7 @@ }; }; - qcom,msm-dai-tdm-pri-tx { + tdm_pri_tx: qcom,msm-dai-tdm-pri-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37121>; qcom,msm-cpudai-tdm-group-num-ports = <4>; @@ -89,11 +89,12 @@ }; }; - qcom,msm-dai-tdm-sec-rx { + tdm_sec_rx: qcom,msm-dai-tdm-sec-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37136>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36880 36882 36884 36886>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36880 36882 36884 + 36886 36894>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -124,9 +125,15 @@ qcom,msm-cpudai-tdm-dev-id = <36886>; qcom,msm-cpudai-tdm-data-align = <0>; }; + + dai_sec_tdm_rx_7: qcom,msm-dai-q6-tdm-sec-rx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36894>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; - qcom,msm-dai-tdm-sec-tx { + tdm_sec_tx: qcom,msm-dai-tdm-sec-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37137>; qcom,msm-cpudai-tdm-group-num-ports = <4>; @@ -163,7 +170,7 @@ }; }; - qcom,msm-dai-tdm-tert-rx { + tdm_tert_rx: qcom,msm-dai-tdm-tert-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37152>; qcom,msm-cpudai-tdm-group-num-ports = <5>; @@ -177,8 +184,10 @@ qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&ter_i2s_sck_active &ter_i2s_data0_active>; - pinctrl-1 = <&ter_i2s_sck_sleep &ter_i2s_data0_sleep>; + pinctrl-0 = <&ter_i2s_sck_active &ter_i2s_data0_active + &ter_i2s_data1_active>; + pinctrl-1 = <&ter_i2s_sck_sleep &ter_i2s_data0_sleep + &ter_i2s_data1_sleep>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36896>; @@ -210,11 +219,12 @@ }; }; - qcom,msm-dai-tdm-tert-tx { + tdm_tert_tx: qcom,msm-dai-tdm-tert-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37153>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36897 36899 36901 36903>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36897 36899 36901 + 36903 36911>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -222,9 +232,6 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&ter_i2s_data1_active>; - pinctrl-1 = <&ter_i2s_data1_sleep>; dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36897>; @@ -248,13 +255,21 @@ qcom,msm-cpudai-tdm-dev-id = <36903>; qcom,msm-cpudai-tdm-data-align = <0>; }; + + dai_tert_tdm_tx_7: qcom,msm-dai-q6-tdm-tert-tx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36911>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; - qcom,msm-dai-tdm-quat-rx { + tdm_quat_rx: qcom,msm-dai-tdm-quat-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37168>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36912 36914 36916 36918>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36912 36914 36916 + 36918 36926>; + qcom,msm-cpudai-tdm-lane-mask = /bits/ 16 <3>; qcom,msm-cpudai-tdm-clk-rate = <24576000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -262,10 +277,11 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&quat_tdm_sclk_active &quat_tdm_ws_active - &quat_tdm_data0_active>; + &quat_tdm_data0_active &quat_tdm_data1_active>; pinctrl-1 = <&quat_tdm_sclk_sleep &quat_tdm_ws_sleep - &quat_tdm_data0_sleep>; + &quat_tdm_data0_sleep &quat_tdm_data1_sleep>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; @@ -289,13 +305,20 @@ qcom,msm-cpudai-tdm-dev-id = <36918>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_quat_tdm_rx_7: qcom,msm-dai-q6-tdm-quat-rx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36926>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; - qcom,msm-dai-tdm-quat-tx { + tdm_quat_tx: qcom,msm-dai-tdm-quat-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37169>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36913 36915 36917 36919>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36913 36915 36917 + 36919 36927>; + qcom,msm-cpudai-tdm-lane-mask = /bits/ 16 <12>; qcom,msm-cpudai-tdm-clk-rate = <24576000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -303,8 +326,6 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-0 = <&quat_tdm_data1_active>; - pinctrl-1 = <&quat_tdm_data1_sleep>; dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36913>; @@ -328,24 +349,32 @@ qcom,msm-cpudai-tdm-dev-id = <36919>; qcom,msm-cpudai-tdm-data-align = <0>; }; + + dai_quat_tdm_tx_7: qcom,msm-dai-q6-tdm-quat-tx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36927>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; - qcom,msm-dai-tdm-quin-rx { + tdm_quin_rx: qcom,msm-dai-tdm-quin-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37184>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 36934>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 + 36934 36942>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; - qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-clk-internal = <0>; qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&quin_tdm_sclk_active &quin_tdm_ws_active - &quin_tdm_data0_active>; + &quin_tdm_data0_active &quin_tdm_data1_active>; pinctrl-1 = <&quin_tdm_sclk_sleep &quin_tdm_ws_sleep - &quin_tdm_data0_sleep>; + &quin_tdm_data0_sleep &quin_tdm_data1_sleep>; dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36928>; @@ -369,22 +398,26 @@ qcom,msm-cpudai-tdm-dev-id = <36934>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_quin_tdm_rx_7: qcom,msm-dai-q6-tdm-quin-rx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36942>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; - qcom,msm-dai-tdm-quin-tx { + tdm_quin_tx: qcom,msm-dai-tdm-quin-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37185>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 36935>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 + 36935 36943>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; - qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-clk-internal = <0>; qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-0 = <&quin_tdm_data1_active>; - pinctrl-1 = <&quin_tdm_data1_sleep>; dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36929>; @@ -408,6 +441,11 @@ qcom,msm-cpudai-tdm-dev-id = <36935>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_quin_tdm_tx_7: qcom,msm-dai-q6-tdm-quin-tx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36943>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; dai_pri_auxpcm: qcom,msm-pri-auxpcm { @@ -435,13 +473,16 @@ &q6core { sound-adp-star { - status = "ok"; compatible = "qcom,sa6155-asoc-snd-adp-star"; qcom,model = "sa6155-adp-star-snd-card"; qcom,mi2s-audio-intf; qcom,auxpcm-audio-intf; qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,tert-tdm-gpios = <&tdm_tert_rx>; + qcom,quat-tdm-gpios = <&tdm_quat_rx>; + qcom,quin-tdm-gpios = <&tdm_quin_rx>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, @@ -471,21 +512,24 @@ <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, - <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, - <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, - <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, - <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, - <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>, - <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>, - <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>, + <&dai_sec_tdm_rx_7>, <&dai_sec_tdm_tx_0>, + <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, + <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, + <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, + <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_rx_4>, + <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, + <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>, + <&dai_tert_tdm_tx_7>, <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, - <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>, - <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, - <&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_rx_7>, + <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, + <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>, + <&dai_quat_tdm_tx_7>, <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, - <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, - <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, - <&dai_quin_tdm_tx_3>; + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_rx_7>, + <&dai_quin_tdm_tx_0>, <&dai_quin_tdm_tx_1>, + <&dai_quin_tdm_tx_2>, <&dai_quin_tdm_tx_3>, + <&dai_quin_tdm_tx_7>; asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -503,21 +547,24 @@ "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", - "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", - "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", - "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", - "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", - "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897", - "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901", - "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36894", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", + "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", + "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36904", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", + "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903", + "msm-dai-q6-tdm.36911", "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", - "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913", - "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917", - "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36926", + "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915", + "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919", + "msm-dai-q6-tdm.36927", "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", - "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", - "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", - "msm-dai-q6-tdm.36935"; + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36942", + "msm-dai-q6-tdm.36929", "msm-dai-q6-tdm.36931", + "msm-dai-q6-tdm.36933", "msm-dai-q6-tdm.36935", + "msm-dai-q6-tdm.36943"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; diff --git a/arch/arm64/boot/dts/qcom/sa6155-cnss.dtsi b/arch/arm64/boot/dts/qcom/sa6155-cnss.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..948571cab28ca0eae6da8dfe9a990f7b164ff1a9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-cnss.dtsi @@ -0,0 +1,223 @@ +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This 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 { + /* PWR_CTR1_VDD_1P8 supply */ + vreg_conn_1p8: vreg_conn_1p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_1p8"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pm6155_1_gpios 1 0>; + }; + + /* PWR_CTR2_VDD_PA supply */ + vreg_conn_pa: vreg_conn_pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pm6155_1_gpios 6 0>; + }; + + vreg_wlan: vreg_wlan { + compatible = "qcom,stub-regulator"; + regulator-name = "vreg_wlan"; + }; + + bluetooth_ext: bt_qca6174 { + compatible = "qca,qca6174"; + /* BT_EN */ + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_active>; + qca,bt-reset-gpio = <&tlmm 85 0>; + /* PWR_CTR1_VDD_PA */ + qca,bt-vdd-pa-supply = <&vreg_conn_pa>; + qca,bt-chip-pwd-supply = <&vreg_conn_1p8>; + qca,bt-vdd-vm-supply = <&pm6155_1_s6>; + qca,bt-vdd-5a-supply = <&pm6155_1_s5>; + qca,bt-vdd-vh-supply = <&pm6155_1_l15>; + + qca,bt-vdd-vm-voltage-level = <1370000 1370000>; + qca,bt-vdd-5a-voltage-level = <2040000 2040000>; + qca,bt-vdd-vh-voltage-level = <1904000 1904000>; + + qca,bt-vdd-vm-current-level = <0>; + qca,bt-vdd-5a-current-level = <0>; + qca,bt-vdd-vh-current-level = <450000>; + + status = "disabled"; + }; + + cnss_pcie: qcom,cnss-qca-converged { + compatible = "qcom,cnss-qca-converged"; + + qcom,converged-dt; + qcom,wlan-rc-num = <0>; + qcom,bus-type=<0>; + qcom,notify-modem-status; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, <1 512 0 0>, + /* Upto 200 Mbps */ + <45 512 41421 655360>, <1 512 41421 655360>, + /* Upto 400 Mbps */ + <45 512 98572 655360>, <1 512 98572 1600000>, + /* Upto 800 Mbps */ + <45 512 207108 1146880>, <1 512 207108 3124992>; + + #address-cells=<1>; + #size-cells=<1>; + ranges = <0x10000000 0x10000000 0x10000000>, + <0x20000000 0x20000000 0x10000>, + <0xa0000000 0xa0000000 0x10000000>, + <0xb0000000 0xb0000000 0x10000>; + + vdd-wlan-ctrl1-supply = <&vreg_conn_pa>; + vdd-wlan-ctrl2-supply = <&vreg_conn_1p8>; + vdd-wlan-supply = <&vreg_wlan>; + vdd-wlan-rfa1-supply = <&pm6155_1_s6>; + vdd-wlan-rfa2-supply = <&pm6155_1_s5>; + vdd-wlan-rfa3-supply = <&pm6155_1_l15>; + + wlan_vregs = "vdd-wlan-ctrl1", "vdd-wlan-ctrl2"; + qcom,vdd-wlan-ctrl1-info = <0 0 0 0>; + qcom,vdd-wlan-ctrl2-info = <0 0 0 0>; + + wlan-en-gpio = <&tlmm 98 0>; + pinctrl-names = "wlan_en_active", "wlan_en_sleep"; + pinctrl-0 = <&cnss_wlan_en_active>; + pinctrl-1 = <&cnss_wlan_en_sleep>; + + chip_cfg@0 { + reg = <0x10000000 0x10000000>, + <0x20000000 0x10000>; + reg-names = "smmu_iova_base", "smmu_iova_ipa"; + + supported-ids = <0x003e>; + wlan_vregs = "vdd-wlan"; + qcom,vdd-wlan-info = <0 0 0 10>; + + qcom,smmu-s1-enable; + qcom,wlan-ramdump-dynamic = <0x200000>; + }; + + chip_cfg@1 { + reg = <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "smmu_iova_base", "smmu_iova_ipa"; + + supported-ids = <0x1101>; + wlan_vregs = "vdd-wlan-rfa1", "vdd-wlan-rfa2", + "vdd-wlan-rfa3"; + qcom,vdd-wlan-rfa1-info = <1350000 1350000 0 0>; + qcom,vdd-wlan-rfa2-info = <2040000 2040000 0 0>; + qcom,vdd-wlan-rfa3-info = <1904000 1904000 0 0>; + + qcom,wlan-ramdump-dynamic = <0x400000>; + mhi,max-channels = <30>; + mhi,timeout = <10000>; + + mhi_channels { + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-queue; + mhi,auto-start; + }; + }; + + mhi_events { + 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>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi index 6de3f59a480ccb8b6a660392d1248a5677bcd2ab..8e203077e4c9b767c8f24eb9fee5003ea66b813d 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi @@ -154,6 +154,10 @@ }; }; +&dsi_ext_bridge_1080p { + qcom,mdss-dsi-ext-bridge = <0>; +}; + &soc { dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; diff --git a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi index 3e00782bcd6827f6ac629770a92e41da610352bd..737ab8022869e31142224809edc17fb66dc2b1b0 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -137,9 +137,15 @@ /delete-node/ pm6150-vbat-lvl0; /delete-node/ pm6150-vbat-lvl1; /delete-node/ pm6150-vbat-lvl2; + /delete-node/ pm6150-bcl-lvl0; + /delete-node/ pm6150-bcl-lvl1; + /delete-node/ pm6150-bcl-lvl2; /delete-node/ pm6150l-vph-lvl0; /delete-node/ pm6150l-vph-lvl1; /delete-node/ pm6150l-vph-lvl2; + /delete-node/ pm6150l-bcl-lvl0; + /delete-node/ pm6150l-bcl-lvl1; + /delete-node/ pm6150l-bcl-lvl2; /delete-node/ xo-therm; /delete-node/ sdm-therm; /delete-node/ conn-therm; diff --git a/arch/arm64/boot/dts/qcom/sa6155-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa6155-regulator.dtsi index f03a12391c4aeae7eb403882bd397a29ff76afd8..b7745ffd32dad676c2784342b7f4ab066e96fcdc 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-regulator.dtsi @@ -533,28 +533,5 @@ qcom,init-mode = ; }; }; - - /* PWR_CTR1_VDD_1P8 supply */ - vreg_conn_1p8: vreg_conn_1p8 { - compatible = "regulator-fixed"; - regulator-name = "vreg_conn_1p8"; - startup-delay-us = <4000>; - enable-active-high; - gpio = <&pm6155_1_gpios 1 0>; - }; - - /* PWR_CTR2_VDD_PA supply */ - vreg_conn_pa: vreg_conn_pa { - compatible = "regulator-fixed"; - regulator-name = "vreg_conn_pa"; - startup-delay-us = <4000>; - enable-active-high; - gpio = <&pm6155_1_gpios 6 0>; - }; - - vreg_wlan: vreg_wlan { - compatible = "qcom,stub-regulator"; - regulator-name = "vreg_wlan"; - }; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dts b/arch/arm64/boot/dts/qcom/sa6155.dts index 0494f3f96a369e5678635ff43745e17a426f51f3..7ee1fede69063fa33d526f8a3db87f7e5d395ea3 100644 --- a/arch/arm64/boot/dts/qcom/sa6155.dts +++ b/arch/arm64/boot/dts/qcom/sa6155.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ /dts-v1/; #include "sa6155.dtsi" +#include "sa6155-cnss.dtsi" / { model = "Qualcomm Technologies, Inc. SA6155 SoC"; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dtsi b/arch/arm64/boot/dts/qcom/sa6155.dtsi index ff6c4b6f79f5be12f3d0e73405658345dac149b7..b59622839485eaa0216d99bca26df98e322e8b97 100644 --- a/arch/arm64/boot/dts/qcom/sa6155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155.dtsi @@ -60,6 +60,7 @@ &clock_gcc { compatible = "qcom,gcc-sa6155", "syscon"; + /delete-property/ protected-clocks; }; &clock_videocc { @@ -89,36 +90,6 @@ #include "sa6155-pcie.dtsi" &soc { - cnss_pcie: qcom,cnss { - compatible = "qcom,cnss"; - wlan-en-gpio = <&tlmm 98 0>; - vdd-wlan-supply = <&vreg_wlan>; - vdd-wlan-io-supply = <&pm6155_1_s4>; - vdd-wlan-ctrl1-supply = <&vreg_conn_pa>; - vdd-wlan-ctrl2-supply = <&vreg_conn_1p8>; - reg = <0x10000000 0x10000000>, - <0x20000000 0x10000>; - reg-names = "smmu_iova_base", "smmu_iova_ipa"; - qcom,notify-modem-status; - pinctrl-names = "wlan_en_active", "wlan_en_sleep"; - pinctrl-0 = <&cnss_wlan_en_active>; - pinctrl-1 = <&cnss_wlan_en_sleep>; - qcom,wlan-rc-num = <0>; - qcom,wlan-ramdump-dynamic = <0x200000>; - - qcom,msm-bus,name = "msm-cnss"; - qcom,msm-bus,num-cases = <4>; - qcom,msm-bus,num-paths = <2>; - qcom,msm-bus,vectors-KBps = - <45 512 0 0>, <1 512 0 0>, - /* Upto 200 Mbps */ - <45 512 41421 655360>, <1 512 41421 655360>, - /* Upto 400 Mbps */ - <45 512 98572 655360>, <1 512 98572 1600000>, - /* Upto 800 Mbps */ - <45 512 207108 1146880>, <1 512 207108 3124992>; - qcom,smmu-s1-enable; - }; qfprom: qfprom@780130 { compatible = "qcom,qfprom"; reg = <0x00780130 0x4>; @@ -147,4 +118,424 @@ }; }; }; + + cpuss-0-step { + trips { + cpu45-config { + temperature = <115000>; + }; + }; + }; + + cpuss-1-step { + trips { + cpu23-config { + temperature = <115000>; + }; + }; + }; + + cpuss-2-step { + trips { + cpu01-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-0-step { + trips { + cpu6-0-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-1-step { + trips { + cpu6-1-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-2-step { + trips { + cpu7-0-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-3-step { + trips { + cpu7-1-config { + temperature = <115000>; + }; + }; + }; +}; + +/* GPU power level overrides */ +&msm_gpu { + /* + * 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-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <5>; + qcom,ca-target-pwrlevel = <3>; + + /* 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 = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <500000000>; + 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>; + }; + + /* 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>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <177>; + + qcom,initial-pwrlevel = <5>; + qcom,ca-target-pwrlevel = <3>; + + /* 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 = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <500000000>; + 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>; + }; + + /* 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>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <156>; + + qcom,initial-pwrlevel = <4>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <136>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <1>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-4 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <105>; + + qcom,initial-pwrlevel = <1>; + qcom,ca-target-pwrlevel = <2>; + + /* SVS L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-5 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <73>; + + qcom,initial-pwrlevel = <1>; + qcom,ca-target-pwrlevel = <0>; + + /* SVS */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <350000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm-pcie.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm-pcie.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ff0e56593e78a3a8d9f1e5ccad2c00e0b8fb9050 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm-pcie.dtsi @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + pcie0: qcom,pcie@1c08000 { + compatible = "qcom,pci-msm"; + cell-index = <0>; + + reg = <0x1c08000 0x4000>, + <0x1c0e000 0x1000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40001000 0x1000>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1fd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "iatu", "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1fd00000>; + interrupts = <0 140 0>, <0 149 0>, <0 150 0>, <0 151 0>, + <0 152 0>; + interrupt-names = "int_global_int", "int_a", "int_b", "int_c", + "int_d"; + + qcom,phy-sequence = <0x0800 0x01 0x0 + 0x0804 0x03 0x0 + 0x0034 0x18 0x0 + 0x0038 0x10 0x0 + 0x0294 0x06 0x0 + 0x00c8 0x01 0x0 + 0x0128 0x00 0x0 + 0x0144 0xff 0x0 + 0x0148 0x1f 0x0 + 0x0070 0x0f 0x0 + 0x0048 0x0f 0x0 + 0x0178 0x00 0x0 + 0x019c 0x01 0x0 + 0x018c 0x20 0x0 + 0x0184 0x0a 0x0 + 0x00b4 0x20 0x0 + 0x000c 0x09 0x0 + 0x00ac 0x04 0x0 + 0x00d0 0x82 0x0 + 0x00e4 0x03 0x0 + 0x00e0 0x55 0x0 + 0x00dc 0x55 0x0 + 0x0054 0x00 0x0 + 0x0050 0x0d 0x0 + 0x004c 0x04 0x0 + 0x0174 0x33 0x0 + 0x003c 0x02 0x0 + 0x0040 0x1f 0x0 + 0x0078 0x0b 0x0 + 0x0084 0x16 0x0 + 0x0090 0x28 0x0 + 0x010c 0x00 0x0 + 0x0108 0x80 0x0 + 0x0010 0x01 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0014 0x02 0x0 + 0x0018 0x00 0x0 + 0x0024 0x2f 0x0 + 0x0028 0x19 0x0 + 0x0268 0x45 0x0 + 0x0194 0x06 0x0 + 0x024c 0x02 0x0 + 0x02ac 0x12 0x0 + 0x0510 0x1c 0x0 + 0x051c 0x14 0x0 + 0x04d8 0x01 0x0 + 0x04dc 0x00 0x0 + 0x04e0 0xdb 0x0 + 0x0448 0x4b 0x0 + 0x041c 0x04 0x0 + 0x0410 0x04 0x0 + 0x0074 0x19 0x0 + 0x0854 0x04 0x0 + 0x09ac 0x00 0x0 + 0x08a0 0x40 0x0 + 0x09e0 0x00 0x0 + 0x09dc 0x40 0x0 + 0x09a8 0x00 0x0 + 0x08a4 0x40 0x0 + 0x08a8 0x73 0x0 + 0x0518 0x99 0x0 + 0x0824 0x15 0x0 + 0x0828 0x0e 0x0 + 0x09b0 0x07 0x0 + 0x0800 0x00 0x0 + 0x0808 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 101 0>; + wake-gpio = <&tlmm 100 0>; + + gdsc-vdd-supply = <&pcie_0_gdsc>; + vreg-1.8-supply = <&pm6155_1_l12>; + vreg-0.9-supply = <&pm6155_1_l5>; + + vreg-cx-supply = <&VDD_CX_LEVEL>; + + qcom,vreg-1.8-voltage-level = <1800000 1800000 24000>; + qcom,vreg-0.9-voltage-level = <925000 925000 24000>; + qcom,vreg-cx-voltage-level = ; + + msi-parent = <&pcie0_msi>; + + qcom,no-l0s-supported; + qcom,no-l1-supported; + qcom,no-l1ss-supported; + qcom,no-aux-clk-sync; + + qcom,max-link-speed = <0x2>; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x20000000>; + + qcom,phy-status-offset = <0x974>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0x804>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <0>; + + qcom,pcie-phy-ver = <0x10>; + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x0400>; + + iommu-map = <0x0 &apps_smmu 0x0400 0x1>, + <0x100 &apps_smmu 0x0401 0x1>, + <0x200 &apps_smmu 0x0402 0x1>, + <0x300 &apps_smmu 0x0403 0x1>, + <0x400 &apps_smmu 0x0404 0x1>, + <0x500 &apps_smmu 0x0405 0x1>, + <0x600 &apps_smmu 0x0406 0x1>, + <0x700 &apps_smmu 0x0407 0x1>, + <0x800 &apps_smmu 0x0408 0x1>, + <0x900 &apps_smmu 0x0409 0x1>, + <0xa00 &apps_smmu 0x040a 0x1>, + <0xb00 &apps_smmu 0x040b 0x1>, + <0xc00 &apps_smmu 0x040c 0x1>, + <0xd00 &apps_smmu 0x040d 0x1>, + <0xe00 &apps_smmu 0x040e 0x1>, + <0xf00 &apps_smmu 0x040f 0x1>; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_virt GCC_PCIE_0_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_virt GCC_PCIE_0_AUX_CLK>, + <&clock_virt GCC_PCIE_0_CFG_AHB_CLK>, + <&clock_virt GCC_PCIE_0_MSTR_AXI_CLK>, + <&clock_virt GCC_PCIE_0_SLV_AXI_CLK>, + <&clock_virt GCC_PCIE_0_CLKREF_CLK>, + <&clock_virt GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&clock_virt GCC_PCIE0_PHY_REFGEN_CLK>, + <&clock_virt GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_phy_refgen_clk", "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_virt GCC_PCIE_0_BCR>, + <&clock_virt GCC_PCIE_0_PHY_BCR>; + + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + status = "disabled"; + }; + + pcie0_msi: qcom,pcie0_msi@17a00040 { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a00040 0x0>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi index 3db66cf1455fdcbd9f5fd0c0ae98b2410b4945e8..ef2dcb739f3538842b85798cde19e2b54f2ed6ba 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi @@ -119,9 +119,9 @@ "tune2_efuse_addr", "tcsr_conn_box_spare_0"; - vdd-supply = <&pm6150_l4>; - vdda18-supply = <&pm6150_l11>; - vdda33-supply = <&pm6150_l17>; + vdd-supply = <&L5A>; + vdda18-supply = <&L12A>; + vdda33-supply = <&L13A>; qcom,vdd-voltage-level = <0 925000 975000>; qcom,tune2-efuse-bit-pos = <25>; qcom,tune2-efuse-num-bits = <4>; @@ -159,8 +159,8 @@ reg-names = "qmp_phy_base", "vls_clamp_reg"; - vdd-supply = <&pm6150_l4>; - core-supply = <&pm6150_l11>; + vdd-supply = <&L5A>; + core-supply = <&L12A>; qcom,vdd-voltage-level = <0 925000 975000>; qcom,core-voltage-level = <0 1800000 1800000>; qcom,qmp-phy-init-seq = @@ -370,9 +370,9 @@ reg-names = "qusb_phy_base", "tcsr_conn_box_spare_0"; - vdd-supply = <&pm6150_l4>; - vdda18-supply = <&pm6150_l11>; - vdda33-supply = <&pm6150_l17>; + vdd-supply = <&L5A>; + vdda18-supply = <&L12A>; + vdda33-supply = <&L13A>; qcom,vdd-voltage-level = <0 925000 975000>; qcom,qusb-phy-init-seq = <0xc8 0x80 0xb3 0x84 diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm.dts b/arch/arm64/boot/dts/qcom/sa6155p-vm.dts index 743ddf095a7d1bbca8b0ae555f87c4ba4d6ec74d..0caf78c1b2e6f88ba9d5564ee30867a0115cefec 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm.dts @@ -37,3 +37,16 @@ &qusb_phy0 { status = "ok"; }; + +&pcie0_msi { + status = "ok"; +}; + +&pcie0 { + status = "ok"; +}; + +&sdhc_2 { + status = "ok"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi index 40d6218312c8e1ed7a947717cca2d561a0dc8479..6c189b5b15ce1c4365cc863d904712e7fa29b498 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi @@ -14,173 +14,96 @@ #include "skeleton64.dtsi" #include #include +#include #include +#include "quin-vm-common.dtsi" / { model = "Qualcomm Technologies, Inc. SA6155P Virtual Machine"; qcom,msm-name = "SA6155P"; qcom,msm-id = <377 0x0>; - psci { - compatible = "arm,psci-1.0"; - method = "smc"; + aliases { + pci-domain0 = &pcie0; /* PCIe0 domain */ }; - chosen { - bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; + aliases { + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ }; - soc: soc { }; - reserved_memory: reserved-memory { - #address-cells = <2>; - #size-cells = <2>; - ranges; - - /* global autoconfigured region for contiguous allocations */ - linux,cma { - compatible = "shared-dma-pool"; - alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; - reusable; - alignment = <0x0 0x400000>; - size = <0x0 0x2000000>; - linux,cma-default; - }; pmem_shared: pmem_shared_region@a1600000 { reg = <0x0 0xa1600000 0x0 0x20000000>; label = "pmem_shared_mem"; }; }; - - 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/vdevs/1c0f0000.virtio_blk/vdc"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; - }; - }; }; &soc { - #address-cells = <1>; - #size-cells = <1>; - virtual-interrupt-parent = "gic"; - ranges = <0 0 0 0xffffffff>; - compatible = "simple-bus"; - - clock_virt: qcom,virt-gcc { - compatible = "qcom,virt-clk-sm6150-gcc"; + clock_virt: qcom,virtio-gcc { + compatible = "virtio,mmio"; + reg = <0x1c200000 0x1000>; + interrupts = <0 48 0>; #clock-cells = <1>; #reset-cells = <1>; }; - clock_virt_scc: qcom,virt-scc { - compatible = "qcom,virt-clk-sm6150-scc"; + clock_virt_scc: qcom,virtio-scc { + compatible = "virtio,mmio"; + reg = <0x1c300000 0x1000>; + interrupts = <0 49 0>; #clock-cells = <1>; - #reset-cells = <1>; }; - clock_gcc: qcom,gcc { - compatible = "qcom,dummycc"; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - qcom,ion { - compatible = "qcom,msm-ion"; - #address-cells = <1>; - #size-cells = <0>; + regulator_virt: virtio_regulator@1c700000 { + compatible = "virtio,mmio"; + reg = <0x1c700000 0x1000>; + interrupts = <0 42 0>; - system_heap: qcom,ion-heap@25 { - reg = <25>; - qcom,ion-heap-type = "SYSTEM"; - }; - }; - - qcom,hab { - compatible = "qcom,hab"; - vmid = <2>; - - mmidgrp100: mmidgrp100 { - grp-start-id = <100>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp200: mmidgrp200 { - grp-start-id = <200>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp300: mmidgrp300 { - grp-start-id = <300>; - role = "fe"; - remote-vmids = <0>; + usb30_prim_gdsc: usb30_prim_gdsc { + regulator-name = "usb30_prim_gdsc"; }; - mmidgrp400: mmidgrp400 { - grp-start-id = <400>; - role = "fe"; - remote-vmids = <0>; + usb20_sec_gdsc: usb20_sec_gdsc { + regulator-name = "usb20_sec_gdsc"; }; - mmidgrp500: mmidgrp500 { - grp-start-id = <500>; - role = "fe"; - remote-vmids = <0>; + pcie_0_gdsc: pcie_0_gdsc { + regulator-name = "pcie_0_gdsc"; }; - mmidgrp600: mmidgrp600 { - grp-start-id = <600>; - role = "fe"; - remote-vmids = <0>; + L2A: pm6155_1_l2: regulator-pm6155-1-l2 { + regulator-name = "ldoa2"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3100000>; }; - mmidgrp700: mmidgrp700 { - grp-start-id = <700>; - role = "fe"; - remote-vmids = <0>; + L5A: pm6155_1_l5: regulator-pm6155-1-l5 { + regulator-name = "ldoa5"; + regulator-min-microvolt = <875000>; + regulator-max-microvolt = <975000>; }; - mmidgrp800: mmidgrp800 { - grp-start-id = <800>; - role = "fe"; - remote-vmids = <0>; + L10A: pm6155_1_l10: regulator-pm6155-1-l10 { + regulator-name = "ldoa10"; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3312000>; }; - mmidgrp900: mmidgrp900 { - grp-start-id = <900>; - role = "fe"; - remote-vmids = <0>; + L12A: pm6155_1_l12: regulator-pm6155-1-l12 { + regulator-name = "ldoa12"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1890000>; }; - mmidgrp1000: mmidgrp1000 { - grp-start-id = <1000>; - role = "fe"; - remote-vmids = <0>; + L13A: pm6155_1_l13: regulator-pm6155-1-l13 { + regulator-name = "ldoa13"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3230000>; }; }; - sde_kms_hyp: qcom,sde_kms_hyp@ae00000 { - compatible = "qcom,sde-kms-hyp"; - qcom,client-id = "7815"; - }; - apps_smmu: apps-smmu@0x15000000 { compatible = "qcom,qsmmu-v500"; reg = <0x15000000 0x80000>, @@ -268,43 +191,129 @@ status = "ok"; }; - usb30_prim_gdsc: usb30_prim_gdsc { - compatible = "qcom,stub-regulator"; - regulator-name = "usb30_prim_gdsc"; - status = "ok"; + 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,no-clock-support; + qcom,qsee-reentrancy-support = <2>; }; - usb20_sec_gdsc: usb20_sec_gdsc { + VDD_CX_LEVEL: VDD_MX_LEVEL: S2A_LEVEL: + pm6155_1_s2_level: regulator-pm6155-1-s2-level { compatible = "qcom,stub-regulator"; - regulator-name = "usb20_sec_gdsc"; - status = "ok"; + regulator-name = "pm6155_1_s2_level"; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; }; - pm6150_l11: regulator-pm6150-l11 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm6150_l11"; - qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1890000>; - status = "ok"; + vreg_wlan: vreg_wlan { + compatible = "qcom,stub-regulator"; + regulator-name = "vreg_wlan"; }; - pm6150_l4: regulator-pm6150-l4 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm6150_l4"; - qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <875000>; - regulator-max-microvolt = <975000>; - status = "ok"; + cnss_pcie: qcom,cnss { + compatible = "qcom,cnss"; + wlan-en-gpio = <&tlmm 98 0>; + vdd-wlan-supply = <&vreg_wlan>; + reg = <0x10000000 0x10000000>, + <0x20000000 0x10000>; + reg-names = "smmu_iova_base", "smmu_iova_ipa"; + qcom,smmu-s1-enable; + qcom,notify-modem-status; + pinctrl-names = "wlan_en_active", "wlan_en_sleep"; + pinctrl-0 = <&cnss_wlan_en_active>; + pinctrl-1 = <&cnss_wlan_en_sleep>; + qcom,wlan-rc-num = <0>; + qcom,wlan-ramdump-dynamic = <0x200000>; + + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, <1 512 0 0>, + /* Upto 200 Mbps */ + <45 512 41421 655360>, <1 512 41421 655360>, + /* Upto 400 Mbps */ + <45 512 98572 655360>, <1 512 98572 1600000>, + /* Upto 800 Mbps */ + <45 512 207108 1146880>, <1 512 207108 3124992>; }; - pm6150_l17: regulator-pm6150-l17 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm6150_l17"; - qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3230000>; - status = "ok"; + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + interrupts = <0 204 0>, <0 222 0>; + interrupt-names = "hc_irq", "pwr_irq"; + qcom,bus-width = <4>; + qcom,large-address-bus; + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 202000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + qcom,devfreq,freq-table = <50000000 202000000>; + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 1600>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 80000>, + <1 608 80000 80000>, + /* 25 MB/s */ + <81 512 65360 100000>, + <1 608 100000 100000>, + /* 50 MB/s */ + <81 512 130718 200000>, + <1 608 133320 133320>, + /* 100 MB/s */ + <81 512 261438 200000>, + <1 608 150000 150000>, + /* 200 MB/s */ + <81 512 261438 400000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 4294967295>; + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <67 67>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <67 67>, <67 67>; + clocks = <&clock_virt GCC_SDCC2_AHB_CLK>, + <&clock_virt GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642C 0x0 0x0 0x00010800 0x80040868>; + + vdd-supply = <&pm6155_1_l10>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + vdd-io-supply = <&pm6155_1_l2>; + 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 1>; + + status = "disabled"; }; }; @@ -313,3 +322,10 @@ #include "sa6155p-vm-qupv3.dtsi" #include "sa6155p-vm-usb.dtsi" #include "sa8155-vm-audio.dtsi" +#include "sa6155p-vm-pcie.dtsi" +#include "pm6155-vm.dtsi" + +&tlmm { + dirconn-list = <100 216 1>, + <99 215 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dts b/arch/arm64/boot/dts/qcom/sa6155p.dts index 371125467fd69049b5633a1efd86827362e6d9c1..980ec1b967767fba6a6506ab179e9f87dd9ee2ef 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ /dts-v1/; #include "sa6155p.dtsi" +#include "sa6155-cnss.dtsi" / { model = "Qualcomm Technologies, Inc. SA6155P SoC"; diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dtsi b/arch/arm64/boot/dts/qcom/sa6155p.dtsi index 1180a756c73338615cfdf8690b70c66ffc2bb636..5d233dd7021a2e588b2a702c5fc19f209c1f3ee0 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p.dtsi @@ -13,8 +13,8 @@ #include "sm6150.dtsi" #include "sa6155-pmic.dtsi" #include "sa6155-display.dtsi" - #include "sm6150-camera-sensor-adp.dtsi" + / { model = "Qualcomm Technologies, Inc. SA6155P"; qcom,msm-name = "SA6155P"; @@ -43,61 +43,6 @@ /delete-node/ rpmh-regulator-ldoc18; /delete-node/ bt_wcn3990; - bluetooth_ext: bt_qca6174 { - compatible = "qca,qca6174"; - /* BT_EN */ - pinctrl-names = "default"; - pinctrl-0 = <&bt_en_active>; - qca,bt-reset-gpio = <&tlmm 85 0>; - /* PWR_CTR1_VDD_PA */ - qca,bt-vdd-pa-supply = <&vreg_conn_pa>; - qca,bt-chip-pwd-supply = <&vreg_conn_1p8>; - qca,bt-vdd-vm-supply = <&pm6155_1_s6>; - qca,bt-vdd-5a-supply = <&pm6155_1_s5>; - qca,bt-vdd-vh-supply = <&pm6155_1_l15>; - - qca,bt-vdd-vm-voltage-level = <1370000 1370000>; - qca,bt-vdd-5a-voltage-level = <2040000 2040000>; - qca,bt-vdd-vh-voltage-level = <1904000 1904000>; - - qca,bt-vdd-vm-current-level = <0>; - qca,bt-vdd-5a-current-level = <0>; - qca,bt-vdd-vh-current-level = <450000>; - - status = "disabled"; - }; - - cnss_pcie: qcom,cnss { - compatible = "qcom,cnss"; - wlan-en-gpio = <&tlmm 98 0>; - vdd-wlan-supply = <&vreg_wlan>; - vdd-wlan-io-supply = <&pm6155_1_s4>; - vdd-wlan-ctrl1-supply = <&vreg_conn_pa>; - vdd-wlan-ctrl2-supply = <&vreg_conn_1p8>; - reg = <0x10000000 0x10000000>, - <0x20000000 0x10000>; - reg-names = "smmu_iova_base", "smmu_iova_ipa"; - qcom,smmu-s1-enable; - qcom,notify-modem-status; - pinctrl-names = "wlan_en_active", "wlan_en_sleep"; - pinctrl-0 = <&cnss_wlan_en_active>; - pinctrl-1 = <&cnss_wlan_en_sleep>; - qcom,wlan-rc-num = <0>; - qcom,wlan-ramdump-dynamic = <0x200000>; - - qcom,msm-bus,name = "msm-cnss"; - qcom,msm-bus,num-cases = <4>; - qcom,msm-bus,num-paths = <2>; - qcom,msm-bus,vectors-KBps = - <45 512 0 0>, <1 512 0 0>, - /* Upto 200 Mbps */ - <45 512 41421 655360>, <1 512 41421 655360>, - /* Upto 400 Mbps */ - <45 512 98572 655360>, <1 512 98572 1600000>, - /* Upto 800 Mbps */ - <45 512 207108 1146880>, <1 512 207108 3124992>; - }; - qcom,rmnet-ipa { status="disabled"; }; @@ -120,6 +65,12 @@ }; &qusb_phy0 { + reg = <0x88e2000 0x180>, + <0x007801f8 0x4>, + <0x01fcb3e4 0x4>; + reg-names = "qusb_phy_base", + "tune2_efuse_addr", + "tcsr_conn_box_spare_0"; vdd-supply = <&L5A>; vdda18-supply = <&L12A>; vdda33-supply = <&L13A>; @@ -150,6 +101,7 @@ &clock_gcc { compatible = "qcom,gcc-sa6155", "syscon"; + /delete-property/ protected-clocks; }; &clock_videocc { @@ -194,6 +146,426 @@ }; }; }; + + cpuss-0-step { + trips { + cpu45-config { + temperature = <115000>; + }; + }; + }; + + cpuss-1-step { + trips { + cpu23-config { + temperature = <115000>; + }; + }; + }; + + cpuss-2-step { + trips { + cpu01-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-0-step { + trips { + cpu6-0-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-1-step { + trips { + cpu6-1-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-2-step { + trips { + cpu7-0-config { + temperature = <115000>; + }; + }; + }; + + cpu-1-3-step { + trips { + cpu7-1-config { + temperature = <115000>; + }; + }; + }; +}; + +/* GPU power level overrides */ +&msm_gpu { + /* + * 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-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <5>; + qcom,ca-target-pwrlevel = <3>; + + /* 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 = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <500000000>; + 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>; + }; + + /* 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>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <177>; + + qcom,initial-pwrlevel = <5>; + qcom,ca-target-pwrlevel = <3>; + + /* 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 = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <500000000>; + 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>; + }; + + /* 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>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <156>; + + qcom,initial-pwrlevel = <4>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <136>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <1>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-4 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <105>; + + qcom,initial-pwrlevel = <1>; + qcom,ca-target-pwrlevel = <2>; + + /* SVS L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-5 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <73>; + + qcom,initial-pwrlevel = <1>; + qcom,ca-target-pwrlevel = <0>; + + /* SVS */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <350000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; }; /* Audio device tree */ diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-alcor-display.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-alcor-display.dtsi index ab266f1e4108040b2c8fcc6d30642b02fa74373c..7de3fa3b22ba5845b29349563a592013f219dbc7 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-alcor-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-alcor-display.dtsi @@ -61,6 +61,9 @@ }; &soc { + #address-cells = <1>; + #size-cells = <1>; + refgen: refgen-regulator@88e7000 { compatible = "qcom,refgen-regulator"; reg = <0x88e7000 0x60>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi index fd8b6c6fec7188c9cfe3f93aebb544eed851a79b..16e671cfb580913ab57a4e733d5ebc13300df986 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi @@ -14,6 +14,7 @@ #include #include "sa8155-pmic-overlay.dtsi" +#include "sa8155-cnss.dtsi" &qupv3_se0_spi { status = "ok"; @@ -51,6 +52,9 @@ }; &qupv3_se10_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; asm330@6a { compatible = "st,asm330lhh"; @@ -160,10 +164,6 @@ linux,can-disable; }; }; - - bluetooth: bt_qca6174 { - status = "ok"; - }; }; &ufsphy_mem { diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi index 0db9ec2f68a18a63c9ffad4c7a92798e65af7745..1ab460283332fbb8db637086496136a6a61dae72 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi @@ -62,6 +62,9 @@ }; &qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; pinctrl-0 = <&qupv3_se15_i2c_active @@ -119,9 +122,9 @@ #size-cells = <0>; i2c@0 { + reg = <0>; #address-cells = <1>; #size-cells = <0>; - reg = <0>; anx_7625_1: anx7625@2c { compatible = "analogix,anx7625"; @@ -135,9 +138,9 @@ }; i2c@1 { + reg = <1>; #address-cells = <1>; #size-cells = <0>; - reg = <1>; anx_7625_2: anx7625@2c { compatible = "analogix,anx7625"; @@ -183,6 +186,8 @@ #include "dsi-panel-ext-bridge-1080p.dtsi" &dsi_ext_bridge_1080p { + qcom,mdss-dsi-ext-bridge = <0>; + qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1E 08 07 24 22 @@ -192,6 +197,9 @@ }; &soc { + #address-cells = <1>; + #size-cells = <1>; + dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi index 340c9edb77473939eb7422770b5a8f49b2086c95..b1f546fbfc688134b9306d4c1a23c78a290da862 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi @@ -13,3 +13,40 @@ #include "sa8155-adp-common.dtsi" #include "sa8155-adp-star-display.dtsi" +&pcie1 { + qcom,boot-option = <0x0>; +}; + +&pcie_rc1 { + nvme_x8: qcom,nvme@pcie_rc1 { + reg = <0 0 0 0 0>; + compatible = "qcom,nvme"; + pci-ids = + "8086:0953", + "8086:0a54", + "8086:0a55", + "8086:f1a5", + "8086:f1a5", + "1c58:0003", + "1c58:0023", + "1c5c:1327", + "1c5f:0540", + "144d:a821", + "144d:a822", + "144d:a808", + "1d1d:1f1f", + "1d1d:2807", + "1d1d:2601", + "106b:2001", + "106b:2003", + "1179:0115", + "1179:0116"; + + qcom,smmu; + qcom,smmu-iova-base = /bits/ 64 <0x20000000>; + qcom,smmu-iova-size = /bits/ 64 <0x40000000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-s1-bypass; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi b/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi index b18164fa69df69d489b84692eaecb6e550d050c1..8a0a1c793982e6440dffd95cb6ba43a936dd354c 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi @@ -12,7 +12,7 @@ */ &soc { - qcom,msm-dai-tdm-pri-rx { + tdm_pri_rx: qcom,msm-dai-tdm-pri-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37120>; qcom,msm-cpudai-tdm-group-num-ports = <4>; @@ -50,7 +50,7 @@ }; }; - qcom,msm-dai-tdm-pri-tx { + tdm_pri_tx: qcom,msm-dai-tdm-pri-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37121>; qcom,msm-cpudai-tdm-group-num-ports = <4>; @@ -88,7 +88,7 @@ }; }; - qcom,msm-dai-tdm-sec-rx { + tdm_sec_rx: qcom,msm-dai-tdm-sec-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37136>; qcom,msm-cpudai-tdm-group-num-ports = <5>; @@ -102,8 +102,10 @@ qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&sec_tdm_active &sec_tdm_dout_active>; - pinctrl-1 = <&sec_tdm_sleep &sec_tdm_dout_sleep>; + pinctrl-0 = <&sec_tdm_active &sec_tdm_din_active + &sec_tdm_dout_active>; + pinctrl-1 = <&sec_tdm_sleep &sec_tdm_din_sleep + &sec_tdm_dout_sleep>; dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36880>; @@ -135,7 +137,7 @@ }; }; - qcom,msm-dai-tdm-sec-tx { + tdm_sec_tx: qcom,msm-dai-tdm-sec-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37137>; qcom,msm-cpudai-tdm-group-num-ports = <4>; @@ -147,9 +149,6 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&sec_tdm_din_active>; - pinctrl-1 = <&sec_tdm_din_sleep>; dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36881>; @@ -175,7 +174,7 @@ }; }; - qcom,msm-dai-tdm-tert-rx { + tdm_tert_rx: qcom,msm-dai-tdm-tert-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37152>; qcom,msm-cpudai-tdm-group-num-ports = <5>; @@ -189,8 +188,10 @@ qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&tert_tdm_active &tert_tdm_dout_active>; - pinctrl-1 = <&tert_tdm_sleep &tert_tdm_dout_sleep>; + pinctrl-0 = <&tert_tdm_active &tert_tdm_din_active + &tert_tdm_dout_active>; + pinctrl-1 = <&tert_tdm_sleep &tert_tdm_din_sleep + &tert_tdm_dout_sleep>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36896>; @@ -222,7 +223,7 @@ }; }; - qcom,msm-dai-tdm-tert-tx { + tdm_tert_tx: qcom,msm-dai-tdm-tert-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37153>; qcom,msm-cpudai-tdm-group-num-ports = <5>; @@ -235,9 +236,6 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&tert_tdm_din_active>; - pinctrl-1 = <&tert_tdm_din_sleep>; dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36897>; @@ -269,7 +267,7 @@ }; }; - qcom,msm-dai-tdm-quat-rx { + tdm_quat_rx: qcom,msm-dai-tdm-quat-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37168>; qcom,msm-cpudai-tdm-group-num-ports = <5>; @@ -284,8 +282,10 @@ qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>; - pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>; + pinctrl-0 = <&quat_tdm_active &quat_tdm_din_active + &quat_tdm_dout_active>; + pinctrl-1 = <&quat_tdm_sleep &quat_tdm_din_sleep + &quat_tdm_dout_sleep>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; @@ -316,7 +316,7 @@ }; }; - qcom,msm-dai-tdm-quat-tx { + tdm_quat_tx: qcom,msm-dai-tdm-quat-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37169>; qcom,msm-cpudai-tdm-group-num-ports = <5>; @@ -330,9 +330,6 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&quat_tdm_din_active>; - pinctrl-1 = <&quat_tdm_din_sleep>; dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36913>; @@ -364,11 +361,12 @@ }; }; - qcom,msm-dai-tdm-quin-rx { + tdm_quin_rx: qcom,msm-dai-tdm-quin-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37184>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 36934>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 + 36934 36942>; qcom,msm-cpudai-tdm-clk-rate = <24576000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -377,8 +375,10 @@ qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&quin_tdm_active &quin_tdm_dout_active>; - pinctrl-1 = <&quin_tdm_sleep &quin_tdm_dout_sleep>; + pinctrl-0 = <&quin_tdm_active &quin_tdm_din_active + &quin_tdm_dout_active>; + pinctrl-1 = <&quin_tdm_sleep &quin_tdm_din_sleep + &quin_tdm_dout_sleep>; dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36928>; @@ -402,13 +402,19 @@ qcom,msm-cpudai-tdm-dev-id = <36934>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_quin_tdm_rx_7: qcom,msm-dai-q6-tdm-quin-rx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36942>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; - qcom,msm-dai-tdm-quin-tx { + tdm_quin_tx: qcom,msm-dai-tdm-quin-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37185>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 36935>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 + 36935 36943>; qcom,msm-cpudai-tdm-clk-rate = <24576000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -416,9 +422,6 @@ qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; qcom,msm-cpudai-tdm-data-delay = <0>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&quin_tdm_din_active>; - pinctrl-1 = <&quin_tdm_din_sleep>; dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36929>; @@ -442,6 +445,11 @@ qcom,msm-cpudai-tdm-dev-id = <36935>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_quin_tdm_tx_7: qcom,msm-dai-q6-tdm-quin-tx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36943>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; dai_pri_auxpcm: qcom,msm-pri-auxpcm { @@ -475,6 +483,11 @@ qcom,auxpcm-audio-intf; qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,sec-tdm-gpios = <&tdm_sec_rx>; + qcom,tert-tdm-gpios = <&tdm_tert_rx>; + qcom,quat-tdm-gpios = <&tdm_quat_rx>; + qcom,quin-tdm-gpios = <&tdm_quin_rx>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, @@ -518,9 +531,10 @@ <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>, <&dai_quat_tdm_tx_7>, <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, - <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, - <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, - <&dai_quin_tdm_tx_3>; + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_rx_7>, + <&dai_quin_tdm_tx_0>, <&dai_quin_tdm_tx_1>, + <&dai_quin_tdm_tx_2>, <&dai_quin_tdm_tx_3>, + <&dai_quin_tdm_tx_7>; asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -552,9 +566,10 @@ "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36927", "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", - "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", - "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", - "msm-dai-q6-tdm.36935"; + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36942", + "msm-dai-q6-tdm.36929", "msm-dai-q6-tdm.36931", + "msm-dai-q6-tdm.36933", "msm-dai-q6-tdm.36935", + "msm-dai-q6-tdm.36943"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-cnss.dtsi b/arch/arm64/boot/dts/qcom/sa8155-cnss.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2fa828eba6fc2a91a0bda4804e13259df165de84 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-cnss.dtsi @@ -0,0 +1,350 @@ +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This 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 { + /* Rome 3.3V supply */ + vreg_wlan: vreg_wlan { + compatible = "qcom,stub-regulator"; + regulator-name = "vreg_wlan"; + }; + + /* PWR_CTR2_VDD_1P8 supply */ + vreg_conn_1p8: vreg_conn_1p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_1p8"; + pinctrl-names = "default"; + pinctrl-0 = <&conn_power_1p8_active>; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&tlmm 173 0>; + }; + + /* PWR_CTR1_VDD_PA supply */ + vreg_conn_pa: vreg_conn_pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + pinctrl-names = "default"; + pinctrl-0 = <&conn_power_pa_active>; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&tlmm 174 0>; + }; + + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_active>; + /* BT_EN */ + qca,bt-reset-gpio = <&tlmm 172 0>; + /* PWR_CTR1_VDD_PA */ + qca,bt-vdd-pa-supply = <&vreg_conn_pa>; + /* PWR_CTR2_VDD_1P8 */ + qca,bt-chip-pwd-supply = <&vreg_conn_1p8>; + qca,bt-vdd-vl-supply = <&pm8150_1_s6>; + qca,bt-vdd-vm-supply = <&pm8150_2_s4>; + qca,bt-vdd-5c-supply = <&pm8150_2_s5>; + qca,bt-vdd-vh-supply = <&pm8150_2_l15>; + + qca,bt-vdd-vl-voltage-level = <1055000 1055000>; + qca,bt-vdd-vm-voltage-level = <1370000 1370000>; + qca,bt-vdd-5c-voltage-level = <2040000 2040000>; + qca,bt-vdd-vh-voltage-level = <1900000 1900000>; + + qca,bt-vdd-vl-current-level = <0>; + qca,bt-vdd-vm-current-level = <0>; + qca,bt-vdd-5c-current-level = <0>; + qca,bt-vdd-vh-current-level = <450000>; + }; + + qcom,cnss-qca6390@a0000000 { + status = "disabled"; + }; + + cnss_pcie: qcom,cnss-qca-converged { + compatible = "qcom,cnss-qca-converged"; + + qcom,converged-dt; + qcom,wlan-rc-num = <0>; + qcom,bus-type=<0>; + qcom,notify-modem-status; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, <1 512 0 0>, + /* Upto 200 Mbps */ + <45 512 41421 655360>, <1 512 41421 655360>, + /* Upto 400 Mbps */ + <45 512 98572 655360>, <1 512 98572 1600000>, + /* Upto 800 Mbps */ + <45 512 207108 1146880>, <1 512 207108 3124992>; + + #address-cells=<1>; + #size-cells=<1>; + ranges = <0x10000000 0x10000000 0x10000000>, + <0x20000000 0x20000000 0x10000>, + <0xa0000000 0xa0000000 0x10000000>, + <0xb0000000 0xb0000000 0x10000>; + + vdd-wlan-ctrl1-supply = <&vreg_conn_pa>; + vdd-wlan-ctrl2-supply = <&vreg_conn_1p8>; + vdd-wlan-supply = <&vreg_wlan>; + vdd-wlan-aon-supply = <&pm8150_1_s6>; + vdd-wlan-rfa1-supply = <&pm8150_2_s4>; + vdd-wlan-rfa2-supply = <&pm8150_2_s5>; + vdd-wlan-rfa3-supply = <&pm8150_2_l15>; + + wlan_vregs = "vdd-wlan-ctrl1", "vdd-wlan-ctrl2"; + qcom,vdd-wlan-ctrl1-info = <0 0 0 0>; + qcom,vdd-wlan-ctrl2-info = <0 0 0 0>; + wlan-en-gpio = <&tlmm 169 0>; + pinctrl-names = "wlan_en_active", "wlan_en_sleep"; + pinctrl-0 = <&cnss_wlan_en_active>; + pinctrl-1 = <&cnss_wlan_en_sleep>; + + chip_cfg@0 { + reg = <0x10000000 0x10000000>, + <0x20000000 0x10000>; + reg-names = "smmu_iova_base", "smmu_iova_ipa"; + + supported-ids = <0x003e>; + wlan_vregs = "vdd-wlan"; + qcom,vdd-wlan-info = <0 0 0 10>; + + qcom,smmu-s1-enable; + qcom,wlan-ramdump-dynamic = <0x200000>; + }; + + chip_cfg@1 { + reg = <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "smmu_iova_base", "smmu_iova_ipa"; + + supported-ids = <0x1101>; + wlan_vregs = "vdd-wlan-aon", "vdd-wlan-rfa1", + "vdd-wlan-rfa2", "vdd-wlan-rfa3"; + qcom,vdd-wlan-aon-info = <1055000 1055000 0 0>; + qcom,vdd-wlan-rfa1-info = <1370000 1370000 0 0>; + qcom,vdd-wlan-rfa2-info = <2040000 2040000 0 0>; + qcom,vdd-wlan-rfa3-info = <1900000 1900000 450000 0>; + + qcom,wlan-ramdump-dynamic = <0x400000>; + mhi,max-channels = <30>; + mhi,timeout = <10000>; + + mhi_channels { + #address-cells = <1>; + #size-cells = <0>; + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-queue; + mhi,auto-start; + }; + }; + + mhi_events { + 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>; + }; + }; + }; + + chip_cfg@2 { + reg = <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "smmu_iova_base", "smmu_iova_ipa"; + + supported-ids = <0x1102>; + wlan_vregs = "vdd-wlan-aon", "vdd-wlan-rfa1", + "vdd-wlan-rfa2", "vdd-wlan-rfa3"; + qcom,vdd-wlan-aon-info = <1055000 1055000 0 0>; + qcom,vdd-wlan-rfa1-info = <1370000 1370000 0 0>; + qcom,vdd-wlan-rfa2-info = <2040000 2040000 0 0>; + qcom,vdd-wlan-rfa3-info = <1900000 1900000 0 0>; + + qcom,wlan-ramdump-dynamic = <0x300000>; + mhi,max-channels = <30>; + mhi,timeout = <10000>; + mhi,ee = <0x3>, <0x4>; + mhi,ee-names = "SBL", "RDDM"; + mhi,bhie-offset = <0x0324>; + + mhi_channels { + #address-cells = <1>; + #size-cells = <0>; + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@16 { + reg = <16>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-start; + }; + + mhi_chan@17 { + reg = <17>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-queue; + mhi,auto-start; + }; + }; + + mhi_events { + 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>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi index 02c9fe63a2178f13f583c6c9f12240cc355a3a19..33e45516d62d735313817680cee60cf2f1575d62 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -723,33 +723,4 @@ qcom,init-mode = ; }; }; - - /* Rome 3.3V supply */ - vreg_wlan: vreg_wlan { - compatible = "qcom,stub-regulator"; - regulator-name = "vreg_wlan"; - }; - - /* PWR_CTR2_VDD_1P8 supply */ - vreg_conn_1p8: vreg_conn_1p8 { - compatible = "regulator-fixed"; - regulator-name = "vreg_conn_1p8"; - pinctrl-names = "default"; - pinctrl-0 = <&conn_power_1p8_active>; - startup-delay-us = <4000>; - enable-active-high; - gpio = <&tlmm 173 0>; - }; - - /* PWR_CTR1_VDD_PA supply */ - vreg_conn_pa: vreg_conn_pa { - compatible = "regulator-fixed"; - regulator-name = "vreg_conn_pa"; - pinctrl-names = "default"; - pinctrl-0 = <&conn_power_pa_active>; - startup-delay-us = <4000>; - enable-active-high; - gpio = <&tlmm 174 0>; - }; - }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi index a98d5206152463116d3c9c7b4ead019c2277d122..b43385b399fb17cba30c535fec073c5475803138 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi @@ -48,6 +48,11 @@ opp-microvolt = ; }; + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = ; + }; + opp-427000000 { opp-hz = /bits/ 64 <427000000>; opp-microvolt = ; @@ -101,30 +106,38 @@ qcom,gpu-pwrlevel@3 { reg = <3>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <6>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; qcom,gpu-freq = <427000000>; qcom,bus-freq = <6>; qcom,bus-min = <5>; qcom,bus-max = <9>; }; - qcom,gpu-pwrlevel@4 { - reg = <4>; + qcom,gpu-pwrlevel@5 { + reg = <5>; qcom,gpu-freq = <345000000>; qcom,bus-freq = <3>; qcom,bus-min = <3>; qcom,bus-max = <8>; }; - qcom,gpu-pwrlevel@5 { - reg = <5>; + qcom,gpu-pwrlevel@6 { + reg = <6>; qcom,gpu-freq = <257000000>; qcom,bus-freq = <2>; qcom,bus-min = <1>; qcom,bus-max = <8>; }; - qcom,gpu-pwrlevel@6 { - reg = <6>; + qcom,gpu-pwrlevel@7 { + reg = <7>; qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi index e101ced50d9d8cdd2f2984897fe59af2e390057d..a9480a4a430f701b345d3db0d4a08b49d472942e 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi @@ -351,8 +351,9 @@ qcom,msm-dai-tdm-quin-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37184>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 36934>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 + 36934 36942>; qcom,msm-cpudai-tdm-clk-rate = <24576000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -383,13 +384,20 @@ qcom,msm-cpudai-tdm-dev-id = <36934>; qcom,msm-cpudai-tdm-data-align = <0>; }; + + dai_quin_tdm_rx_7: qcom,msm-dai-q6-tdm-quin-rx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36942>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,msm-dai-tdm-quin-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37185>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 36935>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 + 36935 36943>; qcom,msm-cpudai-tdm-clk-rate = <24576000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <1>; @@ -420,6 +428,12 @@ qcom,msm-cpudai-tdm-dev-id = <36935>; qcom,msm-cpudai-tdm-data-align = <0>; }; + + dai_quin_tdm_tx_7: qcom,msm-dai-q6-tdm-quin-tx-7 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36943>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,avtimer@170f7000 { @@ -489,9 +503,10 @@ <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>, <&dai_quat_tdm_tx_7>, <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, - <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, - <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, - <&dai_quin_tdm_tx_3>; + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_rx_7>, + <&dai_quin_tdm_tx_0>, <&dai_quin_tdm_tx_1>, + <&dai_quin_tdm_tx_2>, <&dai_quin_tdm_tx_3>, + <&dai_quin_tdm_tx_7>; asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -523,9 +538,10 @@ "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36927", "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", - "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", - "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", - "msm-dai-q6-tdm.36935"; + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36942", + "msm-dai-q6-tdm.36929", "msm-dai-q6-tdm.36931", + "msm-dai-q6-tdm.36933", "msm-dai-q6-tdm.36935", + "msm-dai-q6-tdm.36943"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts new file mode 100644 index 0000000000000000000000000000000000000000..ad4132c52f38d8d2f5a4f282b54155a42c06e9d6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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-vm.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 Virtual Machine"; + compatible = "qcom,sa8155"; + qcom,pmic-name = "PM8150"; + qcom,board-id = <0 0>; +}; + +&slpi_tlmm { + status = "ok"; +}; + +&apps_smmu { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts new file mode 100644 index 0000000000000000000000000000000000000000..c2a9e394cbaaf88ef9711be2e23aed476ba75a41 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts @@ -0,0 +1,59 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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-vm.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 Virtual Machine"; + compatible = "qcom,sa8155"; + qcom,pmic-name = "PM8150"; + qcom,board-id = <0 0>; +}; + +&hab { + vmid = <3>; +}; + +&slpi_tlmm { + status = "ok"; +}; + +&apps_smmu { + status = "ok"; +}; + +&qupv3_se13_4uart { + status = "ok"; +}; + +&usb0 { + status = "ok"; +}; + +&usb2_phy0 { + status = "ok"; +}; + +&pcie0_msi { + status = "ok"; +}; + +&pcie0 { + status = "ok"; +}; + +&sde_kms_hyp { + /delete-property/ qcom,client-id; + qcom,client-id = "7816"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts index a409dc74b083891c863f040aa8b0638ceabc3765..28aa9ce98841fab449416695f1f674fc34c02880 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts @@ -29,6 +29,10 @@ status = "ok"; }; +&qupv3_se13_4uart { + status = "ok"; +}; + &usb0 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-pinctrl.dtsi index 919fcc057493bce22d7a0515af0062052ab5c49b..2c54f126b1260ff9414f55177eeb9da1838aca18 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-pinctrl.dtsi @@ -21,5 +21,452 @@ interrupt-controller; #interrupt-cells = <2>; }; + + hs1_i2s_mclk { + hs1_i2s_mclk_sleep: hs1_i2s_mclk_sleep { + mux { + pins = "gpio155"; + function = "gpio"; + }; + + config { + pins = "gpio155"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_mclk_active: hs1_i2s_mclk_active { + mux { + pins = "gpio155"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio155"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_sck { + hs1_i2s_sck_sleep: hs1_i2s_sck_sleep { + mux { + pins = "gpio156"; + function = "gpio"; + }; + + config { + pins = "gpio156"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_sck_active: hs1_i2s_sck_active { + mux { + pins = "gpio156"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio156"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_ws { + hs1_i2s_ws_sleep: hs1_i2s_ws_sleep { + mux { + pins = "gpio157"; + function = "gpio"; + }; + + config { + pins = "gpio157"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_ws_active: hs1_i2s_ws_active { + mux { + pins = "gpio157"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio157"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_data0 { + hs1_i2s_data0_sleep: hs1_i2s_data0_sleep { + mux { + pins = "gpio158"; + function = "sleep"; + }; + + config { + pins = "gpio158"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_data0_active: hs1_i2s_data0_active { + mux { + pins = "gpio158"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio158"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_data1 { + hs1_i2s_data1_sleep: hs1_i2s_data1_sleep { + mux { + pins = "gpio159"; + function = "gpio"; + }; + + config { + pins = "gpio159"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_data1_active: hs1_i2s_data1_active { + mux { + pins = "gpio159"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio159"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + hs2_i2s_mclk { + hs2_i2s_mclk_sleep: hs2_i2s_mclk_sleep { + mux { + pins = "gpio160"; + function = "gpio"; + }; + + config { + pins = "gpio160"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_mclk_active: hs2_i2s_mclk_active { + mux { + pins = "gpio160"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio160"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_sck { + hs2_i2s_sck_sleep: hs2_i2s_sck_sleep { + mux { + pins = "gpio161"; + function = "gpio"; + }; + + config { + pins = "gpio161"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_sck_active: hs2_i2s_sck_active { + mux { + pins = "gpio161"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio161"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_ws { + hs2_i2s_ws_sleep: hs2_i2s_ws_sleep { + mux { + pins = "gpio162"; + function = "gpio"; + }; + + config { + pins = "gpio162"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_ws_active: hs2_i2s_ws_active { + mux { + pins = "gpio162"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio162"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_data0 { + hs2_i2s_data0_sleep: hs2_i2s_data0_sleep { + mux { + pins = "gpio163"; + function = "gpio"; + }; + + config { + pins = "gpio163"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_data0_active: hs2_i2s_data0_active { + mux { + pins = "gpio163"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio163"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_data1 { + hs2_i2s_data1_sleep: hs2_i2s_data1_sleep { + mux { + pins = "gpio164"; + function = "gpio"; + }; + + config { + pins = "gpio164"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_data1_active: hs2_i2s_data1_active { + mux { + pins = "gpio164"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio164"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + hs3_i2s_mclk { + hs3_i2s_mclk_sleep: hs3_i2s_mclk_sleep { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_mclk_active: hs3_i2s_mclk_active { + mux { + pins = "gpio125"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio125"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_sck { + hs3_i2s_sck_sleep: hs3_i2s_sck_sleep { + mux { + pins = "gpio165"; + function = "gpio"; + }; + + config { + pins = "gpio165"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_sck_active: hs3_i2s_sck_active { + mux { + pins = "gpio165"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio165"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_ws { + hs3_i2s_ws_sleep: hs3_i2s_ws_sleep { + mux { + pins = "gpio166"; + function = "gpio"; + }; + + config { + pins = "gpio166"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_ws_active: hs3_i2s_ws_active { + mux { + pins = "gpio166"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio166"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_data0 { + hs3_i2s_data0_sleep: hs3_i2s_data0_sleep { + mux { + pins = "gpio167"; + function = "gpio"; + }; + + config { + pins = "gpio167"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_data0_active: hs3_i2s_data0_active { + mux { + pins = "gpio167"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio167"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_data1 { + hs3_i2s_data1_sleep: hs3_i2s_data1_sleep { + mux { + pins = "gpio168"; + function = "gpio"; + }; + + config { + pins = "gpio168"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_data1_active: hs3_i2s_data1_active { + mux { + pins = "gpio168"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio168"; + drive-strength = <8>; /* 4 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-qupv3.dtsi index aa8957d93480ff9b108ca7b9c0ac200612af4e73..dd9bc5819ec80face028c0e0d530ed4a66f6cdab 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-qupv3.dtsi @@ -599,7 +599,7 @@ pinctrl-1 = <&qupv3_se13_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; - qcom,wrapper-core = <&qupv3_1>; + qcom,wrapper-core = <&qupv3_2>; status = "disabled"; }; @@ -740,11 +740,11 @@ status = "disabled"; }; - qupv3_se15_spi: spi@c90000 { + qupv3_se15_spi: spi@c94000 { compatible = "qcom,spi-geni"; #address-cells = <1>; #size-cells = <0>; - reg = <0xc90000 0x4000>; + reg = <0xc94000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; clocks = <&clock_virt GCC_QUPV3_WRAP2_S5_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi index 5e79647ad0f3c5ac1137e218ec82353fe776eb3c..90366d5cb5db66db7ce278811c14d746e11a0978 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi @@ -118,9 +118,9 @@ reg-names = "hsusb_phy_base", "phy_rcal_reg"; - vdd-supply = <&pm8150_l5>; - vdda18-supply = <&pm8150_l12>; - vdda33-supply = <&pm8150_l2>; + vdd-supply = <&pm8150_1_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_1_l2>; qcom,vdd-voltage-level = <0 880000 880000>; clocks = <&clock_gcc RPMH_CXO_CLK>; @@ -140,10 +140,10 @@ reg = <0x88e8000 0x3000>; reg-names = "qmp_phy_base"; - vdd-supply = <&pm8150_l5>; + vdd-supply = <&pm8150_1_l5>; qcom,vdd-voltage-level = <0 880000 880000>; qcom,vdd-max-load-uA = <47000>; - core-supply = <&pm8150l_l3>; + core-supply = <&pm8150_2_l8>; qcom,vbus-valid-override; qcom,link-training-reset; qcom,qmp-phy-init-seq = @@ -394,9 +394,9 @@ reg-names = "hsusb_phy_base", "phy_rcal_reg"; - vdd-supply = <&pm8150_l5>; - vdda18-supply = <&pm8150_l12>; - vdda33-supply = <&pm8150_l2>; + vdd-supply = <&pm8150_1_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_1_l2>; qcom,vdd-voltage-level = <0 880000 880000>; clocks = <&clock_gcc RPMH_CXO_CLK>; @@ -417,10 +417,10 @@ reg-names = "qmp_phy_base", "pcs_clamp_enable_reg"; - vdd-supply = <&pm8150_l5>; + vdd-supply = <&pm8150_1_l5>; qcom,vdd-voltage-level = <0 880000 880000>; qcom,vdd-max-load-uA = <47000>; - core-supply = <&pm8150l_l3>; + core-supply = <&pm8150_2_l8>; qcom,vbus-valid-override; qcom,qmp-phy-init-seq = /* */ diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm.dts b/arch/arm64/boot/dts/qcom/sa8155-vm.dts index 2b2d2e8b53d488a5d444c9b79b1733930bce82ad..8f9a719cd249c763dccd03dac917768a2f06cbf3 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm.dts @@ -22,6 +22,10 @@ status = "ok"; }; +&qupv3_se13_4uart { + status = "ok"; +}; + &usb0 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi index 4f294ac7d3adb98a403fe0fdbb6573f901a4b1d9..c51daecfce59afa6a044781aa3df36c3d58da40b 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include "quin-vm-common.dtsi" / { model = "Qualcomm Technologies, Inc. SA8155 Virtual Machine"; @@ -18,198 +19,167 @@ pci-domain0 = &pcie0; /* PCIe0 domain */ }; - psci { - compatible = "arm,psci-1.0"; - method = "smc"; - }; - - chosen { - bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; - }; - - soc: soc { }; - reserved_memory: reserved-memory { - #address-cells = <2>; - #size-cells = <2>; - ranges; - - /* global autoconfigured region for contiguous allocations */ - linux,cma { - compatible = "shared-dma-pool"; - alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; - reusable; - alignment = <0x0 0x400000>; - size = <0x0 0x2000000>; - linux,cma-default; - }; pmem_shared: pmem_shared_region@a0000000 { reg = <0x0 0xa0000000 0x0 0x20000000>; label = "pmem_shared_mem"; }; + }; +}; - qseecom_mem: qseecom_region@0x9e400000 { - compatible = "shared-dma-pool"; - alloc-ranges = <0 0x00000000 0 0xffffffff>; - reusable; - alignment = <0 0x400000>; - size = <0 0x1400000>; +&soc { + hsi2s: qcom,hsi2s { + compatible = "qcom,sa8155-hsi2s", "qcom,hsi2s"; + number-of-interfaces = <3>; + reg = <0x172C0000 0x28000>, + <0x17080000 0xE000>; + reg-names = "lpa_if", "lpass_tcsr"; + interrupts = ; + bit-clock-hz = <20000000>; + interrupt-interval-ms = <10>; + + sdr0: qcom,hs0_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs1_i2s_mclk_active &hs1_i2s_sck_active + &hs1_i2s_ws_active &hs1_i2s_data0_active + &hs1_i2s_data1_active>; + pinctrl-1 = <&hs1_i2s_mclk_sleep &hs1_i2s_sck_sleep + &hs1_i2s_ws_sleep &hs1_i2s_data0_sleep + &hs1_i2s_data1_sleep>; }; - qseecom_ta_mem: qseecom_ta_region { - compatible = "shared-dma-pool"; - alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; - reusable; - alignment = <0x0 0x400000>; - size = <0x0 0x1000000>; + sdr1: qcom,hs1_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs2_i2s_mclk_active &hs2_i2s_sck_active + &hs2_i2s_ws_active &hs2_i2s_data0_active + &hs2_i2s_data1_active>; + pinctrl-1 = <&hs2_i2s_mclk_sleep &hs2_i2s_sck_sleep + &hs2_i2s_ws_sleep &hs2_i2s_data0_sleep + &hs2_i2s_data1_sleep>; }; - }; - 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/vdevs/1c0f0000.virtio_blk/vdc"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; + sdr2: qcom,hs2_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <2>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs3_i2s_mclk_active &hs3_i2s_sck_active + &hs3_i2s_ws_active &hs3_i2s_data0_active + &hs3_i2s_data1_active>; + pinctrl-1 = <&hs3_i2s_mclk_sleep &hs3_i2s_sck_sleep + &hs3_i2s_ws_sleep &hs3_i2s_data0_sleep + &hs3_i2s_data1_sleep>; }; }; -}; -&soc { - #address-cells = <1>; - #size-cells = <1>; - virtual-interrupt-parent = "gic"; - ranges = <0 0 0 0xffffffff>; - compatible = "simple-bus"; - - clock_virt: qcom,virt-gcc { - compatible = "qcom,virt-clk-sm8150-gcc"; + clock_virt: qcom,virtio-gcc { + compatible = "virtio,mmio"; + reg = <0x1c200000 0x1000>; + interrupts = <0 48 0>; #clock-cells = <1>; #reset-cells = <1>; }; - clock_virt_scc: qcom,virt-scc { - compatible = "qcom,virt-clk-sm8150-scc"; + clock_virt_scc: qcom,virtio-scc { + compatible = "virtio,mmio"; + reg = <0x1c300000 0x1000>; + interrupts = <0 49 0>; #clock-cells = <1>; #reset-cells = <1>; }; - clock_gcc: qcom,gcc { - compatible = "qcom,dummycc"; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_rpmh: qcom,rpmh { - compatible = "qcom,dummycc"; - #clock-cells = <1>; - }; - - qcom,ion { - compatible = "qcom,msm-ion"; - #address-cells = <1>; - #size-cells = <0>; + regulator_virt: virtio_regulator@1c700000 { + compatible = "virtio,mmio"; + reg = <0x1c700000 0x1000>; + interrupts = <0 42 0>; - system_heap: qcom,ion-heap@25 { - reg = <25>; - qcom,ion-heap-type = "SYSTEM"; + usb30_prim_gdsc: usb30_prim_gdsc { + regulator-name = "usb30_prim_gdsc"; }; - qcom,ion-heap@27 { /* QSEECOM HEAP */ - reg = <27>; - memory-region = <&qseecom_mem>; - qcom,ion-heap-type = "DMA"; + usb30_sec_gdsc: usb30_sec_gdsc { + regulator-name = "usb30_sec_gdsc"; }; - qcom,ion-heap@19 { /* QSEECOM TA HEAP */ - reg = <19>; - memory-region = <&qseecom_ta_mem>; - qcom,ion-heap-type = "DMA"; + pcie_0_gdsc: pcie_0_gdsc { + regulator-name = "pcie_0_gdsc"; }; - }; - - qcom,hab { - compatible = "qcom,hab"; - vmid = <2>; + pcie_1_gdsc: pcie_1_gdsc { + regulator-name = "pcie_1_gdsc"; + }; - mmidgrp100: mmidgrp100 { - grp-start-id = <100>; - role = "fe"; - remote-vmids = <0>; + L2A: pm8150_1_l2: regulator-pm8150-1-l2 { + regulator-name = "ldoa2"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; }; - mmidgrp200: mmidgrp200 { - grp-start-id = <200>; - role = "fe"; - remote-vmids = <0>; + L5A: pm8150_1_l5: regulator-pm8150-1-l5 { + regulator-name = "ldoa5"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; }; - mmidgrp300: mmidgrp300 { - grp-start-id = <300>; - role = "fe"; - remote-vmids = <0>; + L12A: pm8150_1_l12: regulator-pm8150-1-l12 { + regulator-name = "ldoa12"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; }; - mmidgrp400: mmidgrp400 { - grp-start-id = <400>; - role = "fe"; - remote-vmids = <0>; + L17A: pm8150_1_l17: regulator-pm8150-1-l17 { + regulator-name = "ldoa17"; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; }; - mmidgrp500: mmidgrp500 { - grp-start-id = <500>; - role = "fe"; - remote-vmids = <0>; + L8C: pm8150_2_l8: regulator-pm8150-2-l8 { + regulator-name = "ldoc8"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-allow-set-load; }; - mmidgrp600: mmidgrp600 { - grp-start-id = <600>; - role = "fe"; - remote-vmids = <0>; + L13C: pm8150_2_l13: regulator-pm8150-2-l13 { + regulator-name = "ldoc13"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; }; - mmidgrp700: mmidgrp700 { - grp-start-id = <700>; - role = "fe"; - remote-vmids = <0>; + L15C: pm8150_2_l15: regulator-pm8150-2-l15 { + regulator-name = "ldoc15"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1904000>; }; - mmidgrp800: mmidgrp800 { - grp-start-id = <800>; - role = "fe"; - remote-vmids = <0>; + L18C: pm8150_2_l18: regulator-pm8150-2-l18 { + regulator-name = "ldoc18"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-allow-set-load; }; - mmidgrp900: mmidgrp900 { - grp-start-id = <900>; - role = "fe"; - remote-vmids = <0>; + S6A: pm8150_1_s6: regulator-pm8150-1-s6 { + regulator-name = "smpa6"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1352000>; }; - mmidgrp1000: mmidgrp1000 { - grp-start-id = <1000>; - role = "fe"; - remote-vmids = <0>; + S4C: pm8150_2_s4: regulator-pm8150-2-s4 { + regulator-name = "smpc4"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; }; - }; - sde_kms_hyp: qcom,sde_kms_hyp@ae00000 { - compatible = "qcom,sde-kms-hyp"; - qcom,client-id = "7815"; + S5C: pm8150_2_s5: regulator-pm8150-2-s5 { + regulator-name = "smpc5"; + regulator-min-microvolt = <1824000>; + regulator-max-microvolt = <2040000>; + }; }; apps_smmu: apps-smmu@0x15000000 { @@ -316,38 +286,6 @@ status = "disabled"; }; - S6A: pm8150_1_s6: regulator-pm8150-1-s6 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_1_s6"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1352000>; - qcom,init-voltage = <600000>; - }; - - S4C: pm8150_2_s4: regulator-pm8150-2-s4 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_2_s4"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1400000>; - qcom,init-voltage = <800000>; - }; - - S5C: pm8150_2_s5: regulator-pm8150-2-s5 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_2_s5"; - regulator-min-microvolt = <1824000>; - regulator-max-microvolt = <2040000>; - qcom,init-voltage = <1824000>; - }; - - L15C: pm8150_2_l15: regulator-pm8150-2-l15 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_2_l15"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1904000>; - qcom,init-voltage = <1800000>; - }; - vreg_wlan: vreg_wlan { compatible = "qcom,stub-regulator"; regulator-name = "vreg_wlan"; @@ -375,62 +313,6 @@ gpio = <&tlmm 174 0>; }; - pm8150_l2: regulator-pm8150-l2 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_l2"; - regulator-min-microvolt = <3072000>; - regulator-max-microvolt = <3072000>; - qcom,init-voltage = <3072000>; - status = "okay"; - }; - - pm8150_l5: regulator-pm8150-l5 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_l5"; - regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; - qcom,proxy-consumer-enable; - qcom,proxy-consumer-current = <23800>; - qcom,init-voltage = <880000>; - status = "okay"; - }; - - pm8150_l12: regulator-pm8150-l12 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_l12"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - qcom,init-voltage = <1800000>; - status = "okay"; - }; - - pm8150l_l3: regulator-pm8150l-l3 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150l_l3"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - qcom,proxy-consumer-enable; - qcom,proxy-consumer-current = <51800>; - qcom,init-voltage = <1200000>; - status = "okay"; - }; - - pm8150_2_l8: regulator-pm8150-2-l8 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_2_l8"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - status = "okay"; - }; - - pm8150_2_l18: regulator-pm8150-2-l18 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_2_l18"; - regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; - status = "okay"; - }; - VDD_CX_LEVEL: VDD_MMCX_LEVEL: S9C_LEVEL: pm8150_2_s9_level: regulator-pm8150-2-s9-level { compatible = "qcom,stub-regulator"; @@ -441,24 +323,6 @@ = ; }; - pcie_0_gdsc: pcie_0_gdsc { - compatible = "qcom,stub-regulator"; - regulator-name = "pcie_0_gdsc"; - status = "okay"; - }; - - usb30_prim_gdsc: usb30_prim_gdsc { - compatible = "qcom,stub-regulator"; - regulator-name = "usb30_prim_gdsc"; - status = "okay"; - }; - - usb30_sec_gdsc: usb30_sec_gdsc { - compatible = "qcom,stub-regulator"; - regulator-name = "usb30_sec_gdsc"; - status = "okay"; - }; - qcom_seecom: qseecom@87900000 { compatible = "qcom,qseecom"; reg = <0x87900000 0x2200000>; @@ -476,68 +340,12 @@ compatible = "qca,qca6174"; pinctrl-names = "default"; pinctrl-0 = <&bt_en_active>; - qca,bt-reset-gpio = <&tlmm 172 0>; /* BT_EN */ - status = "ok"; - }; - - wdog: qcom,wdt@17c10000{ - compatible = "qcom,msm-watchdog"; - reg = <0x17c10000 0x1000>; - reg-names = "wdt-base"; - interrupts = <0 0 0>, <0 1 0>; - qcom,bark-time = <11000>; - qcom,pet-time = <9360>; - qcom,ipi-ping; - qcom,wakeup-enable; - qcom,scandump-sizes = <0x10100 0x10100 0x10100 0x10100 - 0x18100 0x18100 0x18100 0x18100>; - }; - - qcom,msm-imem@14680000 { - compatible = "qcom,msm-imem"; - reg = <0x14680000 0x1000>; - ranges = <0x0 0x14680000 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>; - }; - - dload_type@1c { - compatible = "qcom,msm-imem-dload-type"; - reg = <0x1c 0x4>; - }; - - 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>; - }; - }; - - vm_restart: restart { - compatible = "qcom,vm-restart"; + /* BT_EN */ + qca,bt-reset-gpio = <&tlmm 172 0>; + /* PWR_CTR1_VDD_PA */ + qca,bt-vdd-pa-supply = <&vreg_conn_pa>; + /* PWR_CTR2_VDD_1P8 */ + qca,bt-chip-pwd-supply = <&vreg_conn_1p8>; status = "ok"; }; @@ -713,7 +521,8 @@ #include "sa8155-vm-audio.dtsi" #include "sa8155-vm-pcie.dtsi" #include "sa8155-vm-mhi.dtsi" +#include "pm8150-vm.dtsi" -&qupv3_se13_4uart { - status = "ok"; +&tlmm { + dirconn-list = <37 216 1>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index 0737dd717dd3f7646ac95d6967d5bdec1d7a2014..95fa47b280ac3abaf230433eea7bdf59e8c268c7 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -63,34 +63,6 @@ /delete-node/ rpmh-regulator-ldof2; /delete-node/ rpmh-regulator-ldof5; /delete-node/ rpmh-regulator-ldof6; - - bluetooth: bt_qca6174 { - compatible = "qca,qca6174"; - pinctrl-names = "default"; - pinctrl-0 = <&bt_en_active>; - /* BT_EN */ - qca,bt-reset-gpio = <&tlmm 172 0>; - /* PWR_CTR1_VDD_PA */ - qca,bt-vdd-pa-supply = <&vreg_conn_pa>; - /* PWR_CTR2_VDD_1P8 */ - qca,bt-chip-pwd-supply = <&vreg_conn_1p8>; - qca,bt-vdd-vl-supply = <&pm8150_1_s6>; - qca,bt-vdd-vm-supply = <&pm8150_2_s4>; - qca,bt-vdd-5c-supply = <&pm8150_2_s5>; - qca,bt-vdd-vh-supply = <&pm8150_2_l15>; - - qca,bt-vdd-vl-voltage-level = <1055000 1055000>; - qca,bt-vdd-vm-voltage-level = <1370000 1370000>; - qca,bt-vdd-5c-voltage-level = <2040000 2040000>; - qca,bt-vdd-vh-voltage-level = <1900000 1900000>; - - qca,bt-vdd-vl-current-level = <0>; - qca,bt-vdd-vm-current-level = <0>; - qca,bt-vdd-5c-current-level = <0>; - qca,bt-vdd-vh-current-level = <450000>; - - status = "disabled"; - }; }; /* Add regulator nodes specific to SA8155 */ @@ -527,6 +499,62 @@ #include &soc { + hsi2s: qcom,hsi2s { + compatible = "qcom,sa8155-hsi2s", "qcom,hsi2s"; + number-of-interfaces = <3>; + reg = <0x172C0000 0x28000>, + <0x17080000 0xE000>; + reg-names = "lpa_if", "lpass_tcsr"; + interrupts = ; + bit-clock-hz = <20000000>; + interrupt-interval-ms = <10>; + + sdr0: qcom,hs0_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs1_i2s_mclk_active &hs1_i2s_sck_active + &hs1_i2s_ws_active &hs1_i2s_data0_active + &hs1_i2s_data1_active>; + pinctrl-1 = <&hs1_i2s_mclk_sleep &hs1_i2s_sck_sleep + &hs1_i2s_ws_sleep &hs1_i2s_data0_sleep + &hs1_i2s_data1_sleep>; + iommus = <&apps_smmu 0x1B5C 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + + sdr1: qcom,hs1_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs2_i2s_mclk_active &hs2_i2s_sck_active + &hs2_i2s_ws_active &hs2_i2s_data0_active + &hs2_i2s_data1_active>; + pinctrl-1 = <&hs2_i2s_mclk_sleep &hs2_i2s_sck_sleep + &hs2_i2s_ws_sleep &hs2_i2s_data0_sleep + &hs2_i2s_data1_sleep>; + iommus = <&apps_smmu 0x1B5D 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + + sdr2: qcom,hs2_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <2>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs3_i2s_mclk_active &hs3_i2s_sck_active + &hs3_i2s_ws_active &hs3_i2s_data0_active + &hs3_i2s_data1_active>; + pinctrl-1 = <&hs3_i2s_mclk_sleep &hs3_i2s_sck_sleep + &hs3_i2s_ws_sleep &hs3_i2s_data0_sleep + &hs3_i2s_data1_sleep>; + iommus = <&apps_smmu 0x1B5E 0x0>; + qcom,smmu-s1-bypass; + qcom,iova-mapping = <0x0 0xFFFFFFFF>; + }; + }; + emac_hw: qcom,emac@00020000 { compatible = "qcom,emac-dwc-eqos"; qcom,arm-smmu; @@ -614,286 +642,6 @@ }; }; - qcom,cnss-qca6390@a0000000 { - status = "disabled"; - }; - - qcom,cnss-qca-converged { - compatible = "qcom,cnss-qca-converged"; - - qcom,converged-dt; - qcom,wlan-rc-num = <0>; - qcom,bus-type=<0>; - qcom,notify-modem-status; - qcom,msm-bus,name = "msm-cnss"; - qcom,msm-bus,num-cases = <4>; - qcom,msm-bus,num-paths = <2>; - qcom,msm-bus,vectors-KBps = - <45 512 0 0>, <1 512 0 0>, - /* Upto 200 Mbps */ - <45 512 41421 655360>, <1 512 41421 655360>, - /* Upto 400 Mbps */ - <45 512 98572 655360>, <1 512 98572 1600000>, - /* Upto 800 Mbps */ - <45 512 207108 1146880>, <1 512 207108 3124992>; - - #address-cells=<1>; - #size-cells=<1>; - ranges = <0x10000000 0x10000000 0x10000000>, - <0x20000000 0x20000000 0x10000>, - <0xa0000000 0xa0000000 0x10000000>, - <0xb0000000 0xb0000000 0x10000>; - - vdd-wlan-ctrl1-supply = <&vreg_conn_pa>; - vdd-wlan-ctrl2-supply = <&vreg_conn_1p8>; - vdd-wlan-supply = <&vreg_wlan>; - vdd-wlan-aon-supply = <&pm8150_1_s6>; - vdd-wlan-rfa1-supply = <&pm8150_2_s4>; - vdd-wlan-rfa2-supply = <&pm8150_2_s5>; - vdd-wlan-rfa3-supply = <&pm8150_2_l15>; - - wlan_vregs = "vdd-wlan-ctrl1", "vdd-wlan-ctrl2"; - qcom,vdd-wlan-ctrl1-info = <0 0 0 0>; - qcom,vdd-wlan-ctrl2-info = <0 0 0 0>; - wlan-en-gpio = <&tlmm 169 0>; - pinctrl-names = "wlan_en_active", "wlan_en_sleep"; - pinctrl-0 = <&cnss_wlan_en_active>; - pinctrl-1 = <&cnss_wlan_en_sleep>; - - chip_cfg@0 { - reg = <0x10000000 0x10000000>, - <0x20000000 0x10000>; - reg-names = "smmu_iova_base", "smmu_iova_ipa"; - - supported-ids = <0x003e>; - wlan_vregs = "vdd-wlan"; - qcom,vdd-wlan-info = <0 0 0 10>; - - qcom,smmu-s1-enable; - qcom,wlan-ramdump-dynamic = <0x200000>; - }; - - chip_cfg@1 { - reg = <0xa0000000 0x10000000>, - <0xb0000000 0x10000>; - reg-names = "smmu_iova_base", "smmu_iova_ipa"; - - supported-ids = <0x1101>; - wlan_vregs = "vdd-wlan-aon", "vdd-wlan-rfa1", - "vdd-wlan-rfa2", "vdd-wlan-rfa3"; - qcom,vdd-wlan-aon-info = <1055000 1055000 0 0>; - qcom,vdd-wlan-rfa1-info = <1370000 1370000 0 0>; - qcom,vdd-wlan-rfa2-info = <2040000 2040000 0 0>; - qcom,vdd-wlan-rfa3-info = <1900000 1900000 450000 0>; - - qcom,wlan-ramdump-dynamic = <0x400000>; - mhi,max-channels = <30>; - mhi,timeout = <10000>; - - mhi_channels { - #address-cells = <1>; - #size-cells = <0>; - mhi_chan@0 { - reg = <0>; - label = "LOOPBACK"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@1 { - reg = <1>; - label = "LOOPBACK"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@4 { - reg = <4>; - label = "DIAG"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@5 { - reg = <5>; - label = "DIAG"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@20 { - reg = <20>; - label = "IPCR"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - mhi,auto-start; - }; - - mhi_chan@21 { - reg = <21>; - label = "IPCR"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - mhi,auto-queue; - mhi,auto-start; - }; - }; - - mhi_events { - 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>; - }; - }; - }; - chip_cfg@2 { - reg = <0xa0000000 0x10000000>, - <0xb0000000 0x10000>; - reg-names = "smmu_iova_base", "smmu_iova_ipa"; - - supported-ids = <0x1102>; - wlan_vregs = "vdd-wlan-aon", "vdd-wlan-rfa1", - "vdd-wlan-rfa2", "vdd-wlan-rfa3"; - qcom,vdd-wlan-aon-info = <1055000 1055000 0 0>; - qcom,vdd-wlan-rfa1-info = <1370000 1370000 0 0>; - qcom,vdd-wlan-rfa2-info = <2040000 2040000 0 0>; - qcom,vdd-wlan-rfa3-info = <1900000 1900000 0 0>; - - qcom,wlan-ramdump-dynamic = <0x300000>; - mhi,max-channels = <30>; - mhi,timeout = <10000>; - mhi,ee = <0x3>, <0x4>; - mhi,ee-names = "SBL", "RDDM"; - mhi,bhie-offset = <0x0324>; - - mhi_channels { - mhi_chan@0 { - reg = <0>; - label = "LOOPBACK"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@1 { - reg = <1>; - label = "LOOPBACK"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@4 { - reg = <4>; - label = "DIAG"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@5 { - reg = <5>; - label = "DIAG"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - }; - - mhi_chan@16 { - reg = <16>; - label = "IPCR"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - mhi,auto-start; - }; - - mhi_chan@17 { - reg = <17>; - label = "IPCR"; - mhi,num-elements = <32>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x14>; - mhi,auto-queue; - mhi,auto-start; - }; - }; - - mhi_events { - 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>; - }; - }; - }; - }; - qcom,rmnet-ipa { status="disabled"; }; @@ -906,6 +654,8 @@ read-only; ranges; }; + + /include/ "dm-verity-boot.dtsi" }; &ipa_hw { diff --git a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c19adc024a9d982179da8f0e78bd9ec17fdcd8f0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi @@ -0,0 +1,97 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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. + */ + +/* Remove regulator nodes specific to sdmshrike */ +&soc { + /* Stub regulators */ + /delete-node/ regulator-pm8150_1-s4; + + /* Logical rails */ + /delete-node/ rpmh-regulator-cxlvl; + /delete-node/ rpmh-regulator-mxlvl; + /delete-node/ rpmh-regulator-gfxlvl; + /delete-node/ rpmh-regulator-lmxlvl; + /delete-node/ rpmh-regulator-lcxlvl; + /delete-node/ rpmh-regulator-mmcxlvl; + /delete-node/ rpmh-regulator-msslvl; + /delete-node/ rpmh-regulator-ebilvl; + + /* PM8150_1 regulators */ + /delete-node/ rpmh-regulator-smpa5; + /delete-node/ rpmh-regulator-ldoa3; + /delete-node/ rpmh-regulator-ldoa5; + /delete-node/ rpmh-regulator-ldoa6; + /delete-node/ rpmh-regulator-ldoa7; + /delete-node/ rpmh-regulator-ldoa9; + /delete-node/ rpmh-regulator-ldoa11; + /delete-node/ rpmh-regulator-ldoa12; + /delete-node/ rpmh-regulator-ldoa13; + /delete-node/ rpmh-regulator-ldoa15; + /delete-node/ rpmh-regulator-ldoa16; + /delete-node/ rpmh-regulator-ldoa18; + /delete-node/ rpmh-regulator-smpe4; + /delete-node/ rpmh-regulator-smpe5; + /delete-node/ rpmh-regulator-ldoe1; + /delete-node/ rpmh-regulator-ldoe2; + /delete-node/ rpmh-regulator-ldoe5; + /delete-node/ rpmh-regulator-ldoe7; + /delete-node/ rpmh-regulator-ldoe10; + /delete-node/ rpmh-regulator-ldoe13; + /delete-node/ rpmh-regulator-ldoe14; + /delete-node/ rpmh-regulator-ldoe15; + /delete-node/ rpmh-regulator-ldoe16; + /delete-node/ rpmh-regulator-ldoe17; + /delete-node/ rpmh-regulator-smpc6; + /delete-node/ rpmh-regulator-smpc7; + /delete-node/ rpmh-regulator-smpc8; + /delete-node/ rpmh-regulator-ldoc1; + /delete-node/ rpmh-regulator-ldoc2; + /delete-node/ rpmh-regulator-ldoc3; + /delete-node/ rpmh-regulator-ldoc4; + /delete-node/ rpmh-regulator-ldoc6; + /delete-node/ rpmh-regulator-ldoc7; + /delete-node/ rpmh-regulator-ldoc8; + /delete-node/ rpmh-regulator-ldoc9; + /delete-node/ rpmh-regulator-ldoc10; + /delete-node/ rpmh-regulator-ldoc11; + /delete-node/ rpmh-regulator-bobc1; + + /* refgen-regulator@88e7000 */ + /delete-node/ refgen; +}; + +&usb2_phy0 { + /delete-property/ vdd-supply; + /delete-property/ vdda18-supply; + /delete-property/ vdda33-supply; +}; + +&lmh_dcvs1 { + isens_vref_0p8-supply = <&pm8195_3_l5>; + isens-vref-0p8-settings = <880000 880000 20000>; + isens_vref_1p8-supply = <&pm8195_1_l12>; + isens-vref-1p8-settings = <1800000 1800000 20000>; +}; + +&clock_camcc { + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; +}; + +&gpu_gx_gdsc { + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; +}; + +#include "sa8195p-regulator.dtsi" +#include "pm8195.dtsi" + diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1035d25de40bd1e16aa4be2502bc73e6fd7eecdc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi @@ -0,0 +1,217 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 + +&soc { + /* Primary USB port related controller */ + usb0: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x140 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 489 0>, <0 130 0>, <0 486 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>; + clocks = <&clock_virt GCC_USB30_PRIM_MASTER_CLK>, + <&clock_virt GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&clock_virt GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&clock_virt GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&clock_virt GCC_USB30_PRIM_SLEEP_CLK>, + <&clock_virt GCC_USB3_PRIM_CLKREF_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_virt GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + + status = "disabled"; + + dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xcd00>; + interrupts = <0 133 0>; + usb-phy = <&usb2_phy0>, <&usb_nop_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,ssp-u3-u0-quirk; + snps,usb3-u1u2-disable; + usb-core-id = <0>; + tx-fifo-resize; + maximum-speed = "high-speed"; + dr_mode = "otg"; + }; + + usbbam: qcom,usbbam@a704000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xa704000 0x17000>; + interrupts = <0 132 0>; + + qcom,usb-bam-fifo-baseaddr = <0x146bb000>; + qcom,usb-bam-num-pipes = <4>; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + status = "disabled"; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x6064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + }; + + /* Primary USB port related High Speed PHY */ + usb2_phy0: hsphy@88e2000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e2000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_gcc RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_virt GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + /* Secondary USB port related controller */ + usb1: ssusb@a800000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a800000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x160 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 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_sec_gdsc>; + clocks = <&clock_virt GCC_USB30_SEC_MASTER_CLK>, + <&clock_virt GCC_CFG_NOC_USB3_SEC_AXI_CLK>, + <&clock_virt GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&clock_virt GCC_USB30_SEC_MOCK_UTMI_CLK>, + <&clock_virt GCC_USB30_SEC_SLEEP_CLK>, + <&clock_virt GCC_USB3_SEC_CLKREF_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_virt GCC_USB30_SEC_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,charging-disabled; + + status = "disabled"; + + dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0x0a800000 0xcd00>; + interrupts = <0 138 0>; + usb-phy = <&usb2_phy1>, <&usb_nop_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <1>; + tx-fifo-resize; + maximum-speed = "high-speed"; + dr_mode = "otg"; + }; + }; + + /* Secondary USB port related High Speed PHY */ + usb2_phy1: hsphy@88e3000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e3000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_gcc RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_virt GCC_QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; + + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm.dts b/arch/arm64/boot/dts/qcom/sa8195-vm.dts index 12807e33cf4ee204257b3d77e2e1357f90c8e185..5c7ef0257b31790a8bd0695c0453f3fe0b89a5ca 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm.dts @@ -36,3 +36,11 @@ &usb2_phy0 { status = "ok"; }; + +&spmi_bus { + status = "disabled"; +}; + +&viospmi { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi index 6764393a4210b2ae05a2b83e2769855205cac536..1f0c3ded4e0f98c8b65db8e51678d6a1b5199e91 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi @@ -11,173 +11,39 @@ */ #include "skeleton64.dtsi" -#include +#include #include #include +#include "quin-vm-common.dtsi" / { model = "Qualcomm Technologies, Inc. SA8195 Virtual Machine"; qcom,msm-name = "SA8195P"; qcom,msm-id = <405 0x20000>; - psci { - compatible = "arm,psci-1.0"; - method = "smc"; - }; - - chosen { - bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; - }; - - soc: soc { }; - reserved_memory: reserved-memory { - #address-cells = <2>; - #size-cells = <2>; - ranges; - - /* global autoconfigured region for contiguous allocations */ - linux,cma { - compatible = "shared-dma-pool"; - alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; - reusable; - alignment = <0x0 0x400000>; - size = <0x0 0x2000000>; - linux,cma-default; - }; pmem_shared: pmem_shared_region@a0000000 { reg = <0x0 0xa0000000 0x0 0x20000000>; label = "pmem_shared_mem"; }; }; - - 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/vdevs/1c0f0000.virtio_blk/vdc"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; - }; - }; }; &soc { - #address-cells = <1>; - #size-cells = <1>; - virtual-interrupt-parent = "gic"; - ranges = <0 0 0 0xffffffff>; - compatible = "simple-bus"; - - clock_virt: qcom,virt-gcc { - compatible = "qcom,virt-clk-sm8150-gcc"; + clock_virt: qcom,virtio-gcc { + compatible = "virtio,mmio"; + reg = <0x1c200000 0x1000>; + interrupts = <0 48 0>; #clock-cells = <1>; #reset-cells = <1>; }; - clock_virt_scc: qcom,virt-scc { - compatible = "qcom,virt-clk-sm8150-scc"; + clock_virt_scc: qcom,virtio-scc { + compatible = "virtio,mmio"; + reg = <0x1c300000 0x1000>; + interrupts = <0 49 0>; #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_gcc: qcom,gcc { - compatible = "qcom,dummycc"; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - qcom,ion { - compatible = "qcom,msm-ion"; - #address-cells = <1>; - #size-cells = <0>; - - system_heap: qcom,ion-heap@25 { - reg = <25>; - qcom,ion-heap-type = "SYSTEM"; - }; - }; - - qcom,hab { - compatible = "qcom,hab"; - vmid = <2>; - - mmidgrp100: mmidgrp100 { - grp-start-id = <100>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp200: mmidgrp200 { - grp-start-id = <200>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp300: mmidgrp300 { - grp-start-id = <300>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp400: mmidgrp400 { - grp-start-id = <400>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp500: mmidgrp500 { - grp-start-id = <500>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp600: mmidgrp600 { - grp-start-id = <600>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp700: mmidgrp700 { - grp-start-id = <700>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp800: mmidgrp800 { - grp-start-id = <800>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp900: mmidgrp900 { - grp-start-id = <900>; - role = "fe"; - remote-vmids = <0>; - }; - - mmidgrp1000: mmidgrp1000 { - grp-start-id = <1000>; - role = "fe"; - remote-vmids = <0>; - }; - }; - - sde_kms_hyp: qcom,sde_kms_hyp@ae00000 { - compatible = "qcom,sde-kms-hyp"; - qcom,client-id = "7815"; }; apps_smmu: apps-smmu@0x15000000 { @@ -273,7 +139,55 @@ , , , - ; + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; status = "disabled"; }; @@ -284,44 +198,31 @@ status = "disabled"; }; - pm8150_l2: regulator-pm8150-l2 { + pm8195_3_l5: regulator-pm8195-3-l5 { compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_l2"; - regulator-min-microvolt = <3072000>; - regulator-max-microvolt = <3072000>; - qcom,init-voltage = <3072000>; - status = "okay"; + regulator-name = "pm8195_3_l5"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <920000>; + qcom,init-voltage = <800000>; + status = "ok"; }; - pm8150_l5: regulator-pm8150-l5 { + pm8195_1_l12: regulator-pm8195-1-l12 { compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_l5"; - regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; - qcom,proxy-consumer-enable; - qcom,proxy-consumer-current = <23800>; - qcom,init-voltage = <880000>; - status = "okay"; - }; - - pm8150_l12: regulator-pm8150-l12 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8150_l12"; + regulator-name = "pm8195_1_l12"; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1890000>; qcom,init-voltage = <1800000>; - status = "okay"; + status = "ok"; }; - pm8150l_l3: regulator-pm8150l-l3 { + pm8195_3_l16: regulator-pm8195-3-l16 { compatible = "qcom,stub-regulator"; - regulator-name = "pm8150l_l3"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - qcom,proxy-consumer-enable; - qcom,proxy-consumer-current = <51800>; - qcom,init-voltage = <1200000>; - status = "okay"; + regulator-name = "pm8195_3_l16"; + regulator-min-microvolt = <2921000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2921000>; + status = "ok"; }; usb30_prim_gdsc: usb30_prim_gdsc { @@ -340,5 +241,5 @@ #include "sdmshrike-pinctrl.dtsi" #include "sm8150-slpi-pinctrl.dtsi" #include "sa8155-vm-qupv3.dtsi" -#include "sa8155-vm-usb.dtsi" +#include "sa8195-vm-usb.dtsi" #include "sa8155-vm-audio.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi index 6b4a017ac2fc46da2039855643f5079750a146a1..24262a3a9614e17900ef1307e256cb2c8e82d77a 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi @@ -183,6 +183,8 @@ #include "dsi-panel-ext-bridge-1080p.dtsi" &dsi_ext_bridge_1080p { + qcom,mdss-dsi-ext-bridge = <0>; + qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1E 08 07 24 22 diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d7752bd2ecec8cd292eb9caf7d64ee712baa7cee --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-overlay.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sa8195p-adp-star.dtsi" + +/ { + model = "ADP-STAR"; + compatible = "qcom,sa8195p-adp-star", "qcom,sa8195p", + "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi index 1232f4bc40d2b6d6399d7075bb9b1638adca42e1..260046900f354788b3034493ff85f78ba4fd2ba9 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi @@ -10,8 +10,80 @@ * GNU General Public License for more details. */ -#include "sdmshrike-v2.dtsi" +#include +#include "sa8195p-adp-star-display.dtsi" + +&qupv3_se0_spi { + status = "ok"; + + #address-cells = <1>; + #size-cells = <0>; + + can-controller@0 { + compatible = "qcom,nxp,mpc5746c"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <38 0>; + spi-max-frequency = <5000000>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <1>; + qcom,bits-per-word = <8>; + qcom,support-can-fd; + }; +}; &qupv3_se12_2uart { status = "ok"; }; + +&sdhc_2 { + vdd-supply = <&pm8195_1_l10>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8195_1_l2>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on + &sdc2_cmd_on &sdc2_data_on &storage_cd_default>; + pinctrl-1 = <&sdc2_clk_off + &sdc2_cmd_off &sdc2_data_off &storage_cd_default>; + + cd-gpios = <&pm8195_1_gpios 4 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pil_lpass { + status = "ok"; +}; + +&pil_ssc { + status = "disabled"; +}; + +&pil_spss { + status = "ok"; +}; + +&pil_turing { + status = "ok"; +}; + +&pil_venus { + status = "ok"; +}; + +&pil_npu { + status = "ok"; +}; + +&glink_modem { + status = "disabled"; +}; + +&ssc_sensors { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi index 80b26749a59487b8f6a64d15714532ce247a5e6f..b7696d23f8d770f41bfaf07be4e090042503628f 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi @@ -11,3 +11,840 @@ */ #include + +&soc { + /* Stub regulator */ + /* + * RPMh does not provide support for PM8195 S4 because it is always-on + * at 1.8 V in auto mode. Therefore, use a stub regulator for S4. + */ + S4A: pm8195_s4: regulator-pm8195-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm8195_s4"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* PM8195_1 S1 = VDD_EBI supply */ + rpmh-regulator-ebilvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ebi.lvl"; + S1A_LEVEL: pm8195_1_s1_level: regulator-pm8195-1-s1-level { + regulator-name = "pm8195_1_s1_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + ebi_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "ebi"; + #cooling-cells = <2>; + }; + }; + + /* PM8195_1 S2 = VDDCX_MM supply */ + rpmh-regulator-mmcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mmcx.lvl"; + + VDD_MMCX_LEVEL: + S7A_LEVEL: pm8195_1_s7_level: regulator-pm8195-1-s7-level { + regulator-name = "pm8195_1_s7_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + VDD_MMCX_LEVEL_AO: S7A_LEVEL_AO: + pm8195_1_s7_level_ao: regulator-pm8195-1-s7-level-ao { + regulator-name = "pm8195_1_s7_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + mm_cx_cdev: mm-cx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MMCX_LEVEL_AO>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa3"; + S3A: pm8195_1_s3: regulator-pm8195-1-s3 { + regulator-name = "pm8195_1_s3"; + qcom,set = ; + regulator-min-microvolt = <788000>; + regulator-max-microvolt = <969000>; + qcom,init-voltage = <788000>; + }; + }; + + rpmh-regulator-smpa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa5"; + S5A: pm8195_1_s5: regulator-pm8195-1-s5 { + regulator-name = "pm8195_1_s5"; + qcom,set = ; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <900000>; + }; + }; + + rpmh-regulator-smpa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa6"; + S6A: pm8195_1_s6: regulator-pm8195-1-s6 { + regulator-name = "pm8195_1_s6"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1300000>; + qcom,init-voltage = <800000>; + }; + }; + + rpmh-regulator-smpa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa2"; + S2A: pm8195_1_s2: regulator-pm8195-1-s2 { + regulator-name = "pm8195_1_s2"; + qcom,set = ; + regulator-min-microvolt = <1179000>; + regulator-max-microvolt = <1379000>; + qcom,init-voltage = <1179000>; + }; + }; + + /* pm8195_1 S8 = VDD_MODEM supply */ + rpmh-regulator-msslvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mss.lvl"; + VDD_MSS_LEVEL: + S8A_LEVEL: pm8195_1_s8_level: regulator-pm8195-1-s8-level { + regulator-name = "pm8195_1_s8_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* PM8195_1 S10 = VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + + VDD_MX_LEVEL: + S10A_LEVEL: pm8195_1_s10_level: regulator-pm8195-1-s10-level { + regulator-name = "pm8195_1_s10_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + VDD_MX_LEVEL_AO: S10A_LEVEL_AO: + pm8195_1_s10_level_ao: regulator-pm8195-1-s10-level-ao { + regulator-name = "pm8195_1_s10_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MX_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2A: pm8195_1_l2: regulator-pm8195-1-l2 { + regulator-name = "pm8195_1_l2"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3A: pm8195_1_l3: regulator-pm8195-1-l3 { + regulator-name = "pm8195_1_l3"; + qcom,set = ; + regulator-min-microvolt = <760000>; + regulator-max-microvolt = <816000>; + qcom,init-voltage = <760000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5A: pm8195_1_l5: regulator-pm8195-1-l5 { + regulator-name = "pm8195_1_l5"; + qcom,set = ; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <720000>; + qcom,init-mode = ; + }; + }; + + /* DSI display 1.2 */ + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L9A: pm8195_1_l9: regulator-pm8195-1-l9 { + regulator-name = "pm8195_1_l9"; + qcom,set = ; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1250000>; + qcom,init-voltage = <1150000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10A: pm8195_1_l10: regulator-pm8195-1-l10 { + regulator-name = "pm8195_1_l10"; + qcom,set = ; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <2700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11A: pm8195_1_l11: regulator-pm8195-1-l11 { + regulator-name = "pm8195_1_l11"; + qcom,set = ; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + qcom,init-voltage = <1100000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12A: pm8195_1_l12: regulator-pm8195-1-l12 { + regulator-name = "pm8195_1_l12"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1890000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L13A: pm8195_1_l13: regulator-pm8195-1-l13 { + regulator-name = "pm8195_1_l13"; + qcom,set = ; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2900000>; + qcom,init-voltage = <2500000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L15A: pm8195_1_l15: regulator-pm8195-1-l15 { + regulator-name = "pm8195_1_l15"; + qcom,set = ; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1751000>; + qcom,init-voltage = <1700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L16A: pm8195_1_l16: regulator-pm8195-1-l16 { + regulator-name = "pm8195_1_l16"; + qcom,set = ; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2900000>; + qcom,init-voltage = <2500000>; + qcom,init-mode = ; + }; + }; + + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L17A: pm8195_1_l17: regulator-pm8195-1-l17 { + regulator-name = "pm8195_1_l17"; + qcom,set = ; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <1700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa18 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L18A: pm8195_1_l18: regulator-pm8195-1-l18 { + regulator-name = "pm8195_1_l18"; + qcom,set = ; + regulator-min-microvolt = <831000>; + regulator-max-microvolt = <918000>; + qcom,init-voltage = <831000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-smpc1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc1"; + S1C: pm8195_2_s1: regulator-pm8195-2-s1 { + regulator-name = "pm8195_2_s1"; + qcom,set = ; + regulator-min-microvolt = <570000>; + regulator-max-microvolt = <648000>; + qcom,init-voltage = <570000>; + }; + }; + + rpmh-regulator-smpc2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc2"; + S2C: pm8195_2_s2: regulator-pm8195-2-s2 { + regulator-name = "pm8195_2_s2"; + qcom,set = ; + regulator-min-microvolt = <1060000>; + regulator-max-microvolt = <1170000>; + qcom,init-voltage = <1060000>; + }; + }; + + rpmh-regulator-smpc4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc4"; + S4C: pm8195_2_s4: regulator-pm8195-2-s4 { + regulator-name = "pm8195_2_s4"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1900000>; + qcom,init-voltage = <1620000>; + }; + }; + + rpmh-regulator-smpc5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc5"; + S5C: pm8195_2_s5: regulator-pm8195-2-s5 { + regulator-name = "pm8195_2_s5"; + qcom,set = ; + regulator-min-microvolt = <1713000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1713000>; + }; + }; + + /* PM8195_2 S10 + S9 + S8 + S7 + S6 = VDD_GFX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "gfx.lvl"; + VDD_GFX: + S10C_LEVEL: pm8195_2_s10_level: regulator-pm8195-2-s10-level { + regulator-name = "pm8195_2_s10_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoc2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2C: pm8195_2_l2: regulator-pm8195-2-l2 { + regulator-name = "pm8195_2_l2"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3330000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5C: pm8195_2_l5: regulator-pm8195-2-l5 { + regulator-name = "pm8195_2_l5"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7C: pm8195_2_l7: regulator-pm8195-2-l7 { + regulator-name = "pm8195_2_l7"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10C: pm8195_2_l10: regulator-pm8195-2-l10 { + regulator-name = "pm8195_2_l10"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11C: pm8195_2_l11: regulator-pm8195-2-l11 { + regulator-name = "pm8195_2_l11"; + qcom,set = ; + regulator-min-microvolt = <1144000>; + regulator-max-microvolt = <1236000>; + qcom,init-voltage = <1144000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12C: pm8195_2_l12: regulator-pm8195-2-l12 { + regulator-name = "pm8195_2_l12"; + qcom,set = ; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + qcom,init-voltage = <1700000>; + qcom,init-mode = ; + }; + }; + + + /* PM8195_3 S3 + S2 + S1 = VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pm8195_3_s3_level-parent-supply = <&VDD_MX_LEVEL>; + pm8195_3_s3_level_ao-parent-supply = <&VDD_MX_LEVEL_AO>; + + VDD_CX_LEVEL: + S3E_LEVEL: pm8195_3_s3_level: regulator-pm8195-3-s3-level { + regulator-name = "pm8195_3_s3_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_LEVEL_AO: S3E_LEVEL_AO: + pm8195_3_s3_level_ao: regulator-pm8195-3-s3-level-ao { + regulator-name = "pm8195_3_s3_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpe4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpe4"; + S4E: pm8195_3_s4: regulator-pm8195-3-s4 { + regulator-name = "pm8195_3_s4"; + qcom,set = ; + regulator-min-microvolt = <402000>; + regulator-max-microvolt = <1980000>; + qcom,init-voltage = <402000>; + }; + }; + + rpmh-regulator-smpe5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpe5"; + S5E: pm8195_3_s5: regulator-pm8195-3-s5 { + regulator-name = "pm8195_3_s5"; + qcom,set = ; + regulator-min-microvolt = <1811000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1811000>; + }; + }; + + /* PM8195_3 L4 - LPI_MX supply */ + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lmx.lvl"; + L4E_LEVEL: pm8195_3_l4_level: regulator-pm8195-3-l4 { + regulator-name = "pm8195_3_l4_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-ldoe5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5E: pm8195_3_l5: regulator-pm8195-3-l5 { + regulator-name = "pm8195_3_l5"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <920000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7E: pm8195_3_l7: regulator-pm8195-3-l7 { + regulator-name = "pm8195_3_l7"; + qcom,set = ; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1950000>; + qcom,init-voltage = <1700000>; + qcom,init-mode = ; + }; + }; + + /* pm8195_3 L8 - LPI_CX supply */ + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lcx.lvl"; + L8E_LEVEL: pm8195_3_l8_level: regulator-pm8195-3-l8 { + regulator-name = "pm8195_3_l8_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-ldoe9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L9E: pm8195_3_l9: regulator-pm8195-3-l9 { + regulator-name = "pm8195_3_l9"; + qcom,set = ; + regulator-min-microvolt = <830000>; + regulator-max-microvolt = <920000>; + qcom,init-voltage = <830000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10E: pm8195_3_l10: regulator-pm8195-3-l10 { + regulator-name = "pm8195_3_l10"; + qcom,set = ; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <2500000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12E: pm8195_3_l12: regulator-pm8195-3-l12 { + regulator-name = "pm8195_3_l12"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L16E: pm8195_3_l16: regulator-pm8195-3-l16 { + regulator-name = "pm8195_3_l16"; + qcom,set = ; + regulator-min-microvolt = <2921000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2921000>; + qcom,init-mode = ; + }; + }; + + + rpmh-regulator-ldoe17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoe17"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L17E: pm8195_3_l17: regulator-pm8195-3-l17 { + regulator-name = "pm8195_3_l17"; + qcom,set = ; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2900000>; + qcom,init-mode = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dts b/arch/arm64/boot/dts/qcom/sa8195p.dts index d664faba56249d532f09840bfb5ad11ad4a3fb8a..da96aeda0b5dad8209c7d6a858201387696528d0 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dts +++ b/arch/arm64/boot/dts/qcom/sa8195p.dts @@ -12,7 +12,7 @@ /dts-v1/; -#include "sdmshrike-v2.dtsi" +#include "sa8195p.dtsi" / { model = "Qualcomm Technologies, Inc. SA8195P AU SoC"; diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dtsi b/arch/arm64/boot/dts/qcom/sa8195p.dtsi index 237ab398e218416c2cc536df1911026c72848892..6fae09a904b5234cd4f62a3ebd972526c4d4bee3 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p.dtsi @@ -10,8 +10,14 @@ * GNU General Public License for more details. */ +#include #include "sdmshrike-v2.dtsi" #include "sa8155-audio.dtsi" +#include "sa8195-pmic.dtsi" +#include "sm8150-camera.dtsi" +#include "sm8150-v2-camera.dtsi" +#include "sa8155-camera-sensor.dtsi" +#include "sa8195p-pcie.dtsi" / { model = "Qualcomm Technologies, Inc. SA8195P"; @@ -19,7 +25,6 @@ qcom,msm-id = <405 0x20000>; }; -#include &soc { emac_hw: qcom,emac@00020000 { compatible = "qcom,emac-dwc-eqos"; @@ -105,4 +110,220 @@ qcom,iova-mapping = <0x80000000 0x40000000>; }; }; + + qcom,cam_smmu { + msm_cam_smmu_ife { + iommus = <&apps_smmu 0xAA0 0x4E0>, + <&apps_smmu 0xA20 0x4E0>, + <&apps_smmu 0xA00 0x4E0>, + <&apps_smmu 0xA80 0x4E0>, + <&apps_smmu 0xEA0 0x4E0>, + <&apps_smmu 0xE20 0x4E0>, + <&apps_smmu 0xE00 0x4E0>, + <&apps_smmu 0xE80 0x4E0>; + }; + + msm_cam_smmu_jpeg { + iommus = <&apps_smmu 0x2100 0x20>, + <&apps_smmu 0x2120 0x20>; + }; + + msm_cam_smmu_icp { + iommus = <&apps_smmu 0x2042 0x0>, + <&apps_smmu 0x2080 0x320>, + <&apps_smmu 0x20A0 0x320>, + <&apps_smmu 0x2380 0x320>, + <&apps_smmu 0x23A0 0x320>, + <&apps_smmu 0x20C0 0x300>, + <&apps_smmu 0x23C0 0x300>; + }; + + msm_cam_smmu_fd { + iommus = <&apps_smmu 0x2140 0x20>, + <&apps_smmu 0x2160 0x20>; + }; + + msm_cam_smmu_lrme { + iommus = <&apps_smmu 0x20e0 0x300>, + <&apps_smmu 0x23E0 0x300>; + }; + }; + + cam_csid0 { + clock-rates = + <400000000 0 0 0 400000000 0 0>, + <400000000 0 0 0 558000000 0 0>, + <480000000 0 0 0 637000000 0 0>, + <600000000 0 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + }; + + cam_csid1 { + clock-rates = + <400000000 0 0 0 400000000 0 0>, + <400000000 0 0 0 558000000 0 0>, + <480000000 0 0 0 637000000 0 0>, + <600000000 0 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + }; + + cam_vfe0 { + clock-rates = + <400000000 0 0>, + <558000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + }; + + cam_vfe1 { + clock-rates = + <400000000 0 0>, + <558000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + }; +}; + +&usb1 { + qcom,default-mode-host; + status = "ok"; +}; + +&slpi_tlmm { + status = "ok"; +}; + +&pil_ssc { + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + status = "ok"; +}; + +&ssc_sensors { + status = "disabled"; +}; + +&clock_rpmh { + compatible = "qcom,rpmh-clk-sm8150"; +}; + +&clock_scc { + compatible = "qcom,scc-sa8195"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + vdda-phy-supply = <&pm8195_3_l5>; + vdda-pll-supply = <&pm8195_1_l9>; + vdda-phy-max-microamp = <138000>; + vdda-pll-max-microamp = <65100>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8195_3_l10>; + vcc-voltage-level = <2894000 2904000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8195_1_l11>; + vccq2-supply = <&pm8195_3_l7>; + vcc-max-microamp = <750000>; + vccq-max-microamp = <750000>; + vccq2-max-microamp = <750000>; + + status= "ok"; +}; + +&usb2_phy0 { + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; +}; + +&usb2_phy1 { + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + status = "ok"; +}; + +&mdss_dsi_phy0 { + vdda-0p9-supply = <&pm8195_3_l5>; +}; + +&mdss_dsi_phy1 { + vdda-0p9-supply = <&pm8195_3_l5>; +}; + +&mdss_dsi0 { + vdda-1p2-supply = <&pm8195_1_l9>; +}; + +&mdss_dsi1 { + vdda-1p2-supply = <&pm8195_1_l9>; +}; + +&sde_dp { + vdda-1p2-supply = <&pm8195_1_l9>; + vdda-0p9-supply = <&pm8195_3_l5>; +}; + +&pil_lpass { + vdd_cx-supply = <&VDD_CX_LEVEL>; + status = "ok"; +}; + +&clock_scc { + vdd_scc_cx-supply = <&pm8195_3_l8_level>; + status = "ok"; +}; + +&cam_csiphy0 { + mipi-csi-vdd-supply = <&pm8195_1_l9>; +}; + +&cam_csiphy1 { + mipi-csi-vdd-supply = <&pm8195_1_l9>; +}; + +&cam_csiphy2 { + mipi-csi-vdd-supply = <&pm8195_1_l9>; +}; + +&cam_csiphy3 { + mipi-csi-vdd-supply = <&pm8195_1_l9>; +}; + +&cam_cci0 { + qcom,cam-sensor@0 { + cam_vio-supply = <&pm8195_s4>; + cam_bob-supply = <&pm8195_s4>; + cam_vana-supply = <&pm8195_s4>; + cam_vdig-supply = <&pm8195_s4>; + }; + + qcom,cam-sensor@1 { + cam_vio-supply = <&pm8195_s4>; + cam_bob-supply = <&pm8195_s4>; + cam_vana-supply = <&pm8195_s4>; + cam_vdig-supply = <&pm8195_s4>; + }; + + qcom,cam-sensor@2 { + cam_vio-supply = <&pm8195_s4>; + cam_bob-supply = <&pm8195_s4>; + cam_vana-supply = <&pm8195_s4>; + cam_vdig-supply = <&pm8195_s4>; + }; + + qcom,cam-sensor@3 { + cam_vio-supply = <&pm8195_s4>; + cam_bob-supply = <&pm8195_s4>; + cam_vana-supply = <&pm8195_s4>; + cam_vdig-supply = <&pm8195_s4>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi index adf4f26ef8c1b5f3cc05f8f8e8bb87f00f7496f0..955f23495de8603fdfd5d1bd177b88950276188d 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -127,9 +127,9 @@ mipi-csi-vdd-supply = <&pm6150l_l3>; clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, <&clock_camcc CAM_CC_CSIPHY0_CLK>, - <&clock_camcc CAM_CC_CSIPHY2_CLK>, - <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + <&clock_camcc CAM_CC_CSIPHY3_CLK>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>; clock-names = "cphy_rx_clk_src", "csiphy0_clk", "csiphy3_clk", @@ -409,10 +409,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; status = "ok"; }; @@ -420,7 +420,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -429,8 +429,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xda00000>; - iova-region-len = <0xace00000>; + iova-region-start = <0x10C00000>; + iova-region-len = <0xA9C00000>; iova-region-id = <0x3>; status = "ok"; }; @@ -438,7 +438,7 @@ iova-mem-qdss-region { /* QDSS region is appropriate 1MB */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; @@ -1076,7 +1076,7 @@ qcom,cam-cx-ipeak = <&cx_ipeak_lm 3>; control-camnoc-axi-clk; camnoc-bus-width = <32>; - camnoc-axi-clk-bw-margin-perc = <10>; + camnoc-axi-clk-bw-margin-perc = <20>; qcom,msm-bus,name = "cam_ahb"; qcom,msm-bus,num-cases = <6>; qcom,msm-bus,num-paths = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi index 6daa7fce7347587c7f31177d0e7d6ab3607328f2..f39f94baa14c606ca687e1ca84db9e212b1f4a0d 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi @@ -534,6 +534,9 @@ qcom,dsi-supported-dfps-list = <60 57 55>; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_hfp"; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <534712320 532484352 530256384 525800448 528028416>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 2e 08 0a 12 18 08 diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi index f47d16937319f90936558fff5b4e5a3a6c7e578e..37c22bca3baf872b585b444e55e3433db6f548cc 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -125,16 +125,16 @@ }; }; - pm6150-vbat-lvl0 { + pm6150-bcl-lvl0 { cooling-maps { vbat_cpu6 { - trip = <&vbat_lvl0>; + trip = <&bcl_lvl0>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vbat_cpu7 { - trip = <&vbat_lvl0>; + trip = <&bcl_lvl0>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; @@ -142,16 +142,33 @@ }; }; - pm6150-ibat-lvl0 { + pm6150-bcl-lvl1 { cooling-maps { ibat_cpu6 { - trip = <&ibat_lvl0>; + trip = <&bcl_lvl1>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; ibat_cpu7 { - trip = <&ibat_lvl0>; + trip = <&bcl_lvl1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm6150-bcl-lvl2 { + cooling-maps { + ibat_cpu6 { + trip = <&bcl_lvl2>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + ibat_cpu7 { + trip = <&bcl_lvl2>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi index 367be23a8c81730c43e7f4e6ce43e15f83adc3e0..28103989d07d2521b655fe7e167937c859fae572 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi @@ -19,6 +19,8 @@ reg = <0x0a600000 0x100000>; reg-names = "core_base"; + iommus = <&apps_smmu 0x540 0x0>; + qcom,smmu-s1-bypass; #address-cells = <1>; #size-cells = <1>; ranges; @@ -52,6 +54,7 @@ 0x130 /* GSI_RING_BASE_ADDR_L */ 0x144 /* GSI_RING_BASE_ADDR_H */ 0x1a4>; /* GSI_IF_STS */ + qcom,gsi-disable-io-coherency; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,pm-qos-latency = <62>; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index f23c2edbeb6ba005ddca6061f2a655b9961fdb18..1083bda78f5e6cab17781fad320771b22321e426 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -660,7 +660,7 @@ }; dfps_data_memory: dfps_data_region@9e300000 { - reg = <0x0 0x9e300000 0x0 0x0100000>; + reg = <0x0 0x9d700000 0x0 0x0100000>; label = "dfps_data_region"; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi index 300b3e67ceaea37da54044337dc9c9b37a0cfbfe..0988d0e1a7c02c5152f838dd36a3036825843562 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi @@ -145,3 +145,12 @@ status = "ok"; }; + +&usb2_phy1 { + status = "ok"; +}; + +&usb1 { + qcom,default-mode-host; + status ="ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi index cbf93be0dfafb1580d43bbd025be5fc6db7b0760..cbc0a8078a3107548ab255ac07f9fa777e4cd20c 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi @@ -1819,6 +1819,77 @@ }; }; + ap2mdm { + ap2mdm_active: ap2mdm_active { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio135", "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio135", "gpio139"; + drive-strength = <16>; + bias-disable; + }; + }; + ap2mdm_sleep: ap2mdm_sleep { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio135", "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio135", "gpio139"; + drive-strength = <8>; + bias-disable; + }; + + }; + }; + + mdm2ap { + mdm2ap_active: mdm2ap_active { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio81", "gpio53"; + function = "gpio"; + }; + + config { + pins = "gpio81", "gpio53"; + drive-strength = <8>; + bias-disable; + }; + }; + mdm2ap_sleep: mdm2ap_sleep { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio81", "gpio53"; + function = "gpio"; + }; + + config { + pins = "gpio81", "gpio53"; + drive-strength = <8>; + bias-disable; + }; + }; + }; + cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { @@ -2714,6 +2785,61 @@ }; }; + cnss_pins { + cnss_wlan_en_active: cnss_wlan_en_active { + mux { + pins = "gpio169"; + function = "gpio"; + }; + + config { + pins = "gpio169"; + drive-strength = <16>; + output-high; + bias-pull-up; + }; + }; + cnss_wlan_en_sleep: cnss_wlan_en_sleep { + mux { + pins = "gpio169"; + function = "gpio"; + }; + + config { + pins = "gpio169"; + drive-strength = <2>; + output-low; + bias-pull-down; + }; + }; + }; + + usb2phy_ac_en1_default: usb2phy_ac_en1_default { + mux { + pins = "gpio113"; + function = "usb2phy_ac"; + }; + + config { + pins = "gpio113"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb2phy_ac_en2_default: usb2phy_ac_en2_default { + mux { + pins = "gpio123"; + function = "usb2phy_ac"; + }; + + config { + pins = "gpio123"; + drive-strength = <2>; + bias-disable; + }; + }; + audio_ioexp_reset_active: audio_ioexp_reset_active { mux { pins = "gpio166"; @@ -2727,6 +2853,105 @@ }; }; + 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 */ + }; + }; + + conn_power_1p8_active: conn_power_1p8_active { + mux { + pins = "gpio173"; + function = "gpio"; + }; + + config { + pins = "gpio173"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + conn_power_pa_active: conn_power_pa_active { + mux { + pins = "gpio174"; + function = "gpio"; + }; + + config { + pins = "gpio174"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + bt_en_active: bt_en_active { + mux { + pins = "gpio172"; + function = "gpio"; + }; + + config { + pins = "gpio172"; + drive-strength = <2>; + bias-pull-down; + }; + }; + /* SE0 pin mappings */ qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { qupv3_se0_i2c_active: qupv3_se0_i2c_active { @@ -3979,6 +4204,18 @@ }; }; + trigout_a: trigout_a { + mux { + pins = "gpio141"; + function = "qdss_cti"; + }; + config { + pins = "gpio141"; + drive-strength = <2>; + bias-disable; + }; + }; + /* SE 10 pin mappings */ qupv3_se10_2uart_pins: qupv3_se10_2uart_pins { qupv3_se10_2uart_active: qupv3_se10_2uart_active { diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi index 220cce9f632ad21db2a1c289b2062e00154f3b2f..b26cb64f139f5a9628817f48d7a00029cfcd85fe 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi @@ -605,7 +605,7 @@ pinctrl-1 = <&qupv3_se13_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; - qcom,wrapper-core = <&qupv3_1>; + qcom,wrapper-core = <&qupv3_2>; status = "disabled"; }; @@ -769,11 +769,11 @@ status = "disabled"; }; - qupv3_se15_spi: spi@c90000 { + qupv3_se15_spi: spi@c94000 { compatible = "qcom,spi-geni"; #address-cells = <1>; #size-cells = <0>; - reg = <0xc90000 0x4000>; + reg = <0xc94000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; clocks = <&clock_gcc GCC_QUPV3_WRAP2_S5_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi index 6b350e54feb2733463747367fdc7e50b57814af6..943f295bb30199c8db3a036bc93c7d8313e1a4f1 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -65,4 +65,28 @@ }; }; + mdss_dp_pll: qcom,mdss_dp_pll@88ea000 { + compatible = "qcom,mdss_dp_pll_7nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x88ea000 0x200>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 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/sdmshrike-sde.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi index 57e4c7fe66f7ceeb3669753e743987a4136262a8..c6717c6de5d5e900b4806f8a055513f78c9daa83 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi @@ -14,9 +14,9 @@ &soc { mdss_mdp: qcom,mdss_mdp@ae00000 { compatible = "qcom,sde-kms"; - reg = <0x0ae00000 0x84208>, - <0x0aeb0000 0x2008>, - <0x0aeac000 0x214>; + reg = <0xae00000 0x84208>, + <0xaeb0000 0x2008>, + <0xaeac000 0x214>; reg-names = "mdp_phys", "vbif_phys", "regdma_phys"; @@ -394,8 +394,8 @@ mdss_rotator: qcom,mdss_rotator@ae00000 { compatible = "qcom,sde_rotator"; - reg = <0x0ae00000 0xac000>, - <0x0aeb8000 0x3000>; + reg = <0xae00000 0xac000>, + <0xaeb8000 0x3000>; reg-names = "mdp_phys", "rot_vbif_phys"; @@ -605,4 +605,113 @@ }; }; }; + + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0xaee1000 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>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_pipe_clk", + "link_clk", "link_iface_clk", + "crypto_clk", "pixel_clk_rcg", "pixel_parent", + "pixel1_clk_rcg", "pixel1_parent", + "strm0_pixel_clk", "strm1_pixel_clk"; + + 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,dsc-feature-enable; + qcom,fec-feature-enable; + qcom,max-dp-dsc-blks = <2>; + qcom,max-dp-dsc-input-width-pixs = <2048>; + + 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/sdmshrike-usb.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi index 9b5e2e1be88b08da95ad8289f716db51a96408a8..9362ddd57f99fae0d387debc6a99f78db25629f7 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -136,4 +136,107 @@ usb_nop_phy: usb_nop_phy { compatible = "usb-nop-xceiv"; }; + + /* Secondary USB port related controller */ + usb1: ssusb@a800000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a800000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x160 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 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_sec_gdsc>; + clocks = <&clock_gcc GCC_USB30_SEC_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, + <&clock_gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&clock_gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_SEC_SLEEP_CLK>, + <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_gcc GCC_USB30_SEC_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,charging-disabled; + + qcom,msm-bus,name = "usb1"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + ; + + status = "disabled"; + + dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0x0a800000 0xcd00>; + interrupts = <0 138 0>; + usb-phy = <&usb2_phy1>, <&usb_nop_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <1>; + tx-fifo-resize; + maximum-speed = "high-speed"; + dr_mode = "otg"; + }; + }; + + /* Secondary USB port related High Speed PHY */ + usb2_phy1: hsphy@88e3000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e3000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8150_2_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_2_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; + + status = "disabled"; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi index b32e6449c89243a7eaf5f2b76ab09ac249d371e7..ee52993f54815d098b1723585ba6d8ae2587ae8d 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi @@ -17,15 +17,377 @@ qcom,msm-id = <340 0x20000>; }; +&soc { + gpu_opp_table_v2: gpu_opp_table_v2 { + compatible = "operating-points-v2"; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = ; + }; + + opp-675000000 { + opp-hz = /bits/ 64 <675000000>; + opp-microvolt = ; + }; + opp-585000000 { + opp-hz = /bits/ 64 <585000000>; + opp-microvolt = ; + }; + + opp-499200000 { + opp-hz = /bits/ 64 <499200000>; + opp-microvolt = ; + }; + + opp-427000000 { + opp-hz = /bits/ 64 <427000000>; + opp-microvolt = ; + }; + + opp-345000000 { + opp-hz = /bits/ 64 <345000000>; + opp-microvolt = ; + }; + + opp-257000000 { + opp-hz = /bits/ 64 <257000000>; + opp-microvolt = ; + }; + }; +}; /* GPU overrides */ &msm_gpu { /* Updated chip ID */ qcom,chipid = <0x6080001>; + /* Power level to start throttling */ + qcom,throttle-pwrlevel = <3>; + + /* Updated Bus Scale Settings */ + qcom,msm-bus,num-cases = <12>; + + /* + * Value for vote is: (DDR freq) * 4 - 5 + * The 5 value is to ensure that there is no rounding errors + * where the total request doesn't divide evenly by the BCM + * DDR bandwidth unit (note, 5 is greater than this unit). + */ + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, // 0 bus=0 + <26 512 0 795000>, // 1 bus=200 + <26 512 0 1195000>, // 2 bus=300 + <26 512 0 1799000>, // 3 bus=451 + <26 512 0 2183000>, // 4 bus=547 + <26 512 0 2719000>, // 5 bus=681 + <26 512 0 3067000>, // 6 bus=768 + <26 512 0 4063000>, // 7 bus=1017 + <26 512 0 5407000>, // 8 bus=1353 + <26 512 0 6215000>, // 9 bus=1555 + <26 512 0 7211000>, // 10 bus=1804 + <26 512 0 8363000>; // 11 bus=2092 + + qcom,initial-pwrlevel = <4>; + + operating-points-v2 = <&gpu_opp_table_v2>; + + qcom,gpu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <675000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <585000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <6>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <427000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <345000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <8>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <257000000>; + qcom,bus-freq = <2>; + qcom,bus-min = <1>; + qcom,bus-max = <8>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + 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>; + }; + }; }; +&gmu { + reg = <0x2c6a000 0x30000>, + <0xb290000 0x10000>, + <0xb490000 0x10000>; + reg-names = "kgsl_gmu_reg", + "kgsl_gmu_pdc_cfg", + "kgsl_gmu_pdc_seq"; + + qcom,gpu-acd-table { + /* Corresponds to levels in the GPU perf table */ + qcom,acd-enable-by-level = <0x7e>; + qcom,acd-stride = <0x2>; + qcom,acd-num-levels = <0x6>; + + /* ACDCR, ACDTD */ + qcom,acd-data = <0xa02d5ffd 0x00007611 /* LowSVS */ + 0xa02d5ffd 0x00006911 /* SVS */ + 0xa02d5ffd 0x00006111 /* SVS_L1 */ + 0xa02d5ffd 0x00006011 /* SVS_L2 */ + 0x802d5ffd 0x00005411 /* NOM */ + 0x802d5ffd 0x00005411>; /* NOM_L1 */ + }; +}; &mdss_mdp { qcom,fullsize-va-map; qcom,sde-min-core-ib-kbps = <0>; qcom,sde-min-llcc-ib-kbps = <0>; }; + +&clock_npucc { + compatible = "qcom,npucc-sm8150-v2", "syscon"; +}; + +&clock_dispcc { + compatible = "qcom,dispcc-sdmshrike-v2", "syscon"; +}; + +&mdss_dsi0_pll { + compatible = "qcom,mdss_dsi_pll_7nm_v2"; +}; + +&mdss_dsi1_pll { + compatible = "qcom,mdss_dsi_pll_7nm_v2"; +}; + +&msm_fastrpc { + qcom,msm_fastrpc_compute_cb1 { + iommus = <&apps_smmu 0x1001 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb2 { + iommus = <&apps_smmu 0x1002 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb3 { + iommus = <&apps_smmu 0x1003 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb4 { + iommus = <&apps_smmu 0x1004 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb5 { + iommus = <&apps_smmu 0x1005 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb6 { + iommus = <&apps_smmu 0x1006 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb7 { + iommus = <&apps_smmu 0x1007 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb8 { + iommus = <&apps_smmu 0x1008 0x0460>; + }; + + qcom,msm_fastrpc_compute_cb9 { + iommus = <&apps_smmu 0x1009 0x0460>; + }; +}; + +&soc { + /delete-node/ llcc-bw-opp-table; + /delete-node/ ddr-bw-opp-table; + /delete-node/ suspendable-ddr-bw-opp-table; + + 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 */ + BW_OPP_ENTRY(1000, 16); /* 15258 MB/s */ + }; + + 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 */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; + + 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 */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; +}; + +&gpubw { + /delete-property/ qcom,bw-tbl; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; +}; + +&cpu4_computemon { + qcom,core-dev-table = + < 1920000 MHZ_TO_MBPS( 200, 4) >, + < 2793600 MHZ_TO_MBPS(1017, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; +}; + +&cpu0_llcc_ddr_latmon { + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 768000 MHZ_TO_MBPS( 451, 4) >, + < 1113600 MHZ_TO_MBPS( 547, 4) >, + < 1478400 MHZ_TO_MBPS( 768, 4) >, + < 1632000 MHZ_TO_MBPS(1017, 4) >; +}; + +&cpu4_llcc_ddr_latmon { + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 710400 MHZ_TO_MBPS( 451, 4) >, + < 825600 MHZ_TO_MBPS( 547, 4) >, + < 1056000 MHZ_TO_MBPS( 768, 4) >, + < 1286400 MHZ_TO_MBPS(1017, 4) >, + < 1612800 MHZ_TO_MBPS(1353, 4) >, + < 1804800 MHZ_TO_MBPS(1555, 4) >, + < 2649600 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; +}; + +&cpu0_cpu_l3_latmon { + qcom,core-dev-table = + < 300000 300000000 >, + < 499200 403200000 >, + < 576000 499200000 >, + < 672000 614400000 >, + < 768000 710400000 >, + < 940800 806400000 >, + < 1036800 902400000 >, + < 1113600 998400000 >, + < 1209600 1075280000 >, + < 1305600 1171200000 >, + < 1382400 1267200000 >, + < 1478400 1344000000 >, + < 1632000 1536000000 >, + < 1785600 1612800000 >; +}; + +&cpu4_cpu_l3_latmon { + qcom,core-dev-table = + < 300000 300000000 >, + < 825600 614400000 >, + < 1171200 806400000 >, + < 1401600 998400000 >, + < 1708800 1267200000 >, + < 2016000 1344000000 >, + < 2419200 1536000000 >, + < 2841600 1612800000 >; +}; + +&cpu0_cpu_llcc_latmon { + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 150, 16) >, + < 768000 MHZ_TO_MBPS( 300, 16) >, + < 1478400 MHZ_TO_MBPS( 466, 16) >, + < 1632000 MHZ_TO_MBPS( 600, 16) >; +}; + +&cpu4_cpu_llcc_latmon { + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 150, 16) >, + < 710400 MHZ_TO_MBPS( 300, 16) >, + < 1056000 MHZ_TO_MBPS( 466, 16) >, + < 1286400 MHZ_TO_MBPS( 600, 16) >, + < 1804800 MHZ_TO_MBPS( 806, 16) >, + < 2649600 MHZ_TO_MBPS( 933, 16) >, + < 3000000 MHZ_TO_MBPS(1000, 16) >; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 1ecb7cda8b37ffb7a60641c5bedf1c7bb9716730..6444e2578bed9b432127a99e444840c2ddb9a894 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -21,9 +21,12 @@ #include #include #include +#include #include #include +#include #include +#include #define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) #define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} @@ -53,8 +56,10 @@ compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; next-level-cache = <&L2_0>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; L2_0: l2-cache { @@ -86,8 +91,10 @@ compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; next-level-cache = <&L2_1>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; L2_1: l2-cache { @@ -113,8 +120,10 @@ compatible = "arm,armv8"; reg = <0x0 0x200>; enable-method = "psci"; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; next-level-cache = <&L2_2>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; L2_2: l2-cache { @@ -140,8 +149,10 @@ compatible = "arm,armv8"; reg = <0x0 0x300>; enable-method = "psci"; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; next-level-cache = <&L2_3>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; L2_3: l2-cache { @@ -167,8 +178,10 @@ compatible = "arm,armv8"; reg = <0x0 0x400>; enable-method = "psci"; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; next-level-cache = <&L2_4>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; L2_4: l2-cache { @@ -194,8 +207,10 @@ compatible = "arm,armv8"; reg = <0x0 0x500>; enable-method = "psci"; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; next-level-cache = <&L2_5>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; L2_5: l2-cache { @@ -221,8 +236,10 @@ compatible = "arm,armv8"; reg = <0x0 0x600>; enable-method = "psci"; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; next-level-cache = <&L2_6>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; L2_6: l2-cache { @@ -248,8 +265,10 @@ compatible = "arm,armv8"; reg = <0x0 0x700>; enable-method = "psci"; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; next-level-cache = <&L2_7>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; L2_7: l2-cache { @@ -314,6 +333,124 @@ }; }; + energy_costs: energy-costs { + compatible = "sched-energy"; + + CPU_COST_0: core-cost0 { + busy-cost-data = < + 300000 24 + 403200 25 + 499200 27 + 576000 29 + 672000 33 + 768000 37 + 844800 42 + 940800 47 + 1036800 54 + 1113600 59 + 1209600 66 + 1305600 73 + 1382400 79 + 1478400 88 + 1555200 96 + 1632000 105 + 1708800 115 + 1785600 128 + >; + idle-cost-data = < + 18 14 12 + >; + }; + + CPU_COST_1: core-cost1 { + busy-cost-data = < + 825600 227 + 940800 262 + 1056000 302 + 1171200 348 + 1286400 398 + 1401600 451 + 1497600 498 + 1612800 556 + 1708800 606 + 1804800 655 + 1920000 716 + 2016000 766 + 2131200 826 + 2227200 878 + 2323200 933 + 2419200 992 + 2534400 1075 + 2649600 1179 + 2745600 1288 + 2841600 1427 + 2956800 1670 + >; + idle-cost-data = < + 110 90 70 + >; + }; + + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 300000 3 + 403200 4 + 499200 4 + 576000 4 + 672000 5 + 768000 5 + 844800 6 + 940800 7 + 1036800 8 + 1113600 9 + 1209600 10 + 1305600 11 + 1382400 12 + 1478400 13 + 1555200 14 + 1632000 15 + 1708800 16 + 1785600 17 + >; + idle-cost-data = < + 3 2 1 + >; + }; + + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 825600 30 + 940800 33 + 1056000 36 + 1171200 39 + 1286400 42 + 1401600 46 + 1497600 49 + 1612800 55 + 1708800 67 + 1804800 77 + 1920000 87 + 2016000 100 + 2131200 110 + 2227200 120 + 2323200 128 + 2419200 135 + 2534400 140 + 2649600 147 + 2745600 160 + 2841600 180 + 2956800 197 + >; + idle-cost-data = < + 3 2 1 + >; + }; + }; /* energy-costs */ + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; + }; + cpuss_dump { compatible = "qcom,cpuss-dump"; @@ -401,6 +538,10 @@ firmware: firmware { android { compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; fstab { compatible = "android,fstab"; vendor { @@ -408,7 +549,7 @@ dev = "/dev/block/platform/soc/8804000.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,slotselect"; + fsmgr_flags = "wait,slotselect,avb"; status = "ok"; }; }; @@ -599,6 +740,13 @@ }; }; + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; + soc: soc { }; }; @@ -1151,7 +1299,7 @@ 0x4400 2>; }; - apr_tal_rpmsg { + qcom,apr_tal_rpmsg { qcom,glink-channels = "apr_audio_svc"; qcom,intents = <0x200 20>; }; @@ -1369,7 +1517,7 @@ }; clock_gcc: qcom,gcc@100000 { - compatible = "qcom,gcc-sdmshrike"; + compatible = "qcom,gcc-sdmshrike", "syscon"; reg = <0x100000 0x1f0000>; reg-names = "cc_base"; vdd_cx-supply = <&VDD_CX_LEVEL>; @@ -1412,7 +1560,7 @@ }; clock_camcc: qcom,camcc@ad00000 { - compatible = "qcom,camcc-sdmshrike"; + compatible = "qcom,camcc-sdmshrike", "syscon"; reg = <0xad00000 0x20000>; reg-names = "cc_base"; vdd_mx-supply = <&pm8150c_s3_level>; @@ -1434,7 +1582,7 @@ }; clock_gpucc: qcom,gpucc@2c90000 { - compatible = "qcom,gpucc-sdmshrike"; + compatible = "qcom,gpucc-sdmshrike", "syscon"; reg = <0x2c90000 0x9000>; reg-names = "cc_base"; vdd_cx-supply = <&VDD_CX_LEVEL>; @@ -1450,6 +1598,11 @@ status = "disabled"; }; + cpucc_debug: syscon@182a0018 { + compatible = "syscon"; + reg = <0x182a0018 0x4>; + }; + tsens0: tsens@c222000 { compatible = "qcom,tsens24xx"; reg = <0xc222000 0x4>, @@ -1486,7 +1639,7 @@ qcom,client-id = <0x00000001>; }; - qcom,lpass@17300000 { + pil_lpass: qcom,lpass@17300000 { compatible = "qcom,pil-tz-generic"; reg = <0x17300000 0x00100>; @@ -1570,7 +1723,7 @@ mbox-names = "slpi-pil"; }; - qcom,spss@1880000 { + pil_spss: qcom,spss@1880000 { compatible = "qcom,pil-tz-generic"; reg = <0x188101c 0x4>, <0x1881024 0x4>, @@ -1603,7 +1756,7 @@ mbox-names = "spss-pil"; }; - qcom,npu@0x9800000 { + pil_npu: qcom,npu@0x9800000 { compatible = "qcom,pil-tz-generic"; reg = <0x9800000 0x800000>; @@ -1614,7 +1767,7 @@ memory-region = <&pil_npu_mem>; }; - qcom,turing@8300000 { + pil_turing: qcom,turing@8300000 { compatible = "qcom,pil-tz-generic"; reg = <0x8300000 0x100000>; @@ -1663,7 +1816,7 @@ mbox-names = "cdsp-pil"; }; - qcom,venus@aae0000 { + pil_venus: qcom,venus@aae0000 { compatible = "qcom,pil-tz-generic"; reg = <0xaae0000 0x4000>; @@ -1692,6 +1845,12 @@ memory-region = <&pil_video_mem>; }; + ssc_sensors: qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + qcom,firmware-name = "slpi"; + status = "disabled"; + }; + wdog: qcom,wdt@17c10000 { compatible = "qcom,msm-watchdog"; reg = <0x17c10000 0x1000>; @@ -1906,6 +2065,184 @@ status = "disabled"; }; + 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>; + }; + + msm_fastrpc: qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,fastrpc-adsp-audio-pdr; + qcom,rpc-latency-us = <235>; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1401 0x2040>, + <&apps_smmu 0x1421 0x0>, + <&apps_smmu 0x2001 0x420>, + <&apps_smmu 0x2041 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x4 0x3440>, + <&apps_smmu 0x24 0x3400>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x5 0x3440>, + <&apps_smmu 0x25 0x3400>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x6 0x3460>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x7 0x3460>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x8 0x3460>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x2 0x3440>, + <&apps_smmu 0x22 0x3400>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x3 0x3440>, + <&apps_smmu 0x1423 0x0>, + <&apps_smmu 0x2023 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x9 0x3460>; + 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 = "sdsprpc-smd"; + iommus = <&apps_smmu 0x5a1 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb14 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x5a2 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb15 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x5a3 0x0>; + shared-cb = <4>; + dma-coherent; + }; + }; + + system_pm { + compatible = "qcom,system-pm"; + mboxes = <&apps_rsc 0>; + }; + + qcom_seecom: qseecom@87900000 { + compatible = "qcom,qseecom"; + reg = <0x87900000 0x2200000>; + 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@87900000 { + compatible = "qcom,smcinvoke"; + reg = <0x87900000 0x2200000>; + 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"; + }; + + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + mem_dump { compatible = "qcom,mem-dump"; memory-region = <&dump_mem>; @@ -1961,6 +2298,11 @@ }; }; + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; }; &emac_gdsc { diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi index cff05a19192ffc5abed82d7a1101bf3b0526e893..ff0802a715b875a05a18f1ee5e90eef8d9b60a30 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi @@ -53,14 +53,21 @@ qcom,rx-proxy = <&atd_proxy_host>, <&atd_proxy_uc>; + qcom,rx-proxy-mode = "counter"; - qcom,rx-gsi-mod-count = <20>; - qcom,rx-gsi-mod-timer = <1>; + qcom,rx-ring-size = <4096>; + qcom,rx-buff-size = <2048>; + qcom,rx-int-mod-usecs = <64>; - qcom,tx-gsi-mod-count = <20>; - qcom,tx-gsi-mod-timer = <1>; + qcom,rx-gsi-mod-pc = <10>; + qcom,rx-gsi-mod-timer = <32>; - qcom,rx-mod-usecs = <30>; + qcom,tx-ring-size = <4096>; + qcom,tx-buff-size = <2048>; + qcom,tx-wrb-mod-pc = <25>; + + qcom,tx-gsi-mod-pc = <10>; + qcom,tx-gsi-mod-timer = <32>; qcom,use-pci-direct; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-cdp-cpe.dts b/arch/arm64/boot/dts/qcom/sdxprairie-cdp-cpe.dts new file mode 100644 index 0000000000000000000000000000000000000000..3db0c885055227f958e46f4ae695b06b82331b3f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-cdp-cpe.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sdxprairie-cdp-cpe.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDXPRAIRIE CDP (CPE)"; + compatible = "qcom,sdxprairie-cdp", + "qcom,sdxprairie", "qcom,cdp"; + qcom,board-id = <0x5010001 0x0>; +}; + + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-cdp-cpe.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-cdp-cpe.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2a33ad5625304599bbdda297635f7c433b591f13 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-cdp-cpe.dtsi @@ -0,0 +1,22 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sdxprairie.dtsi" +#include "sdxprairie-cdp.dtsi" + +&qnand_1 { + status = "ok"; +}; + +&wsa881x_0214 { + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi index 9db702bb4d680e1651b947c9b682a16e4f5b51cc..049fad807e9cc768825de3763f09708e7106231c 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi @@ -1158,6 +1158,22 @@ }; + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb999>; + 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"; + }; + cti0_swao:cti@6b04000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-mtp-cpe.dts b/arch/arm64/boot/dts/qcom/sdxprairie-mtp-cpe.dts new file mode 100644 index 0000000000000000000000000000000000000000..94f1729753ebb3b0af7881998de9daf09053c188 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-mtp-cpe.dts @@ -0,0 +1,55 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sdxprairie-mtp-cpe.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDXPRAIRIE MTP (CPE)"; + compatible = "qcom,sdxprairie-mtp", + "qcom,sdxprairie", "qcom,mtp"; + qcom,board-id = <0x7010008 0x0>; +}; + +/* delete pm8150b nodes */ +&soc { + /delete-node/ thermal-zones; +}; + +&usb { + extcon = <&vbus_detect>; +}; + +&spmi_bus { + /delete-node/ qpnp,fg; + /delete-node/ bcl@1d00; + /delete-node/ qcom,usb-pdphy@1700; + /delete-node/ qcom,qpnp-smb5; + /delete-node/ adc_tm@3500; + /delete-node/ vadc@3100; + /delete-node/ qcom,pm8150b@2; + /delete-node/ qcom,pm8150b@3; +}; + +&qnand_1 { + status = "ok"; +}; + +&blsp1_uart2b_hs { + status = "okay"; +}; + +&vbus_detect { + status = "okay"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-mtp-cpe.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-mtp-cpe.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..007fd6c7faeeaf841f08e3ba0269af6bf068d2b5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-mtp-cpe.dtsi @@ -0,0 +1,18 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "sdxprairie.dtsi" +#include "sdxprairie-mtp.dtsi" + +&qnand_1 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pcie-ep-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pcie-ep-mtp.dtsi index f0dfb1eb9a01be40da9bca589d49056a6ee1b841..8fbf342620c16fa7be1a438665780ebd4e9d1c19 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pcie-ep-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pcie-ep-mtp.dtsi @@ -40,3 +40,7 @@ &mhi_device { status = "ok"; }; + +&mhi_net_device { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi index 841e1675dc7a0b3bf4667e2b49206063d58a040b..2ba4e8fefb26ee91d78a383ae6ddb8c8388baa08 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi @@ -1473,5 +1473,32 @@ }; }; + a2b_cdc_sel { + a2b_cdc_sel_default: a2b_cdc_sel_default { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <8>; + bias-disable; + output-high; + }; + }; + }; + + pinctrl_pps: ppsgrp { + mux { + pins = "gpio32"; + function = "nav_gpio"; + }; + + config { + pins = "gpio32"; + bias-pull-down; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pmic-overlay.dtsi index a523e7ab6b470c5a4cab85b22021138bd5747998..fc9bb5b6f7f31900c84f977759770ae7924036a6 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pmic-overlay.dtsi @@ -38,3 +38,14 @@ &usb { extcon = <&pm8150b_pdphy>; }; + +&pmxprairie_gpios { + vreg_rgmii_off { + vreg_rgmii_off_default: vreg_rgmii_off_default { + pins = "gpio9"; + bias-pull-down; + output-disable; + input-enable; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi index c863b32432280f0485774f6b65727d31c5463562..99a5d9774dbd1e5ceceea1ca87f0413aa3503d87 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi @@ -502,10 +502,19 @@ vreg_rgmii_io_pads: rgmii_io_pads_regulator { compatible = "regulator-fixed"; regulator-name = "rgmii_io_pads"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; regulator-enable-ramp-delay = <100>; gpio = <&tlmm 102 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + /* PWR_CTR1_VDD_PA supply */ + vreg_conn_pa: vreg_conn_pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pmxprairie_gpios 2 GPIO_ACTIVE_HIGH>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-usb.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-usb.dtsi index 5ba14bdda6b0df8b107d1f145c4a8ccb341ede66..a250c6c4fb7414da5010431ffba92a8cc940b79c 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-usb.dtsi @@ -77,6 +77,7 @@ , ; + qcom,default-bus-vote = <2>; /* use svs bus voting */ dwc3@a600000 { compatible = "snps,dwc3"; reg = <0x0a600000 0xcd00>; @@ -145,6 +146,7 @@ resets = <&clock_gcc GCC_QUSB2PHY_BCR>; reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; qcom,no-rext-present; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi index aeacf74c093abbbe94354140ef4fda245a558ce1..a58b88f7b13df744c71b7889cee74cd0c79758eb 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi @@ -25,3 +25,7 @@ &blsp1_uart2b_hs { status = "okay"; }; + +&clock_gcc { + compatible = "qcom,gcc-sdxprairie-v2", "syscon"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index d4f5d2ddb18153050e2212251df3c8671eb5b264..fdb7bca4eee6cbd0a950058404d660d1c5fb56df 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -40,6 +40,13 @@ #size-cells = <1>; ranges; + mpss_adsp_mem: mpss_adsp_region@90c00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x90c00000 0xd400000>; + label = "mpss_adsp_mem"; + }; + tz_apps_mem: tz_apps_region@0x90000000 { no-map; reg = <0x90000000 0xc00000>; @@ -88,13 +95,6 @@ label = "mpss_debug_mem"; }; - mpss_adsp_mem: mpss_adsp_region@82300000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0x82300000 0xcc00000>; - label = "mpss_adsp_mem"; - }; - qseecom_mem: qseecom_region@0 { compatible = "shared-dma-pool"; reusable; @@ -111,7 +111,7 @@ audio_mem: audio_region@0 { compatible = "shared-dma-pool"; - reusable; + no-map; size = <0x400000>; }; @@ -555,6 +555,7 @@ qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; qcom,ipa-wdi3-over-gsi; + qcom,ipa-endp-delay-wa; qcom,msm-bus,num-cases = <5>; qcom,msm-bus,num-paths = <5>; qcom,msm-bus,vectors-KBps = @@ -690,6 +691,11 @@ }; }; + qcom,mhi_dev_qrtr { + compatible = "qcom,qrtr-mhi-dev"; + qcom,net-id = <3>; + }; + qcom,glinkpkt { compatible = "qcom,glinkpkt"; @@ -1224,7 +1230,7 @@ qcom,pcie-vendor-id = /bits/ 16 <0x17cb>; qcom,pcie-device-id = /bits/ 16 <0x0306>; - qcom,pcie-link-speed = <2>; + qcom,pcie-link-speed = <3>; qcom,pcie-phy-ver = <6>; qcom,pcie-active-config; qcom,pcie-aggregated-irq; @@ -1236,12 +1242,12 @@ 0x1044 0x018 0x0 0x1 0x104c 0x007 0x0 0x1 0x1058 0x00f 0x0 0x1 - 0x1074 0x006 0x0 0x1 - 0x1078 0x028 0x0 0x1 - 0x107c 0x016 0x0 0x1 - 0x1080 0x00d 0x0 0x1 - 0x1084 0x036 0x0 0x1 - 0x1088 0x000 0x0 0x1 + 0x1074 0x009 0x0 0x1 + 0x1078 0x00a 0x0 0x1 + 0x107c 0x018 0x0 0x1 + 0x1080 0x019 0x0 0x1 + 0x1084 0x006 0x0 0x1 + 0x1088 0x003 0x0 0x1 0x1094 0x000 0x0 0x1 0x10a4 0x046 0x0 0x1 0x10a8 0x004 0x0 0x1 @@ -1253,7 +1259,7 @@ 0x10c4 0x028 0x0 0x1 0x10d4 0x008 0x0 0x1 0x10f4 0x0fb 0x0 0x1 - 0x10f8 0x003 0x0 0x1 + 0x10f8 0x001 0x0 0x1 0x110c 0x002 0x0 0x1 0x1158 0x012 0x0 0x1 0x115c 0x000 0x0 0x1 @@ -1266,20 +1272,65 @@ 0x11b4 0x04b 0x0 0x1 0x11b8 0x01f 0x0 0x1 0x11bc 0x022 0x0 0x1 + 0x11a4 0x015 0x0 0x1 + 0x11a8 0x00f 0x0 0x1 + 0x008c 0x006 0x0 0x1 + 0x00e0 0x001 0x0 0x1 + 0x00c4 0x001 0x0 0x1 0x0258 0x016 0x0 0x1 0x0378 0x083 0x0 0x1 0x0360 0x0e2 0x0 0x1 0x0364 0x004 0x0 0x1 0x0368 0x030 0x0 0x1 0x0370 0x0ff 0x0 0x1 + 0x03cc 0x042 0x0 0x1 + 0x03d0 0x00d 0x0 0x1 + 0x03d4 0x077 0x0 0x1 + 0x03d8 0x02d 0x0 0x1 + 0x03dc 0x039 0x0 0x1 + 0x03e0 0x09f 0x0 0x1 + 0x03e4 0x00f 0x0 0x1 + 0x03e8 0x063 0x0 0x1 + 0x03ec 0x0bf 0x0 0x1 + 0x03f0 0x079 0x0 0x1 + 0x03f4 0x04f 0x0 0x1 + 0x03f8 0x00f 0x0 0x1 + 0x03fc 0x0d5 0x0 0x1 + 0x02ac 0x075 0x0 0x1 + 0x0310 0x055 0x0 0x1 + 0x0334 0x00c 0x0 0x1 + 0x0338 0x000 0x0 0x1 + 0x0350 0x00f 0x0 0x1 + 0x088c 0x006 0x0 0x1 + 0x08e0 0x001 0x0 0x1 + 0x08c4 0x001 0x0 0x1 0x0a58 0x016 0x0 0x1 0x0b78 0x083 0x0 0x1 0x0b60 0x0e2 0x0 0x1 0x0b64 0x004 0x0 0x1 0x0b68 0x030 0x0 0x1 0x0b70 0x0ff 0x0 0x1 + 0x0bcc 0x042 0x0 0x1 + 0x0bd0 0x00d 0x0 0x1 + 0x0bd4 0x077 0x0 0x1 + 0x0bd8 0x02d 0x0 0x1 + 0x0bdc 0x039 0x0 0x1 + 0x0be0 0x09f 0x0 0x1 + 0x0be4 0x00f 0x0 0x1 + 0x0be8 0x063 0x0 0x1 + 0x0bec 0x0bf 0x0 0x1 + 0x0bf0 0x079 0x0 0x1 + 0x0bf4 0x04f 0x0 0x1 + 0x0bf8 0x00f 0x0 0x1 + 0x0bfc 0x0d5 0x0 0x1 + 0x0aac 0x07f 0x0 0x1 + 0x0b10 0x055 0x0 0x1 + 0x0b34 0x00c 0x0 0x1 + 0x0b38 0x000 0x0 0x1 + 0x0b50 0x00f 0x0 0x1 0x13e4 0x003 0x0 0x1 0x1708 0x003 0x0 0x1 + 0x16a0 0x016 0x0 0x1 0x13e0 0x016 0x0 0x1 0x13d8 0x001 0x0 0x1 0x16fc 0x001 0x0 0x1 @@ -1310,6 +1361,12 @@ status = "disabled"; }; + mhi_net_device: qcom,mhi_net_dev { + compatible = "qcom,msm-mhi-dev-net"; + qcom,mhi-ethernet-interface; + status = "disabled"; + }; + sdhc_1: sdhci@8804000 { compatible = "qcom,sdhci-msm-v5"; reg = <0x8804000 0x1000>; @@ -1348,6 +1405,10 @@ qcom,restore-after-cx-collapse; + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642c 0xa800 0x10 + 0x2c010800 0x80040868>; + status = "disabled"; }; @@ -1356,7 +1417,7 @@ qcom,arm-smmu; reg = <0x20000 0x10000>, <0x36000 0x100>, - <0x3900000 0x300000>; + <0xf100000 0x300000>; reg-names = "emac-base", "rgmii-base", "tlmm-central-base"; interrupts-extended = <&pdc 0 62 4>, <&pdc 0 60 4>, <&tlmm 90 2>, <&pdc 0 49 4>, @@ -1460,7 +1521,7 @@ 0x0007c 0x4e /* PORT0_STATUS */ 0x00094 0x4e /* PORT6_STATUS */ >; - qcom,link-intr-gpio = <84>; + qcom,link-intr-gpio = <90>; qcom,switch-cpu-bmp = <0x01>; /* cpu port bitmap */ qcom,switch-lan-bmp = <0x3e>; /* lan port bitmap */ qcom,switch-wan-bmp = <0x0>; /* wan port bitmap */ diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi index 1301850794aadc94e42679b4a55a7bd92b9b8415..c29345c7cbcbe1fb1b8dd8382b525d82759a1517 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -47,6 +47,16 @@ pinctrl-0 = <&flash_led3_front_en>; }; + led_flash_rear_aux2: qcom,camera-flash@3 { + cell-index = <3>; + reg = <0x03 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2 &pm6150l_switch2>; + status = "ok"; + }; + camera_ldo: gpio-regulator@0 { compatible = "regulator-fixed"; reg = <0x00 0x00>; @@ -135,6 +145,19 @@ rgltr-load-current = <100000>; }; + actuator_triple_tele: qcom,actuator@3 { + cell-index = <3>; + reg = <0x3>; + 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 = <100000>; + }; + ois_rear: qcom,ois@0 { cell-index = <0>; reg = <0x0>; @@ -260,6 +283,43 @@ clock-rates = <24000000>; }; + eeprom_triple_rear_aux: qcom,eeprom@3 { + cell-index = <3>; + reg = <3>; + 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 100000>; + 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@0 { cell-index = <0>; compatible = "qcom,cam-sensor"; @@ -432,4 +492,133 @@ clock-cntl-level = "turbo"; clock-rates = <24000000>; }; + + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + 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>; + 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@5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + reg = <0x5>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + actuator-src = <&actuator_triple_tele>; + eeprom-src = <&eeprom_triple_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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + reg = <0x6>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_rear_aux2>; + 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 index c8b9f524622966e772364a548f58bc2a077c3e4e..dee2b7f4a71ff7f03a18bd117617f299a0376225 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -318,10 +318,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; iova-granularity = <0x15>; status = "ok"; @@ -330,7 +330,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -339,8 +339,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0x10B11000>; + iova-region-len = <0xCF4EF000>; iova-region-id = <0x3>; status = "ok"; }; @@ -348,7 +348,7 @@ iova-mem-qdss-region { /* qdss region is approximately 64K */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x10000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 2edb9047c145d847720b03e46256943377112ef1..82ef40d8a8d00be052c438972bf8b1d6df1baeac 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -165,6 +165,7 @@ compatible = "qcom,ufs-phy-qmp-v3-660"; vdda-phy-supply = <&pm6150_l4>; /* 0.9v */ + vdda-phy-always-on; vdda-pll-supply = <&pm6150_l11>; vdda-phy-max-microamp = <30000>; vdda-pll-max-microamp = <12000>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index 08f833f2731c3bb03f796b33c7924dec8f853d89..037e57511850cd928a9010f5e30595b6d3a41b9b 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -260,6 +260,36 @@ }; }; + ss5_pwr_ctrl_pins: ss5_pwr_ctrl_pins { + ss5_pwr_ctrl_rst_on: ss5_pwr_ctrl_rst_on { + mux { + pins = "gpio87", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-pull-up; + output-high; + }; + }; + + ss5_pwr_ctrl_rst_off: ss5_pwr_ctrl_off { + mux { + pins = "gpio87", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-pull-up; + output-high; + }; + }; + }; + /* QUPv3_1 North instances */ /* SE 4 pin mappings */ qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { @@ -321,6 +351,33 @@ }; }; }; + qupv3_se4_2uart_pins: qupv3_se4_2uart_pins { + qupv3_se4_2uart_active: qupv3_se4_2uart_active { + mux { + pins = "gpio22", "gpio23"; + function = "qup10"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <16>; + bias-disable; + }; + }; + + qupv3_se4_2uart_sleep: qupv3_se4_2uart_sleep { + mux { + pins = "gpio22", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <16>; + bias-disable; + }; + }; + }; /* SE 5 pin mappings */ qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { @@ -1099,6 +1156,7 @@ config { pins = "gpio115", "gpio116"; drive-strength = <2>; /* 2 mA */ + bias-disable; }; }; @@ -1112,6 +1170,7 @@ pins = "gpio115", "gpio116"; drive-strength = <8>; /* 8 mA */ input-enable; + bias-disable; }; }; }; @@ -1126,6 +1185,7 @@ config { pins = "gpio117"; drive-strength = <2>; /* 2 mA */ + bias-pull-up; }; }; @@ -1137,8 +1197,9 @@ config { pins = "gpio117"; - drive-strength = <8>; /* 8 mA */ + drive-strength = <2>; /* 8 mA */ input-enable; + bias-disable; }; }; }; @@ -1153,6 +1214,7 @@ config { pins = "gpio118"; drive-strength = <2>; /* 2 mA */ + bias-disable; }; }; @@ -1166,6 +1228,7 @@ pins = "gpio118"; drive-strength = <8>; /* 8 mA */ output-high; + bias-disable; }; }; }; @@ -1707,6 +1770,174 @@ }; }; + hs0_i2s_sck_ws { + hs0_i2s_sck_sleep: hs0_i2s_sck_sleep { + mux { + pins = "gpio36", "gpio37"; + function = "hs0_mi2s"; + }; + + config { + pins = "gpio36", "gpio37"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + hs0_i2s_sck_active: hs0_i2s_sck_active { + mux { + pins = "gpio36", "gpio37"; + function = "hs0_mi2s"; + }; + + config { + pins = "gpio36", "gpio37"; + drive-strength = <4>; /* 4 mA */ + bias-no-pull; + input-enable; + }; + }; + }; + + hs0_i2s_data0 { + hs0_i2s_data0_sleep: hs0_i2s_data0_sleep { + mux { + pins = "gpio38"; + function = "hs0_mi2s"; + }; + + config { + pins = "gpio38"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + hs0_i2s_data0_active: hs0_i2s_data0_active { + mux { + pins = "gpio38"; + function = "hs0_mi2s"; + }; + + config { + pins = "gpio38"; + drive-strength = <4>; /* 4 mA */ + bias-no-pull; + output-high; + }; + }; + }; + + hs0_i2s_data1 { + hs0_i2s_data1_sleep: hs0_i2s_data1_sleep { + mux { + pins = "gpio39"; + function = "hs0_mi2s"; + }; + + config { + pins = "gpio39"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + hs0_i2s_data1_active: hs0_i2s_data1_active { + mux { + pins = "gpio39"; + function = "hs0_mi2s"; + }; + + config { + pins = "gpio39"; + drive-strength = <4>; /* 4 mA */ + bias-no-pull; + input-enable; + }; + }; + }; + + hs1_i2s_sck_ws { + hs1_i2s_sck_sleep: hs1_i2s_sck_sleep { + mux { + pins = "gpio24", "gpio25"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio24", "gpio25"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + hs1_i2s_sck_active: hs1_i2s_sck_active { + mux { + pins = "gpio24", "gpio25"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio24", "gpio25"; + drive-strength = <4>; /* 4 mA */ + bias-no-pull; + input-enable; + }; + }; + }; + + hs1_i2s_data0 { + hs1_i2s_data0_sleep: hs1_i2s_data0_sleep { + mux { + pins = "gpio26"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio26"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + hs1_i2s_data0_active: hs1_i2s_data0_active { + mux { + pins = "gpio26"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio26"; + drive-strength = <4>; /* 4 mA */ + bias-no-pull; + output-high; + }; + }; + }; + + hs1_i2s_data1 { + hs1_i2s_data1_sleep: hs1_i2s_data1_sleep { + mux { + pins = "gpio27"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio27"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + hs1_i2s_data1_active: hs1_i2s_data1_active { + mux { + pins = "gpio27"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio27"; + drive-strength = <4>; /* 4 mA */ + bias-no-pull; + input-enable; + }; + }; + }; + emac { emac_mdc: emac_mdc { mux { diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 96ac936751b9e9123b7912913b72326306c9c553..8035667588db4aebc8bde7aec0a64382f4f68d41 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -86,6 +86,7 @@ compatible = "qcom,ufs-phy-qmp-v3-660"; vdda-phy-supply = <&pm6150_l4>; /* 0.9v */ + vdda-phy-always-on; vdda-pll-supply = <&pm6150_l11>; vdda-phy-max-microamp = <30000>; vdda-pll-max-microamp = <12000>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi index ce13188e5a98f3189051309e921e8bf49ed88479..cc6dd19ab2270bcc681f20770f77dc7631ceeec0 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi @@ -154,6 +154,23 @@ }; }; + /* GNSS UART Instance for CDP/MTP platform */ + qupv3_se4_2uart: qcom,qup_uart@0xa80000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0xa80000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_2uart_active>; + pinctrl-1 = <&qupv3_se4_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + /* I2C */ qupv3_se4_i2c: i2c@a80000 { compatible = "qcom,i2c-geni"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi index 63e1d55284d9cc2e5e2c8cc7abdfb5cf51911d43..077a3155addb9eed60a68ba594c98c3c1cb75da1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -367,6 +367,9 @@ 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,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <924736320 909324048 913177120 917030184 920883256 928589392>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = diff --git a/arch/arm64/boot/dts/qcom/sm6150-slpi-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-slpi-pinctrl.dtsi index f00b107a6e5f5fdc01e54bbce0da9b29f6b66bcd..a5bac24136b765da39a98f830852b0465807c90d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-slpi-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-slpi-pinctrl.dtsi @@ -258,7 +258,7 @@ config { pins = "gpio23"; drive-strength = <8>; - bias-bus-hold; + bias-disable; }; }; @@ -271,7 +271,7 @@ config { pins = "gpio23"; drive-strength = <2>; - bias-bus-hold; + bias-disable; }; }; @@ -284,7 +284,7 @@ config { pins = "gpio24"; drive-strength = <8>; - bias-bus-hold; + bias-disable; }; }; @@ -297,7 +297,7 @@ config { pins = "gpio24"; drive-strength = <2>; - bias-bus-hold; + bias-disable; }; }; @@ -310,7 +310,7 @@ config { pins = "gpio26"; drive-strength = <8>; - bias-bus-hold; + bias-disable; }; }; @@ -323,7 +323,7 @@ config { pins = "gpio26"; drive-strength = <2>; - bias-bus-hold; + bias-disable; }; }; @@ -335,8 +335,8 @@ config { pins = "gpio25"; - drive-strength = <8>; - bias-bus-hold; + drive-strength = <2>; + bias-disable; }; }; @@ -349,7 +349,7 @@ config { pins = "gpio25"; drive-strength = <2>; - bias-bus-hold; + bias-pull-up; }; }; @@ -361,8 +361,8 @@ config { pins = "gpio18"; - drive-strength = <8>; - bias-bus-hold; + drive-strength = <2>; + bias-disable; }; }; @@ -375,7 +375,7 @@ config { pins = "gpio18"; drive-strength = <2>; - bias-bus-hold; + bias-pull-down; }; }; @@ -387,8 +387,8 @@ config { pins = "gpio20"; - drive-strength = <8>; - bias-bus-hold; + drive-strength = <2>; + bias-disable; }; }; @@ -401,7 +401,7 @@ config { pins = "gpio20"; drive-strength = <2>; - bias-bus-hold; + bias-pull-up; }; }; @@ -413,8 +413,8 @@ config { pins = "gpio21"; - drive-strength = <8>; - bias-bus-hold; + drive-strength = <2>; + bias-disable; }; }; @@ -427,7 +427,7 @@ config { pins = "gpio21"; drive-strength = <2>; - bias-bus-hold; + bias-pull-down; }; }; @@ -440,7 +440,7 @@ config { pins = "gpio22"; drive-strength = <8>; - bias-bus-hold; + bias-disable; }; }; @@ -453,7 +453,7 @@ config { pins = "gpio22"; drive-strength = <2>; - bias-bus-hold; + bias-disable; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi index f47d16937319f90936558fff5b4e5a3a6c7e578e..37c22bca3baf872b585b444e55e3433db6f548cc 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -125,16 +125,16 @@ }; }; - pm6150-vbat-lvl0 { + pm6150-bcl-lvl0 { cooling-maps { vbat_cpu6 { - trip = <&vbat_lvl0>; + trip = <&bcl_lvl0>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vbat_cpu7 { - trip = <&vbat_lvl0>; + trip = <&bcl_lvl0>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; @@ -142,16 +142,33 @@ }; }; - pm6150-ibat-lvl0 { + pm6150-bcl-lvl1 { cooling-maps { ibat_cpu6 { - trip = <&ibat_lvl0>; + trip = <&bcl_lvl1>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; ibat_cpu7 { - trip = <&ibat_lvl0>; + trip = <&bcl_lvl1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm6150-bcl-lvl2 { + cooling-maps { + ibat_cpu6 { + trip = <&bcl_lvl2>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + ibat_cpu7 { + trip = <&bcl_lvl2>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi index 29f8858201567720bd58599ba16a657745ea2aba..f8a5554f5bee7ecb7bb3347842c11e9a52493aae 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi @@ -55,6 +55,7 @@ 0x130 /* GSI_RING_BASE_ADDR_L */ 0x144 /* GSI_RING_BASE_ADDR_H */ 0x1a4>; /* GSI_IF_STS */ + qcom,gsi-disable-io-coherency; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,pm-qos-latency = <61>; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index d963e2e587d76d2ba8aa8d0fb38ed37fdb4eeace..bef0d618e3d1983fdf58cefb53b9ba6791c20124 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -46,6 +46,7 @@ i2c1 = &qupv3_se1_i2c; i2c2 = &qupv3_se3_i2c; hsuart0 = &qupv3_se7_4uart; + hsuart1 = &qupv3_se4_2uart; swr0 = &swr0; swr1 = &swr1; swr2 = &swr2; @@ -645,7 +646,7 @@ }; dfps_data_memory: dfps_data_region@9e300000 { - reg = <0x0 0x9e300000 0x0 0x0100000>; + reg = <0x0 0x9cf00000 0x0 0x0100000>; label = "dfps_data_region"; }; @@ -822,6 +823,13 @@ reg-names = "cc_base"; vdd_cx-supply = <&VDD_CX_LEVEL>; vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + protected-clocks = , + , + , + , + , + , + ; #clock-cells = <1>; #reset-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi index 263b7bb5832f03e3a6193309dd84baaf7e333d44..645640f5d62d97ce84271136d3807490a2da5ddd 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi @@ -124,6 +124,8 @@ }; &cam_cci0 { + #address-cells = <1>; + #size-cells = <0>; qcom,cam-res-mgr { compatible = "qcom,cam-res-mgr"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-hdk.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-hdk.dtsi index ec26a7703c578b5da6a2d32a9fcc6664c55fdbd5..04258207c3d95a0760020de850fb8a880317d40d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-hdk.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-hdk.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,6 +12,9 @@ */ &soc { + #address-cells = <1>; + #size-cells = <1>; + qcom,camera-flash@0 { cell-index = <0>; reg = <0x00 0x00>; @@ -55,6 +58,9 @@ }; &cam_cci0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,cam-res-mgr { compatible = "qcom,cam-res-mgr"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi index c882e5d94843b99674fbd8ba6da542822c15b79b..2bd902951c542ff1e100b4979b615e55c8947e79 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi @@ -124,6 +124,9 @@ }; &cam_cci0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,cam-res-mgr { compatible = "qcom,cam-res-mgr"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi index 40563713b3e4112de5de2f3eaa840d9d44159da6..51751d45d94780507e21a46bf2a3ac6bcd241ebb 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi @@ -49,6 +49,9 @@ }; &cam_cci0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,cam-res-mgr { compatible = "qcom,cam-res-mgr"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-hdk-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-hdk-overlay.dts index 283081ad6651ddb95260366364640b2992c2e357..e1580d227fd9867df56bd0b62ec1834ec0999069 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-hdk-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-hdk-overlay.dts @@ -55,6 +55,9 @@ }; &qupv3_se9_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; lt9611: lt,lt9611@3b { compatible = "lt,lt9611"; @@ -102,6 +105,10 @@ #include "dsi-panel-ext-bridge-hdmi-1080p.dtsi" +&dsi_ext_bridge_hdmi_1080p { + qcom,mdss-dsi-ext-bridge = <0>; +}; + &soc { ext_dsi_bridge_display: qcom,dsi-display@50 { label = "ext_dsi_bridge_display hdmi 1080p"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi index f59f5e7f4769e1ff444d73c1fa685ab0c0f7e12e..ee8c5a375547a7e335d8b7672408ce2f01ed4205 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi @@ -13,6 +13,8 @@ &pcie_rc1 { reg = <0 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; mhi_0: qcom,mhi@0 { reg = <0 0 0 0 0 >; @@ -399,6 +401,9 @@ }; mhi_events { + #address-cells = <1>; + #size-cells = <0>; + mhi_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; @@ -541,12 +546,19 @@ mhi,mru = <0x8000>; mhi,rsc-parent = <&mhi_netdev_0>; }; + + mhi_qrtr { + mhi,chan = "IPCR"; + mhi,early-notify; + }; }; }; }; &pcie_rc0 { reg = <0 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; mhi_1: qcom,mhi@0 { reg = <0 0 0 0 0 >; @@ -940,6 +952,9 @@ }; mhi_events { + #address-cells = <1>; + #size-cells = <0>; + mhi_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index 4835a9c6e98e4f8e169e1132f7acd66316baf7e0..29df85b5fe8273e170cc1f97617b2b3bf7e83643 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -4285,6 +4285,456 @@ }; }; + hs1_i2s_mclk { + hs1_i2s_mclk_sleep: hs1_i2s_mclk_sleep { + mux { + pins = "gpio155"; + function = "gpio"; + }; + + config { + pins = "gpio155"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_mclk_active: hs1_i2s_mclk_active { + mux { + pins = "gpio155"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio155"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_sck { + hs1_i2s_sck_sleep: hs1_i2s_sck_sleep { + mux { + pins = "gpio156"; + function = "gpio"; + }; + + config { + pins = "gpio156"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_sck_active: hs1_i2s_sck_active { + mux { + pins = "gpio156"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio156"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_ws { + hs1_i2s_ws_sleep: hs1_i2s_ws_sleep { + mux { + pins = "gpio157"; + function = "gpio"; + }; + + config { + pins = "gpio157"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_ws_active: hs1_i2s_ws_active { + mux { + pins = "gpio157"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio157"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_data0 { + hs1_i2s_data0_sleep: hs1_i2s_data0_sleep { + mux { + pins = "gpio158"; + function = "sleep"; + }; + + config { + pins = "gpio158"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_data0_active: hs1_i2s_data0_active { + mux { + pins = "gpio158"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio158"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs1_i2s_data1 { + hs1_i2s_data1_sleep: hs1_i2s_data1_sleep { + mux { + pins = "gpio159"; + function = "gpio"; + }; + + config { + pins = "gpio159"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs1_i2s_data1_active: hs1_i2s_data1_active { + mux { + pins = "gpio159"; + function = "hs1_mi2s"; + }; + + config { + pins = "gpio159"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + input-enable; + }; + }; + }; + + hs2_i2s_mclk { + hs2_i2s_mclk_sleep: hs2_i2s_mclk_sleep { + mux { + pins = "gpio160"; + function = "gpio"; + }; + + config { + pins = "gpio160"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_mclk_active: hs2_i2s_mclk_active { + mux { + pins = "gpio160"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio160"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_sck { + hs2_i2s_sck_sleep: hs2_i2s_sck_sleep { + mux { + pins = "gpio161"; + function = "gpio"; + }; + + config { + pins = "gpio161"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_sck_active: hs2_i2s_sck_active { + mux { + pins = "gpio161"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio161"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_ws { + hs2_i2s_ws_sleep: hs2_i2s_ws_sleep { + mux { + pins = "gpio162"; + function = "gpio"; + }; + + config { + pins = "gpio162"; + drive-strength = <2>; /* 8 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_ws_active: hs2_i2s_ws_active { + mux { + pins = "gpio162"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio162"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_data0 { + hs2_i2s_data0_sleep: hs2_i2s_data0_sleep { + mux { + pins = "gpio163"; + function = "gpio"; + }; + + config { + pins = "gpio163"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_data0_active: hs2_i2s_data0_active { + mux { + pins = "gpio163"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio163"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs2_i2s_data1 { + hs2_i2s_data1_sleep: hs2_i2s_data1_sleep { + mux { + pins = "gpio164"; + function = "gpio"; + }; + + config { + pins = "gpio164"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs2_i2s_data1_active: hs2_i2s_data1_active { + mux { + pins = "gpio164"; + function = "hs2_mi2s"; + }; + + config { + pins = "gpio164"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + input-enable; + }; + }; + }; + + hs3_i2s_mclk { + hs3_i2s_mclk_sleep: hs3_i2s_mclk_sleep { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_mclk_active: hs3_i2s_mclk_active { + mux { + pins = "gpio125"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio125"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_sck { + hs3_i2s_sck_sleep: hs3_i2s_sck_sleep { + mux { + pins = "gpio165"; + function = "gpio"; + }; + + config { + pins = "gpio165"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_sck_active: hs3_i2s_sck_active { + mux { + pins = "gpio165"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio165"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_ws { + hs3_i2s_ws_sleep: hs3_i2s_ws_sleep { + mux { + pins = "gpio166"; + function = "gpio"; + }; + + config { + pins = "gpio166"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_ws_active: hs3_i2s_ws_active { + mux { + pins = "gpio166"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio166"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_data0 { + hs3_i2s_data0_sleep: hs3_i2s_data0_sleep { + mux { + pins = "gpio167"; + function = "gpio"; + }; + + config { + pins = "gpio167"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_data0_active: hs3_i2s_data0_active { + mux { + pins = "gpio167"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio167"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + hs3_i2s_data1 { + hs3_i2s_data1_sleep: hs3_i2s_data1_sleep { + mux { + pins = "gpio168"; + function = "gpio"; + }; + + config { + pins = "gpio168"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + hs3_i2s_data1_active: hs3_i2s_data1_active { + mux { + pins = "gpio168"; + function = "hs3_mi2s"; + }; + + config { + pins = "gpio168"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + input-enable; + }; + }; + }; + emac { emac_mdc: emac_mdc { mux { diff --git a/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi index c7e8ad0a23e95a9a700e3e11589345c41908c0f2..aa109f9a7f943525dd0c3f1fdfad2c9716756e99 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi @@ -681,7 +681,7 @@ pinctrl-1 = <&qupv3_se13_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; - qcom,wrapper-core = <&qupv3_1>; + qcom,wrapper-core = <&qupv3_2>; dmas = <&gpi_dma2 0 3 1 64 0>, <&gpi_dma2 1 3 1 64 0>; dma-names = "tx", "rx"; @@ -846,11 +846,11 @@ status = "disabled"; }; - qupv3_se15_spi: spi@c90000 { + qupv3_se15_spi: spi@c94000 { compatible = "qcom,spi-geni"; #address-cells = <1>; #size-cells = <0>; - reg = <0xc90000 0x4000>; + reg = <0xc94000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; clocks = <&clock_gcc GCC_QUPV3_WRAP2_S5_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50-camera-sensor-qrd.dtsi index f7b99c6ec739e0085165ac15fc79dc09c16c60c3..174d572515b99761a4a158c73b52eced6fdd5e34 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,9 @@ #include &soc { + #address-cells = <1>; + #size-cells = <1>; + led_flash_rear: qcom,camera-flash@0 { cell-index = <0>; reg = <0x00 0x00>; @@ -46,6 +49,9 @@ }; &cam_cci0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,cam-res-mgr { compatible = "qcom,cam-res-mgr"; status = "ok"; @@ -312,6 +318,8 @@ }; &cam_cci1 { + #address-cells = <1>; + #size-cells = <0>; overlay_actuator_front: qcom,actuator@2 { cell-index = <2>; reg = <0x2>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd.dtsi index c68d6a07791fb1e2c4e78ba59d4758bc91c03dde..187a93fea2a2f65080391c03b7e1dac15ce6bade 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd.dtsi @@ -89,6 +89,9 @@ }; &qupv3_se17_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; st_fts@49 { @@ -109,6 +112,9 @@ }; &qupv3_se9_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; nq@28 { compatible = "qcom,nq-nci"; @@ -192,6 +198,9 @@ }; &qupv3_se4_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; redriver@19 { compatible = "onnn,redriver"; @@ -606,3 +615,119 @@ <0x49 0x70 0x28 0x74>; }; + +&thermal_zones { + modem1-pa1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&qmi_sensor 101>; + trips { + pa1_lvl0: active-config0 { + temperature = <40000>; + hysteresis = <5000>; + type = "passive"; + }; + pa1_lvl1: active-config1 { + temperature = <45000>; + hysteresis = <3000>; + type = "passive"; + }; + pa1_lvl2: active-config2 { + temperature = <52000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + cooling-maps { + pa1_skin_lvl0 { + trip = <&pa1_lvl0>; + cooling-device = <&modem1_skin0 1 1>; + }; + pa1_skin_lvl1 { + trip = <&pa1_lvl1>; + cooling-device = <&modem1_skin0 2 2>; + }; + pa1_skin_lvl2 { + trip = <&pa1_lvl2>; + cooling-device = <&modem1_skin0 3 3>; + }; + }; + }; + + pa-therm2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + pa2_lvl0: active-config0 { + temperature = <40000>; + hysteresis = <5000>; + type = "passive"; + }; + pa2_lvl1: active-config1 { + temperature = <45000>; + hysteresis = <3000>; + type = "passive"; + }; + pa2_lvl2: active-config2 { + temperature = <52000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + cooling-maps { + pa2_skin_lvl0 { + trip = <&pa2_lvl0>; + cooling-device = <&modem1_skin1 1 1>; + }; + pa2_skin_lvl1 { + trip = <&pa2_lvl1>; + cooling-device = <&modem1_skin1 2 2>; + }; + pa2_skin_lvl2 { + trip = <&pa2_lvl2>; + cooling-device = <&modem1_skin1 3 3>; + }; + }; + }; + + camera-ftherm-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + cam_lvl0: active-config0 { + temperature = <34000>; + hysteresis = <4000>; + type = "passive"; + }; + cam_lvl1: active-config1 { + temperature = <43000>; + hysteresis = <3000>; + type = "passive"; + }; + cam_lvl2: active-config2 { + temperature = <52000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + cooling-maps { + cam_skin_lvl0 { + trip = <&cam_lvl0>; + cooling-device = <&modem1_skin2 1 1>; + }; + cam_skin_lvl1 { + trip = <&cam_lvl1>; + cooling-device = <&modem1_skin2 2 2>; + }; + cam_skin_lvl2 { + trip = <&cam_lvl2>; + cooling-device = <&modem1_skin2 3 3>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index 6055d6eabd0ee86215ba5f94d2f45d9b799bbcb7..63b6df46735a370552656c5e568985bc176c784d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -249,6 +249,10 @@ }; &soc { + ipa_hw: qcom,ipa@1e00000 { + qcom,ipa-mhi-proxy; + }; + imp: qcom,ipa-mhi-proxy { compatible = "qcom,ipa-mhi-proxy"; qcom,mhi-chdb-base = <0x40300300>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi index 78505248b54cdeb0bb5fc36ac2126697e580ee5a..19e713aacb6f3304482df49e22b08f1091d820bf 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include + &mdm3 { compatible = "qcom,ext-sdxprairie"; qcom,mdm-link-info = "0306_01.01.00"; @@ -32,8 +34,16 @@ qcom,addr-win = <0x0 0x20000000 0x0 0x2fffffff>; mhi_channels { + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@9 { + mhi,num-elements = <128>; + }; + mhi_chan@25 { - status = "disabled"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; }; mhi_chan@80 { @@ -81,7 +91,6 @@ mhi_devices { mhi_qrtr { - mhi,chan = "IPCR"; qcom,net-id = <3>; }; }; @@ -119,6 +128,9 @@ qcom,testbus-collection-on-crash; qcom,non-tn-collection-on-crash; qcom,secure-debug-check-action = <0>; + qcom,throughput-threshold = <600 2500 5000>; + qcom,scaling-exceptions = "USB DPL", "0", "2500", + "5000", "ODL", "0", "2500", "5000"; }; qcom,ipa_fws { @@ -193,3 +205,367 @@ &wil6210 { status = "disabled"; }; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = ; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_tj: modem_tj { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_mmw_skin0: modem_mmw_skin0 { + qcom,qmi-dev-name = "modem_skin0"; + #cooling-cells = <2>; + }; + + modem_mmw_skin1: modem_mmw_skin1 { + qcom,qmi-dev-name = "modem_skin1"; + #cooling-cells = <2>; + }; + + modem_mmw_skin2: modem_mmw_skin2 { + qcom,qmi-dev-name = "modem_skin2"; + #cooling-cells = <2>; + }; + + modem_mmw_skin3: modem_mmw_skin3 { + qcom,qmi-dev-name = "modem_skin3"; + #cooling-cells = <2>; + }; + + modem_mmw0: modem_mmw0 { + qcom,qmi-dev-name = "mmw0"; + #cooling-cells = <2>; + }; + + modem_mmw1: modem_mmw1 { + qcom,qmi-dev-name = "mmw1"; + #cooling-cells = <2>; + }; + + modem_mmw2: modem_mmw2 { + qcom,qmi-dev-name = "mmw2"; + #cooling-cells = <2>; + }; + + modem_mmw3: modem_mmw3 { + qcom,qmi-dev-name = "mmw3"; + #cooling-cells = <2>; + }; + + modem_bcl: modem_bcl { + qcom,qmi-dev-name = "vbatt_low"; + #cooling-cells = <2>; + }; + }; + }; + + qmi_sensor: qmi-ts-sensors { + compatible = "qcom,qmi-sensors"; + #thermal-sensor-cells = <1>; + + modem { + qcom,instance-id = ; + qcom,qmi-sensor-names = "pa", + "pa_1", + "qfe_wtr0", + "modem_tsens", + "qfe_mmw0", + "qfe_mmw1", + "qfe_mmw2", + "qfe_mmw3", + "xo_therm", + "qfe_mmw_streamer0", + "qfe_mmw0_mod", + "qfe_mmw1_mod", + "qfe_mmw2_mod", + "qfe_mmw3_mod", + "qfe_ret_pa0", + "qfe_wtr_pa0", + "qfe_wtr_pa1", + "qfe_wtr_pa2", + "qfe_wtr_pa3", + "sys_therm1", + "sys_therm2", + "modem_tsens1"; + }; + }; +}; + +&thermal_zones { + modem-lte-sub6-pa1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_PA)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-lte-sub6-pa2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_PA_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_0)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_2)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_3)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-skin-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_XO_THERM)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-wifi-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_SYS_THERM_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-ambient-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_SYS_THERM_2)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_MODEM_TSENS)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_MODEM_TSENS_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-streamer-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_STREAMER_0)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw0-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_0_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw1-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_1_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw2-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_2_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw3-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_3_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi index 9c8b8ea200f73f3311674729b77dbee6b244012c..643bb84e36699c2a13b58c0c3de2682569959de9 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -154,149 +154,107 @@ }; }; - pm8150b-vbat-lvl0 { + pm8150b-bcl-lvl0 { cooling-maps { vbat_cpu4 { - trip = <&vbat_lvl0>; + trip = <&b_bcl_lvl0>; cooling-device = <&CPU4 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vbat_cpu5 { - trip = <&vbat_lvl0>; + trip = <&b_bcl_lvl0>; cooling-device = <&CPU5 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vbat_gpu0 { - trip = <&vbat_lvl0>; + trip = <&b_bcl_lvl0>; cooling-device = <&msm_gpu 2 2>; }; }; }; - pm8150b-vbat-lvl1 { + pm8150b-bcl-lvl1 { cooling-maps { vbat_cpu6 { - trip = <&vbat_lvl1>; + trip = <&b_bcl_lvl1>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vbat_cpu7 { - trip = <&vbat_lvl1>; + trip = <&b_bcl_lvl1>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vbat_gpu1 { - trip = <&vbat_lvl1>; + trip = <&b_bcl_lvl1>; cooling-device = <&msm_gpu 4 4>; }; }; }; - pm8150b-vbat-lvl2 { + pm8150b-bcl-lvl2 { cooling-maps { vbat_gpu2 { - trip = <&vbat_lvl2>; + trip = <&b_bcl_lvl2>; cooling-device = <&msm_gpu THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; }; }; - pm8150b-ibat-lvl0 { - cooling-maps { - ibat_cpu4 { - trip = <&ibat_lvl0>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - ibat_cpu5 { - trip = <&ibat_lvl0>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - ibat_gpu0 { - trip = <&ibat_lvl0>; - cooling-device = <&msm_gpu 2 2>; - }; - }; - }; - - pm8150b-ibat-lvl1 { - cooling-maps { - ibat_cpu6 { - trip = <&ibat_lvl1>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - ibat_cpu7 { - trip = <&ibat_lvl1>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - ibat_gpu1 { - trip = <&ibat_lvl1>; - cooling-device = <&msm_gpu 4 4>; - }; - }; - }; - - pm8150l-vph-lvl0 { + pm8150l-bcl-lvl0 { disable-thermal-zone; cooling-maps { vph_cpu4 { - trip = <&vph_lvl0>; + trip = <&l_bcl_lvl0>; cooling-device = <&CPU4 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vph_cpu5 { - trip = <&vph_lvl0>; + trip = <&l_bcl_lvl0>; cooling-device = <&CPU5 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vph_gpu0 { - trip = <&vph_lvl0>; + trip = <&l_bcl_lvl0>; cooling-device = <&msm_gpu 2 2>; }; }; }; - pm8150l-vph-lvl1 { + pm8150l-bcl-lvl1 { disable-thermal-zone; cooling-maps { vph_cpu6 { - trip = <&vph_lvl1>; + trip = <&l_bcl_lvl1>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vph_cpu7 { - trip = <&vph_lvl1>; + trip = <&l_bcl_lvl1>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; vph_gpu1 { - trip = <&vph_lvl1>; + trip = <&l_bcl_lvl1>; cooling-device = <&msm_gpu 4 4>; }; }; }; - pm8150l-vph-lvl2 { + pm8150l-bcl-lvl2 { disable-thermal-zone; cooling-maps { vph_gpu2 { - trip = <&vph_lvl2>; + trip = <&l_bcl_lvl2>; cooling-device = <&msm_gpu THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi index 359ef4332885be77148de865642b1f25cef21598..371859ade666c21c71aacfcaadae65434e564c56 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018 - 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -45,8 +45,11 @@ "core_clk", "vcodec_clk", "cvp_clk"; resets = <&clock_gcc GCC_VIDEO_AXIC_CLK_BCR>, - <&clock_videocc VIDEO_CC_MVSC_CORE_CLK_BCR>; - reset-names = "video_axi_reset", "video_core_reset"; + <&clock_videocc VIDEO_CC_MVSC_CORE_CLK_BCR>, + <&clock_gcc GCC_VIDEO_AXI0_CLK_BCR>, + <&clock_gcc GCC_VIDEO_AXI1_CLK_BCR>; + reset-names = "video_axi_reset", "video_core_reset", + "video_axi0_reset", "video_axi1_reset"; qcom,clock-configs = <0x0 0x0 0x0 0x1 0x1 0x1>; qcom,allowed-clock-rates = <225000000 300000000 diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index f719583f3a3750191d6a1a6d931072debc5cd73f..2799385f733a76d82f1bb82f9b083cbf98ad6316 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1384,14 +1384,20 @@ compatible = "qcom,bus-proxy-client"; qcom,msm-bus,name = "bus-proxy-client"; qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,num-paths = <5>; qcom,msm-bus,vectors-KBps = , , , + , + , , , - ; + , + , + ; status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/trinket-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/trinket-audio-overlay.dtsi index d2ab4cb4ecb6738c38f5ce67d022a1f13063d3b8..2568fab8077ba1f34046924ba27145ab09610dbf 100644 --- a/arch/arm64/boot/dts/qcom/trinket-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-audio-overlay.dtsi @@ -186,7 +186,7 @@ &sm6150_snd { qcom,model = "trinket-idp-snd-card"; qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; - qcom,ext-disp-audio-rx = <0>; + qcom,ext-disp-audio-rx = <1>; qcom,audio-routing = "AMIC2", "MIC BIAS2", "MIC BIAS2", "Analog Mic2", @@ -227,8 +227,9 @@ qcom,msm-mbhc-gnd-swh = <1>; qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; - asoc-codec = <&stub_codec>, <&bolero>; - asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; qcom,wsa-max-devs = <1>; qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, <&wsa881x_0213>, <&wsa881x_0214>; diff --git a/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi b/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi index c23f23efc5876c7c8768785718cd348f6964a5ef..e991d4159b1af129a894d6b7626b30201e7b41b1 100644 --- a/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi @@ -2219,8 +2219,15 @@ coresight-name = "coresight-cti-gpu_isdb_cti"; - clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>; - clock-names = "apb_pclk"; + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_gpucc GPU_CC_CX_APB_CLK>; + clock-names = "apb_pclk", "gpu_apb_clk"; + qcom,proxy-clks = "gpu_apb_clk"; + + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + regulator-names = "vddcx", "vdd"; + qcom,proxy-regs = "vddcx", "vdd"; }; cti_lpass_q6_cti: cti@8987000 { diff --git a/arch/arm64/boot/dts/qcom/trinket-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/trinket-dp-idp-overlay.dts index 0607e35329bf8cff4b71d2daaa55b9f96b4d5059..930307886ea195dd201e36548216e7ae252023f4 100644 --- a/arch/arm64/boot/dts/qcom/trinket-dp-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/trinket-dp-idp-overlay.dts @@ -28,3 +28,24 @@ &dsi_td4330_truly_cmd_display { qcom,dsi-display-active; }; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-dp-idp.dts b/arch/arm64/boot/dts/qcom/trinket-dp-idp.dts index a8ee1e96b57f5701013b36db79121709d583122f..8321f5877c7401d396d642cae5c10f30cb0338a9 100644 --- a/arch/arm64/boot/dts/qcom/trinket-dp-idp.dts +++ b/arch/arm64/boot/dts/qcom/trinket-dp-idp.dts @@ -21,3 +21,24 @@ compatible = "qcom,trinket-idp", "qcom,trinket", "qcom,idp"; qcom,board-id = <34 4>; }; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi index a59cc200ba1df609dc803a804322337a84b201c0..19c93d69922b874de7780b9811804f1430d2c8f5 100644 --- a/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi @@ -1255,6 +1255,60 @@ }; }; + sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + bias-disable; + drive-strength = <16>; + }; + }; + + sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_suspend { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + sde_dp_hotplug_ctrl: sde_dp_hotplug_ctrl { + mux { + pins = "gpio100"; + function = "dp_hot"; + }; + + config { + pins = "gpio100"; + bias-disable; + input-enable; + drive-strength = <2>; + }; + }; + + sde_dp_hotplug_tlmm: sde_dp_hotplug_tlmm { + mux { + pins = "gpio100"; + function = "gpio"; + }; + + config { + pins = "gpio100"; + bias-disable; + input-enable; + drive-strength = <2>; + }; + }; + /* SDC pin type */ sdc1_clk_on: sdc1_clk_on { config { diff --git a/arch/arm64/boot/dts/qcom/trinket-qrd.dtsi b/arch/arm64/boot/dts/qcom/trinket-qrd.dtsi index 84f5f479c6e847a9e6b8adaad0ae0267cac49af1..6a4eecf616a33133aee3062be1d6a411a6fb3512 100644 --- a/arch/arm64/boot/dts/qcom/trinket-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-qrd.dtsi @@ -368,8 +368,9 @@ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <1>; - asoc-codec = <&stub_codec>, <&bolero>; - asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; qcom,codec-max-aux-devs = <1>; qcom,codec-aux-devs = <&wcd937x_codec>; qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, diff --git a/arch/arm64/boot/dts/qcom/trinket-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/trinket-sde-pll.dtsi index 052a163c6556197b5f8aab7b6a5936ea1094bbbf..701bb570f20e470008a27e5a4461fd36346ad295 100644 --- a/arch/arm64/boot/dts/qcom/trinket-sde-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-sde-pll.dtsi @@ -41,4 +41,45 @@ }; }; }; + + mdss_dp_pll: qcom,mdss_dp_pll@1616000 { + status = "disabled"; + compatible = "qcom,mdss_dp_pll_14nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x01616c00 0x1c4>, + <0x01616000 0x17c>, + <0x01616400 0x10c>, + <0x01616800 0x10c>, + <0x05f03000 0xc>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmcc CXO_SMD_OTG_CLK>, + <&clock_gcc GCC_AHB2PHY_USB_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>; + clock-names = "iface_clk", + "ref_clk_src", + "cfg_ahb_clk", + "gcc_iface", "ref_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>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi index d1420bfd09a492809e0a51eb4685741f77d89ae2..7419634f0b0d79a3ecf68ebdf84c8b1ce7452fb2 100644 --- a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi @@ -414,4 +414,150 @@ }; }; }; + + 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"; + }; + }; + + sde_dp: qcom,dp_display@0{ + status = "disabled"; + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p8-supply = <&pm6125_l10>; + vdda-0p9-supply = <&pm6125_l7>; + vdda-3p1-supply = <&pm6125_l15>; + hpd-pwr-supply = <&pm6125_l9>; + + reg = <0x05e90000 0xf4>, + <0x05e90200 0xc0>, + <0x05e90400 0x600>, + <0x05e90a00 0x98>, + <0x01616000 0x17c>, + <0x01616400 0x10c>, + <0x01616800 0x10c>, + <0x05f0212c 0x8>, + <0x01b40000 0x7000>, + <0x01616c30 0x10>, + <0x05ee1000 0x2c>, + <0x003cb248 0x4>; + reg-names = "dp_ahb", "dp_aux", "dp_link", "dp_p0", + "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_pixel_mn", "qfprom_physical", "dp_pll", + "hdcp_physical", "dp_tcsr"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_gcc GCC_AHB2PHY_USB_CLK>, + <&clock_rpmcc CXO_SMD_OTG_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_PHY_PLL_VCO_DIV_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; + + clock-names = "core_aux_clk", "core_usb_ahb_clk", + "core_usb_ref_clk_src", + "core_usb_ref_clk", + "core_usb_pipe_clk", "link_clk", "link_iface_clk", + "crypto_clk", "pixel_clk_rcg", "pixel_parent", + "strm0_pixel_clk"; + + qcom,phy-version = <0x200>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13 23 1d]; + 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 bb]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,logical2physical-lane-map = [00 01 02 03]; + + qcom,max-lclk-frequency-khz = <540000>; + qcom,max-pclk-frequency-khz = <200000>; + + qcom,ext-disp = <&ext_disp>; + + qcom,usbplug-cc-gpio = <&tlmm 102 0>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep", + "mdss_dp_hpd_active", "mdss_dp_hpd_tlmm", + "mdss_dp_hpd_ctrl"; + pinctrl-0 = <&sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_usbplug_cc_suspend>; + pinctrl-2 = <&sde_dp_hotplug_tlmm>; + pinctrl-3 = <&sde_dp_hotplug_tlmm>; + pinctrl-4 = <&sde_dp_hotplug_ctrl>; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p8"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1896000>; + qcom,supply-enable-load = <20000>; + 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 = <872000>; + qcom,supply-max-voltage = <976000>; + qcom,supply-enable-load = <50000>; + qcom,supply-disable-load = <0>; + }; + qcom,phy-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdda-3p1"; + qcom,supply-min-voltage = <3104000>; + qcom,supply-max-voltage = <3232000>; + qcom,supply-enable-load = <5250>; + qcom,supply-disable-load = <0>; + }; + qcom,phy-supply-entry@2 { + reg = <2>; + qcom,supply-name = "hpd-pwr"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1896000>; + qcom,supply-enable-load = <10000>; + 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/trinket-tasha-codec.dtsi b/arch/arm64/boot/dts/qcom/trinket-tasha-codec.dtsi index 0276333f392da15f0f3890468832c21fd599bbaf..94c4bba291fb80a01d813f3112e8296dd9dbdd78 100644 --- a/arch/arm64/boot/dts/qcom/trinket-tasha-codec.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-tasha-codec.dtsi @@ -39,7 +39,7 @@ "msm-pcm-routing", "msm-compr-dsp", "msm-pcm-dsp-noirq", "msm-cpe-lsm", "msm-cpe-lsm.3"; - asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + asoc-cpu = <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s4>, <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, @@ -59,7 +59,8 @@ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>; - asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", @@ -117,8 +118,8 @@ qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <1>; qcom,msm-mclk-freq = <9600000>; - asoc-codec = <&stub_codec>; - asoc-codec-names = "msm-stub-codec.1"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-ext-disp-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_70212>, <&wsa881x_70211>, <&wsa881x_70214>, <&wsa881x_70213>; diff --git a/arch/arm64/boot/dts/qcom/trinket-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/trinket-thermal-overlay.dtsi index cc055b4a542ddecf2fd5a57beceeff8af65f1747..1c3a5fe6a9509a95ed4e0ba574731e619732f561 100644 --- a/arch/arm64/boot/dts/qcom/trinket-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-thermal-overlay.dtsi @@ -125,52 +125,52 @@ }; }; - pmi632-vbat-lvl0 { + pmi632-bcl-lvl0 { cooling-maps { - vbat_cpu0 { - trip = <&pmi632_vbat_lvl0>; + cpu0_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu1 { - trip = <&pmi632_vbat_lvl0>; + cpu1_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU1 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu2 { - trip = <&pmi632_vbat_lvl0>; + cpu2_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU2 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu3 { - trip = <&pmi632_vbat_lvl0>; + cpu3_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU3 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu4 { - trip = <&pmi632_vbat_lvl0>; + cpu4_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU4 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu5 { - trip = <&pmi632_vbat_lvl0>; + cpu5_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU5 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu6 { - trip = <&pmi632_vbat_lvl0>; + cpu6_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; }; - vbat_cpu7 { - trip = <&pmi632_vbat_lvl0>; + cpu7_cdev { + trip = <&bcl_lvl0>; cooling-device = <&CPU7 (THERMAL_MAX_LIMIT-6) (THERMAL_MAX_LIMIT-6)>; @@ -178,52 +178,52 @@ }; }; - pmi632-vbat-lvl1 { + pmi632-bcl-lvl1 { cooling-maps { - vbat_cpu0 { - trip = <&pmi632_vbat_lvl1>; + cpu0_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu1 { - trip = <&pmi632_vbat_lvl1>; + cpu1_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU1 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu2 { - trip = <&pmi632_vbat_lvl1>; + cpu2_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU2 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu3 { - trip = <&pmi632_vbat_lvl1>; + cpu3_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU3 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu4 { - trip = <&pmi632_vbat_lvl1>; + cpu4_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU4 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu5 { - trip = <&pmi632_vbat_lvl1>; + cpu5_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU5 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu6 { - trip = <&pmi632_vbat_lvl1>; + cpu6_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; - vbat_cpu7 { - trip = <&pmi632_vbat_lvl1>; + cpu7_cdev { + trip = <&bcl_lvl1>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; @@ -231,158 +231,52 @@ }; }; - pmi632-vbat-lvl2 { + pmi632-bcl-lvl2 { cooling-maps { - vbat_cpu0 { - trip = <&pmi632_vbat_lvl2>; + cpu0_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu1 { - trip = <&pmi632_vbat_lvl2>; + cpu1_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU1 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu2 { - trip = <&pmi632_vbat_lvl2>; + cpu2_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU2 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu3 { - trip = <&pmi632_vbat_lvl2>; + cpu3_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU3 (THERMAL_MAX_LIMIT-5) (THERMAL_MAX_LIMIT-5)>; }; - vbat_cpu4 { - trip = <&pmi632_vbat_lvl2>; + cpu4_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU4 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; - vbat_cpu5 { - trip = <&pmi632_vbat_lvl2>; + cpu5_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU5 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; - vbat_cpu6 { - trip = <&pmi632_vbat_lvl2>; + cpu6_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; }; - vbat_cpu7 { - trip = <&pmi632_vbat_lvl2>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; - - pmi632-ibat-lvl0 { - cooling-maps { - ibat_cpu0 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU0 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu1 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU1 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu2 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU2 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu3 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU3 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu4 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU4 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu5 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU5 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu6 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU6 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - ibat_cpu7 { - trip = <&pmi632_ibat_lvl0>; - cooling-device = - <&CPU7 (THERMAL_MAX_LIMIT-6) - (THERMAL_MAX_LIMIT-6)>; - }; - }; - }; - - pmi632-ibat-lvl1 { - cooling-maps { - ibat_cpu0 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU0 (THERMAL_MAX_LIMIT-5) - (THERMAL_MAX_LIMIT-5)>; - }; - ibat_cpu1 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU1 (THERMAL_MAX_LIMIT-5) - (THERMAL_MAX_LIMIT-5)>; - }; - ibat_cpu2 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU2 (THERMAL_MAX_LIMIT-5) - (THERMAL_MAX_LIMIT-5)>; - }; - ibat_cpu3 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU3 (THERMAL_MAX_LIMIT-5) - (THERMAL_MAX_LIMIT-5)>; - }; - ibat_cpu4 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU4 (THERMAL_MAX_LIMIT-5) - (THERMAL_MAX_LIMIT-5)>; - }; - ibat_cpu5 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU5 (THERMAL_MAX_LIMIT-5) - (THERMAL_MAX_LIMIT-5)>; - }; - ibat_cpu6 { - trip = <&pmi632_ibat_lvl1>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - ibat_cpu7 { - trip = <&pmi632_ibat_lvl1>; + cpu7_cdev { + trip = <&bcl_lvl2>; cooling-device = <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; diff --git a/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi b/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi index 261e9d9d091043ac6c5ec55be39626b098d4f369..bd964c615005575e5c38b7f7b3402159ac0a06b7 100644 --- a/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi @@ -117,7 +117,7 @@ quiet-therm-adc { polling-delay-passive = <0>; - polling-delay = <0>; + polling-delay = <5000>; thermal-governor = "user_space"; thermal-sensors = <&pm6125_adc_tm ADC_AMUX_THM2_PU2>; wake-capable-sensor; diff --git a/arch/arm64/boot/dts/qcom/trinket-usb.dtsi b/arch/arm64/boot/dts/qcom/trinket-usb.dtsi index 5a7c14dd4bb8fde198dafe6f2d5a0c0abf15d3e3..bb5087492c11d57d4a6edd2a96bd0967941d6647 100644 --- a/arch/arm64/boot/dts/qcom/trinket-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-usb.dtsi @@ -54,6 +54,7 @@ 0x144 /* GSI_RING_BASE_ADDR_H */ 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,gsi-disable-io-coherency; qcom,msm-bus,name = "usb0"; qcom,msm-bus,num-cases = <4>; diff --git a/arch/arm64/boot/dts/qcom/trinket.dtsi b/arch/arm64/boot/dts/qcom/trinket.dtsi index ec6b86a8bd5db490bc522d9a2adaf484f7cbee6d..83ae25fdc9e8d6dcbd8dcbe277c8c03eb5aae99d 100644 --- a/arch/arm64/boot/dts/qcom/trinket.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket.dtsi @@ -1188,7 +1188,7 @@ qcom,complete-ramdump; /* Inputs from mss */ - interrupts-extended = <&intc 0 307 1>, + interrupts-extended = <&wakegic 0 307 1>, <&modem_smp2p_in 0 0>, <&modem_smp2p_in 2 0>, <&modem_smp2p_in 1 0>, @@ -1312,7 +1312,7 @@ qcom,complete-ramdump; /* Inputs from lpass */ - interrupts-extended = <&intc 0 396 1>, + interrupts-extended = <&wakegic 0 396 1>, <&adsp_smp2p_in 0 0>, <&adsp_smp2p_in 2 0>, <&adsp_smp2p_in 1 0>, @@ -1352,7 +1352,7 @@ qcom,complete-ramdump; /* Inputs from turing */ - interrupts-extended = <&intc 0 265 1>, + interrupts-extended = <&wakegic 0 265 1>, <&cdsp_smp2p_in 0 0>, <&cdsp_smp2p_in 2 0>, <&cdsp_smp2p_in 1 0>, @@ -2072,6 +2072,10 @@ <&apps_smmu 0x01B6 0x0011>; }; + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + qcom_crypto: qcrypto@1b20000 { compatible = "qcom,qcrypto"; reg = <0x1b20000 0x20000>, @@ -2807,6 +2811,8 @@ compatible = "qcom,adc-tm5-iio"; reg = <0x3400 0x100>; #thermal-sensor-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; io-channels = <&pm6125_vadc ADC_GPIO1_PU2>, <&pm6125_vadc ADC_GPIO3_PU2>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index 28257724a56e74b79b83c69a76bea0da4e0fd9ed..e720f40bbd5d7ed1ca02da99e9f56250110b1b8d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -82,8 +82,7 @@ vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio0 RK_PD3 GPIO_ACTIVE_HIGH>; + gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&usb20_host_drv>; regulator-name = "vcc_host1_5v"; @@ -275,7 +274,7 @@ usb2 { usb20_host_drv: usb20-host-drv { - rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index efac2202b16ec10301a40dea1b10ef464bad8e1a..f6b4b8f0260f68d2a5d5c6c8d067a8e96575eb11 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -1333,11 +1333,11 @@ sdmmc0 { sdmmc0_clk: sdmmc0-clk { - rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_4ma>; + rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_8ma>; }; sdmmc0_cmd: sdmmc0-cmd { - rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_8ma>; }; sdmmc0_dectn: sdmmc0-dectn { @@ -1349,14 +1349,14 @@ }; sdmmc0_bus1: sdmmc0-bus1 { - rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_8ma>; }; sdmmc0_bus4: sdmmc0-bus4 { - rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>, - <1 RK_PA1 1 &pcfg_pull_up_4ma>, - <1 RK_PA2 1 &pcfg_pull_up_4ma>, - <1 RK_PA3 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_8ma>, + <1 RK_PA1 1 &pcfg_pull_up_8ma>, + <1 RK_PA2 1 &pcfg_pull_up_8ma>, + <1 RK_PA3 1 &pcfg_pull_up_8ma>; }; sdmmc0_gpio: sdmmc0-gpio { @@ -1530,50 +1530,50 @@ rgmiim1_pins: rgmiim1-pins { rockchip,pins = /* mac_txclk */ - <1 RK_PB4 2 &pcfg_pull_none_12ma>, + <1 RK_PB4 2 &pcfg_pull_none_8ma>, /* mac_rxclk */ - <1 RK_PB5 2 &pcfg_pull_none_2ma>, + <1 RK_PB5 2 &pcfg_pull_none_4ma>, /* mac_mdio */ - <1 RK_PC3 2 &pcfg_pull_none_2ma>, + <1 RK_PC3 2 &pcfg_pull_none_4ma>, /* mac_txen */ - <1 RK_PD1 2 &pcfg_pull_none_12ma>, + <1 RK_PD1 2 &pcfg_pull_none_8ma>, /* mac_clk */ - <1 RK_PC5 2 &pcfg_pull_none_2ma>, + <1 RK_PC5 2 &pcfg_pull_none_4ma>, /* mac_rxdv */ - <1 RK_PC6 2 &pcfg_pull_none_2ma>, + <1 RK_PC6 2 &pcfg_pull_none_4ma>, /* mac_mdc */ - <1 RK_PC7 2 &pcfg_pull_none_2ma>, + <1 RK_PC7 2 &pcfg_pull_none_4ma>, /* mac_rxd1 */ - <1 RK_PB2 2 &pcfg_pull_none_2ma>, + <1 RK_PB2 2 &pcfg_pull_none_4ma>, /* mac_rxd0 */ - <1 RK_PB3 2 &pcfg_pull_none_2ma>, + <1 RK_PB3 2 &pcfg_pull_none_4ma>, /* mac_txd1 */ - <1 RK_PB0 2 &pcfg_pull_none_12ma>, + <1 RK_PB0 2 &pcfg_pull_none_8ma>, /* mac_txd0 */ - <1 RK_PB1 2 &pcfg_pull_none_12ma>, + <1 RK_PB1 2 &pcfg_pull_none_8ma>, /* mac_rxd3 */ - <1 RK_PB6 2 &pcfg_pull_none_2ma>, + <1 RK_PB6 2 &pcfg_pull_none_4ma>, /* mac_rxd2 */ - <1 RK_PB7 2 &pcfg_pull_none_2ma>, + <1 RK_PB7 2 &pcfg_pull_none_4ma>, /* mac_txd3 */ - <1 RK_PC0 2 &pcfg_pull_none_12ma>, + <1 RK_PC0 2 &pcfg_pull_none_8ma>, /* mac_txd2 */ - <1 RK_PC1 2 &pcfg_pull_none_12ma>, + <1 RK_PC1 2 &pcfg_pull_none_8ma>, /* mac_txclk */ - <0 RK_PB0 1 &pcfg_pull_none>, + <0 RK_PB0 1 &pcfg_pull_none_8ma>, /* mac_txen */ - <0 RK_PB4 1 &pcfg_pull_none>, + <0 RK_PB4 1 &pcfg_pull_none_8ma>, /* mac_clk */ - <0 RK_PD0 1 &pcfg_pull_none>, + <0 RK_PD0 1 &pcfg_pull_none_4ma>, /* mac_txd1 */ - <0 RK_PC0 1 &pcfg_pull_none>, + <0 RK_PC0 1 &pcfg_pull_none_8ma>, /* mac_txd0 */ - <0 RK_PC1 1 &pcfg_pull_none>, + <0 RK_PC1 1 &pcfg_pull_none_8ma>, /* mac_txd3 */ - <0 RK_PC7 1 &pcfg_pull_none>, + <0 RK_PC7 1 &pcfg_pull_none_8ma>, /* mac_txd2 */ - <0 RK_PC6 1 &pcfg_pull_none>; + <0 RK_PC6 1 &pcfg_pull_none_8ma>; }; rmiim1_pins: rmiim1-pins { diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 0aa3968857c1282cd8533aa3517fb787eef627e9..2c161483bd4a34512aaa37845e8d6ad72540561c 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -59,8 +59,6 @@ CONFIG_SETEND_EMULATION=y CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_ARM64_LSE_ATOMICS=y CONFIG_RANDOMIZE_BASE=y -CONFIG_CMDLINE="console=ttyAMA0" -CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y @@ -83,6 +81,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -286,6 +285,7 @@ CONFIG_SERIAL_8250_NR_UARTS=48 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_VIRTIO_CONSOLE=y @@ -385,6 +385,7 @@ CONFIG_MMC=y # CONFIG_MMC_BLOCK is not set CONFIG_RTC_CLASS=y # CONFIG_RTC_SYSTOHC is not set +CONFIG_RTC_DRV_PL030=y CONFIG_RTC_DRV_PL031=y CONFIG_VIRTIO_PCI=y # CONFIG_VIRTIO_PCI_LEGACY is not set @@ -413,6 +414,7 @@ CONFIG_F2FS_FS_ENCRYPTION=y # CONFIG_DNOTIFY is not set CONFIG_QUOTA=y CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y diff --git a/arch/arm64/configs/vendor/atoll-perf_defconfig b/arch/arm64/configs/vendor/atoll-perf_defconfig index 2b0d8b75375fd9d1412a92235a207f25b474fbac..36b5d05c549a34f04a2881116db2f2990401a61f 100644 --- a/arch/arm64/configs/vendor/atoll-perf_defconfig +++ b/arch/arm64/configs/vendor/atoll-perf_defconfig @@ -37,7 +37,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -68,6 +67,7 @@ CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_ARM64_SSBD=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -96,6 +96,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -324,6 +325,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_WITH_HALF_SAMPLING=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y # CONFIG_DEVPORT is not set @@ -346,7 +348,6 @@ CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -CONFIG_PINCTRL_SDMMAGPIE=y CONFIG_PINCTRL_ATOLL=y CONFIG_PINCTRL_SLPI=y CONFIG_GPIO_SYSFS=y @@ -370,11 +371,11 @@ CONFIG_QTI_THERMAL_LIMITS_DCVS=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_AOP_REG_COOLING_DEVICE=y CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_QTI_QMI_SENSOR=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_ADC_TM=y -CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -554,8 +555,6 @@ CONFIG_RPMSG_QCOM_GLINK_SPI=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_SM6150_LLCC=y -CONFIG_QCOM_SDMMAGPIE_LLCC=y CONFIG_QCOM_ATOLL_LLCC=y CONFIG_QCOM_LLCC_PERFMON=m CONFIG_QCOM_QMI_HELPERS=y diff --git a/arch/arm64/configs/vendor/atoll_defconfig b/arch/arm64/configs/vendor/atoll_defconfig index 23927235cf45cf2cfd338676b4d7dbc7a03b4e76..be5758ffd2eb8f5fe055c17fb05b0120dfcf26b1 100644 --- a/arch/arm64/configs/vendor/atoll_defconfig +++ b/arch/arm64/configs/vendor/atoll_defconfig @@ -39,7 +39,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -73,6 +72,7 @@ CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_PRINT_VMEMLAYOUT=y +CONFIG_ARM64_SSBD=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -101,6 +101,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -343,6 +344,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_SERIAL_MSM_WITH_HALF_SAMPLING=y CONFIG_SERIAL_DEV_BUS=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y @@ -367,7 +369,6 @@ CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -CONFIG_PINCTRL_SDMMAGPIE=y CONFIG_PINCTRL_ATOLL=y CONFIG_PINCTRL_SLPI=y CONFIG_GPIO_SYSFS=y @@ -391,11 +392,11 @@ CONFIG_QTI_THERMAL_LIMITS_DCVS=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_AOP_REG_COOLING_DEVICE=y CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_QTI_QMI_SENSOR=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_ADC_TM=y -CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -584,8 +585,6 @@ CONFIG_RPMSG_QCOM_GLINK_SPI=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_SM6150_LLCC=y -CONFIG_QCOM_SDMMAGPIE_LLCC=y CONFIG_QCOM_ATOLL_LLCC=y CONFIG_QCOM_LLCC_PERFMON=m CONFIG_QCOM_QMI_HELPERS=y diff --git a/arch/arm64/configs/vendor/qcs403-perf_defconfig b/arch/arm64/configs/vendor/qcs403-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..cf04736e1c47163ec43c59540341d7b8b69ced11 --- /dev/null +++ b/arch/arm64/configs/vendor/qcs403-perf_defconfig @@ -0,0 +1,554 @@ +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_QCS403=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_NR_CPUS=4 +CONFIG_PREEMPT=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_ARP=y +CONFIG_BRIDGE_EBT_IP=y +CONFIG_BRIDGE_EBT_IP6=y +CONFIG_BRIDGE_EBT_ARPREPLY=y +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_USB=y +CONFIG_RMNET_USB=y +CONFIG_BT=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_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_DEBUGFS=y +CONFIG_RFKILL=y +CONFIG_NTAG_NQ=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +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 +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AT803X_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_HS=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_QCS405=y +CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_RPM_SMD_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_RC_DEVICES=y +CONFIG_IR_MSM_GENI=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_PLATFORM=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y +CONFIG_FB_MSM_MDSS_RGB_PANEL=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_USB_TYPEC_MUX_NXP5150A=y +CONFIG_USB_QCOM_DIAG_BRIDGE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MSM_SNPS_FEMTO_PHY=y +CONFIG_USB_MSM_SSPHY=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=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 +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MDM_DEBUGCC_QCS405=y +CONFIG_CLOCK_CPU_QCS405=y +CONFIG_QCS_CMN_BLK_PLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_ARM_ARCH_TIMER_VCT_ACCESS=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_TZ_SMMU=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_MSM_JTAGV8=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_PM=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +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 +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_IPC_LOGGING=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/qcs403_defconfig b/arch/arm64/configs/vendor/qcs403_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..c859d4b29da2503e3d7f060100236ed362f81fd9 --- /dev/null +++ b/arch/arm64/configs/vendor/qcs403_defconfig @@ -0,0 +1,604 @@ +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_QCS403=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_NR_CPUS=4 +CONFIG_PREEMPT=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_ARP=y +CONFIG_BRIDGE_EBT_IP=y +CONFIG_BRIDGE_EBT_IP6=y +CONFIG_BRIDGE_EBT_ARPREPLY=y +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_USB=y +CONFIG_RMNET_USB=y +CONFIG_BT=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_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_DEBUGFS=y +CONFIG_RFKILL=y +CONFIG_NTAG_NQ=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +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 +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AT803X_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_DEBUG=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_QCS405=y +CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_RPM_SMD_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_RC_DEVICES=y +CONFIG_IR_MSM_GENI=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_PLATFORM=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y +CONFIG_FB_MSM_MDSS_RGB_PANEL=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_USB_TYPEC_MUX_NXP5150A=y +CONFIG_USB_QCOM_DIAG_BRIDGE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MSM_SNPS_FEMTO_PHY=y +CONFIG_USB_MSM_SSPHY=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=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 +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MDM_DEBUGCC_QCS405=y +CONFIG_CLOCK_CPU_QCS405=y +CONFIG_QCS_CMN_BLK_PLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_ARM_ARCH_TIMER_VCT_ACCESS=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_DEBUG_LAR_UNLOCK=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_TZ_SMMU=y +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_PM=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +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 +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm64/configs/vendor/qcs405-perf_defconfig b/arch/arm64/configs/vendor/qcs405-perf_defconfig index 705577dab1fbdbc7607e2eadd46372b3789f6268..566555ddcfea82afab007637daf6c25d1a7a11fe 100644 --- a/arch/arm64/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs405-perf_defconfig @@ -21,7 +21,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_DEFAULT_USE_ENERGY_AWARE=y -CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y @@ -208,10 +207,17 @@ CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_DEBUGFS=y CONFIG_RFKILL=y CONFIG_NTAG_NQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y @@ -259,8 +265,15 @@ CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_USB_NET_SMSC75XX=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y diff --git a/arch/arm64/configs/vendor/qcs405_defconfig b/arch/arm64/configs/vendor/qcs405_defconfig index 4f9f43edd4fdbf649f7f788adba82ad0c67869e1..ac035ea258f5457861a7e766e75b6b269ab01021 100644 --- a/arch/arm64/configs/vendor/qcs405_defconfig +++ b/arch/arm64/configs/vendor/qcs405_defconfig @@ -213,10 +213,18 @@ CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_DEBUGFS=y CONFIG_RFKILL=y CONFIG_NTAG_NQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y @@ -264,8 +272,15 @@ CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_USB_NET_SMSC75XX=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig index 9d0eb2b5db78f02f1a9c075e06dff5e055a7db5a..43f066057da59ae4beb645a83099e58cd25eedd6 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig @@ -308,7 +308,9 @@ CONFIG_SPI=y CONFIG_SPI_QCOM_GENI=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SM8150=y CONFIG_PINCTRL_SDMSHRIKE=y CONFIG_PINCTRL_SM6150=y @@ -322,11 +324,13 @@ CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_STUB=y +CONFIG_VIRTIO_REGULATOR=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y @@ -390,6 +394,17 @@ CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y CONFIG_RTC_CLASS=y CONFIG_DMADEVICES=y CONFIG_UIO=y @@ -404,6 +419,7 @@ CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y CONFIG_COMMON_CLK_QCOM=y CONFIG_QCOM_CLK_VIRT=y +CONFIG_VIRTIO_CLK=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_FAST=y @@ -421,6 +437,8 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_EXTCON_USB_GPIO=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig index ef71e9d141f40506169312cf8818636f2ec8b340..42e89099a1034b63ee2f04fef7cccbf3fa19220c 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig @@ -320,7 +320,9 @@ CONFIG_SPI=y CONFIG_SPI_QCOM_GENI=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SM8150=y CONFIG_PINCTRL_SDMSHRIKE=y CONFIG_PINCTRL_SM6150=y @@ -334,11 +336,13 @@ CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_STUB=y +CONFIG_VIRTIO_REGULATOR=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y @@ -403,6 +407,18 @@ CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y CONFIG_RTC_CLASS=y CONFIG_DMADEVICES=y CONFIG_UIO=y @@ -417,6 +433,7 @@ CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y CONFIG_COMMON_CLK_QCOM=y CONFIG_QCOM_CLK_VIRT=y +CONFIG_VIRTIO_CLK=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_FAST=y @@ -434,6 +451,8 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_EXTCON_USB_GPIO=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm64/configs/vendor/sa2150p-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..763c76f695002747447245f82c970fa572ca0036 --- /dev/null +++ b/arch/arm64/configs/vendor/sa2150p-perf_defconfig @@ -0,0 +1,558 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_QCS405=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_NR_CPUS=4 +CONFIG_PREEMPT=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_ARP=y +CONFIG_BRIDGE_EBT_IP=y +CONFIG_BRIDGE_EBT_IP6=y +CONFIG_BRIDGE_EBT_ARPREPLY=y +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_USB=y +CONFIG_RMNET_USB=y +CONFIG_BT=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_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_DEBUGFS=y +CONFIG_RFKILL=y +CONFIG_NTAG_NQ=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +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 +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AT803X_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_HS=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_QCS405=y +CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_RPM_SMD_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_RC_DEVICES=y +CONFIG_IR_MSM_GENI=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_PLATFORM=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y +CONFIG_FB_MSM_MDSS_RGB_PANEL=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_USB_TYPEC_MUX_NXP5150A=y +CONFIG_USB_QCOM_DIAG_BRIDGE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MSM_SNPS_FEMTO_PHY=y +CONFIG_USB_MSM_SSPHY=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=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 +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MDM_DEBUGCC_QCS405=y +CONFIG_CLOCK_CPU_QCS405=y +CONFIG_QCS_CMN_BLK_PLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_ARM_ARCH_TIMER_VCT_ACCESS=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_TZ_SMMU=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_MSM_JTAGV8=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_PM=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +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 +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_IPC_LOGGING=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/sa2150p_defconfig b/arch/arm64/configs/vendor/sa2150p_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..f725b5d3683bb553a51064ffe817b92086f587dc --- /dev/null +++ b/arch/arm64/configs/vendor/sa2150p_defconfig @@ -0,0 +1,608 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_QCS405=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_NR_CPUS=4 +CONFIG_PREEMPT=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_ARP=y +CONFIG_BRIDGE_EBT_IP=y +CONFIG_BRIDGE_EBT_IP6=y +CONFIG_BRIDGE_EBT_ARPREPLY=y +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_USB=y +CONFIG_RMNET_USB=y +CONFIG_BT=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_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_DEBUGFS=y +CONFIG_RFKILL=y +CONFIG_NTAG_NQ=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +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 +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AT803X_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_DEBUG=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_QCS405=y +CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_RPM_SMD_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_RC_DEVICES=y +CONFIG_IR_MSM_GENI=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_PLATFORM=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y +CONFIG_FB_MSM_MDSS_RGB_PANEL=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_USB_TYPEC_MUX_NXP5150A=y +CONFIG_USB_QCOM_DIAG_BRIDGE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MSM_SNPS_FEMTO_PHY=y +CONFIG_USB_MSM_SSPHY=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=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 +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MDM_DEBUGCC_QCS405=y +CONFIG_CLOCK_CPU_QCS405=y +CONFIG_QCS_CMN_BLK_PLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_ARM_ARCH_TIMER_VCT_ACCESS=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_DEBUG_LAR_UNLOCK=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_TZ_SMMU=y +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_PM=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +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 +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index 33156827a505779669c3813ac290b054b7e5f887..ca9ff962ff294a5776c860793f074af6e89a21d5 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -67,7 +67,6 @@ CONFIG_HZ_100=y CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set # CONFIG_HARDEN_BRANCH_PREDICTOR is not set CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y @@ -80,7 +79,6 @@ 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 CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -301,6 +299,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y @@ -310,6 +309,9 @@ CONFIG_CNSS2_DEBUG=y CONFIG_CNSS2_QMI=y CONFIG_CNSS_ASYNC=y CONFIG_CNSS_GENL=y +CONFIG_NVM=y +CONFIG_NVM_RRPC=y +CONFIG_NVM_PBLK=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm64/configs/vendor/sa8155_defconfig b/arch/arm64/configs/vendor/sa8155_defconfig index 5596252e06a8e1faabf90ed74cb8975a467a7c9e..940dbf4ca5929002a49cd70c9e7997fb7b7b65c1 100644 --- a/arch/arm64/configs/vendor/sa8155_defconfig +++ b/arch/arm64/configs/vendor/sa8155_defconfig @@ -73,7 +73,6 @@ CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set # CONFIG_HARDEN_BRANCH_PREDICTOR is not set CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y @@ -86,7 +85,8 @@ 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 +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="/dev/sda7" CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -312,6 +312,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y @@ -321,6 +322,9 @@ CONFIG_CNSS2_DEBUG=y CONFIG_CNSS2_QMI=y CONFIG_CNSS_ASYNC=y CONFIG_CNSS_GENL=y +CONFIG_NVM=y +CONFIG_NVM_RRPC=y +CONFIG_NVM_PBLK=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm64/configs/vendor/sdmshrike-perf_defconfig b/arch/arm64/configs/vendor/sdmshrike-perf_defconfig index d2b5346cb894f0b86f4bbc58552decd0de72fd41..df3b04bcccb784b291f73b245abd26a3cf884d11 100644 --- a/arch/arm64/configs/vendor/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmshrike-perf_defconfig @@ -270,6 +270,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y diff --git a/arch/arm64/configs/vendor/sdmshrike_defconfig b/arch/arm64/configs/vendor/sdmshrike_defconfig index e0cdaf032fc9d9864a4eaabe39793ffd73a759df..415ff0c6156ed697e15a424b68ee51c5abb05e66 100644 --- a/arch/arm64/configs/vendor/sdmshrike_defconfig +++ b/arch/arm64/configs/vendor/sdmshrike_defconfig @@ -283,6 +283,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig index 2ee606b3211fb62ab9638411b49418312d865a21..a449ce2f488074b85ca81e94ee43adc9f811387f 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig @@ -236,6 +236,7 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y CONFIG_QRTR_USB=y CONFIG_RMNET_USB=y CONFIG_SOCKEV_NLMCAST=y @@ -249,6 +250,8 @@ CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_REGMAP_WCD_IRQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y @@ -306,6 +309,8 @@ CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_CNSS2=y +CONFIG_CNSS2_QMI=y +CONFIG_CNSS_ASYNC=y CONFIG_CNSS_UTILS=y CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y @@ -510,11 +515,7 @@ CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y -CONFIG_IPA3=y -CONFIG_IPA_WDI_UNIFIED_API=y -CONFIG_RMNET_IPA3=y -CONFIG_RNDIS_IPA=y -CONFIG_IPA_UT=y +CONFIG_GSI=y CONFIG_MSM_11AD=m CONFIG_QCOM_MDSS_PLL=y CONFIG_SPMI_PMIC_CLKDIV=y @@ -639,6 +640,9 @@ CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig b/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig index f6e53d4cf14f2dc15ef3fd9f0d8728f3aef368d4..1ddb89cc282fe1e70d8792d6d1e115c7f1d8a09a 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig @@ -244,6 +244,7 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y CONFIG_QRTR_USB=y CONFIG_RMNET_USB=y CONFIG_SOCKEV_NLMCAST=y @@ -258,11 +259,14 @@ CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y CONFIG_NFC_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_REGMAP_WCD_IRQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -316,6 +320,8 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_CNSS2=y CONFIG_CNSS2_DEBUG=y +CONFIG_CNSS2_QMI=y +CONFIG_CNSS_ASYNC=y CONFIG_CNSS_UTILS=y CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y @@ -371,6 +377,7 @@ CONFIG_PINCTRL_SDMMAGPIE=y CONFIG_PINCTRL_SM6150=y CONFIG_PINCTRL_SLPI=y CONFIG_GPIO_SYSFS=y +CONFIG_GNSS_SIRF=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y @@ -533,12 +540,7 @@ CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y -CONFIG_IPA3=y -CONFIG_IPA_DEBUG=y -CONFIG_IPA_WDI_UNIFIED_API=y -CONFIG_RMNET_IPA3=y -CONFIG_RNDIS_IPA=y -CONFIG_IPA_UT=y +CONFIG_GSI=y CONFIG_MSM_11AD=m CONFIG_QCOM_MDSS_PLL=y CONFIG_SPMI_PMIC_CLKDIV=y @@ -668,6 +670,9 @@ CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 3ce011349ca1ac98a7b09c6dc95d69c1eaab41db..c560420f7c1ec0cdc849a696fad7fb7d71ee5b8f 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -37,7 +37,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -67,7 +66,6 @@ CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -97,6 +95,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index aa236990de168e4b32e5a5d44f7ab220df616b70..b83c506497a7b3468a0b2f2a4a8c8a61a0b75c08 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -39,7 +39,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -72,7 +71,6 @@ CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y @@ -103,6 +101,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index dd384cb57a31e4062d3219312a234066e640817a..1105ae35f0dcdca7150dbb097a16647afe0a557f 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -38,7 +38,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -74,7 +73,6 @@ CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y CONFIG_OKL4_GUEST=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -82,12 +80,10 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -105,6 +101,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -267,6 +264,7 @@ CONFIG_MHI_NETDEV=y CONFIG_MHI_UCI=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y @@ -312,6 +310,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y CONFIG_USB_LAN78XX=y CONFIG_USB_USBNET=y CONFIG_WIL6210=m @@ -516,6 +515,7 @@ CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y CONFIG_RNDIS_IPA=y +CONFIG_IPA3_MHI_PROXY=y CONFIG_IPA3_MHI_PRIME_MANAGER=y CONFIG_IPA_UT=y CONFIG_MSM_11AD=m @@ -563,6 +563,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 diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 8d17e3d7064803f4a5db7d0fc8d32c8a787a9f6e..0aa80bf5bdff1602245ec91cb3aba2d0082f9b66 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -40,7 +40,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -80,7 +79,6 @@ CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y CONFIG_OKL4_GUEST=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y @@ -88,12 +86,10 @@ CONFIG_CP15_BARRIER_EMULATION=y 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_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -112,6 +108,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -278,6 +275,7 @@ CONFIG_MHI_NETDEV=y CONFIG_MHI_UCI=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y @@ -323,6 +321,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y CONFIG_USB_LAN78XX=y CONFIG_USB_USBNET=y CONFIG_WIL6210=m @@ -540,6 +539,7 @@ CONFIG_IPA_DEBUG=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y CONFIG_RNDIS_IPA=y +CONFIG_IPA3_MHI_PROXY=y CONFIG_IPA3_MHI_PRIME_MANAGER=y CONFIG_IPA_UT=y CONFIG_MSM_11AD=m @@ -588,6 +588,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 diff --git a/arch/arm64/configs/vendor/trinket-perf_defconfig b/arch/arm64/configs/vendor/trinket-perf_defconfig index 87cb508d09735e1abfde70d0f6d4faea89e3723b..797f8f1fba9a20ab6f4050ead1b86645b271c8bd 100644 --- a/arch/arm64/configs/vendor/trinket-perf_defconfig +++ b/arch/arm64/configs/vendor/trinket-perf_defconfig @@ -38,7 +38,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -72,7 +71,6 @@ CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -81,10 +79,8 @@ CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_PAN is not set # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -102,6 +98,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -260,6 +257,7 @@ CONFIG_DMA_CMA=y CONFIG_ZRAM=y CONFIG_ZRAM_DEDUP=y CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y @@ -303,6 +301,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig index e90883cb6c1d7441d7ce38056d7a42ea78ca2031..b9019ce1f73d9723c797dcfb877b749e6a802099 100644 --- a/arch/arm64/configs/vendor/trinket_defconfig +++ b/arch/arm64/configs/vendor/trinket_defconfig @@ -40,7 +40,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -77,7 +76,6 @@ CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y @@ -87,10 +85,8 @@ CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_PAN is not set # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -109,6 +105,7 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -269,6 +266,7 @@ CONFIG_DMA_CMA=y CONFIG_ZRAM=y CONFIG_ZRAM_DEDUP=y CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y @@ -314,6 +312,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index ab1149efda437496dc2f62ca8fe9fd73e3f00407..8bd1be2f4d79ba4c7fdc3c11433d02bc6f020978 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -46,7 +46,8 @@ #define ARM64_HW_DBM 26 #define ARM64_SSBD 27 #define ARM64_MISMATCHED_CACHE_TYPE 28 +#define ARM64_SSBS 29 -#define ARM64_NCAPS 29 +#define ARM64_NCAPS 30 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index fd740b045113fc88b140d6867241f58938e27291..a576942f8b76824682c84dcf646bf6bbc37b4d4f 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -43,7 +43,8 @@ #define ESR_ELx_EC_HVC64 (0x16) #define ESR_ELx_EC_SMC64 (0x17) #define ESR_ELx_EC_SYS64 (0x18) -/* Unallocated EC: 0x19 - 0x1E */ +#define ESR_ELx_EC_SVE (0x19) +/* Unallocated EC: 0x1A - 0x1E */ #define ESR_ELx_EC_IMP_DEF (0x1f) #define ESR_ELx_EC_IABT_LOW (0x20) #define ESR_ELx_EC_IABT_CUR (0x21) diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 07fe2479d3105da29feafcb57a209d3942e6dca3..fd1e722f38215f70a63645104715461e5edf676f 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -30,8 +30,8 @@ do { \ " prfm pstl1strm, %2\n" \ "1: ldxr %w1, %2\n" \ insn "\n" \ -"2: stlxr %w3, %w0, %2\n" \ -" cbnz %w3, 1b\n" \ +"2: stlxr %w0, %w3, %2\n" \ +" cbnz %w0, 1b\n" \ " dmb ish\n" \ "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ @@ -57,23 +57,23 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("mov %w0, %w4", + __futex_atomic_op("mov %w3, %w4", ret, oldval, uaddr, tmp, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("add %w0, %w1, %w4", + __futex_atomic_op("add %w3, %w1, %w4", ret, oldval, uaddr, tmp, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("orr %w0, %w1, %w4", + __futex_atomic_op("orr %w3, %w1, %w4", ret, oldval, uaddr, tmp, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and %w0, %w1, %w4", + __futex_atomic_op("and %w3, %w1, %w4", ret, oldval, uaddr, tmp, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("eor %w0, %w1, %w4", + __futex_atomic_op("eor %w3, %w1, %w4", ret, oldval, uaddr, tmp, oparg); break; default: diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 1d6d980f80ac0020f6aeedfd47f8a99896b8fdcb..99e75847606c2994161a9cc213f1c8f7e2d80e56 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -187,6 +187,7 @@ #define CPTR_EL2_TCPAC (1 << 31) #define CPTR_EL2_TTA (1 << 20) #define CPTR_EL2_TFP (1 << CPTR_EL2_TFP_SHIFT) +#define CPTR_EL2_TZ (1 << 8) #define CPTR_EL2_DEFAULT 0x000033ff /* Hyp Debug Configuration Register bits */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index e02c4bd7c68ff8e977e88916c71f6bfce5bdb89e..87653c86b2e6d141440cc211a9066a8f9651cf84 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -147,6 +147,10 @@ static inline void start_thread(struct pt_regs *regs, unsigned long pc, { start_thread_common(regs, pc); regs->pstate = PSR_MODE_EL0t; + + if (arm64_get_ssbd_state() != ARM64_SSBD_FORCE_ENABLE) + regs->pstate |= PSR_SSBS_BIT; + regs->sp = sp; } @@ -163,6 +167,9 @@ static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc, regs->pstate |= COMPAT_PSR_E_BIT; #endif + if (arm64_get_ssbd_state() != ARM64_SSBD_FORCE_ENABLE) + regs->pstate |= COMPAT_PSR_SSBS_BIT; + regs->compat_sp = sp; } #endif diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index 9faaba0064a292d7d6328168798705a6d67930b2..17c7e949e42ce64af7d8ccf7207473a25388a8de 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -50,6 +50,7 @@ #define COMPAT_PSR_I_BIT 0x00000080 #define COMPAT_PSR_A_BIT 0x00000100 #define COMPAT_PSR_E_BIT 0x00000200 +#define COMPAT_PSR_SSBS_BIT 0x00800000 #define COMPAT_PSR_J_BIT 0x01000000 #define COMPAT_PSR_Q_BIT 0x08000000 #define COMPAT_PSR_V_BIT 0x10000000 diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 7bbbba5ae6813d1bdd1cc12ab0e74343b4e1dc46..82e4c7eea8cf46fa5d64904803c4a31d94745598 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -83,13 +83,26 @@ #endif /* CONFIG_BROKEN_GAS_INST */ -#define REG_PSTATE_PAN_IMM sys_reg(0, 0, 4, 0, 4) -#define REG_PSTATE_UAO_IMM sys_reg(0, 0, 4, 0, 3) +/* + * Instructions for modifying PSTATE fields. + * As per Arm ARM for v8-A, Section "C.5.1.3 op0 == 0b00, architectural hints, + * barriers and CLREX, and PSTATE access", ARM DDI 0487 C.a, system instructions + * for accessing PSTATE fields have the following encoding: + * Op0 = 0, CRn = 4 + * Op1, Op2 encodes the PSTATE field modified and defines the constraints. + * CRm = Imm4 for the instruction. + * Rt = 0x1f + */ +#define pstate_field(op1, op2) ((op1) << Op1_shift | (op2) << Op2_shift) +#define PSTATE_Imm_shift CRm_shift + +#define PSTATE_PAN pstate_field(0, 4) +#define PSTATE_UAO pstate_field(0, 3) +#define PSTATE_SSBS pstate_field(3, 1) -#define SET_PSTATE_PAN(x) __emit_inst(0xd5000000 | REG_PSTATE_PAN_IMM | \ - (!!x)<<8 | 0x1f) -#define SET_PSTATE_UAO(x) __emit_inst(0xd5000000 | REG_PSTATE_UAO_IMM | \ - (!!x)<<8 | 0x1f) +#define SET_PSTATE_PAN(x) __emit_inst(0xd500401f | PSTATE_PAN | ((!!x) << PSTATE_Imm_shift)) +#define SET_PSTATE_UAO(x) __emit_inst(0xd500401f | PSTATE_UAO | ((!!x) << PSTATE_Imm_shift)) +#define SET_PSTATE_SSBS(x) __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift)) #define SYS_DC_ISW sys_insn(1, 0, 7, 6, 2) #define SYS_DC_CSW sys_insn(1, 0, 7, 10, 2) @@ -145,6 +158,7 @@ #define SYS_ID_AA64PFR0_EL1 sys_reg(3, 0, 0, 4, 0) #define SYS_ID_AA64PFR1_EL1 sys_reg(3, 0, 0, 4, 1) +#define SYS_ID_AA64ZFR0_EL1 sys_reg(3, 0, 0, 4, 4) #define SYS_ID_AA64DFR0_EL1 sys_reg(3, 0, 0, 5, 0) #define SYS_ID_AA64DFR1_EL1 sys_reg(3, 0, 0, 5, 1) @@ -160,6 +174,8 @@ #define SYS_ACTLR_EL1 sys_reg(3, 0, 1, 0, 1) #define SYS_CPACR_EL1 sys_reg(3, 0, 1, 0, 2) +#define SYS_ZCR_EL1 sys_reg(3, 0, 1, 2, 0) + #define SYS_TTBR0_EL1 sys_reg(3, 0, 2, 0, 0) #define SYS_TTBR1_EL1 sys_reg(3, 0, 2, 0, 1) #define SYS_TCR_EL1 sys_reg(3, 0, 2, 0, 2) @@ -250,6 +266,8 @@ #define SYS_PMCCFILTR_EL0 sys_reg (3, 3, 14, 15, 7) +#define SYS_ZCR_EL2 sys_reg(3, 4, 1, 2, 0) + #define SYS_DACR32_EL2 sys_reg(3, 4, 3, 0, 0) #define SYS_IFSR32_EL2 sys_reg(3, 4, 5, 0, 1) #define SYS_FPEXC32_EL2 sys_reg(3, 4, 5, 3, 0) @@ -296,6 +314,7 @@ #define SYS_ICH_LR15_EL2 __SYS__LR8_EL2(7) /* Common SCTLR_ELx flags. */ +#define SCTLR_ELx_DSSBS (1UL << 44) #define SCTLR_ELx_EE (1 << 25) #define SCTLR_ELx_I (1 << 12) #define SCTLR_ELx_SA (1 << 3) @@ -338,6 +357,7 @@ /* id_aa64pfr0 */ #define ID_AA64PFR0_CSV3_SHIFT 60 #define ID_AA64PFR0_CSV2_SHIFT 56 +#define ID_AA64PFR0_SVE_SHIFT 32 #define ID_AA64PFR0_GIC_SHIFT 24 #define ID_AA64PFR0_ASIMD_SHIFT 20 #define ID_AA64PFR0_FP_SHIFT 16 @@ -346,6 +366,7 @@ #define ID_AA64PFR0_EL1_SHIFT 4 #define ID_AA64PFR0_EL0_SHIFT 0 +#define ID_AA64PFR0_SVE 0x1 #define ID_AA64PFR0_FP_NI 0xf #define ID_AA64PFR0_FP_SUPPORTED 0x0 #define ID_AA64PFR0_ASIMD_NI 0xf @@ -354,6 +375,13 @@ #define ID_AA64PFR0_EL0_64BIT_ONLY 0x1 #define ID_AA64PFR0_EL0_32BIT_64BIT 0x2 +/* id_aa64pfr1 */ +#define ID_AA64PFR1_SSBS_SHIFT 4 + +#define ID_AA64PFR1_SSBS_PSTATE_NI 0 +#define ID_AA64PFR1_SSBS_PSTATE_ONLY 1 +#define ID_AA64PFR1_SSBS_PSTATE_INSNS 2 + /* id_aa64mmfr0 */ #define ID_AA64MMFR0_TGRAN4_SHIFT 28 #define ID_AA64MMFR0_TGRAN64_SHIFT 24 @@ -447,6 +475,20 @@ #endif +/* + * The ZCR_ELx_LEN_* definitions intentionally include bits [8:4] which + * are reserved by the SVE architecture for future expansion of the LEN + * field, with compatible semantics. + */ +#define ZCR_ELx_LEN_SHIFT 0 +#define ZCR_ELx_LEN_SIZE 9 +#define ZCR_ELx_LEN_MASK 0x1ff + +#define CPACR_EL1_ZEN_EL1EN (1 << 16) /* enable EL1 access */ +#define CPACR_EL1_ZEN_EL0EN (1 << 17) /* enable EL0 access, if EL1EN set */ +#define CPACR_EL1_ZEN (CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN) + + /* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */ #define SYS_MPIDR_SAFE_VAL (1UL << 31) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 53f4e5bed353d2736829aef11aea446917d42489..2958518decc374fcdb27f3dfd9d1e6faf4ad2bd9 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -37,6 +37,12 @@ void unregister_undef_hook(struct undef_hook *hook); void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr); +/* + * Move regs->pc to next instruction and do necessary setup before it + * is executed. + */ +void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size); + static inline int __in_irqentry_text(unsigned long ptr) { return ptr >= (unsigned long)&__irqentry_text_start && diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h index f243c57d1670a7e2d1e1144bffb6ab24d26a5561..eed4600efdad3a9c2dcd5e648ebce7b5c9b32230 100644 --- a/arch/arm64/include/uapi/asm/hwcap.h +++ b/arch/arm64/include/uapi/asm/hwcap.h @@ -42,5 +42,6 @@ #define HWCAP_SM4 (1 << 19) #define HWCAP_ASIMDDP (1 << 20) #define HWCAP_SHA512 (1 << 21) +#define HWCAP_SSBS (1 << 22) #endif /* _UAPI__ASM_HWCAP_H */ diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 67d4c33974e886d0a4798e341b2a0c5293a4a4b6..eea58f8ec35516535a14a27c63b67be1616cd180 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -45,6 +45,7 @@ #define PSR_I_BIT 0x00000080 #define PSR_A_BIT 0x00000100 #define PSR_D_BIT 0x00000200 +#define PSR_SSBS_BIT 0x00001000 #define PSR_PAN_BIT 0x00400000 #define PSR_UAO_BIT 0x00800000 #define PSR_Q_BIT 0x08000000 diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index d06fbe4cd38d7423c900aff64b0e728f995478d3..a4dc115d765941afde81e9feed053d994e038fbe 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -431,7 +431,7 @@ static int swp_handler(struct pt_regs *regs, u32 instr) pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", current->comm, (unsigned long)current->pid, regs->pc); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, 4); return 0; fault: @@ -512,7 +512,7 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr) pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n", current->comm, (unsigned long)current->pid, regs->pc); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, 4); return 0; } @@ -586,14 +586,14 @@ static int compat_setend_handler(struct pt_regs *regs, u32 big_endian) static int a32_setend_handler(struct pt_regs *regs, u32 instr) { int rc = compat_setend_handler(regs, (instr >> 9) & 1); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, 4); return rc; } static int t16_setend_handler(struct pt_regs *regs, u32 instr) { int rc = compat_setend_handler(regs, (instr >> 3) & 1); - regs->pc += 2; + arm64_skip_faulting_instruction(regs, 2); return rc; } diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 7617215b8ffc8c233dd54d03fa0eb4a947a523c6..4aa42be3fa2c4e137a6aea7ba780eba2b50ad4cf 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -271,6 +271,14 @@ early_param("ssbd", ssbd_cfg); void arm64_set_ssbd_mitigation(bool state) { + if (this_cpu_has_cap(ARM64_SSBS)) { + if (state) + asm volatile(SET_PSTATE_SSBS(0)); + else + asm volatile(SET_PSTATE_SSBS(1)); + return; + } + switch (psci_ops.conduit) { case PSCI_CONDUIT_HVC: arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_2, state, NULL); @@ -295,6 +303,11 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); + if (this_cpu_has_cap(ARM64_SSBS)) { + required = false; + goto out_printmsg; + } + if (psci_ops.smccc_version == SMCCC_VERSION_1_0) { ssbd_state = ARM64_SSBD_UNKNOWN; return false; @@ -343,7 +356,6 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, switch (ssbd_state) { case ARM64_SSBD_FORCE_DISABLE: - pr_info_once("%s disabled from command-line\n", entry->desc); arm64_set_ssbd_mitigation(false); required = false; break; @@ -356,7 +368,6 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, break; case ARM64_SSBD_FORCE_ENABLE: - pr_info_once("%s forced from command-line\n", entry->desc); arm64_set_ssbd_mitigation(true); required = true; break; @@ -366,6 +377,17 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, break; } +out_printmsg: + switch (ssbd_state) { + case ARM64_SSBD_FORCE_DISABLE: + pr_info_once("%s disabled from command-line\n", entry->desc); + break; + + case ARM64_SSBD_FORCE_ENABLE: + pr_info_once("%s forced from command-line\n", entry->desc); + break; + } + return required; } #endif /* CONFIG_ARM64_SSBD */ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index c48c51012f5a8e12103a0dfd7bdcf4a268fd0205..fa4924bad29031ea9202ac5d496855e8f24675e0 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -142,6 +142,11 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = { ARM64_FTR_END, }; +static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = { + ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_SSBS_SHIFT, 4, ID_AA64PFR1_SSBS_PSTATE_NI), + ARM64_FTR_END, +}; + static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = { S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI), S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI), @@ -341,7 +346,8 @@ static const struct __ftr_reg_entry { /* Op1 = 0, CRn = 0, CRm = 4 */ ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0), - ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_raz), + ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1), + ARM64_FTR_REG(SYS_ID_AA64ZFR0_EL1, ftr_raz), /* Op1 = 0, CRn = 0, CRm = 5 */ ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0), @@ -609,7 +615,6 @@ void update_cpu_features(int cpu, /* * EL3 is not our concern. - * ID_AA64PFR1 is currently RES0. */ taint |= check_update_ftr_reg(SYS_ID_AA64PFR0_EL1, cpu, info->reg_id_aa64pfr0, boot->reg_id_aa64pfr0); @@ -978,6 +983,50 @@ static int cpu_copy_el2regs(void *__unused) return 0; } +#ifdef CONFIG_ARM64_SSBD +static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr) +{ + if (user_mode(regs)) + return 1; + + if (instr & BIT(PSTATE_Imm_shift)) + regs->pstate |= PSR_SSBS_BIT; + else + regs->pstate &= ~PSR_SSBS_BIT; + + regs->pc += 4; + return 0; +} + +static struct undef_hook ssbs_emulation_hook = { + .instr_mask = ~(1U << PSTATE_Imm_shift), + .instr_val = 0xd500401f | PSTATE_SSBS, + .fn = ssbs_emulation_handler, +}; + +static int cpu_enable_ssbs(void *__unsused) +{ + static bool undef_hook_registered = false; + static DEFINE_SPINLOCK(hook_lock); + + spin_lock(&hook_lock); + if (!undef_hook_registered) { + register_undef_hook(&ssbs_emulation_hook); + undef_hook_registered = true; + } + spin_unlock(&hook_lock); + + if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) { + write_sysreg((read_sysreg(sctlr_el1) | SCTLR_ELx_DSSBS), + sctlr_el1); + arm64_set_ssbd_mitigation(false); + } else { + arm64_set_ssbd_mitigation(true); + } + return 0; +} +#endif /* CONFIG_ARM64_SSBD */ + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -1110,6 +1159,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_hw_dbm, .enable = cpu_enable_hw_dbm, }, +#endif +#ifdef CONFIG_ARM64_SSBD + { + .desc = "Speculative Store Bypassing Safe (SSBS)", + .capability = ARM64_SSBS, + .matches = has_cpuid_feature, + .sys_reg = SYS_ID_AA64PFR1_EL1, + .field_pos = ID_AA64PFR1_SSBS_SHIFT, + .sign = FTR_UNSIGNED, + .min_field_value = ID_AA64PFR1_SSBS_PSTATE_ONLY, + .enable = cpu_enable_ssbs, + }, #endif {}, }; @@ -1148,6 +1209,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_JSCVT), HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FCMA), HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_LRCPC), + HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, HWCAP_SSBS), {}, }; @@ -1504,7 +1566,7 @@ static int emulate_mrs(struct pt_regs *regs, u32 insn) if (!rc) { dst = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RT, insn); pt_regs_write_reg(regs, dst, val); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); } return rc; diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 5bca95fcdfe9cb5f2e2be3257393e052bbff5c1f..1e3fbfb2b977f41aa6724e5142d665a314c4d8d5 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -81,6 +81,7 @@ static const char *const hwcap_str[] = { "sm4", "asimddp", "sha512", + "ssbs", NULL }; diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 7e50aec45858ddf17edfe3d1c4d45b67d1f82f1e..de16794fd64cef946c680a3c5792c7c32124c38e 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -602,7 +602,7 @@ el1_undef: enable_dbg mov x0, sp bl do_undefinstr - ASM_BUG() + kernel_exit 1 el1_dbg: /* * Debug exception handling diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index e31f59db93976478a96ca11c5707171f99afe799..6f3258a9d0ebe319a718ac2e5e89c9fb1f4539f5 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -365,6 +365,10 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, if (IS_ENABLED(CONFIG_ARM64_UAO) && cpus_have_const_cap(ARM64_HAS_UAO)) childregs->pstate |= PSR_UAO_BIT; + + if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) + childregs->pstate |= PSR_SSBS_BIT; + p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; } diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c index 0560738c1d5ccad415d1f50d2ffec56ba7e9ff08..477ede8809c8e2d86019d02a945a43378264db46 100644 --- a/arch/arm64/kernel/ssbd.c +++ b/arch/arm64/kernel/ssbd.c @@ -3,13 +3,31 @@ * Copyright (C) 2018 ARM Ltd, All Rights Reserved. */ +#include #include #include #include +#include #include #include +static void ssbd_ssbs_enable(struct task_struct *task) +{ + u64 val = is_compat_thread(task_thread_info(task)) ? + COMPAT_PSR_SSBS_BIT : PSR_SSBS_BIT; + + task_pt_regs(task)->pstate |= val; +} + +static void ssbd_ssbs_disable(struct task_struct *task) +{ + u64 val = is_compat_thread(task_thread_info(task)) ? + COMPAT_PSR_SSBS_BIT : PSR_SSBS_BIT; + + task_pt_regs(task)->pstate &= ~val; +} + /* * prctl interface for SSBD */ @@ -45,12 +63,14 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) return -EPERM; task_clear_spec_ssb_disable(task); clear_tsk_thread_flag(task, TIF_SSBD); + ssbd_ssbs_enable(task); break; case PR_SPEC_DISABLE: if (state == ARM64_SSBD_FORCE_DISABLE) return -EPERM; task_set_spec_ssb_disable(task); set_tsk_thread_flag(task, TIF_SSBD); + ssbd_ssbs_disable(task); break; case PR_SPEC_FORCE_DISABLE: if (state == ARM64_SSBD_FORCE_DISABLE) @@ -58,6 +78,7 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) task_set_spec_ssb_disable(task); task_set_spec_ssb_force_disable(task); set_tsk_thread_flag(task, TIF_SSBD); + ssbd_ssbs_disable(task); break; default: return -ERANGE; diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 0d7c20f50ec9a0cc6b66c2107731cc46c095ecc4..d1a891023b10239657b8c06cdcffa1d3b6e47576 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -101,13 +101,19 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) { struct stackframe frame; - int skip; + int skip = 0; long cur_state = 0; unsigned long cur_sp = 0; unsigned long cur_fp = 0; pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); + if (regs) { + if (user_mode(regs)) + return; + skip = 1; + } + if (!tsk) tsk = current; @@ -131,7 +137,6 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) frame.graph = tsk->curr_ret_stack; #endif - skip = !!regs; printk("Call trace:\n"); do { if (tsk != current && (cur_state != tsk->state @@ -198,15 +203,13 @@ static int __die(const char *str, int err, struct pt_regs *regs) return ret; print_modules(); - __show_regs(regs); pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n", TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk)); + show_regs(regs); - if (!user_mode(regs)) { - dump_backtrace(regs, tsk); + if (!user_mode(regs)) dump_instr(KERN_EMERG, regs); - } return ret; } @@ -259,6 +262,18 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, } } +void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size) +{ + regs->pc += size; + + /* + * If we were single stepping, we want to get the step exception after + * we return from the trap. + */ + if (user_mode(regs)) + user_fastforward_single_step(current); +} + static LIST_HEAD(undef_hook); static DEFINE_RAW_SPINLOCK(undef_lock); @@ -288,10 +303,12 @@ static int call_undef_hook(struct pt_regs *regs) int (*fn)(struct pt_regs *regs, u32 instr) = NULL; void __user *pc = (void __user *)instruction_pointer(regs); - if (!user_mode(regs)) - return 1; - - if (compat_thumb_mode(regs)) { + if (!user_mode(regs)) { + __le32 instr_le; + if (probe_kernel_address((__force __le32 *)pc, instr_le)) + goto exit; + instr = le32_to_cpu(instr_le); + } else if (compat_thumb_mode(regs)) { /* 16-bit Thumb instruction */ __le16 instr_le; if (get_user(instr_le, (__le16 __user *)pc)) @@ -389,6 +406,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) trace_undef_instr(regs, pc); force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); + BUG_ON(!user_mode(regs)); } int cpu_enable_cache_maint_trap(void *__unused) @@ -450,7 +468,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) if (ret) arm64_notify_segfault(regs, address); else - regs->pc += 4; + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); } static void ctr_read_handler(unsigned int esr, struct pt_regs *regs) @@ -460,7 +478,7 @@ static void ctr_read_handler(unsigned int esr, struct pt_regs *regs) pt_regs_write_reg(regs, rt, val); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); } static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs) @@ -469,7 +487,7 @@ static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs) isb(); pt_regs_write_reg(regs, rt, arch_counter_get_cntvct()); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); } static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs) @@ -477,7 +495,7 @@ static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs) int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; pt_regs_write_reg(regs, rt, arch_timer_get_rate()); - regs->pc += 4; + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); } struct sys64_hook { @@ -684,6 +702,7 @@ static const char *esr_class_str[] = { [ESR_ELx_EC_HVC64] = "HVC (AArch64)", [ESR_ELx_EC_SMC64] = "SMC (AArch64)", [ESR_ELx_EC_SYS64] = "MSR/MRS (AArch64)", + [ESR_ELx_EC_SVE] = "SVE", [ESR_ELx_EC_IMP_DEF] = "EL3 IMP DEF", [ESR_ELx_EC_IABT_LOW] = "IABT (lower EL)", [ESR_ELx_EC_IABT_CUR] = "IABT (current EL)", @@ -842,7 +861,7 @@ static int bug_handler(struct pt_regs *regs, unsigned int esr) } /* If thread survives, skip over the BUG instruction and continue: */ - regs->pc += AARCH64_INSN_SIZE; /* skip BRK and resume */ + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); return DBG_HOOK_HANDLED; } diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 75b611997a524e7848e67d0a10ae18119fb67f36..78ceb2ea71e9ccc3707013356c1aec4ce5c2c531 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -843,6 +843,7 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, { struct vm_struct *area; int ret; + unsigned long pfn = 0; vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, is_dma_coherent(dev, attrs)); @@ -850,20 +851,23 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) return ret; - if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) { + area = find_vm_area(cpu_addr); + + if (area && area->pages) + return iommu_dma_mmap(area->pages, size, vma); + else if (!is_vmalloc_addr(cpu_addr)) + pfn = page_to_pfn(virt_to_page(cpu_addr)); + else if (is_vmalloc_addr(cpu_addr)) /* - * DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped, - * hence in the vmalloc space. + * DMA_ATTR_FORCE_CONTIGUOUS and atomic pool allocations are + * always remapped, hence in the vmalloc space. */ - unsigned long pfn = vmalloc_to_pfn(cpu_addr); - return __swiotlb_mmap_pfn(vma, pfn, size); - } + pfn = vmalloc_to_pfn(cpu_addr); - area = find_vm_area(cpu_addr); - if (WARN_ON(!area || !area->pages)) - return -ENXIO; + if (pfn) + return __swiotlb_mmap_pfn(vma, pfn, size); - return iommu_dma_mmap(area->pages, size, vma); + return -ENXIO; } static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt, @@ -871,22 +875,24 @@ static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt, size_t size, unsigned long attrs) { unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct page *page = NULL; struct vm_struct *area = find_vm_area(cpu_addr); - if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) { + if (area && area->pages) + return sg_alloc_table_from_pages(sgt, area->pages, count, 0, + size, GFP_KERNEL); + else if (!is_vmalloc_addr(cpu_addr)) + page = virt_to_page(cpu_addr); + else if (is_vmalloc_addr(cpu_addr)) /* - * DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped, - * hence in the vmalloc space. + * DMA_ATTR_FORCE_CONTIGUOUS and atomic pool allocations + * are always remapped, hence in the vmalloc space. */ - struct page *page = vmalloc_to_page(cpu_addr); - return __swiotlb_get_sgtable_page(sgt, page, size); - } + page = vmalloc_to_page(cpu_addr); - if (WARN_ON(!area || !area->pages)) - return -ENXIO; - - return sg_alloc_table_from_pages(sgt, area->pages, count, 0, size, - GFP_KERNEL); + if (page) + return __swiotlb_get_sgtable_page(sgt, page, size); + return -ENXIO; } static void __iommu_sync_single_for_cpu(struct device *dev, diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 9ebe3e2403b1d7b84d66732cd261364208f6020d..c6b2e484d6c11cb9783467b5f8026bade7662ee9 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -125,7 +125,7 @@ trace_a_syscall: subu t1, v0, __NR_O32_Linux move a1, v0 bnez t1, 1f /* __NR_syscall at offset 0 */ - lw a1, PT_R4(sp) /* Arg1 for __NR_syscall case */ + ld a1, PT_R4(sp) /* Arg1 for __NR_syscall case */ .set pop 1: jal syscall_trace_enter diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h index 46da07670c2bea266084945fd9ff4f5a42b25c58..c8f70f965e8ecfe75f121dcad42b07c7cc7a0834 100644 --- a/arch/parisc/include/asm/ptrace.h +++ b/arch/parisc/include/asm/ptrace.h @@ -22,7 +22,7 @@ unsigned long profile_pc(struct pt_regs *); static inline unsigned long regs_return_value(struct pt_regs *regs) { - return regs->gr[20]; + return regs->gr[28]; } #endif diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index cad3e8661cd6cf1895c8b69605dbdad730a4c8e6..4d712c1d64b8eee33c8a8b721e7b071d2a92e32a 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -209,12 +209,6 @@ void __cpuidle arch_cpu_idle(void) static int __init parisc_idle_init(void) { - const char *marker; - - /* check QEMU/SeaBIOS marker in PAGE0 */ - marker = (char *) &PAGE0->pad0; - running_on_qemu = (memcmp(marker, "SeaBIOS", 8) == 0); - if (!running_on_qemu) cpu_idle_poll_ctrl(1); diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index f7d0c3b33d70a53b5350729f1e3d59b2e803749b..550f80ae9c8f1fa12acb56fb234e0be13280994a 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -406,6 +406,9 @@ void __init start_parisc(void) int ret, cpunum; struct pdc_coproc_cfg coproc_cfg; + /* check QEMU/SeaBIOS marker in PAGE0 */ + running_on_qemu = (memcmp(&PAGE0->pad0, "SeaBIOS", 8) == 0); + cpunum = smp_processor_id(); set_firmware_width_unlocked(); diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 9ad37f827a975f1f2a7f165447f951c9e2aa8fa7..7b59cc853abf74b19398716b67b260670075170d 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -712,6 +713,12 @@ static void kvm_use_magic_page(void) static __init void kvm_free_tmp(void) { + /* + * Inform kmemleak about the hole in the .bss section since the + * corresponding pages will be unmapped with DEBUG_PAGEALLOC=y. + */ + kmemleak_free_part(&kvm_tmp[kvm_tmp_index], + ARRAY_SIZE(kvm_tmp) - kvm_tmp_index); free_reserved_area(&kvm_tmp[kvm_tmp_index], &kvm_tmp[ARRAY_SIZE(kvm_tmp)], -1, NULL); } diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 0f0b1b2f3b60068ea2a4e9ef9d63526383172841..7caeae73348d328c38f0e8f67d95da55839b8080 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -274,27 +274,16 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) } #ifdef CONFIG_PPC_PSERIES -static s32 prrn_update_scope; - -static void prrn_work_fn(struct work_struct *work) +static void handle_prrn_event(s32 scope) { /* * For PRRN, we must pass the negative of the scope value in * the RTAS event. */ - pseries_devicetree_update(-prrn_update_scope); + pseries_devicetree_update(-scope); numa_update_cpu_topology(false); } -static DECLARE_WORK(prrn_work, prrn_work_fn); - -static void prrn_schedule_update(u32 scope) -{ - flush_work(&prrn_work); - prrn_update_scope = scope; - schedule_work(&prrn_work); -} - static void handle_rtas_event(const struct rtas_error_log *log) { if (rtas_error_type(log) != RTAS_TYPE_PRRN || !prrn_is_enabled()) @@ -303,7 +292,7 @@ static void handle_rtas_event(const struct rtas_error_log *log) /* For PRRN Events the extended log length is used to denote * the scope for calling rtas update-nodes. */ - prrn_schedule_update(rtas_error_extended_log_length(log)); + handle_prrn_event(rtas_error_extended_log_length(log)); } #else diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 979b9463e17bc7e7f4c74e4737eb9bb560285e43..927384d85fafb2531ad248bedf3701df49f0f1cd 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -746,12 +746,25 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, if (restore_tm_sigcontexts(current, &uc->uc_mcontext, &uc_transact->uc_mcontext)) goto badframe; - } - else - /* Fall through, for non-TM restore */ + } else #endif - if (restore_sigcontext(current, NULL, 1, &uc->uc_mcontext)) - goto badframe; + { + /* + * Fall through, for non-TM restore + * + * Unset MSR[TS] on the thread regs since MSR from user + * context does not have MSR active, and recheckpoint was + * not called since restore_tm_sigcontexts() was not called + * also. + * + * If not unsetting it, the code can RFID to userspace with + * MSR[TS] set, but without CPU in the proper state, + * causing a TM bad thing. + */ + current->thread.regs->msr &= ~MSR_TS_MASK; + if (restore_sigcontext(current, NULL, 1, &uc->uc_mcontext)) + goto badframe; + } if (restore_altstack(&uc->uc_stack)) goto badframe; diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 8baaa6c6f21ce2dd00026496ca648df735b69665..e4db715ebe067dbfbf4aa05a90a7891f18fc8c55 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -328,6 +329,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm, int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT); unsigned long addr, found, prev; struct vm_unmapped_area_info info; + unsigned long min_addr = max(PAGE_SIZE, mmap_min_addr); info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; @@ -344,7 +346,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm, if (high_limit > DEFAULT_MAP_WINDOW) addr += mm->context.addr_limit - DEFAULT_MAP_WINDOW; - while (addr > PAGE_SIZE) { + while (addr > min_addr) { info.high_limit = addr; if (!slice_scan_available(addr - 1, available, 0, &addr)) continue; @@ -356,8 +358,8 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm, * Check if we need to reduce the range, or if we can * extend it to cover the previous available slice. */ - if (addr < PAGE_SIZE) - addr = PAGE_SIZE; + if (addr < min_addr) + addr = min_addr; else if (slice_scan_available(addr - 1, available, 0, &prev)) { addr = prev; goto prev_slice; @@ -479,7 +481,7 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, addr = _ALIGN_UP(addr, page_size); slice_dbg(" aligned addr=%lx\n", addr); /* Ignore hint if it's too large or overlaps a VMA */ - if (addr > high_limit - len || + if (addr > high_limit - len || addr < mmap_min_addr || !slice_area_is_free(mm, addr, len)) addr = 0; } diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 1a61b1b997f2a0da08882411a8b701780fffba9a..3055c030f76579ff5fd45ffc5cb17d483b5f2e0e 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -252,11 +252,14 @@ do { \ /* * Cache aliasing on the latest machines calls for a mapping granularity - * of 512KB. For 64-bit processes use a 512KB alignment and a randomization - * of up to 1GB. For 31-bit processes the virtual address space is limited, - * use no alignment and limit the randomization to 8MB. + * of 512KB for the anonymous mapping base. For 64-bit processes use a + * 512KB alignment and a randomization of up to 1GB. For 31-bit processes + * the virtual address space is limited, use no alignment and limit the + * randomization to 8MB. + * For the additional randomization of the program break use 32MB for + * 64-bit and 8MB for 31-bit. */ -#define BRK_RND_MASK (is_compat_task() ? 0x7ffUL : 0x3ffffUL) +#define BRK_RND_MASK (is_compat_task() ? 0x7ffUL : 0x1fffUL) #define MMAP_RND_MASK (is_compat_task() ? 0x7ffUL : 0x3ff80UL) #define MMAP_ALIGN_MASK (is_compat_task() ? 0 : 0x7fUL) #define STACK_RND_MASK MMAP_RND_MASK diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c index 4feb7c86f4acfb56e18561ffdcd24188a5ba4ee8..5e83ea12303b697732f9b30b74fa56bf7d0e486e 100644 --- a/arch/sh/boards/of-generic.c +++ b/arch/sh/boards/of-generic.c @@ -180,10 +180,10 @@ static struct sh_machine_vector __initmv sh_of_generic_mv = { struct sh_clk_ops; -void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx) +void __init __weak arch_init_clk_ops(struct sh_clk_ops **ops, int idx) { } -void __init plat_irq_setup(void) +void __init __weak plat_irq_setup(void) { } diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 40ed41e328068bb79e96579c87be3ed2b24a634a..6026181cd79e126eb2237d6fe28162fe8e4fc548 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -245,6 +245,15 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables # Avoid indirect branches in kernel to deal with Spectre ifdef CONFIG_RETPOLINE KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) + # Additionally, avoid generating expensive indirect jumps which + # are subject to retpolines for small number of switch cases. + # clang turns off jump table generation by default when under + # retpoline builds, however, gcc does not for x86. This has + # only been fixed starting from gcc stable version 8.4.0 and + # onwards, but not for older ones. See gcc bug #86952. + ifndef CONFIG_CC_IS_CLANG + KBUILD_CFLAGS += $(call cc-option,-fno-jump-tables) + endif endif archscripts: scripts_basic diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index b46c7cfeee3cc7fb354689db2a205a741e44b10b..9b96bb74af0701b60adbf31ed00cdd304f4ce78e 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -82,6 +82,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -89,6 +90,7 @@ CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_MULTIPATH=y CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_NET_IPGRE_DEMUX=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -146,6 +148,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y CONFIG_NETFILTER_XT_MATCH_HELPER=y CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set CONFIG_NETFILTER_XT_MATCH_LENGTH=y CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y @@ -188,6 +191,7 @@ CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y +CONFIG_L2TP=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_NETEM=y @@ -242,6 +246,8 @@ CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y # CONFIG_USB_NET_AX8817X is not set @@ -426,6 +432,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y # CONFIG_PRINT_QUOTA_WARNING is not set CONFIG_QFMT_V2=y CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -472,6 +479,7 @@ CONFIG_CRYPTO_RSA=y # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_ADIANTUM=y CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_AES_NI_INTEL=y CONFIG_CRYPTO_LZ4=y CONFIG_CRYPTO_ZSTD=y CONFIG_CRYPTO_DEV_VIRTIO=y diff --git a/arch/x86/crypto/poly1305-avx2-x86_64.S b/arch/x86/crypto/poly1305-avx2-x86_64.S index 3b6e70d085da89775317c8e2a560625ab4799e01..8457cdd47f751167a2321ebf063eb18bdb4ef8aa 100644 --- a/arch/x86/crypto/poly1305-avx2-x86_64.S +++ b/arch/x86/crypto/poly1305-avx2-x86_64.S @@ -323,6 +323,12 @@ ENTRY(poly1305_4block_avx2) vpaddq t2,t1,t1 vmovq t1x,d4 + # Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 -> + # h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small + # amount. Careful: we must not assume the carry bits 'd0 >> 26', + # 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit + # integers. It's true in a single-block implementation, but not here. + # d1 += d0 >> 26 mov d0,%rax shr $26,%rax @@ -361,16 +367,16 @@ ENTRY(poly1305_4block_avx2) # h0 += (d4 >> 26) * 5 mov d4,%rax shr $26,%rax - lea (%eax,%eax,4),%eax - add %eax,%ebx + lea (%rax,%rax,4),%rax + add %rax,%rbx # h4 = d4 & 0x3ffffff mov d4,%rax and $0x3ffffff,%eax mov %eax,h4 # h1 += h0 >> 26 - mov %ebx,%eax - shr $26,%eax + mov %rbx,%rax + shr $26,%rax add %eax,h1 # h0 = h0 & 0x3ffffff andl $0x3ffffff,%ebx diff --git a/arch/x86/crypto/poly1305-sse2-x86_64.S b/arch/x86/crypto/poly1305-sse2-x86_64.S index c88c670cb5fc6d4b6331ba18882fae34038400b4..5851c7418fb73241cd0f346a2d26f008865c5715 100644 --- a/arch/x86/crypto/poly1305-sse2-x86_64.S +++ b/arch/x86/crypto/poly1305-sse2-x86_64.S @@ -253,16 +253,16 @@ ENTRY(poly1305_block_sse2) # h0 += (d4 >> 26) * 5 mov d4,%rax shr $26,%rax - lea (%eax,%eax,4),%eax - add %eax,%ebx + lea (%rax,%rax,4),%rax + add %rax,%rbx # h4 = d4 & 0x3ffffff mov d4,%rax and $0x3ffffff,%eax mov %eax,h4 # h1 += h0 >> 26 - mov %ebx,%eax - shr $26,%eax + mov %rbx,%rax + shr $26,%rax add %eax,h1 # h0 = h0 & 0x3ffffff andl $0x3ffffff,%ebx @@ -520,6 +520,12 @@ ENTRY(poly1305_2block_sse2) paddq t2,t1 movq t1,d4 + # Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 -> + # h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small + # amount. Careful: we must not assume the carry bits 'd0 >> 26', + # 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit + # integers. It's true in a single-block implementation, but not here. + # d1 += d0 >> 26 mov d0,%rax shr $26,%rax @@ -558,16 +564,16 @@ ENTRY(poly1305_2block_sse2) # h0 += (d4 >> 26) * 5 mov d4,%rax shr $26,%rax - lea (%eax,%eax,4),%eax - add %eax,%ebx + lea (%rax,%rax,4),%rax + add %rax,%rbx # h4 = d4 & 0x3ffffff mov d4,%rax and $0x3ffffff,%eax mov %eax,h4 # h1 += h0 >> 26 - mov %ebx,%eax - shr $26,%eax + mov %rbx,%rax + shr $26,%rax add %eax,h1 # h0 = h0 & 0x3ffffff andl $0x3ffffff,%ebx diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 4505ffe2a505f29dc46f7a32acfcd8a9a9dc9523..839015f1b0de08c801a8184d5cda51d40155f88c 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -48,10 +48,8 @@ targets += $(vdso_img_sodbg) export CPPFLAGS_vdso.lds += -P -C -VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ - -Wl,--no-undefined \ - -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \ - $(DISABLE_LTO) +VDSO_LDFLAGS_vdso.lds = -m elf_x86_64 -soname linux-vdso.so.1 --no-undefined \ + -z max-page-size=4096 $(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE $(call if_changed,vdso) @@ -103,10 +101,8 @@ CFLAGS_REMOVE_vvar.o = -pg # CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds) -VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \ - -Wl,-soname=linux-vdso.so.1 \ - -Wl,-z,max-page-size=4096 \ - -Wl,-z,common-page-size=4096 +VDSO_LDFLAGS_vdsox32.lds = -m elf32_x86_64 -soname linux-vdso.so.1 \ + -z max-page-size=4096 # 64-bit objects to re-brand as x32 vobjs64-for-x32 := $(filter-out $(vobjs-nox32),$(vobjs-y)) @@ -134,7 +130,7 @@ $(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE $(call if_changed,vdso) CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds) -VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1 +VDSO_LDFLAGS_vdso32.lds = -m elf_i386 -soname linux-gate.so.1 # This makes sure the $(obj) subdirectory exists even though vdso32/ # is not a kbuild sub-make subdirectory. @@ -180,14 +176,13 @@ $(obj)/vdso32.so.dbg: FORCE \ # The DSO images are built using a special linker script. # quiet_cmd_vdso = VDSO $@ - cmd_vdso = $(CC) -nostdlib -o $@ \ + cmd_vdso = $(LD) -nostdlib -o $@ \ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ - -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ + -T $(filter %.lds,$^) $(filter %.o,$^) && \ sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' -VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=both) \ - $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS) \ - $(filter --target=% --gcc-toolchain=%,$(KBUILD_CFLAGS)) +VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \ + $(call ld-option, --build-id) -Bsymbolic GCOV_PROFILE := n # diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index c84584bb940280b56f3b7d6d5365803ec4364505..27ade3cb6482ce417e0798d531f1c9ad3cf3c17c 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -3,10 +3,14 @@ #include #include #include +#include #include +#include #include "../perf_event.h" +static DEFINE_PER_CPU(unsigned int, perf_nmi_counter); + static __initconst const u64 amd_hw_cache_event_ids [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] @@ -112,23 +116,144 @@ static __initconst const u64 amd_hw_cache_event_ids }, }; +static __initconst const u64 amd_hw_cache_event_ids_f17h + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { +[C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x0040, /* Data Cache Accesses */ + [C(RESULT_MISS)] = 0xc860, /* L2$ access from DC Miss */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = 0xff5a, /* h/w prefetch DC Fills */ + [C(RESULT_MISS)] = 0, + }, +}, +[C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x0080, /* Instruction cache fetches */ + [C(RESULT_MISS)] = 0x0081, /* Instruction cache misses */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, +}, +[C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, +}, +[C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0xff45, /* All L2 DTLB accesses */ + [C(RESULT_MISS)] = 0xf045, /* L2 DTLB misses (PT walks) */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, +}, +[C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x0084, /* L1 ITLB misses, L2 ITLB hits */ + [C(RESULT_MISS)] = 0xff85, /* L1 ITLB misses, L2 misses */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, +}, +[C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x00c2, /* Retired Branch Instr. */ + [C(RESULT_MISS)] = 0x00c3, /* Retired Mispredicted BI */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, +}, +[C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = 0, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, +}, +}; + /* - * AMD Performance Monitor K7 and later. + * AMD Performance Monitor K7 and later, up to and including Family 16h: */ static const u64 amd_perfmon_event_map[PERF_COUNT_HW_MAX] = { - [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, - [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, - [PERF_COUNT_HW_CACHE_REFERENCES] = 0x077d, - [PERF_COUNT_HW_CACHE_MISSES] = 0x077e, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, - [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, - [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */ - [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */ + [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x077d, + [PERF_COUNT_HW_CACHE_MISSES] = 0x077e, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */ + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */ +}; + +/* + * AMD Performance Monitor Family 17h and later: + */ +static const u64 amd_f17h_perfmon_event_map[PERF_COUNT_HW_MAX] = +{ + [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0xff60, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x0287, + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x0187, }; static u64 amd_pmu_event_map(int hw_event) { + if (boot_cpu_data.x86 >= 0x17) + return amd_f17h_perfmon_event_map[hw_event]; + return amd_perfmon_event_map[hw_event]; } @@ -429,6 +554,132 @@ static void amd_pmu_cpu_dead(int cpu) } } +/* + * When a PMC counter overflows, an NMI is used to process the event and + * reset the counter. NMI latency can result in the counter being updated + * before the NMI can run, which can result in what appear to be spurious + * NMIs. This function is intended to wait for the NMI to run and reset + * the counter to avoid possible unhandled NMI messages. + */ +#define OVERFLOW_WAIT_COUNT 50 + +static void amd_pmu_wait_on_overflow(int idx) +{ + unsigned int i; + u64 counter; + + /* + * Wait for the counter to be reset if it has overflowed. This loop + * should exit very, very quickly, but just in case, don't wait + * forever... + */ + for (i = 0; i < OVERFLOW_WAIT_COUNT; i++) { + rdmsrl(x86_pmu_event_addr(idx), counter); + if (counter & (1ULL << (x86_pmu.cntval_bits - 1))) + break; + + /* Might be in IRQ context, so can't sleep */ + udelay(1); + } +} + +static void amd_pmu_disable_all(void) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + int idx; + + x86_pmu_disable_all(); + + /* + * This shouldn't be called from NMI context, but add a safeguard here + * to return, since if we're in NMI context we can't wait for an NMI + * to reset an overflowed counter value. + */ + if (in_nmi()) + return; + + /* + * Check each counter for overflow and wait for it to be reset by the + * NMI if it has overflowed. This relies on the fact that all active + * counters are always enabled when this function is caled and + * ARCH_PERFMON_EVENTSEL_INT is always set. + */ + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + if (!test_bit(idx, cpuc->active_mask)) + continue; + + amd_pmu_wait_on_overflow(idx); + } +} + +static void amd_pmu_disable_event(struct perf_event *event) +{ + x86_pmu_disable_event(event); + + /* + * This can be called from NMI context (via x86_pmu_stop). The counter + * may have overflowed, but either way, we'll never see it get reset + * by the NMI if we're already in the NMI. And the NMI latency support + * below will take care of any pending NMI that might have been + * generated by the overflow. + */ + if (in_nmi()) + return; + + amd_pmu_wait_on_overflow(event->hw.idx); +} + +/* + * Because of NMI latency, if multiple PMC counters are active or other sources + * of NMIs are received, the perf NMI handler can handle one or more overflowed + * PMC counters outside of the NMI associated with the PMC overflow. If the NMI + * doesn't arrive at the LAPIC in time to become a pending NMI, then the kernel + * back-to-back NMI support won't be active. This PMC handler needs to take into + * account that this can occur, otherwise this could result in unknown NMI + * messages being issued. Examples of this is PMC overflow while in the NMI + * handler when multiple PMCs are active or PMC overflow while handling some + * other source of an NMI. + * + * Attempt to mitigate this by using the number of active PMCs to determine + * whether to return NMI_HANDLED if the perf NMI handler did not handle/reset + * any PMCs. The per-CPU perf_nmi_counter variable is set to a minimum of the + * number of active PMCs or 2. The value of 2 is used in case an NMI does not + * arrive at the LAPIC in time to be collapsed into an already pending NMI. + */ +static int amd_pmu_handle_irq(struct pt_regs *regs) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + int active, handled; + + /* + * Obtain the active count before calling x86_pmu_handle_irq() since + * it is possible that x86_pmu_handle_irq() may make a counter + * inactive (through x86_pmu_stop). + */ + active = __bitmap_weight(cpuc->active_mask, X86_PMC_IDX_MAX); + + /* Process any counter overflows */ + handled = x86_pmu_handle_irq(regs); + + /* + * If a counter was handled, record the number of possible remaining + * NMIs that can occur. + */ + if (handled) { + this_cpu_write(perf_nmi_counter, + min_t(unsigned int, 2, active)); + + return handled; + } + + if (!this_cpu_read(perf_nmi_counter)) + return NMI_DONE; + + this_cpu_dec(perf_nmi_counter); + + return NMI_HANDLED; +} + static struct event_constraint * amd_get_event_constraints(struct cpu_hw_events *cpuc, int idx, struct perf_event *event) @@ -621,11 +872,11 @@ static ssize_t amd_event_sysfs_show(char *page, u64 config) static __initconst const struct x86_pmu amd_pmu = { .name = "AMD", - .handle_irq = x86_pmu_handle_irq, - .disable_all = x86_pmu_disable_all, + .handle_irq = amd_pmu_handle_irq, + .disable_all = amd_pmu_disable_all, .enable_all = x86_pmu_enable_all, .enable = x86_pmu_enable_event, - .disable = x86_pmu_disable_event, + .disable = amd_pmu_disable_event, .hw_config = amd_pmu_hw_config, .schedule_events = x86_schedule_events, .eventsel = MSR_K7_EVNTSEL0, @@ -714,9 +965,10 @@ __init int amd_pmu_init(void) x86_pmu.amd_nb_constraints = 0; } - /* Events are common for all AMDs */ - memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, - sizeof(hw_cache_event_ids)); + if (boot_cpu_data.x86 >= 0x17) + memcpy(hw_cache_event_ids, amd_hw_cache_event_ids_f17h, sizeof(hw_cache_event_ids)); + else + memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, sizeof(hw_cache_event_ids)); return 0; } @@ -728,7 +980,7 @@ void amd_pmu_enable_virt(void) cpuc->perf_ctr_virt_mask = 0; /* Reload all events */ - x86_pmu_disable_all(); + amd_pmu_disable_all(); x86_pmu_enable_all(0); } EXPORT_SYMBOL_GPL(amd_pmu_enable_virt); @@ -746,7 +998,7 @@ void amd_pmu_disable_virt(void) cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY; /* Reload all events */ - x86_pmu_disable_all(); + amd_pmu_disable_all(); x86_pmu_enable_all(0); } EXPORT_SYMBOL_GPL(amd_pmu_disable_virt); diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 65e44f0588e241815f0b6cdd416c13654faaa905..6ed99de2ddf5994e45388e276eab33eb050e1189 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1328,8 +1328,9 @@ void x86_pmu_stop(struct perf_event *event, int flags) struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; - if (__test_and_clear_bit(hwc->idx, cpuc->active_mask)) { + if (test_bit(hwc->idx, cpuc->active_mask)) { x86_pmu.disable(event); + __clear_bit(hwc->idx, cpuc->active_mask); cpuc->events[hwc->idx] = NULL; WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); hwc->state |= PERF_HES_STOPPED; @@ -1426,16 +1427,8 @@ int x86_pmu_handle_irq(struct pt_regs *regs) apic_write(APIC_LVTPC, APIC_DM_NMI); for (idx = 0; idx < x86_pmu.num_counters; idx++) { - if (!test_bit(idx, cpuc->active_mask)) { - /* - * Though we deactivated the counter some cpus - * might still deliver spurious interrupts still - * in flight. Catch them: - */ - if (__test_and_clear_bit(idx, cpuc->running)) - handled++; + if (!test_bit(idx, cpuc->active_mask)) continue; - } event = cpuc->events[idx]; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index dc8f8b3e6cec6666c890c032d2c6672104a96125..99d45660242e35d0413a944f1f8b65b80dc645b9 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3001,7 +3001,7 @@ static unsigned long intel_pmu_free_running_flags(struct perf_event *event) flags &= ~PERF_SAMPLE_TIME; if (!event->attr.exclude_kernel) flags &= ~PERF_SAMPLE_REGS_USER; - if (event->attr.sample_regs_user & ~PEBS_REGS) + if (event->attr.sample_regs_user & ~PEBS_GP_REGS) flags &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR); return flags; } diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 84b3841c131d46567ff068db389544a1ff7cbb3a..bfe16631fd1d724020da0cfdb5bf14fd30cfb7f5 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -95,25 +95,25 @@ struct amd_nb { PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | \ PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER) -#define PEBS_REGS \ - (PERF_REG_X86_AX | \ - PERF_REG_X86_BX | \ - PERF_REG_X86_CX | \ - PERF_REG_X86_DX | \ - PERF_REG_X86_DI | \ - PERF_REG_X86_SI | \ - PERF_REG_X86_SP | \ - PERF_REG_X86_BP | \ - PERF_REG_X86_IP | \ - PERF_REG_X86_FLAGS | \ - PERF_REG_X86_R8 | \ - PERF_REG_X86_R9 | \ - PERF_REG_X86_R10 | \ - PERF_REG_X86_R11 | \ - PERF_REG_X86_R12 | \ - PERF_REG_X86_R13 | \ - PERF_REG_X86_R14 | \ - PERF_REG_X86_R15) +#define PEBS_GP_REGS \ + ((1ULL << PERF_REG_X86_AX) | \ + (1ULL << PERF_REG_X86_BX) | \ + (1ULL << PERF_REG_X86_CX) | \ + (1ULL << PERF_REG_X86_DX) | \ + (1ULL << PERF_REG_X86_DI) | \ + (1ULL << PERF_REG_X86_SI) | \ + (1ULL << PERF_REG_X86_SP) | \ + (1ULL << PERF_REG_X86_BP) | \ + (1ULL << PERF_REG_X86_IP) | \ + (1ULL << PERF_REG_X86_FLAGS) | \ + (1ULL << PERF_REG_X86_R8) | \ + (1ULL << PERF_REG_X86_R9) | \ + (1ULL << PERF_REG_X86_R10) | \ + (1ULL << PERF_REG_X86_R11) | \ + (1ULL << PERF_REG_X86_R12) | \ + (1ULL << PERF_REG_X86_R13) | \ + (1ULL << PERF_REG_X86_R14) | \ + (1ULL << PERF_REG_X86_R15)) /* * Per register state. diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h index 982c325dad3377a4f0d80a5808f4d731a87926a5..8be6afb584715dc8d5a50d1bbd989bf053366294 100644 --- a/arch/x86/include/asm/suspend_32.h +++ b/arch/x86/include/asm/suspend_32.h @@ -12,7 +12,13 @@ /* image of the saved processor state */ struct saved_context { - u16 es, fs, gs, ss; + /* + * On x86_32, all segment registers, with the possible exception of + * gs, are saved at kernel entry in pt_regs. + */ +#ifdef CONFIG_X86_32_LAZY_GS + u16 gs; +#endif unsigned long cr0, cr2, cr3, cr4; u64 misc_enable; bool misc_enable_saved; diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h index 7306e911faee20694908bdf482166546776a7e92..a7af9f53c0cb773d05fd84ebe94525a1971e3ebb 100644 --- a/arch/x86/include/asm/suspend_64.h +++ b/arch/x86/include/asm/suspend_64.h @@ -20,8 +20,20 @@ */ struct saved_context { struct pt_regs regs; - u16 ds, es, fs, gs, ss; - unsigned long gs_base, gs_kernel_base, fs_base; + + /* + * User CS and SS are saved in current_pt_regs(). The rest of the + * segment selectors need to be saved and restored here. + */ + u16 ds, es, fs, gs; + + /* + * Usermode FSBASE and GSBASE may not match the fs and gs selectors, + * so we save them separately. We save the kernelmode GSBASE to + * restore percpu access after resume. + */ + unsigned long kernelmode_gs_base, usermode_gs_base, fs_base; + unsigned long cr0, cr2, cr3, cr4, cr8; u64 misc_enable; bool misc_enable_saved; @@ -30,8 +42,7 @@ struct saved_context { u16 gdt_pad; /* Unused */ struct desc_ptr gdt_desc; u16 idt_pad; - u16 idt_limit; - unsigned long idt_base; + struct desc_ptr idt; u16 ldt; u16 tss; unsigned long tr; diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index bfd882617613923f0db79c4aae82690bda7a8d4f..e7e6254480086442c5b3699e30f2ffdbeb7d2487 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -217,6 +217,9 @@ privcmd_call(unsigned call, __HYPERCALL_DECLS; __HYPERCALL_5ARG(a1, a2, a3, a4, a5); + if (call >= PAGE_SIZE / sizeof(hypercall_page[0])) + return -EINVAL; + stac(); asm volatile(CALL_NOSPEC : __HYPERCALL_5PARAM diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index ec7aedba3d74ce6d4a1ca6467cafd04470f61aaf..5567705e060100766737a28f5edfff46af48b151 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -271,7 +271,7 @@ static const struct { const char *option; enum spectre_v2_user_cmd cmd; bool secure; -} v2_user_options[] __initdata = { +} v2_user_options[] __initconst = { { "auto", SPECTRE_V2_USER_CMD_AUTO, false }, { "off", SPECTRE_V2_USER_CMD_NONE, false }, { "on", SPECTRE_V2_USER_CMD_FORCE, true }, @@ -406,7 +406,7 @@ static const struct { const char *option; enum spectre_v2_mitigation_cmd cmd; bool secure; -} mitigation_options[] __initdata = { +} mitigation_options[] __initconst = { { "off", SPECTRE_V2_CMD_NONE, false }, { "on", SPECTRE_V2_CMD_FORCE, true }, { "retpoline", SPECTRE_V2_CMD_RETPOLINE, false }, @@ -642,7 +642,7 @@ static const char * const ssb_strings[] = { static const struct { const char *option; enum ssb_mitigation_cmd cmd; -} ssb_mitigation_options[] __initdata = { +} ssb_mitigation_options[] __initconst = { { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c index 8949b7ae6d92536c1bbff659d7463588d2bdfb06..fa61c870ada94e6fc01426242d3836766f8d76be 100644 --- a/arch/x86/kernel/cpu/cyrix.c +++ b/arch/x86/kernel/cpu/cyrix.c @@ -124,7 +124,7 @@ static void set_cx86_reorder(void) setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ /* Load/Store Serialize to mem access disable (=reorder it) */ - setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80); + setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80); /* set load/store serialize from 1GB to 4GB */ ccr3 |= 0xe0; setCx86(CX86_CCR3, ccr3); @@ -135,11 +135,11 @@ static void set_cx86_memwb(void) pr_info("Enable Memory-Write-back mode on Cyrix/NSC processor.\n"); /* CCR2 bit 2: unlock NW bit */ - setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04); + setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04); /* set 'Not Write-through' */ write_cr0(read_cr0() | X86_CR0_NW); /* CCR2 bit 2: lock NW bit and set WT1 */ - setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14); + setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14); } /* @@ -153,14 +153,14 @@ static void geode_configure(void) local_irq_save(flags); /* Suspend on halt power saving and enable #SUSP pin */ - setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88); + setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ /* FPU fast, DTE cache, Mem bypass */ - setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38); + setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38); setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ set_cx86_memwb(); @@ -296,7 +296,7 @@ static void init_cyrix(struct cpuinfo_x86 *c) /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { /* Enable cxMMX extensions (GX1 Datasheet 54) */ - setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1); + setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1); /* * GXm : 0x30 ... 0x5f GXm datasheet 51 @@ -319,7 +319,7 @@ static void init_cyrix(struct cpuinfo_x86 *c) if (dir1 > 7) { dir0_msn++; /* M II */ /* Enable MMX extensions (App note 108) */ - setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1); + setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); } else { /* A 6x86MX - it has the bug. */ set_cpu_bug(c, X86_BUG_COMA); diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index c51353569492544c317c318b66385034889aa9b6..20d133ec3ef98558bd0970f5ea232892a68b4c18 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -148,6 +148,11 @@ static struct severity { SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA), KERNEL ), + MCESEV( + PANIC, "Instruction fetch error in kernel", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR), + KERNEL + ), #endif MCESEV( PANIC, "Action required: unknown MCACOD", diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index afa1a204bc6d69029a2520725b174ba201dd7cd7..df767e6de8ddc82e19b945fe74492e06fcf3a0c1 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -909,6 +909,8 @@ int __init hpet_enable(void) return 0; hpet_set_mapping(); + if (!hpet_virt_address) + return 0; /* * Read the period and check for a sane value: diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 8771766d46b6c3e74d914136578f0b8d6f64b5ad..9954a604a8227f53a26e118fa0bcf338b485e5b1 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -352,6 +352,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) #endif default: WARN_ON_ONCE(1); + return -EINVAL; } /* diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 65452d555f0514178528bfc13d96c7bbd8d19cab..56cf6c26325494ea1bf983ffd8b17e17e83bc012 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -553,6 +553,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) unsigned long *sara = stack_addr(regs); ri->ret_addr = (kprobe_opcode_t *) *sara; + ri->fp = sara; /* Replace the return addr with trampoline addr */ *sara = (unsigned long) &kretprobe_trampoline; @@ -754,15 +755,21 @@ __visible __used void *trampoline_handler(struct pt_regs *regs) unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; kprobe_opcode_t *correct_ret_addr = NULL; + void *frame_pointer; + bool skipped = false; INIT_HLIST_HEAD(&empty_rp); kretprobe_hash_lock(current, &head, &flags); /* fixup registers */ #ifdef CONFIG_X86_64 regs->cs = __KERNEL_CS; + /* On x86-64, we use pt_regs->sp for return address holder. */ + frame_pointer = ®s->sp; #else regs->cs = __KERNEL_CS | get_kernel_rpl(); regs->gs = 0; + /* On x86-32, we use pt_regs->flags for return address holder. */ + frame_pointer = ®s->flags; #endif regs->ip = trampoline_address; regs->orig_ax = ~0UL; @@ -784,8 +791,25 @@ __visible __used void *trampoline_handler(struct pt_regs *regs) if (ri->task != current) /* another task is sharing our hash bucket */ continue; + /* + * Return probes must be pushed on this hash list correct + * order (same as return order) so that it can be poped + * correctly. However, if we find it is pushed it incorrect + * order, this means we find a function which should not be + * probed, because the wrong order entry is pushed on the + * path of processing other kretprobe itself. + */ + if (ri->fp != frame_pointer) { + if (!skipped) + pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n"); + skipped = true; + continue; + } orig_ret_address = (unsigned long)ri->ret_addr; + if (skipped) + pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n", + ri->rp->kp.addr); if (orig_ret_address != trampoline_address) /* @@ -803,6 +827,8 @@ __visible __used void *trampoline_handler(struct pt_regs *regs) if (ri->task != current) /* another task is sharing our hash bucket */ continue; + if (ri->fp != frame_pointer) + continue; orig_ret_address = (unsigned long)ri->ret_addr; if (ri->rp && ri->rp->handler) { diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index bc6bc6689e68a7bd602b11849d5d13892b05c982..1c52acaa5becdd140c2242481ba161a6b55f8976 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -596,8 +596,8 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) mpf_base = base; mpf_found = true; - pr_info("found SMP MP-table at [mem %#010lx-%#010lx] mapped at [%p]\n", - base, base + sizeof(*mpf) - 1, mpf); + pr_info("found SMP MP-table at [mem %#010lx-%#010lx]\n", + base, base + sizeof(*mpf) - 1); memblock_reserve(base, sizeof(*mpf)); if (mpf->physptr) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index a98d1cdd6299a5cc3b73f4ee7dd1df8745a5a049..d2ef967bfafb688f377ad77d8ca19d77110db8e9 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -465,10 +465,12 @@ static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk) void speculation_ctrl_update(unsigned long tif) { + unsigned long flags; + /* Forced update. Make sure all relevant TIF flags are different */ - preempt_disable(); + local_irq_save(flags); __speculation_ctrl_update(~tif, tif); - preempt_enable(); + local_irq_restore(flags); } /* Called from seccomp/prctl update */ diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5f758568fc448afc457cc533db6683b7c073fd4f..2bcadfc5b2f080568318a6744874b56d1ebb1ec5 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2588,15 +2588,13 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) * CR0/CR3/CR4/EFER. It's all a bit more complicated if the vCPU * supports long mode. */ - cr4 = ctxt->ops->get_cr(ctxt, 4); if (emulator_has_longmode(ctxt)) { struct desc_struct cs_desc; /* Zero CR4.PCIDE before CR0.PG. */ - if (cr4 & X86_CR4_PCIDE) { + cr4 = ctxt->ops->get_cr(ctxt, 4); + if (cr4 & X86_CR4_PCIDE) ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PCIDE); - cr4 &= ~X86_CR4_PCIDE; - } /* A 32-bit code segment is required to clear EFER.LMA. */ memset(&cs_desc, 0, sizeof(cs_desc)); @@ -2610,13 +2608,16 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) if (cr0 & X86_CR0_PE) ctxt->ops->set_cr(ctxt, 0, cr0 & ~(X86_CR0_PG | X86_CR0_PE)); - /* Now clear CR4.PAE (which must be done before clearing EFER.LME). */ - if (cr4 & X86_CR4_PAE) - ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PAE); + if (emulator_has_longmode(ctxt)) { + /* Clear CR4.PAE before clearing EFER.LME. */ + cr4 = ctxt->ops->get_cr(ctxt, 4); + if (cr4 & X86_CR4_PAE) + ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PAE); - /* And finally go back to 32-bit mode. */ - efer = 0; - ctxt->ops->set_msr(ctxt, MSR_EFER, efer); + /* And finally go back to 32-bit mode. */ + efer = 0; + ctxt->ops->set_msr(ctxt, MSR_EFER, efer); + } smbase = ctxt->ops->get_smbase(ctxt); if (emulator_has_longmode(ctxt)) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index c387047e926a2463a3628b99fa7113bd864bc544..1296e44fd9697fd0f1d68f2880348e0b832e1f0d 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2211,6 +2211,7 @@ static int pf_interception(struct vcpu_svm *svm) static int db_interception(struct vcpu_svm *svm) { struct kvm_run *kvm_run = svm->vcpu.run; + struct kvm_vcpu *vcpu = &svm->vcpu; if (!(svm->vcpu.guest_debug & (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) && @@ -2221,6 +2222,8 @@ static int db_interception(struct vcpu_svm *svm) if (svm->nmi_singlestep) { disable_nmi_singlestep(svm); + /* Make sure we check for pending NMIs upon entry */ + kvm_make_request(KVM_REQ_EVENT, vcpu); } if (svm->vcpu.guest_debug & @@ -4014,14 +4017,25 @@ static int avic_incomplete_ipi_interception(struct vcpu_svm *svm) kvm_lapic_reg_write(apic, APIC_ICR, icrl); break; case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: { + int i; + struct kvm_vcpu *vcpu; + struct kvm *kvm = svm->vcpu.kvm; struct kvm_lapic *apic = svm->vcpu.arch.apic; /* - * Update ICR high and low, then emulate sending IPI, - * which is handled when writing APIC_ICR. + * At this point, we expect that the AVIC HW has already + * set the appropriate IRR bits on the valid target + * vcpus. So, we just need to kick the appropriate vcpu. */ - kvm_lapic_reg_write(apic, APIC_ICR2, icrh); - kvm_lapic_reg_write(apic, APIC_ICR, icrl); + kvm_for_each_vcpu(i, vcpu, kvm) { + bool m = kvm_apic_match_dest(vcpu, apic, + icrl & KVM_APIC_SHORT_MASK, + GET_APIC_DEST_FIELD(icrh), + icrl & KVM_APIC_DEST_MASK); + + if (m && !avic_vcpu_is_running(vcpu)) + kvm_vcpu_wake_up(vcpu); + } break; } case AVIC_IPI_FAILURE_INVALID_TARGET: diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 4bd878c9f7d2ec04fe983b76fad6ea5fce751595..90b7eee6d0f95400a063115079444bb340c9e125 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11846,24 +11846,6 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, kvm_clear_interrupt_queue(vcpu); } -static void load_vmcs12_mmu_host_state(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) -{ - u32 entry_failure_code; - - nested_ept_uninit_mmu_context(vcpu); - - /* - * Only PDPTE load can fail as the value of cr3 was checked on entry and - * couldn't have changed. - */ - if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, &entry_failure_code)) - nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_PDPTE_FAIL); - - if (!enable_ept) - vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; -} - /* * A part of what we need to when the nested L2 guest exits and we want to * run its L1 parent, is to reset L1's guest state to the host state specified @@ -11877,6 +11859,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { struct kvm_segment seg; + u32 entry_failure_code; if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) vcpu->arch.efer = vmcs12->host_ia32_efer; @@ -11903,7 +11886,17 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); vmx_set_cr4(vcpu, vmcs12->host_cr4); - load_vmcs12_mmu_host_state(vcpu, vmcs12); + nested_ept_uninit_mmu_context(vcpu); + + /* + * Only PDPTE load can fail as the value of cr3 was checked on entry and + * couldn't have changed. + */ + if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, &entry_failure_code)) + nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_PDPTE_FAIL); + + if (!enable_ept) + vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; if (enable_vpid) { /* @@ -11994,6 +11987,140 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_MSR_FAIL); } +static inline u64 nested_vmx_get_vmcs01_guest_efer(struct vcpu_vmx *vmx) +{ + struct shared_msr_entry *efer_msr; + unsigned int i; + + if (vm_entry_controls_get(vmx) & VM_ENTRY_LOAD_IA32_EFER) + return vmcs_read64(GUEST_IA32_EFER); + + if (cpu_has_load_ia32_efer) + return host_efer; + + for (i = 0; i < vmx->msr_autoload.guest.nr; ++i) { + if (vmx->msr_autoload.guest.val[i].index == MSR_EFER) + return vmx->msr_autoload.guest.val[i].value; + } + + efer_msr = find_msr_entry(vmx, MSR_EFER); + if (efer_msr) + return efer_msr->data; + + return host_efer; +} + +static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) +{ + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct vmx_msr_entry g, h; + struct msr_data msr; + gpa_t gpa; + u32 i, j; + + vcpu->arch.pat = vmcs_read64(GUEST_IA32_PAT); + + if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) { + /* + * L1's host DR7 is lost if KVM_GUESTDBG_USE_HW_BP is set + * as vmcs01.GUEST_DR7 contains a userspace defined value + * and vcpu->arch.dr7 is not squirreled away before the + * nested VMENTER (not worth adding a variable in nested_vmx). + */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) + kvm_set_dr(vcpu, 7, DR7_FIXED_1); + else + WARN_ON(kvm_set_dr(vcpu, 7, vmcs_readl(GUEST_DR7))); + } + + /* + * Note that calling vmx_set_{efer,cr0,cr4} is important as they + * handle a variety of side effects to KVM's software model. + */ + vmx_set_efer(vcpu, nested_vmx_get_vmcs01_guest_efer(vmx)); + + vcpu->arch.cr0_guest_owned_bits = X86_CR0_TS; + vmx_set_cr0(vcpu, vmcs_readl(CR0_READ_SHADOW)); + + vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); + vmx_set_cr4(vcpu, vmcs_readl(CR4_READ_SHADOW)); + + nested_ept_uninit_mmu_context(vcpu); + vcpu->arch.cr3 = vmcs_readl(GUEST_CR3); + __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); + + /* + * Use ept_save_pdptrs(vcpu) to load the MMU's cached PDPTRs + * from vmcs01 (if necessary). The PDPTRs are not loaded on + * VMFail, like everything else we just need to ensure our + * software model is up-to-date. + */ + ept_save_pdptrs(vcpu); + + kvm_mmu_reset_context(vcpu); + + if (cpu_has_vmx_msr_bitmap()) + vmx_update_msr_bitmap(vcpu); + + /* + * This nasty bit of open coding is a compromise between blindly + * loading L1's MSRs using the exit load lists (incorrect emulation + * of VMFail), leaving the nested VM's MSRs in the software model + * (incorrect behavior) and snapshotting the modified MSRs (too + * expensive since the lists are unbound by hardware). For each + * MSR that was (prematurely) loaded from the nested VMEntry load + * list, reload it from the exit load list if it exists and differs + * from the guest value. The intent is to stuff host state as + * silently as possible, not to fully process the exit load list. + */ + msr.host_initiated = false; + for (i = 0; i < vmcs12->vm_entry_msr_load_count; i++) { + gpa = vmcs12->vm_entry_msr_load_addr + (i * sizeof(g)); + if (kvm_vcpu_read_guest(vcpu, gpa, &g, sizeof(g))) { + pr_debug_ratelimited( + "%s read MSR index failed (%u, 0x%08llx)\n", + __func__, i, gpa); + goto vmabort; + } + + for (j = 0; j < vmcs12->vm_exit_msr_load_count; j++) { + gpa = vmcs12->vm_exit_msr_load_addr + (j * sizeof(h)); + if (kvm_vcpu_read_guest(vcpu, gpa, &h, sizeof(h))) { + pr_debug_ratelimited( + "%s read MSR failed (%u, 0x%08llx)\n", + __func__, j, gpa); + goto vmabort; + } + if (h.index != g.index) + continue; + if (h.value == g.value) + break; + + if (nested_vmx_load_msr_check(vcpu, &h)) { + pr_debug_ratelimited( + "%s check failed (%u, 0x%x, 0x%x)\n", + __func__, j, h.index, h.reserved); + goto vmabort; + } + + msr.index = h.index; + msr.data = h.value; + if (kvm_set_msr(vcpu, &msr)) { + pr_debug_ratelimited( + "%s WRMSR failed (%u, 0x%x, 0x%llx)\n", + __func__, j, h.index, h.value); + goto vmabort; + } + } + } + + return; + +vmabort: + nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_MSR_FAIL); +} + /* * Emulate an exit from nested guest (L2) to L1, i.e., prepare to run L1 * and modify vmcs12 to make it see what it would expect to see there if @@ -12126,7 +12253,13 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, */ nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - load_vmcs12_mmu_host_state(vcpu, vmcs12); + /* + * Restore L1's host state to KVM's software model. We're here + * because a consistency check was caught by hardware, which + * means some amount of guest state has been propagated to KVM's + * model and needs to be unwound to the host's state. + */ + nested_vmx_restore_host_state(vcpu); /* * The emulated instruction was already skipped in diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index 04d5157fe7f8f3de4b43e7056a9317fde7c61931..a7d966964c6f20577c927cf5e618bc86b3331977 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -82,12 +82,8 @@ static void __save_processor_state(struct saved_context *ctxt) /* * descriptor tables */ -#ifdef CONFIG_X86_32 store_idt(&ctxt->idt); -#else -/* CONFIG_X86_64 */ - store_idt((struct desc_ptr *)&ctxt->idt_limit); -#endif + /* * We save it here, but restore it only in the hibernate case. * For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit @@ -103,22 +99,18 @@ static void __save_processor_state(struct saved_context *ctxt) /* * segment registers */ -#ifdef CONFIG_X86_32 - savesegment(es, ctxt->es); - savesegment(fs, ctxt->fs); +#ifdef CONFIG_X86_32_LAZY_GS savesegment(gs, ctxt->gs); - savesegment(ss, ctxt->ss); -#else -/* CONFIG_X86_64 */ - asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds)); - asm volatile ("movw %%es, %0" : "=m" (ctxt->es)); - asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs)); - asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs)); - asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss)); +#endif +#ifdef CONFIG_X86_64 + savesegment(gs, ctxt->gs); + savesegment(fs, ctxt->fs); + savesegment(ds, ctxt->ds); + savesegment(es, ctxt->es); rdmsrl(MSR_FS_BASE, ctxt->fs_base); - rdmsrl(MSR_GS_BASE, ctxt->gs_base); - rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); + rdmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base); + rdmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base); mtrr_save_fixed_ranges(NULL); rdmsrl(MSR_EFER, ctxt->efer); @@ -180,6 +172,9 @@ static void fix_processor_context(void) write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS); syscall_init(); /* This sets MSR_*STAR and related */ +#else + if (boot_cpu_has(X86_FEATURE_SEP)) + enable_sep_cpu(); #endif load_TR_desc(); /* This does ltr */ load_mm_ldt(current->active_mm); /* This does lldt */ @@ -192,9 +187,12 @@ static void fix_processor_context(void) } /** - * __restore_processor_state - restore the contents of CPU registers saved - * by __save_processor_state() - * @ctxt - structure to load the registers contents from + * __restore_processor_state - restore the contents of CPU registers saved + * by __save_processor_state() + * @ctxt - structure to load the registers contents from + * + * The asm code that gets us here will have restored a usable GDT, although + * it will be pointing to the wrong alias. */ static void notrace __restore_processor_state(struct saved_context *ctxt) { @@ -217,46 +215,52 @@ static void notrace __restore_processor_state(struct saved_context *ctxt) write_cr2(ctxt->cr2); write_cr0(ctxt->cr0); + /* Restore the IDT. */ + load_idt(&ctxt->idt); + /* - * now restore the descriptor tables to their proper values - * ltr is done i fix_processor_context(). + * Just in case the asm code got us here with the SS, DS, or ES + * out of sync with the GDT, update them. */ -#ifdef CONFIG_X86_32 - load_idt(&ctxt->idt); + loadsegment(ss, __KERNEL_DS); + loadsegment(ds, __USER_DS); + loadsegment(es, __USER_DS); + + /* + * Restore percpu access. Percpu access can happen in exception + * handlers or in complicated helpers like load_gs_index(). + */ +#ifdef CONFIG_X86_64 + wrmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base); #else -/* CONFIG_X86_64 */ - load_idt((const struct desc_ptr *)&ctxt->idt_limit); + loadsegment(fs, __KERNEL_PERCPU); + loadsegment(gs, __KERNEL_STACK_CANARY); #endif + /* Restore the TSS, RO GDT, LDT, and usermode-relevant MSRs. */ + fix_processor_context(); + /* - * segment registers + * Now that we have descriptor tables fully restored and working + * exception handling, restore the usermode segments. */ -#ifdef CONFIG_X86_32 +#ifdef CONFIG_X86_64 + loadsegment(ds, ctxt->es); loadsegment(es, ctxt->es); loadsegment(fs, ctxt->fs); - loadsegment(gs, ctxt->gs); - loadsegment(ss, ctxt->ss); + load_gs_index(ctxt->gs); /* - * sysenter MSRs + * Restore FSBASE and GSBASE after restoring the selectors, since + * restoring the selectors clobbers the bases. Keep in mind + * that MSR_KERNEL_GS_BASE is horribly misnamed. */ - if (boot_cpu_has(X86_FEATURE_SEP)) - enable_sep_cpu(); -#else -/* CONFIG_X86_64 */ - asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds)); - asm volatile ("movw %0, %%es" :: "r" (ctxt->es)); - asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs)); - load_gs_index(ctxt->gs); - asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss)); - wrmsrl(MSR_FS_BASE, ctxt->fs_base); - wrmsrl(MSR_GS_BASE, ctxt->gs_base); - wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); + wrmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base); +#elif defined(CONFIG_X86_32_LAZY_GS) + loadsegment(gs, ctxt->gs); #endif - fix_processor_context(); - do_fpu_end(); tsc_verify_tsc_adjust(true); x86_platform.restore_sched_clock_state(); diff --git a/arch/xtensa/kernel/stacktrace.c b/arch/xtensa/kernel/stacktrace.c index 0df4080fa20f2276563eb64f8694959548a3f557..a94da7dd3eae822c6680f3c2b24177661081be66 100644 --- a/arch/xtensa/kernel/stacktrace.c +++ b/arch/xtensa/kernel/stacktrace.c @@ -253,10 +253,14 @@ static int return_address_cb(struct stackframe *frame, void *data) return 1; } +/* + * level == 0 is for the return address from the caller of this function, + * not from this function itself. + */ unsigned long return_address(unsigned level) { struct return_addr_data r = { - .skip = level + 1, + .skip = level, }; walk_stackframe(stack_pointer(NULL), return_address_cb, &r); return r.addr; diff --git a/block/bio.c b/block/bio.c index dc247bbbe704d31617c33a3b16eeca366e2cd429..06c08873b2cc5e1b43a44a9f54839b8eb7762eda 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1293,8 +1293,11 @@ struct bio *bio_copy_user_iov(struct request_queue *q, } } - if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) + if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) { + if (!map_data) + __free_page(page); break; + } len -= bytes; offset = 0; diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 50ed007959276d296983f0d4d11a2d5ed8969571..7519eb5345ed9e35f0051313071bac0619146031 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -4660,7 +4660,49 @@ static const struct hash_testvec poly1305_tv_template[] = { .psize = 80, .digest = "\x13\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", - }, + }, { /* Regression test for overflow in AVX2 implementation */ + .plaintext = "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff", + .psize = 300, + .digest = "\xfb\x5e\x96\xd8\x61\xd5\xc7\xc8" + "\x78\xe5\x87\xcc\x2d\x5a\x22\xe1", + } }; /* NHPoly1305 test vectors from https://github.com/google/adiantum */ diff --git a/drivers/Kconfig b/drivers/Kconfig index 29096a4caa440f04eb17c53a671eeaefb9156760..ed96eb7d8ba25d9213a4478b8531e4d3b8ff2aaa 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -71,6 +71,8 @@ source "drivers/pinctrl/Kconfig" source "drivers/gpio/Kconfig" +source "drivers/gnsssirf/Kconfig" + source "drivers/w1/Kconfig" source "drivers/power/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f409e6ddf143b813a2de6326dd3bd05c9c0bb40b..cef0160448bc4f0e228cecbe09cc1ab8c4d7342e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -188,3 +188,5 @@ obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_SENSORS_SSC) += sensors/ obj-$(CONFIG_ESOC) += esoc/ +# GNSS driver +obj-$(CONFIG_GNSS_SIRF) += gnsssirf/ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 70a0f8b2f6c13a5416866141370d36a91dfbffda..bcadb6fd47290b841da3d8bd269ee36f65112683 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -194,6 +194,7 @@ static struct workqueue_struct *ec_query_wq; static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */ static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */ +static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ /* -------------------------------------------------------------------------- * Logging/Debugging @@ -499,6 +500,26 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) ec_log_drv("event blocked"); } +/* + * Process _Q events that might have accumulated in the EC. + * Run with locked ec mutex. + */ +static void acpi_ec_clear(struct acpi_ec *ec) +{ + int i, status; + u8 value = 0; + + for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { + status = acpi_ec_query(ec, &value); + if (status || !value) + break; + } + if (unlikely(i == ACPI_EC_CLEAR_MAX)) + pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); + else + pr_info("%d stale EC events cleared\n", i); +} + static void acpi_ec_enable_event(struct acpi_ec *ec) { unsigned long flags; @@ -507,6 +528,10 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) if (acpi_ec_started(ec)) __acpi_ec_enable_event(ec); spin_unlock_irqrestore(&ec->lock, flags); + + /* Drain additional events if hardware requires that */ + if (EC_FLAGS_CLEAR_ON_RESUME) + acpi_ec_clear(ec); } #ifdef CONFIG_PM_SLEEP @@ -1802,6 +1827,31 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id) } #endif +/* + * On some hardware it is necessary to clear events accumulated by the EC during + * sleep. These ECs stop reporting GPEs until they are manually polled, if too + * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) + * + * https://bugzilla.kernel.org/show_bug.cgi?id=44161 + * + * Ideally, the EC should also be instructed NOT to accumulate events during + * sleep (which Windows seems to do somehow), but the interface to control this + * behaviour is not known at this time. + * + * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, + * however it is very likely that other Samsung models are affected. + * + * On systems which don't accumulate _Q events during sleep, this extra check + * should be harmless. + */ +static int ec_clear_on_resume(const struct dmi_system_id *id) +{ + pr_debug("Detected system needing EC poll on resume.\n"); + EC_FLAGS_CLEAR_ON_RESUME = 1; + ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS; + return 0; +} + /* * Some ECDTs contain wrong register addresses. * MSI MS-171F @@ -1851,6 +1901,9 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = { ec_honor_ecdt_gpe, "ASUS X580VD", { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL}, + { + ec_clear_on_resume, "Samsung hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, {}, }; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index a2428e9462dd9f10ac5483d7cc42f928f25bf642..3c092f07d7e38fb8b7aac8f6e854880c0fe1f324 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -441,9 +441,13 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) /* * The spec requires that bit 4 always be 1. If it's not set, assume - * that the implementation doesn't support an SBS charger + * that the implementation doesn't support an SBS charger. + * + * And on some MacBooks a status of 0xffff is always returned, no + * matter whether the charger is plugged in or not, which is also + * wrong, so ignore the SBS charger for those too. */ - if (!((status >> 4) & 0x1)) + if (!((status >> 4) & 0x1) || status == 0xffff) return -ENODEV; sbs->charger_present = (status >> 15) & 0x1; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 648d8f8e3d6803e92b55aa7063c2329c992b7aca..7b8a4bea865060c11ea93dc4542dd143ea1e2941 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -916,14 +916,13 @@ enum lru_status binder_alloc_free_page(struct list_head *item, index = page - alloc->pages; page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; + + mm = alloc->vma_vm_mm; + if (!mmget_not_zero(mm)) + goto err_mmget; + if (!down_write_trylock(&mm->mmap_sem)) + goto err_down_write_mmap_sem_failed; vma = binder_alloc_get_vma(alloc); - if (vma) { - if (!mmget_not_zero(alloc->vma_vm_mm)) - goto err_mmget; - mm = alloc->vma_vm_mm; - if (!down_write_trylock(&mm->mmap_sem)) - goto err_down_write_mmap_sem_failed; - } list_lru_isolate(lru, item); spin_unlock(lock); @@ -934,10 +933,9 @@ enum lru_status binder_alloc_free_page(struct list_head *item, zap_page_range(vma, page_addr, PAGE_SIZE); trace_binder_unmap_user_end(alloc, index); - - up_write(&mm->mmap_sem); - mmput(mm); } + up_write(&mm->mmap_sem); + mmput(mm); trace_binder_unmap_kernel_start(alloc, index); diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index b3ed8f9953a862ea3ae67ef065ca5469330a44e0..173e6f2dd9af0f12afdc1fee7e372cfa4291e0aa 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -52,38 +52,52 @@ static int eject_tray(struct ata_device *dev) /* Per the spec, only slot type and drawer type ODD can be supported */ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) { - char buf[16]; + char *buf; unsigned int ret; - struct rm_feature_desc *desc = (void *)(buf + 8); + struct rm_feature_desc *desc; struct ata_taskfile tf; static const char cdb[] = { GPCMD_GET_CONFIGURATION, 2, /* only 1 feature descriptor requested */ 0, 3, /* 3, removable medium feature */ 0, 0, 0,/* reserved */ - 0, sizeof(buf), + 0, 16, 0, 0, 0, }; + buf = kzalloc(16, GFP_KERNEL); + if (!buf) + return ODD_MECH_TYPE_UNSUPPORTED; + desc = (void *)(buf + 8); + ata_tf_init(dev, &tf); tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.command = ATA_CMD_PACKET; tf.protocol = ATAPI_PROT_PIO; - tf.lbam = sizeof(buf); + tf.lbam = 16; ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, - buf, sizeof(buf), 0); - if (ret) + buf, 16, 0); + if (ret) { + kfree(buf); return ODD_MECH_TYPE_UNSUPPORTED; + } - if (be16_to_cpu(desc->feature_code) != 3) + if (be16_to_cpu(desc->feature_code) != 3) { + kfree(buf); return ODD_MECH_TYPE_UNSUPPORTED; + } - if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1) + if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1) { + kfree(buf); return ODD_MECH_TYPE_SLOT; - else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1) + } else if (desc->mech_type == 1 && desc->load == 0 && + desc->eject == 1) { + kfree(buf); return ODD_MECH_TYPE_DRAWER; - else + } else { + kfree(buf); return ODD_MECH_TYPE_UNSUPPORTED; + } } /* Test if ODD is zero power ready by sense code */ diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index 036eec40428943b7d2c4a32b0db77de40a48ef54..2d927feb3db4f5069c071023dd16725bdba36a6b 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -302,6 +302,8 @@ static int hd44780_remove(struct platform_device *pdev) struct charlcd *lcd = platform_get_drvdata(pdev); charlcd_unregister(lcd); + + kfree(lcd); return 0; } diff --git a/drivers/base/node.c b/drivers/base/node.c index ee090ab9171c269dfaeade5f1c1c4e5584566e70..5c39f14d15a566fe5273711dfa261ef93ac7eff7 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -197,11 +197,16 @@ static ssize_t node_read_vmstat(struct device *dev, sum_zone_numa_state(nid, i)); #endif - for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) + for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) { + /* Skip hidden vmstat items. */ + if (*vmstat_text[i + NR_VM_ZONE_STAT_ITEMS + + NR_VM_NUMA_STAT_ITEMS] == '\0') + continue; n += sprintf(buf+n, "%s %lu\n", vmstat_text[i + NR_VM_ZONE_STAT_ITEMS + NR_VM_NUMA_STAT_ITEMS], node_page_state(pgdat, i)); + } return n; } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 24a3fb35614f2d6d194416e9ddd6cfa2ba58b636..bd447de4a5b8a3f36cfb09e9881cd6ec1d055636 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -82,7 +82,6 @@ static DEFINE_IDR(loop_index_idr); static DEFINE_MUTEX(loop_index_mutex); -static DEFINE_MUTEX(loop_ctl_mutex); static int max_part; static int part_shift; @@ -1019,7 +1018,7 @@ static int loop_clr_fd(struct loop_device *lo) */ if (atomic_read(&lo->lo_refcnt) > 1) { lo->lo_flags |= LO_FLAGS_AUTOCLEAR; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return 0; } @@ -1071,12 +1070,12 @@ static int loop_clr_fd(struct loop_device *lo) if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; loop_unprepare_queue(lo); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); /* - * Need not hold loop_ctl_mutex to fput backing file. - * Calling fput holding loop_ctl_mutex triggers a circular + * Need not hold lo_ctl_mutex to fput backing file. + * Calling fput holding lo_ctl_mutex triggers a circular * lock dependency possibility warning as fput can take - * bd_mutex which is usually taken before loop_ctl_mutex. + * bd_mutex which is usually taken before lo_ctl_mutex. */ fput(filp); return 0; @@ -1195,7 +1194,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) int ret; if (lo->lo_state != Lo_bound) { - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return -ENXIO; } @@ -1214,10 +1213,10 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) lo->lo_encrypt_key_size); } - /* Drop loop_ctl_mutex while we call into the filesystem. */ + /* Drop lo_ctl_mutex while we call into the filesystem. */ path = lo->lo_backing_file->f_path; path_get(&path); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); ret = vfs_getattr(&path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT); if (!ret) { info->lo_device = huge_encode_dev(stat.dev); @@ -1309,7 +1308,7 @@ loop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) { int err; if (!arg) { - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return -EINVAL; } err = loop_get_status(lo, &info64); @@ -1327,7 +1326,7 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) { int err; if (!arg) { - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return -EINVAL; } err = loop_get_status(lo, &info64); @@ -1402,7 +1401,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, struct loop_device *lo = bdev->bd_disk->private_data; int err; - mutex_lock_nested(&loop_ctl_mutex, 1); + mutex_lock_nested(&lo->lo_ctl_mutex, 1); switch (cmd) { case LOOP_SET_FD: err = loop_set_fd(lo, mode, bdev, arg); @@ -1411,7 +1410,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, err = loop_change_fd(lo, bdev, arg); break; case LOOP_CLR_FD: - /* loop_clr_fd would have unlocked loop_ctl_mutex on success */ + /* loop_clr_fd would have unlocked lo_ctl_mutex on success */ err = loop_clr_fd(lo); if (!err) goto out_unlocked; @@ -1424,7 +1423,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, break; case LOOP_GET_STATUS: err = loop_get_status_old(lo, (struct loop_info __user *) arg); - /* loop_get_status() unlocks loop_ctl_mutex */ + /* loop_get_status() unlocks lo_ctl_mutex */ goto out_unlocked; case LOOP_SET_STATUS64: err = -EPERM; @@ -1434,7 +1433,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, break; case LOOP_GET_STATUS64: err = loop_get_status64(lo, (struct loop_info64 __user *) arg); - /* loop_get_status() unlocks loop_ctl_mutex */ + /* loop_get_status() unlocks lo_ctl_mutex */ goto out_unlocked; case LOOP_SET_CAPACITY: err = -EPERM; @@ -1454,7 +1453,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, default: err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); out_unlocked: return err; @@ -1571,7 +1570,7 @@ loop_get_status_compat(struct loop_device *lo, int err; if (!arg) { - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return -EINVAL; } err = loop_get_status(lo, &info64); @@ -1588,16 +1587,16 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, switch(cmd) { case LOOP_SET_STATUS: - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); err = loop_set_status_compat( lo, (const struct compat_loop_info __user *) arg); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; case LOOP_GET_STATUS: - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); err = loop_get_status_compat( lo, (struct compat_loop_info __user *) arg); - /* loop_get_status() unlocks loop_ctl_mutex */ + /* loop_get_status() unlocks lo_ctl_mutex */ break; case LOOP_SET_CAPACITY: case LOOP_CLR_FD: @@ -1641,7 +1640,7 @@ static void __lo_release(struct loop_device *lo) if (atomic_dec_return(&lo->lo_refcnt)) return; - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_flags & LO_FLAGS_AUTOCLEAR) { /* * In autoclear mode, stop the loop thread @@ -1659,7 +1658,7 @@ static void __lo_release(struct loop_device *lo) blk_mq_unfreeze_queue(lo->lo_queue); } - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); } static void lo_release(struct gendisk *disk, fmode_t mode) @@ -1705,10 +1704,10 @@ static int unregister_transfer_cb(int id, void *ptr, void *data) struct loop_device *lo = ptr; struct loop_func_table *xfer = data; - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_encryption == xfer) loop_release_xfer(lo); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return 0; } @@ -1881,6 +1880,7 @@ static int loop_add(struct loop_device **l, int i) if (!part_shift) disk->flags |= GENHD_FL_NO_PART_SCAN; disk->flags |= GENHD_FL_EXT_DEVT; + mutex_init(&lo->lo_ctl_mutex); atomic_set(&lo->lo_refcnt, 0); lo->lo_number = i; spin_lock_init(&lo->lo_lock); @@ -1993,19 +1993,19 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd, ret = loop_lookup(&lo, parm); if (ret < 0) break; - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_state != Lo_unbound) { ret = -EBUSY; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; } if (atomic_read(&lo->lo_refcnt) > 0) { ret = -EBUSY; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; } lo->lo_disk->private_data = NULL; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); idr_remove(&loop_index_idr, lo->lo_number); loop_remove(lo); break; diff --git a/drivers/block/loop.h b/drivers/block/loop.h index b2251752452bc75ebc02049b1395c1a072981a77..dfc54ceba410a87c5a42cd7861aff3d543c3cba0 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -54,6 +54,7 @@ struct loop_device { spinlock_t lo_lock; int lo_state; + struct mutex lo_ctl_mutex; struct kthread_worker worker; struct task_struct *worker_task; bool use_dio; diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 14459d66ef0cd8ac223992f2f69ad2b725f8481c..51ff7ee1b2b1249f169a3e56043c09d54c489dd3 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1063,6 +1063,8 @@ static int ace_setup(struct ace_device *ace) return 0; err_read: + /* prevent double queue cleanup */ + ace->gd->queue = NULL; put_disk(ace->gd); err_alloc_disk: blk_cleanup_queue(ace->queue); diff --git a/drivers/block/zram/zram_dedup.c b/drivers/block/zram/zram_dedup.c index 14c4988f8ff73c122bd0fb727e260a5077c1035f..e441289fff810a057b880784493c101cc859dfdd 100644 --- a/drivers/block/zram/zram_dedup.c +++ b/drivers/block/zram/zram_dedup.c @@ -92,13 +92,14 @@ static unsigned long zram_dedup_put(struct zram *zram, { struct zram_hash *hash; u32 checksum; + unsigned long val; checksum = entry->checksum; hash = &zram->hash[checksum % zram->hash_size]; spin_lock(&hash->lock); - entry->refcount--; + val = --entry->refcount; if (!entry->refcount) rb_erase(&entry->rb_node, &hash->rb_root); else @@ -106,7 +107,7 @@ static unsigned long zram_dedup_put(struct zram *zram, spin_unlock(&hash->lock); - return entry->refcount; + return val; } static struct zram_entry *__zram_dedup_get(struct zram *zram, diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f3b22abff43b8d551f0052b4e05b1c0fbd8adac1..97ebd71d1c4af35eca187f1f5ffdceb5bb44dc81 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -782,18 +782,18 @@ struct zram_work { struct zram *zram; unsigned long entry; struct bio *bio; + struct bio_vec bvec; }; #if PAGE_SIZE != 4096 static void zram_sync_read(struct work_struct *work) { - struct bio_vec bvec; struct zram_work *zw = container_of(work, struct zram_work, work); struct zram *zram = zw->zram; unsigned long entry = zw->entry; struct bio *bio = zw->bio; - read_from_bdev_async(zram, &bvec, entry, bio); + read_from_bdev_async(zram, &zw->bvec, entry, bio); } /* @@ -806,6 +806,7 @@ static int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec, { struct zram_work work; + work.bvec = *bvec; work.zram = zram; work.entry = entry; work.bio = bio; diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 18195b4f583319a34616184c0fc51e8319332ed2..b7774077d03eedbcc68beb6cece903f58bb8c09b 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -28,7 +28,7 @@ #include #include -#if defined(CONFIG_CNSS) +#if defined(CONFIG_CNSS) && !defined(CONFIG_ICNSS) #include #endif @@ -338,7 +338,7 @@ static const struct rfkill_ops bluetooth_power_rfkill_ops = { .set_block = bluetooth_toggle_radio, }; -#if defined(CONFIG_CNSS) +#if defined(CONFIG_CNSS) && !defined(CONFIG_ICNSS) static ssize_t enable_extldo(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/bluetooth/btfm_slim_wcn3990.h b/drivers/bluetooth/btfm_slim_wcn3990.h index 7cf07d8ae6ca9ebac28e9ed719af757281fdc6eb..545d21ec67e97a9e6e72779d83371cc34802d2f1 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.h +++ b/drivers/bluetooth/btfm_slim_wcn3990.h @@ -103,8 +103,8 @@ enum{ QCA_APACHE_SOC_ID_0102 = 0x40020122, QCA_APACHE_SOC_ID_0103 = 0x40020123, QCA_APACHE_SOC_ID_0110 = 0x40020130, - QCA_APACHE_SOC_ID_0111 = 0x40020140, - QCA_APACHE_SOC_ID_0120 = 0x40020240, + QCA_APACHE_SOC_ID_0120 = 0x40020140, + QCA_APACHE_SOC_ID_0121 = 0x40020150, }; enum { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b8dffe937f4ff7df519ed2e106d6216cd910ffc3..dae8723dde8cde03b89f18a51eb64f42a639dcc0 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2893,6 +2893,7 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) return 0; } + irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler, 0, "OOB Wake-on-BT", data); if (ret) { @@ -2907,7 +2908,6 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) } data->oob_wake_irq = irq; - disable_irq(irq); bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq); return 0; } diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c index 0de99ee81c88bb14521bfd8fa2098ba0bd1a8003..56708218081ef2a58dba7e8eeeae9280d7b0a857 100644 --- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "mhi_qcom.h" @@ -35,17 +36,23 @@ struct arch_info { u32 bus_client; struct msm_pcie_register_event pcie_reg_event; struct pci_saved_state *pcie_state; - struct pci_saved_state *ref_pcie_state; struct dma_iommu_mapping *mapping; async_cookie_t cookie; void *boot_ipc_log; + void *tsync_ipc_log; struct mhi_device *boot_dev; + struct mhi_link_info current_link_info; + struct work_struct bw_scale_work; + struct notifier_block pm_notifier; + struct completion pm_completion; }; /* ipc log markings */ #define DLOG "Dev->Host: " #define HLOG "Host: " +#define MHI_TSYNC_LOG_PAGES (10) + #ifdef CONFIG_MHI_DEBUG #define MHI_IPC_LOG_PAGES (100) @@ -58,6 +65,38 @@ enum MHI_DEBUG_LEVEL mhi_ipc_log_lvl = MHI_MSG_LVL_ERROR; #endif +static int mhi_arch_pm_notifier(struct notifier_block *nb, + unsigned long event, void *unused) +{ + struct arch_info *arch_info = + container_of(nb, struct arch_info, pm_notifier); + + switch (event) { + case PM_SUSPEND_PREPARE: + reinit_completion(&arch_info->pm_completion); + break; + + case PM_POST_SUSPEND: + complete_all(&arch_info->pm_completion); + break; + } + + return NOTIFY_DONE; +} + +static void mhi_arch_timesync_log(struct mhi_controller *mhi_cntrl, + u64 remote_time) +{ + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + struct arch_info *arch_info = mhi_dev->arch_info; + + if (remote_time != U64_MAX) + ipc_log_string(arch_info->tsync_ipc_log, "%6u.%06lu 0x%llx", + REMOTE_TICKS_TO_SEC(remote_time), + REMOTE_TIME_REMAINDER_US(remote_time), + remote_time); +} + static int mhi_arch_set_bus_request(struct mhi_controller *mhi_cntrl, int index) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); @@ -80,7 +119,8 @@ static void mhi_arch_pci_link_state_cb(struct msm_pcie_notify *notify) struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct pci_dev *pci_dev = mhi_dev->pci_dev; - if (notify->event == MSM_PCIE_EVENT_WAKEUP) { + switch (notify->event) { + case MSM_PCIE_EVENT_WAKEUP: MHI_LOG("Received MSM_PCIE_EVENT_WAKE signal\n"); /* bring link out of d3cold */ @@ -88,6 +128,15 @@ static void mhi_arch_pci_link_state_cb(struct msm_pcie_notify *notify) pm_runtime_get(&pci_dev->dev); pm_runtime_put_noidle(&pci_dev->dev); } + break; + case MSM_PCIE_EVENT_L1SS_TIMEOUT: + MHI_VERB("Received MSM_PCIE_EVENT_L1SS_TIMEOUT signal\n"); + + pm_runtime_mark_last_busy(&pci_dev->dev); + pm_request_autosuspend(&pci_dev->dev); + break; + default: + MHI_ERR("Unhandled event 0x%x\n", notify->event); } } @@ -96,7 +145,6 @@ static int mhi_arch_esoc_ops_power_on(void *priv, unsigned int flags) struct mhi_controller *mhi_cntrl = priv; struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct pci_dev *pci_dev = mhi_dev->pci_dev; - struct arch_info *arch_info = mhi_dev->arch_info; int ret; mutex_lock(&mhi_cntrl->pm_mutex); @@ -126,41 +174,86 @@ static int mhi_arch_esoc_ops_power_on(void *priv, unsigned int flags) MHI_ERR("Failed to resume pcie bus ret %d\n", ret); return ret; } - pci_load_saved_state(pci_dev, arch_info->ref_pcie_state); return mhi_pci_probe(pci_dev, NULL); } +static void mhi_arch_link_off(struct mhi_controller *mhi_cntrl) +{ + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + struct pci_dev *pci_dev = mhi_dev->pci_dev; + + MHI_LOG("Entered\n"); + + pci_set_power_state(pci_dev, PCI_D3hot); + + /* release the resources */ + msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); + mhi_arch_set_bus_request(mhi_cntrl, 0); + + MHI_LOG("Exited\n"); +} + static void mhi_arch_esoc_ops_power_off(void *priv, unsigned int flags) { struct mhi_controller *mhi_cntrl = priv; struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); bool mdm_state = (flags & ESOC_HOOK_MDM_CRASH); struct arch_info *arch_info = mhi_dev->arch_info; + struct pci_dev *pci_dev = mhi_dev->pci_dev; MHI_LOG("Enter: mdm_crashed:%d\n", mdm_state); + /* + * Abort system suspend if system is preparing to go to suspend + * by grabbing wake source. + * If system is suspended, wait for pm notifier callback to notify + * that resume has occurred with PM_POST_SUSPEND event. + */ + pm_stay_awake(&mhi_cntrl->mhi_dev->dev); + wait_for_completion(&arch_info->pm_completion); + + /* if link is in drv suspend, wake it up */ + pm_runtime_get_sync(&pci_dev->dev); + mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on) { MHI_LOG("Not in active state\n"); mutex_unlock(&mhi_cntrl->pm_mutex); + pm_runtime_put_noidle(&pci_dev->dev); return; } mhi_dev->powered_on = false; mutex_unlock(&mhi_cntrl->pm_mutex); + pm_runtime_put_noidle(&pci_dev->dev); + MHI_LOG("Triggering shutdown process\n"); mhi_power_down(mhi_cntrl, !mdm_state); /* turn the link off */ mhi_deinit_pci_dev(mhi_cntrl); - mhi_arch_link_off(mhi_cntrl, false); + mhi_arch_link_off(mhi_cntrl); /* wait for boot monitor to exit */ async_synchronize_cookie(arch_info->cookie + 1); mhi_arch_iommu_deinit(mhi_cntrl); mhi_arch_pcie_deinit(mhi_cntrl); + + pm_relax(&mhi_cntrl->mhi_dev->dev); +} + +static void mhi_arch_esoc_ops_mdm_error(void *priv) +{ + struct mhi_controller *mhi_cntrl = priv; + + MHI_LOG("Enter: mdm asserted\n"); + + /* transition MHI state into error state */ + mhi_control_error(mhi_cntrl); + + MHI_LOG("Exit\n"); } static void mhi_bl_dl_cb(struct mhi_device *mhi_device, @@ -211,9 +304,13 @@ static void mhi_boot_monitor(void *data, async_cookie_t cookie) TO_MHI_EXEC_STR(mhi_cntrl->ee)); /* if we successfully booted to amss disable boot log channel */ - boot_dev = arch_info->boot_dev; - if (boot_dev && mhi_cntrl->ee == MHI_EE_AMSS) - mhi_unprepare_from_transfer(boot_dev); + if (mhi_cntrl->ee == MHI_EE_AMSS) { + boot_dev = arch_info->boot_dev; + if (boot_dev) + mhi_unprepare_from_transfer(boot_dev); + + pm_runtime_allow(&mhi_dev->pci_dev->dev); + } } int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) @@ -227,6 +324,76 @@ int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) return 0; } +static int mhi_arch_pcie_scale_bw(struct mhi_controller *mhi_cntrl, + struct pci_dev *pci_dev, + struct mhi_link_info *link_info) +{ + int ret, scale; + + mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data); + ret = msm_pcie_set_link_bandwidth(pci_dev, link_info->target_link_speed, + link_info->target_link_width); + mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data); + + if (ret) + return ret; + + /* if we switch to low bw release bus scale voting */ + scale = !(link_info->target_link_speed == PCI_EXP_LNKSTA_CLS_2_5GB); + mhi_arch_set_bus_request(mhi_cntrl, scale); + + MHI_VERB("bw changed to speed:0x%x width:0x%x bus_scale:%d\n", + link_info->target_link_speed, link_info->target_link_width, + scale); + + return 0; +} + +static void mhi_arch_pcie_bw_scale_work(struct work_struct *work) +{ + struct arch_info *arch_info = container_of(work, + struct arch_info, + bw_scale_work); + struct mhi_dev *mhi_dev = arch_info->mhi_dev; + struct pci_dev *pci_dev = mhi_dev->pci_dev; + struct device *dev = &pci_dev->dev; + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + struct mhi_link_info mhi_link_info; + struct mhi_link_info *cur_info = &arch_info->current_link_info; + int ret; + + mutex_lock(&mhi_cntrl->pm_mutex); + if (!mhi_dev->powered_on || MHI_IS_SUSPENDED(mhi_dev->suspend_mode)) + goto exit_work; + + /* copy the latest speed change */ + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_link_info = mhi_cntrl->mhi_link_info; + write_unlock_irq(&mhi_cntrl->pm_lock); + + /* link is already set to current settings */ + if (cur_info->target_link_speed == mhi_link_info.target_link_speed && + cur_info->target_link_width == mhi_link_info.target_link_width) + goto exit_work; + + ret = mhi_arch_pcie_scale_bw(mhi_cntrl, pci_dev, &mhi_link_info); + if (ret) + goto exit_work; + + *cur_info = mhi_link_info; + +exit_work: + mutex_unlock(&mhi_cntrl->pm_mutex); +} + +static void mhi_arch_pcie_bw_scale_cb(struct mhi_controller *mhi_cntrl, + struct mhi_dev *mhi_dev) +{ + struct arch_info *arch_info = mhi_dev->arch_info; + + schedule_work(&arch_info->bw_scale_work); +} + static int mhi_bl_probe(struct mhi_device *mhi_device, const struct mhi_device_id *id) { @@ -271,9 +438,11 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) struct arch_info *arch_info = mhi_dev->arch_info; char node[32]; int ret; + u16 linkstat; if (!arch_info) { struct msm_pcie_register_event *reg_event; + struct mhi_link_info *cur_link_info; arch_info = devm_kzalloc(&mhi_dev->pci_dev->dev, sizeof(*arch_info), GFP_KERNEL); @@ -281,6 +450,7 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) return -ENOMEM; mhi_dev->arch_info = arch_info; + arch_info->mhi_dev = mhi_dev; snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u", mhi_cntrl->dev_id, mhi_cntrl->domain, mhi_cntrl->bus, @@ -289,6 +459,14 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) node, 0); mhi_cntrl->log_lvl = mhi_ipc_log_lvl; + snprintf(node, sizeof(node), "mhi_tsync_%04x_%02u.%02u.%02u", + mhi_cntrl->dev_id, mhi_cntrl->domain, mhi_cntrl->bus, + mhi_cntrl->slot); + arch_info->tsync_ipc_log = ipc_log_context_create( + MHI_TSYNC_LOG_PAGES, node, 0); + if (arch_info->tsync_ipc_log) + mhi_cntrl->tsync_log = mhi_arch_timesync_log; + /* register for bus scale if defined */ arch_info->msm_bus_pdata = msm_bus_cl_get_pdata_from_dev( &mhi_dev->pci_dev->dev); @@ -302,7 +480,9 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* register with pcie rc for WAKE# events */ reg_event = &arch_info->pcie_reg_event; - reg_event->events = MSM_PCIE_EVENT_WAKEUP; + reg_event->events = + MSM_PCIE_EVENT_WAKEUP | MSM_PCIE_EVENT_L1SS_TIMEOUT; + reg_event->user = mhi_dev->pci_dev; reg_event->callback = mhi_arch_pci_link_state_cb; reg_event->notify.data = mhi_cntrl; @@ -310,6 +490,18 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) if (ret) MHI_LOG("Failed to reg. for link up notification\n"); + init_completion(&arch_info->pm_completion); + + /* register PM notifier to get post resume events */ + arch_info->pm_notifier.notifier_call = mhi_arch_pm_notifier; + register_pm_notifier(&arch_info->pm_notifier); + + /* + * Mark as completed at initial boot-up to allow ESOC power on + * callback to proceed if system has not gone to suspend + */ + complete_all(&arch_info->pm_completion); + arch_info->esoc_client = devm_register_esoc_client( &mhi_dev->pci_dev->dev, "mdm"); if (IS_ERR_OR_NULL(arch_info->esoc_client)) { @@ -325,6 +517,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) mhi_arch_esoc_ops_power_on; esoc_ops->esoc_link_power_off = mhi_arch_esoc_ops_power_off; + esoc_ops->esoc_link_mdm_crash = + mhi_arch_esoc_ops_mdm_error; ret = esoc_register_client_hook(arch_info->esoc_client, esoc_ops); @@ -332,9 +526,31 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) MHI_ERR("Failed to register esoc ops\n"); } - /* save reference state for pcie config space */ - arch_info->ref_pcie_state = pci_store_saved_state( - mhi_dev->pci_dev); + /* + * MHI host driver has full autonomy to manage power state. + * Disable all automatic power collapse features + */ + msm_pcie_pm_control(MSM_PCIE_DISABLE_PC, mhi_cntrl->bus, + mhi_dev->pci_dev, NULL, 0); + mhi_dev->pci_dev->no_d3hot = true; + + INIT_WORK(&arch_info->bw_scale_work, + mhi_arch_pcie_bw_scale_work); + mhi_dev->bw_scale = mhi_arch_pcie_bw_scale_cb; + + /* store the current bw info */ + ret = pcie_capability_read_word(mhi_dev->pci_dev, + PCI_EXP_LNKSTA, &linkstat); + if (ret) + return ret; + + cur_link_info = &arch_info->current_link_info; + cur_link_info->target_link_speed = + linkstat & PCI_EXP_LNKSTA_CLS; + cur_link_info->target_link_width = + (linkstat & PCI_EXP_LNKSTA_NLW) >> + PCI_EXP_LNKSTA_NLW_SHIFT; + mhi_cntrl->mhi_link_info = *cur_link_info; mhi_driver_register(&mhi_bl_driver); } @@ -476,56 +692,68 @@ void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl) mhi_cntrl->dev = NULL; } -int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful) +int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; - int ret; + int ret = 0; MHI_LOG("Entered\n"); - if (graceful) { + /* disable inactivity timer */ + msm_pcie_l1ss_timeout_disable(pci_dev); + + switch (mhi_dev->suspend_mode) { + case MHI_DEFAULT_SUSPEND: pci_clear_master(pci_dev); ret = pci_save_state(mhi_dev->pci_dev); if (ret) { MHI_ERR("Failed with pci_save_state, ret:%d\n", ret); - return ret; + goto exit_suspend; } arch_info->pcie_state = pci_store_saved_state(pci_dev); pci_disable_device(pci_dev); - } - /* - * We will always attempt to put link into D3hot, however - * link down may have happened due to error fatal, so - * ignoring the return code - */ - pci_set_power_state(pci_dev, PCI_D3hot); + pci_set_power_state(pci_dev, PCI_D3hot); + + /* release the resources */ + msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, + NULL, 0); + mhi_arch_set_bus_request(mhi_cntrl, 0); + break; + case MHI_FAST_LINK_OFF: + case MHI_ACTIVE_STATE: + case MHI_FAST_LINK_ON:/* keeping link on do nothing */ + break; + } - /* release the resources */ - msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); - mhi_arch_set_bus_request(mhi_cntrl, 0); +exit_suspend: + if (ret) + msm_pcie_l1ss_timeout_enable(pci_dev); - MHI_LOG("Exited\n"); + MHI_LOG("Exited with ret:%d\n", ret); - return 0; + return ret; } -int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) +static int __mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; + struct mhi_link_info *cur_info = &arch_info->current_link_info; int ret; MHI_LOG("Entered\n"); - /* request resources and establish link trainning */ - ret = mhi_arch_set_bus_request(mhi_cntrl, 1); - if (ret) - MHI_LOG("Could not set bus frequency, ret:%d\n", ret); + /* request bus scale voting if we're on Gen 2 or higher speed */ + if (cur_info->target_link_speed != PCI_EXP_LNKSTA_CLS_2_5GB) { + ret = mhi_arch_set_bus_request(mhi_cntrl, 1); + if (ret) + MHI_LOG("Could not set bus frequency, ret:%d\n", ret); + } ret = msm_pcie_pm_control(MSM_PCIE_RESUME, mhi_cntrl->bus, pci_dev, NULL, 0); @@ -553,6 +781,45 @@ int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) pci_restore_state(pci_dev); pci_set_master(pci_dev); + return 0; +} + +int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) +{ + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + struct arch_info *arch_info = mhi_dev->arch_info; + struct pci_dev *pci_dev = mhi_dev->pci_dev; + struct mhi_link_info *cur_info = &arch_info->current_link_info; + struct mhi_link_info *updated_info = &mhi_cntrl->mhi_link_info; + int ret = 0; + + MHI_LOG("Entered\n"); + + switch (mhi_dev->suspend_mode) { + case MHI_DEFAULT_SUSPEND: + ret = __mhi_arch_link_resume(mhi_cntrl); + break; + case MHI_FAST_LINK_OFF: + case MHI_ACTIVE_STATE: + case MHI_FAST_LINK_ON: + break; + } + + if (ret) { + MHI_ERR("Link training failed, ret:%d\n", ret); + return ret; + } + + /* BW request from device doesn't match current link speed */ + if (cur_info->target_link_speed != updated_info->target_link_speed || + cur_info->target_link_width != updated_info->target_link_width) { + ret = mhi_arch_pcie_scale_bw(mhi_cntrl, pci_dev, updated_info); + if (!ret) + *cur_info = *updated_info; + } + + msm_pcie_l1ss_timeout_enable(pci_dev); + MHI_LOG("Exited\n"); return 0; diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 88ccb14935485218d2a259deec122cecfc0b63a0..fd08c6cbf937a47348439991366ed8c739f03fe2 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -79,6 +79,10 @@ void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl) pm_runtime_mark_last_busy(&pci_dev->dev); pm_runtime_dont_use_autosuspend(&pci_dev->dev); pm_runtime_disable(&pci_dev->dev); + + /* reset counter for lpm state changes */ + mhi_dev->lpm_disable_depth = 0; + pci_free_irq_vectors(pci_dev); kfree(mhi_cntrl->irq); mhi_cntrl->irq = NULL; @@ -195,7 +199,44 @@ static int mhi_init_pci_dev(struct mhi_controller *mhi_cntrl) static int mhi_runtime_suspend(struct device *dev) { - return -EBUSY; + int ret = 0; + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + + MHI_LOG("Enter\n"); + + mutex_lock(&mhi_cntrl->pm_mutex); + + if (!mhi_dev->powered_on) { + MHI_LOG("Not fully powered, return success\n"); + mutex_unlock(&mhi_cntrl->pm_mutex); + return 0; + } + + ret = mhi_pm_suspend(mhi_cntrl); + + if (ret) { + MHI_LOG("Abort due to ret:%d\n", ret); + mhi_dev->suspend_mode = MHI_ACTIVE_STATE; + goto exit_runtime_suspend; + } + + mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; + + ret = mhi_arch_link_suspend(mhi_cntrl); + + /* failed suspending link abort mhi suspend */ + if (ret) { + MHI_LOG("Failed to suspend link, abort suspend\n"); + mhi_pm_resume(mhi_cntrl); + mhi_dev->suspend_mode = MHI_ACTIVE_STATE; + } + +exit_runtime_suspend: + mutex_unlock(&mhi_cntrl->pm_mutex); + MHI_LOG("Exited with ret:%d\n", ret); + + return ret; } static int mhi_runtime_idle(struct device *dev) @@ -236,12 +277,18 @@ static int mhi_runtime_resume(struct device *dev) } /* turn on link */ - ret = mhi_arch_link_on(mhi_cntrl); + ret = mhi_arch_link_resume(mhi_cntrl); if (ret) goto rpm_resume_exit; - /* enter M0 state */ - ret = mhi_pm_resume(mhi_cntrl); + + /* transition to M0 state */ + if (mhi_dev->suspend_mode == MHI_DEFAULT_SUSPEND) + ret = mhi_pm_resume(mhi_cntrl); + else + ret = mhi_pm_fast_resume(mhi_cntrl, MHI_FAST_LINK_ON); + + mhi_dev->suspend_mode = MHI_ACTIVE_STATE; rpm_resume_exit: mutex_unlock(&mhi_cntrl->pm_mutex); @@ -252,41 +299,122 @@ static int mhi_runtime_resume(struct device *dev) static int mhi_system_resume(struct device *dev) { - int ret = 0; + return mhi_runtime_resume(dev); +} + +int mhi_system_suspend(struct device *dev) +{ struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + int ret; - ret = mhi_runtime_resume(dev); - if (ret) { - MHI_ERR("Failed to resume link\n"); + MHI_LOG("Entered\n"); + + mutex_lock(&mhi_cntrl->pm_mutex); + + if (!mhi_dev->powered_on) { + MHI_LOG("Not fully powered, return success\n"); + mutex_unlock(&mhi_cntrl->pm_mutex); + return 0; + } + + /* + * pci framework always makes a dummy vote to rpm + * framework to resume before calling system suspend + * hence usage count is minimum one + */ + if (atomic_read(&dev->power.usage_count) > 1) { + /* + * clients have requested to keep link on, try + * fast suspend. No need to notify clients since + * we will not be turning off the pcie link + */ + ret = mhi_pm_fast_suspend(mhi_cntrl, false); + mhi_dev->suspend_mode = MHI_FAST_LINK_ON; } else { - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + /* try normal suspend */ + mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; + ret = mhi_pm_suspend(mhi_cntrl); + + /* + * normal suspend failed because we're busy, try + * fast suspend before aborting system suspend. + * this could happens if client has disabled + * device lpm but no active vote for PCIe from + * apps processor + */ + if (ret == -EBUSY) { + ret = mhi_pm_fast_suspend(mhi_cntrl, true); + mhi_dev->suspend_mode = MHI_FAST_LINK_ON; + } } + if (ret) { + MHI_LOG("Abort due to ret:%d\n", ret); + mhi_dev->suspend_mode = MHI_ACTIVE_STATE; + goto exit_system_suspend; + } + + ret = mhi_arch_link_suspend(mhi_cntrl); + + /* failed suspending link abort mhi suspend */ + if (ret) { + MHI_LOG("Failed to suspend link, abort suspend\n"); + if (mhi_dev->suspend_mode == MHI_DEFAULT_SUSPEND) + mhi_pm_resume(mhi_cntrl); + else + mhi_pm_fast_resume(mhi_cntrl, MHI_FAST_LINK_OFF); + + mhi_dev->suspend_mode = MHI_ACTIVE_STATE; + } + +exit_system_suspend: + mutex_unlock(&mhi_cntrl->pm_mutex); + + MHI_LOG("Exit with ret:%d\n", ret); + return ret; } -int mhi_system_suspend(struct device *dev) +static int mhi_force_suspend(struct mhi_controller *mhi_cntrl) { - struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); - int ret; + int ret = -EIO; + const u32 delayms = 100; + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + int itr = DIV_ROUND_UP(mhi_cntrl->timeout_ms, delayms); MHI_LOG("Entered\n"); - /* if rpm status still active then force suspend */ - if (!pm_runtime_status_suspended(dev)) { - ret = mhi_runtime_suspend(dev); - if (ret) { - MHI_LOG("suspend failed ret:%d\n", ret); - return ret; - } + mutex_lock(&mhi_cntrl->pm_mutex); + + for (; itr; itr--) { + /* + * This function get called soon as device entered mission mode + * so most of the channels are still in disabled state. However, + * sbl channels are active and clients could be trying to close + * channels while we trying to suspend the link. So, we need to + * re-try if MHI is busy + */ + ret = mhi_pm_suspend(mhi_cntrl); + if (!ret || ret != -EBUSY) + break; + + MHI_LOG("MHI busy, sleeping and retry\n"); + msleep(delayms); } - pm_runtime_set_suspended(dev); - pm_runtime_disable(dev); + if (ret) + goto exit_force_suspend; - MHI_LOG("Exit\n"); - return 0; + mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; + ret = mhi_arch_link_suspend(mhi_cntrl); + +exit_force_suspend: + MHI_LOG("Force suspend ret with %d\n", ret); + + mutex_unlock(&mhi_cntrl->pm_mutex); + + return ret; } /* checks if link is down */ @@ -309,26 +437,38 @@ static int mhi_lpm_disable(struct mhi_controller *mhi_cntrl, void *priv) struct pci_dev *pci_dev = mhi_dev->pci_dev; int lnkctl = pci_dev->pcie_cap + PCI_EXP_LNKCTL; u8 val; - int ret; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&mhi_dev->lpm_lock, flags); + + /* L1 is already disabled */ + if (mhi_dev->lpm_disable_depth) { + mhi_dev->lpm_disable_depth++; + goto lpm_disable_exit; + } ret = pci_read_config_byte(pci_dev, lnkctl, &val); if (ret) { MHI_ERR("Error reading LNKCTL, ret:%d\n", ret); - return ret; + goto lpm_disable_exit; } - /* L1 is not supported or already disabled */ - if (!(val & PCI_EXP_LNKCTL_ASPM_L1)) - return 0; + /* L1 is not supported, do not increment lpm_disable_depth */ + if (unlikely(!(val & PCI_EXP_LNKCTL_ASPM_L1))) + goto lpm_disable_exit; val &= ~PCI_EXP_LNKCTL_ASPM_L1; ret = pci_write_config_byte(pci_dev, lnkctl, val); if (ret) { MHI_ERR("Error writing LNKCTL to disable LPM, ret:%d\n", ret); - return ret; + goto lpm_disable_exit; } - mhi_dev->lpm_disabled = true; + mhi_dev->lpm_disable_depth++; + +lpm_disable_exit: + spin_unlock_irqrestore(&mhi_dev->lpm_lock, flags); return ret; } @@ -340,26 +480,40 @@ static int mhi_lpm_enable(struct mhi_controller *mhi_cntrl, void *priv) struct pci_dev *pci_dev = mhi_dev->pci_dev; int lnkctl = pci_dev->pcie_cap + PCI_EXP_LNKCTL; u8 val; - int ret; + unsigned long flags; + int ret = 0; - /* L1 is not supported or already disabled */ - if (!mhi_dev->lpm_disabled) - return 0; + spin_lock_irqsave(&mhi_dev->lpm_lock, flags); + + /* + * Exit if L1 is not supported or is already disabled or + * decrementing lpm_disable_depth still keeps it above 0 + */ + if (!mhi_dev->lpm_disable_depth) + goto lpm_enable_exit; + + if (mhi_dev->lpm_disable_depth > 1) { + mhi_dev->lpm_disable_depth--; + goto lpm_enable_exit; + } ret = pci_read_config_byte(pci_dev, lnkctl, &val); if (ret) { MHI_ERR("Error reading LNKCTL, ret:%d\n", ret); - return ret; + goto lpm_enable_exit; } val |= PCI_EXP_LNKCTL_ASPM_L1; ret = pci_write_config_byte(pci_dev, lnkctl, val); if (ret) { MHI_ERR("Error writing LNKCTL to enable LPM, ret:%d\n", ret); - return ret; + goto lpm_enable_exit; } - mhi_dev->lpm_disabled = false; + mhi_dev->lpm_disable_depth = 0; + +lpm_enable_exit: + spin_unlock_irqrestore(&mhi_dev->lpm_lock, flags); return ret; } @@ -432,11 +586,31 @@ static void mhi_status_cb(struct mhi_controller *mhi_cntrl, { struct mhi_dev *mhi_dev = priv; struct device *dev = &mhi_dev->pci_dev->dev; + int ret; - if (reason == MHI_CB_IDLE) { - MHI_LOG("Schedule runtime suspend 1\n"); + switch (reason) { + case MHI_CB_IDLE: + MHI_LOG("Schedule runtime suspend\n"); pm_runtime_mark_last_busy(dev); pm_request_autosuspend(dev); + break; + case MHI_CB_BW_REQ: + if (mhi_dev->bw_scale) + mhi_dev->bw_scale(mhi_cntrl, mhi_dev); + break; + case MHI_CB_EE_MISSION_MODE: + /* + * we need to force a suspend so device can switch to + * mission mode pcie phy settings. + */ + pm_runtime_get(dev); + ret = mhi_force_suspend(mhi_cntrl); + if (!ret) + mhi_runtime_resume(dev); + pm_runtime_put(dev); + break; + default: + MHI_ERR("Unhandled cb:0x%x\n", reason); } } @@ -569,6 +743,7 @@ static struct mhi_controller *mhi_register_controller(struct pci_dev *pci_dev) mhi_cntrl->of_node = of_node; mhi_dev->pci_dev = pci_dev; + spin_lock_init(&mhi_dev->lpm_lock); /* setup power management apis */ mhi_cntrl->status_cb = mhi_status_cb; @@ -579,6 +754,8 @@ static struct mhi_controller *mhi_register_controller(struct pci_dev *pci_dev) mhi_cntrl->lpm_disable = mhi_lpm_disable; mhi_cntrl->lpm_enable = mhi_lpm_enable; mhi_cntrl->time_get = mhi_time_get; + mhi_cntrl->remote_timer_freq = 19200000; + mhi_cntrl->local_timer_freq = 19200000; ret = of_register_mhi_controller(mhi_cntrl); if (ret) @@ -650,7 +827,6 @@ int mhi_pci_probe(struct pci_dev *pci_dev, } pm_runtime_mark_last_busy(&pci_dev->dev); - pm_runtime_allow(&pci_dev->dev); MHI_LOG("Return successful\n"); diff --git a/drivers/bus/mhi/controllers/mhi_qcom.h b/drivers/bus/mhi/controllers/mhi_qcom.h index a843c98341b98e71d20bbfaa796ff3539e5eb7fe..91396c4aac08e7ee7aa3c1e202a44d719a9e92f5 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.h +++ b/drivers/bus/mhi/controllers/mhi_qcom.h @@ -26,18 +26,43 @@ #define MHI_RPM_SUSPEND_TMR_MS (250) #define MHI_PCI_BAR_NUM (0) +/* timesync time calculations */ +#define REMOTE_TICKS_TO_US(x) (div_u64((x) * 100ULL, \ + div_u64(mhi_cntrl->remote_timer_freq, 10000ULL))) +#define REMOTE_TICKS_TO_SEC(x) (div_u64((x), \ + mhi_cntrl->remote_timer_freq)) +#define REMOTE_TIME_REMAINDER_US(x) (REMOTE_TICKS_TO_US((x)) % \ + (REMOTE_TICKS_TO_SEC((x)) * 1000000ULL)) + 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]) +enum mhi_suspend_mode { + MHI_ACTIVE_STATE, + MHI_DEFAULT_SUSPEND, + MHI_FAST_LINK_OFF, + MHI_FAST_LINK_ON, +}; + +#define MHI_IS_SUSPENDED(mode) (mode) + struct mhi_dev { struct pci_dev *pci_dev; + bool drv_supported; u32 smmu_cfg; int resn; void *arch_info; bool powered_on; dma_addr_t iova_start; dma_addr_t iova_stop; - bool lpm_disabled; + enum mhi_suspend_mode suspend_mode; + + /* if set, soc support dynamic bw scaling */ + void (*bw_scale)(struct mhi_controller *mhi_cntrl, + struct mhi_dev *mhi_dev); + unsigned int lpm_disable_depth; + /* lock to toggle low power modes */ + spinlock_t lpm_lock; }; void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl); @@ -51,8 +76,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl); void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl); int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl); void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl); -int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful); -int mhi_arch_link_on(struct mhi_controller *mhi_cntrl); +int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl); +int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl); #else @@ -78,13 +103,12 @@ static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl) { } -static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, - bool graceful) +static inline int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl) { return 0; } -static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) +static inline int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { return 0; } diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 291c41b2dca2d5091a7e98c66dad6161add43dff..ccde51335022b9bdc06f5d23938a9bd79a9c6330 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,12 +27,14 @@ #include "mhi_internal.h" -/* setup rddm vector table for rddm transfer */ -static void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, +/* setup rddm vector table for rddm transfer and program rxvec */ +void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, struct image_info *img_info) { struct mhi_buf *mhi_buf = img_info->mhi_buf; struct bhi_vec_entry *bhi_vec = img_info->bhi_vec; + void __iomem *base = mhi_cntrl->bhie; + u32 sequence_id; int i = 0; for (i = 0; i < img_info->entries - 1; i++, mhi_buf++, bhi_vec++) { @@ -41,17 +43,35 @@ static void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, bhi_vec->dma_addr = mhi_buf->dma_addr; bhi_vec->size = mhi_buf->len; } + + MHI_LOG("BHIe programming for RDDM\n"); + + mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS, + upper_32_bits(mhi_buf->dma_addr)); + + mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS, + lower_32_bits(mhi_buf->dma_addr)); + + mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len); + sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK; + + if (unlikely(!sequence_id)) + sequence_id = 1; + + mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS, + BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT, + sequence_id); + + MHI_LOG("address:%pad len:0x%lx sequence:%u\n", + &mhi_buf->dma_addr, mhi_buf->len, sequence_id); } /* collect rddm during kernel panic */ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) { int ret; - struct mhi_buf *mhi_buf; - u32 sequence_id; u32 rx_status; enum mhi_ee ee; - struct image_info *rddm_image = mhi_cntrl->rddm_image; const u32 delayus = 2000; u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus; const u32 rddm_timeout_us = 200000; @@ -77,51 +97,40 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) /* update should take the effect immediately */ smp_wmb(); - /* setup the RX vector table */ - mhi_rddm_prepare(mhi_cntrl, rddm_image); - mhi_buf = &rddm_image->mhi_buf[rddm_image->entries - 1]; - - MHI_LOG("Starting BHIe programming for RDDM\n"); - - mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS, - upper_32_bits(mhi_buf->dma_addr)); - - mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS, - lower_32_bits(mhi_buf->dma_addr)); - - mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len); - sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK; + /* + * Make sure device is not already in RDDM. + * In case device asserts and a kernel panic follows, device will + * already be in RDDM. Do not trigger SYS ERR again and proceed with + * waiting for image download completion. + */ + ee = mhi_get_exec_env(mhi_cntrl); + if (ee != MHI_EE_RDDM) { - if (unlikely(!sequence_id)) - sequence_id = 1; + MHI_LOG("Trigger device into RDDM mode using SYSERR\n"); + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR); + MHI_LOG("Waiting for device to enter RDDM\n"); + while (rddm_retry--) { + ee = mhi_get_exec_env(mhi_cntrl); + if (ee == MHI_EE_RDDM) + break; - mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS, - BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT, - sequence_id); + udelay(delayus); + } - MHI_LOG("Trigger device into RDDM mode\n"); - mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR); + if (rddm_retry <= 0) { + /* Hardware reset; force device to enter rddm */ + MHI_LOG( + "Did not enter RDDM, do a host req. reset\n"); + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, + MHI_SOC_RESET_REQ_OFFSET, + MHI_SOC_RESET_REQ); + udelay(delayus); + } - MHI_LOG("Waiting for device to enter RDDM\n"); - while (rddm_retry--) { ee = mhi_get_exec_env(mhi_cntrl); - if (ee == MHI_EE_RDDM) - break; - - udelay(delayus); - } - - if (rddm_retry <= 0) { - /* This is a hardware reset, will force device to enter rddm */ - MHI_LOG( - "Did not enter RDDM triggering host req. reset to force rddm\n"); - mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, - MHI_SOC_RESET_REQ_OFFSET, MHI_SOC_RESET_REQ); - udelay(delayus); } - ee = mhi_get_exec_env(mhi_cntrl); MHI_LOG("Waiting for image download completion, current EE:%s\n", TO_MHI_EXEC_STR(ee)); while (retry--) { @@ -154,70 +163,15 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic) { void __iomem *base = mhi_cntrl->bhie; - rwlock_t *pm_lock = &mhi_cntrl->pm_lock; - struct image_info *rddm_image = mhi_cntrl->rddm_image; - struct mhi_buf *mhi_buf; - int ret; u32 rx_status; - u32 sequence_id; - - if (!rddm_image) - return -ENOMEM; if (in_panic) return __mhi_download_rddm_in_panic(mhi_cntrl); - MHI_LOG("Waiting for device to enter RDDM state from EE:%s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee)); - - ret = wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_RDDM || - MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - - if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - MHI_ERR("MHI is not in valid state, pm_state:%s ee:%s\n", - to_mhi_pm_state_str(mhi_cntrl->pm_state), - TO_MHI_EXEC_STR(mhi_cntrl->ee)); - return -EIO; - } - - mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image); - - /* vector table is the last entry */ - mhi_buf = &rddm_image->mhi_buf[rddm_image->entries - 1]; - - read_lock_bh(pm_lock); - if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { - read_unlock_bh(pm_lock); - return -EIO; - } - - MHI_LOG("Starting BHIe Programming for RDDM\n"); - - mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS, - upper_32_bits(mhi_buf->dma_addr)); - - mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS, - lower_32_bits(mhi_buf->dma_addr)); - - mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len); - - sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK; - mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS, - BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT, - sequence_id); - read_unlock_bh(pm_lock); - - MHI_LOG("Upper:0x%x Lower:0x%x len:0x%lx sequence:%u\n", - upper_32_bits(mhi_buf->dma_addr), - lower_32_bits(mhi_buf->dma_addr), - mhi_buf->len, sequence_id); MHI_LOG("Waiting for image download completion\n"); /* waiting for image download completion */ wait_event_timeout(mhi_cntrl->state_event, - MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, BHIE_RXVECSTATUS_STATUS_BMSK, @@ -225,9 +179,6 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic) &rx_status) || rx_status, msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) - return -EIO; - return (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) ? 0 : -EIO; } EXPORT_SYMBOL(mhi_download_rddm_img); @@ -490,9 +441,9 @@ void mhi_fw_load_worker(struct work_struct *work) MHI_LOG("Device current EE:%s\n", TO_MHI_EXEC_STR(mhi_cntrl->ee)); - /* if device in pthru, we do not have to load firmware */ + /* if device in pthru, do reset to ready state transition */ if (mhi_cntrl->ee == MHI_EE_PTHRU) - return; + goto fw_load_ee_pthru; fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ? mhi_cntrl->edl_image : mhi_cntrl->fw_image; @@ -556,6 +507,7 @@ void mhi_fw_load_worker(struct work_struct *work) mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image); } +fw_load_ee_pthru: /* transitioning into MHI RESET->READY state */ ret = mhi_ready_state_transition(mhi_cntrl); diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index da5df8d8466186a0716ba71870e0bf185bb563a1..da10001d560c7215d250e1baee22f4c811da709f 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -49,6 +49,7 @@ const char * const mhi_state_str[MHI_STATE_MAX] = { [MHI_STATE_M1] = "M1", [MHI_STATE_M2] = "M2", [MHI_STATE_M3] = "M3", + [MHI_STATE_M3_FAST] = "M3_FAST", [MHI_STATE_BHI] = "BHI", [MHI_STATE_SYS_ERR] = "SYS_ERR", }; @@ -80,6 +81,95 @@ const char *to_mhi_pm_state_str(enum MHI_PM_STATE state) return mhi_pm_state_str[index]; } +static ssize_t bus_vote_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + atomic_read(&mhi_dev->bus_vote)); +} + +static ssize_t bus_vote_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + int ret = -EINVAL; + + if (sysfs_streq(buf, "get")) { + ret = mhi_device_get_sync(mhi_dev, MHI_VOTE_BUS); + } else if (sysfs_streq(buf, "put")) { + mhi_device_put(mhi_dev, MHI_VOTE_BUS); + ret = 0; + } + + return ret ? ret : count; +} +static DEVICE_ATTR_RW(bus_vote); + +static ssize_t device_vote_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + atomic_read(&mhi_dev->dev_vote)); +} + +static ssize_t device_vote_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + int ret = -EINVAL; + + if (sysfs_streq(buf, "get")) { + ret = mhi_device_get_sync(mhi_dev, MHI_VOTE_DEVICE); + } else if (sysfs_streq(buf, "put")) { + mhi_device_put(mhi_dev, MHI_VOTE_DEVICE); + ret = 0; + } + + return ret ? ret : count; +} +static DEVICE_ATTR_RW(device_vote); + +static struct attribute *mhi_vote_attrs[] = { + &dev_attr_bus_vote.attr, + &dev_attr_device_vote.attr, + NULL, +}; + +static const struct attribute_group mhi_vote_group = { + .attrs = mhi_vote_attrs, +}; + +int mhi_create_vote_sysfs(struct mhi_controller *mhi_cntrl) +{ + return sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj, + &mhi_vote_group); +} + +void mhi_destroy_vote_sysfs(struct mhi_controller *mhi_cntrl) +{ + struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev; + + sysfs_remove_group(&mhi_dev->dev.kobj, &mhi_vote_group); + + /* relinquish any pending votes for device */ + while (atomic_read(&mhi_dev->dev_vote)) + mhi_device_put(mhi_dev, MHI_VOTE_DEVICE); + + /* remove pending votes for the bus */ + while (atomic_read(&mhi_dev->bus_vote)) + mhi_device_put(mhi_dev, MHI_VOTE_BUS); +} + /* MHI protocol require transfer ring to be aligned to ring length */ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl, struct mhi_ring *ring, @@ -119,7 +209,8 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl) /* for BHI INTVEC msi */ ret = request_threaded_irq(mhi_cntrl->irq[0], mhi_intvec_handlr, - mhi_intvec_threaded_handlr, IRQF_ONESHOT, + mhi_intvec_threaded_handlr, + IRQF_ONESHOT | IRQF_NO_SUSPEND, "mhi", mhi_cntrl); if (ret) return ret; @@ -129,8 +220,8 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl) continue; ret = request_irq(mhi_cntrl->irq[mhi_event->msi], - mhi_msi_handlr, IRQF_SHARED, "mhi", - mhi_event); + mhi_msi_handlr, IRQF_SHARED | IRQF_NO_SUSPEND, + "mhi", mhi_event); if (ret) { MHI_ERR("Error requesting irq:%d for ev:%d\n", mhi_cntrl->irq[mhi_event->msi], i); @@ -458,6 +549,7 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl) return -ENOMEM; spin_lock_init(&mhi_tsync->lock); + mutex_init(&mhi_tsync->lpm_mutex); INIT_LIST_HEAD(&mhi_tsync->head); init_completion(&mhi_tsync->completion); @@ -667,7 +759,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size, tre_ring->pre_aligned, tre_ring->dma_handle); - kfree(buf_ring->base); + vfree(buf_ring->base); buf_ring->base = tre_ring->base = NULL; chan_ctxt->rbase = 0; @@ -692,7 +784,7 @@ int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, buf_ring->el_size = sizeof(struct mhi_buf_info); buf_ring->len = buf_ring->el_size * buf_ring->elements; - buf_ring->base = kzalloc(buf_ring->len, GFP_KERNEL); + buf_ring->base = vzalloc(buf_ring->len); if (!buf_ring->base) { mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size, @@ -906,8 +998,8 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, if (!of_node) return -EINVAL; - mhi_cntrl->mhi_chan = kcalloc(mhi_cntrl->max_chan, - sizeof(*mhi_cntrl->mhi_chan), GFP_KERNEL); + mhi_cntrl->mhi_chan = vzalloc(mhi_cntrl->max_chan * + sizeof(*mhi_cntrl->mhi_chan)); if (!mhi_cntrl->mhi_chan) return -ENOMEM; @@ -1054,7 +1146,7 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, return 0; error_chan_cfg: - kfree(mhi_cntrl->mhi_chan); + vfree(mhi_cntrl->mhi_chan); return -EINVAL; } @@ -1274,6 +1366,7 @@ void mhi_unregister_mhi_controller(struct mhi_controller *mhi_cntrl) list_del(&mhi_cntrl->node); mutex_unlock(&mhi_bus.lock); } +EXPORT_SYMBOL(mhi_unregister_mhi_controller); /* set ptr to control private data */ static inline void mhi_controller_set_devdata(struct mhi_controller *mhi_cntrl, @@ -1335,6 +1428,9 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) memset_io(mhi_cntrl->bhie + BHIE_RXVECADDR_LOW_OFFS, 0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS + 4); + + if (mhi_cntrl->rddm_image) + mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image); } mhi_cntrl->pre_init = true; @@ -1371,6 +1467,7 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl) mhi_deinit_dev_ctxt(mhi_cntrl); mhi_cntrl->pre_init = false; } +EXPORT_SYMBOL(mhi_unprepare_after_power_down); /* match dev to drv */ static int mhi_match(struct device *dev, struct device_driver *drv) @@ -1424,7 +1521,7 @@ static int mhi_driver_probe(struct device *dev) int ret; /* bring device out of lpm */ - ret = mhi_device_get_sync(mhi_dev); + ret = mhi_device_get_sync(mhi_dev, MHI_VOTE_DEVICE); if (ret) return ret; @@ -1472,7 +1569,7 @@ static int mhi_driver_probe(struct device *dev) mhi_prepare_for_transfer(mhi_dev); exit_probe: - mhi_device_put(mhi_dev); + mhi_device_put(mhi_dev, MHI_VOTE_DEVICE); return ret; } @@ -1547,11 +1644,13 @@ static int mhi_driver_remove(struct device *dev) if (mhi_cntrl->tsync_dev == mhi_dev) mhi_cntrl->tsync_dev = NULL; - /* relinquish any pending votes */ - read_lock_bh(&mhi_cntrl->pm_lock); - while (atomic_read(&mhi_dev->dev_wake)) - mhi_device_put(mhi_dev); - read_unlock_bh(&mhi_cntrl->pm_lock); + /* relinquish any pending votes for device */ + while (atomic_read(&mhi_dev->dev_vote)) + mhi_device_put(mhi_dev, MHI_VOTE_DEVICE); + + /* remove pending votes for the bus */ + while (atomic_read(&mhi_dev->bus_vote)) + mhi_device_put(mhi_dev, MHI_VOTE_BUS); return 0; } @@ -1595,7 +1694,8 @@ struct mhi_device *mhi_alloc_device(struct mhi_controller *mhi_cntrl) mhi_dev->bus = mhi_cntrl->bus; mhi_dev->slot = mhi_cntrl->slot; mhi_dev->mtu = MHI_MAX_MTU; - atomic_set(&mhi_dev->dev_wake, 0); + atomic_set(&mhi_dev->dev_vote, 0); + atomic_set(&mhi_dev->bus_vote, 0); return mhi_dev; } diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 5da0feab0eabb108d5ee90b6b3da93f7b6e35772..8853ba4a97c4be8eab329bd2f66b98699ed6edf6 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -234,8 +234,11 @@ extern struct bus_type mhi_bus_type; #define SOC_HW_VERSION_MINOR_VER_BMSK (0x000000FF) #define SOC_HW_VERSION_MINOR_VER_SHFT (0) -/* convert ticks to micro seconds by dividing by 19.2 */ -#define TIME_TICKS_TO_US(x) (div_u64((x) * 10, 192)) +/* timesync time calculations */ +#define LOCAL_TICKS_TO_US(x) (div_u64((x) * 100ULL, \ + div_u64(mhi_cntrl->local_timer_freq, 10000ULL))) +#define REMOTE_TICKS_TO_US(x) (div_u64((x) * 100ULL, \ + div_u64(mhi_cntrl->remote_timer_freq, 10000ULL))) struct mhi_event_ctxt { u32 reserved : 8; @@ -336,6 +339,8 @@ enum mhi_cmd_type { #define MHI_TRE_GET_EV_TIME(tre) ((tre)->ptr) #define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits((tre)->ptr) #define MHI_TRE_GET_EV_VEID(tre) (((tre)->dword[0] >> 16) & 0xFF) +#define MHI_TRE_GET_EV_LINKSPEED(tre) (((tre)->dword[1] >> 24) & 0xFF) +#define MHI_TRE_GET_EV_LINKWIDTH(tre) ((tre)->dword[0] & 0xFF) /* transfer descriptor macros */ #define MHI_TRE_DATA_PTR(ptr) (ptr) @@ -368,6 +373,7 @@ enum MHI_PKT_TYPE { MHI_PKT_TYPE_RSC_TX_EVENT = 0x28, MHI_PKT_TYPE_EE_EVENT = 0x40, MHI_PKT_TYPE_TSYNC_EVENT = 0x48, + MHI_PKT_TYPE_BW_REQ_EVENT = 0x50, MHI_PKT_TYPE_STALE_EVENT, /* internal event */ }; @@ -753,6 +759,19 @@ int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability, int mhi_init_timesync(struct mhi_controller *mhi_cntrl); int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl); void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl); +int mhi_create_vote_sysfs(struct mhi_controller *mhi_cntrl); +void mhi_destroy_vote_sysfs(struct mhi_controller *mhi_cntrl); +int mhi_early_notify_device(struct device *dev, void *data); + +/* timesync log support */ +static inline void mhi_timesync_log(struct mhi_controller *mhi_cntrl) +{ + struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; + + if (mhi_tsync && mhi_cntrl->tsync_log) + mhi_cntrl->tsync_log(mhi_cntrl, + readq_no_log(mhi_tsync->time_reg)); +} /* memory allocation methods */ static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, @@ -808,6 +827,8 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl); int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl); void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl); int mhi_dtr_init(void); +void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, + struct image_info *img_info); /* isr handlers */ irqreturn_t mhi_msi_handlr(int irq_number, void *dev); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index d4d943c6a64e14c65cd9d0903a123e8dca2a9069..52df21b68e9f8f5f0408148451615c7bf0fc53bf 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -646,6 +646,22 @@ int mhi_destroy_device(struct device *dev, void *data) return 0; } +int mhi_early_notify_device(struct device *dev, void *data) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + + /* skip early notification */ + if (!mhi_dev->early_notif) + return 0; + + MHI_LOG("Early notification for dev:%s\n", mhi_dev->chan_name); + + mhi_notify(mhi_dev, MHI_CB_FATAL_ERROR); + + return 0; +} + void mhi_notify(struct mhi_device *mhi_dev, enum MHI_CB cb_reason) { struct mhi_driver *mhi_drv; @@ -717,7 +733,8 @@ static ssize_t time_us_show(struct device *dev, } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n", - TIME_TICKS_TO_US(t_host), TIME_TICKS_TO_US(t_device)); + LOCAL_TICKS_TO_US(t_host), + REMOTE_TICKS_TO_US(t_device)); } static DEVICE_ATTR_RO(time_us); @@ -855,6 +872,13 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) /* add if there is a matching DT node */ mhi_assign_of_node(mhi_cntrl, mhi_dev); + /* + * if set, these device should get a early notification during + * early notification state + */ + mhi_dev->early_notif = + of_property_read_bool(mhi_dev->dev.of_node, + "mhi,early-notify"); /* init wake source */ if (mhi_dev->dl_chan && mhi_dev->dl_chan->wake_capable) device_init_wakeup(&mhi_dev->dev, true); @@ -1124,6 +1148,25 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, local_rp->ptr, local_rp->dword[0], local_rp->dword[1]); switch (type) { + case MHI_PKT_TYPE_BW_REQ_EVENT: + { + struct mhi_link_info *link_info; + + link_info = &mhi_cntrl->mhi_link_info; + write_lock_irq(&mhi_cntrl->pm_lock); + link_info->target_link_speed = + MHI_TRE_GET_EV_LINKSPEED(local_rp); + link_info->target_link_width = + MHI_TRE_GET_EV_LINKWIDTH(local_rp); + write_unlock_irq(&mhi_cntrl->pm_lock); + MHI_VERB( + "Received BW_REQ with link speed:0x%x width:0x%x\n", + link_info->target_link_speed, + link_info->target_link_width); + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, + MHI_CB_BW_REQ); + break; + } case MHI_PKT_TYPE_STATE_CHANGE_EVENT: { enum mhi_dev_state new_state; @@ -1383,8 +1426,16 @@ void mhi_ctrl_ev_task(unsigned long data) * pm_state can change from reg access valid to no access while this * therad being executed. */ - if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { + /* + * we may have a pending event but not allowed to + * process it since we probably in a suspended state, + * trigger a resume. + */ + mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); return; + } /* process ctrl events events */ ret = mhi_event->process_event(mhi_cntrl, mhi_event, U32_MAX); @@ -1439,15 +1490,17 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) struct mhi_controller *mhi_cntrl = dev; enum mhi_dev_state state = MHI_STATE_MAX; enum MHI_PM_STATE pm_state = 0; - enum mhi_ee ee; + enum mhi_ee ee = 0; MHI_VERB("Enter\n"); write_lock_irq(&mhi_cntrl->pm_lock); if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { state = mhi_get_mhi_state(mhi_cntrl); - ee = mhi_get_exec_env(mhi_cntrl); - MHI_LOG("device ee:%s dev_state:%s\n", TO_MHI_EXEC_STR(ee), + ee = mhi_cntrl->ee; + mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); + MHI_LOG("device ee:%s dev_state:%s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), TO_MHI_STATE_STR(state)); } @@ -1457,6 +1510,17 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) MHI_PM_SYS_ERR_DETECT); } write_unlock_irq(&mhi_cntrl->pm_lock); + + /* if device in rddm don't bother processing sys error */ + if (mhi_cntrl->ee == MHI_EE_RDDM) { + if (mhi_cntrl->ee != ee) { + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, + MHI_CB_EE_RDDM); + wake_up_all(&mhi_cntrl->state_event); + } + goto exit_intvec; + } + if (pm_state == MHI_PM_SYS_ERR_DETECT) { wake_up_all(&mhi_cntrl->state_event); @@ -1468,6 +1532,7 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) schedule_work(&mhi_cntrl->syserr_worker); } +exit_intvec: MHI_VERB("Exit\n"); return IRQ_HANDLED; @@ -1842,12 +1907,12 @@ int mhi_debugfs_mhi_states_show(struct seq_file *m, void *d) struct mhi_controller *mhi_cntrl = m->private; seq_printf(m, - "pm_state:%s dev_state:%s EE:%s M0:%u M2:%u M3:%u wake:%d dev_wake:%u alloc_size:%u pending_pkts:%u\n", + "pm_state:%s dev_state:%s EE:%s M0:%u M2:%u M3:%u M3_Fast:%u wake:%d dev_wake:%u alloc_size:%u pending_pkts:%u\n", to_mhi_pm_state_str(mhi_cntrl->pm_state), TO_MHI_STATE_STR(mhi_cntrl->dev_state), TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_cntrl->M0, mhi_cntrl->M2, mhi_cntrl->M3, - mhi_cntrl->wake_set, + mhi_cntrl->M3_FAST, mhi_cntrl->wake_set, atomic_read(&mhi_cntrl->dev_wake), atomic_read(&mhi_cntrl->alloc_size), atomic_read(&mhi_cntrl->pending_pkts)); diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index ac4b2bc3d47977600339f8373a567527fe4f9033..93f642895ac09fb7cf3db45b42e8841025d13698 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -39,6 +39,7 @@ * POR -> M0 -> M2 --> M0 * POR -> FW_DL_ERR * FW_DL_ERR <--> FW_DL_ERR + * M0 <--> M0 * M0 -> FW_DL_ERR * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR @@ -60,9 +61,9 @@ static struct mhi_pm_transitions const mhi_state_transitions[] = { }, { MHI_PM_M0, - MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_SYS_ERR_DETECT | - MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | - MHI_PM_FW_DL_ERR + MHI_PM_M0 | MHI_PM_M2 | MHI_PM_M3_ENTER | + MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR }, { MHI_PM_M2, @@ -144,6 +145,9 @@ enum MHI_PM_STATE __must_check mhi_tryset_pm_state( MHI_VERB("Transition to pm state from:%s to:%s\n", to_mhi_pm_state_str(cur_state), to_mhi_pm_state_str(state)); + if (MHI_REG_ACCESS_VALID(cur_state) && MHI_REG_ACCESS_VALID(state)) + mhi_timesync_log(mhi_cntrl); + mhi_cntrl->pm_state = state; return mhi_cntrl->pm_state; } @@ -328,7 +332,7 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) } mhi_cntrl->M0++; read_lock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->wake_get(mhi_cntrl, false); + mhi_cntrl->wake_get(mhi_cntrl, true); /* ring all event rings and CMD ring only if we're in mission mode */ if (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) { @@ -441,27 +445,31 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) MHI_LOG("Processing Mission Mode Transition\n"); - /* force MHI to be in M0 state before continuing */ - ret = __mhi_device_get_sync(mhi_cntrl); - if (ret) - return ret; - - ret = -EIO; - write_lock_irq(&mhi_cntrl->pm_lock); 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); - read_lock_bh(&mhi_cntrl->pm_lock); if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) - goto error_mission_mode; + return -EIO; wake_up_all(&mhi_cntrl->state_event); + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, + MHI_CB_EE_MISSION_MODE); + + /* force MHI to be in M0 state before continuing */ + ret = __mhi_device_get_sync(mhi_cntrl); + if (ret) + return ret; + + read_lock_bh(&mhi_cntrl->pm_lock); + /* add elements to all HW event rings */ - if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { + ret = -EIO; goto error_mission_mode; + } mhi_event = mhi_cntrl->mhi_event; for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) { @@ -492,7 +500,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) /* add supported devices */ mhi_create_devices(mhi_cntrl); - ret = 0; + /* setup sysfs nodes for userspace votes */ + mhi_create_vote_sysfs(mhi_cntrl); read_lock_bh(&mhi_cntrl->pm_lock); @@ -522,9 +531,20 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, to_mhi_pm_state_str(transition_state)); /* We must notify MHI control driver so it can clean up first */ - if (transition_state == MHI_PM_SYS_ERR_PROCESS) + if (transition_state == MHI_PM_SYS_ERR_PROCESS) { + /* + * if controller support rddm, we do not process + * sys error state, instead we will jump directly + * to rddm state + */ + if (mhi_cntrl->rddm_image) { + MHI_LOG( + "Controller Support RDDM, skipping SYS_ERR_PROCESS\n"); + return; + } mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_SYS_ERROR); + } mutex_lock(&mhi_cntrl->pm_mutex); write_lock_irq(&mhi_cntrl->pm_lock); @@ -590,6 +610,9 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, MHI_LOG("Finish resetting channels\n"); + /* remove support for userspace votes */ + mhi_destroy_vote_sysfs(mhi_cntrl); + MHI_LOG("Waiting for all pending threads to complete\n"); wake_up_all(&mhi_cntrl->state_event); flush_work(&mhi_cntrl->st_worker); @@ -870,6 +893,36 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) } EXPORT_SYMBOL(mhi_async_power_up); +/* Transition MHI into error state and notify critical clients */ +void mhi_control_error(struct mhi_controller *mhi_cntrl) +{ + enum MHI_PM_STATE cur_state; + + MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); + + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT); + write_unlock_irq(&mhi_cntrl->pm_lock); + + if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) { + MHI_ERR("Failed to transition to state:%s from:%s\n", + to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT), + to_mhi_pm_state_str(cur_state)); + goto exit_control_error; + } + + /* start notifying all clients who request early notification */ + device_for_each_child(mhi_cntrl->dev, NULL, mhi_early_notify_device); + +exit_control_error: + MHI_LOG("Exit with pm_state:%s MHI_STATE:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); +} +EXPORT_SYMBOL(mhi_control_error); + void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) { enum MHI_PM_STATE cur_state; @@ -925,6 +978,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) int ret; enum MHI_PM_STATE new_state; struct mhi_chan *itr, *tmp; + struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev; if (mhi_cntrl->pm_state == MHI_PM_DISABLE) return -EINVAL; @@ -932,9 +986,10 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) return -EIO; - /* do a quick check to see if any pending data, then exit */ + /* do a quick check to see if any pending votes to keep us busy */ if (atomic_read(&mhi_cntrl->dev_wake) || - atomic_read(&mhi_cntrl->pending_pkts)) { + atomic_read(&mhi_cntrl->pending_pkts) || + atomic_read(&mhi_dev->bus_vote)) { MHI_VERB("Busy, aborting M3\n"); return -EBUSY; } @@ -961,9 +1016,13 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) write_lock_irq(&mhi_cntrl->pm_lock); - /* we're asserting wake so count would be @ least 1 */ + /* + * Check the votes once more to see if we should abort + * suepend. We're asserting wake so count would be @ least 1 + */ if (atomic_read(&mhi_cntrl->dev_wake) > 1 || - atomic_read(&mhi_cntrl->pending_pkts)) { + atomic_read(&mhi_cntrl->pending_pkts) || + atomic_read(&mhi_dev->bus_vote)) { MHI_VERB("Busy, aborting M3\n"); write_unlock_irq(&mhi_cntrl->pm_lock); ret = -EBUSY; @@ -1020,6 +1079,114 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) } EXPORT_SYMBOL(mhi_pm_suspend); +/** + * mhi_pm_fast_suspend - Faster suspend path where we transition host to + * inactive state w/o suspending device. Useful for cases where we want apps to + * go into power collapse but keep the physical link in active state. + */ +int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) +{ + int ret; + enum MHI_PM_STATE new_state; + struct mhi_chan *itr, *tmp; + + if (mhi_cntrl->pm_state == MHI_PM_DISABLE) + return -EINVAL; + + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) + return -EIO; + + /* do a quick check to see if any pending votes to keep us busy */ + if (atomic_read(&mhi_cntrl->pending_pkts)) { + MHI_VERB("Busy, aborting M3\n"); + return -EBUSY; + } + + /* disable ctrl event processing */ + tasklet_disable(&mhi_cntrl->mhi_event->task); + + write_lock_irq(&mhi_cntrl->pm_lock); + + /* + * Check the votes once more to see if we should abort + * suspend. + */ + if (atomic_read(&mhi_cntrl->pending_pkts)) { + MHI_VERB("Busy, aborting M3\n"); + ret = -EBUSY; + goto error_suspend; + } + + /* anytime after this, we will resume thru runtime pm framework */ + MHI_LOG("Allowing Fast M3 transition\n"); + + /* save the current states */ + mhi_cntrl->saved_pm_state = mhi_cntrl->pm_state; + mhi_cntrl->saved_dev_state = mhi_cntrl->dev_state; + + /* If we're in M2, we need to switch back to M0 first */ + if (mhi_cntrl->pm_state == MHI_PM_M2) { + new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M0); + if (new_state != MHI_PM_M0) { + MHI_ERR("Error set pm_state to:%s from pm_state:%s\n", + to_mhi_pm_state_str(MHI_PM_M0), + to_mhi_pm_state_str(mhi_cntrl->pm_state)); + ret = -EIO; + goto error_suspend; + } + } + + new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M3_ENTER); + if (new_state != MHI_PM_M3_ENTER) { + MHI_ERR("Error setting to pm_state:%s from pm_state:%s\n", + to_mhi_pm_state_str(MHI_PM_M3_ENTER), + to_mhi_pm_state_str(mhi_cntrl->pm_state)); + ret = -EIO; + goto error_suspend; + } + + /* set dev to M3_FAST and host to M3 */ + new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M3); + if (new_state != MHI_PM_M3) { + MHI_ERR("Error setting to pm_state:%s from pm_state:%s\n", + to_mhi_pm_state_str(MHI_PM_M3), + to_mhi_pm_state_str(mhi_cntrl->pm_state)); + ret = -EIO; + goto error_suspend; + } + + mhi_cntrl->dev_state = MHI_STATE_M3_FAST; + mhi_cntrl->M3_FAST++; + write_unlock_irq(&mhi_cntrl->pm_lock); + + /* now safe to check ctrl event ring */ + tasklet_enable(&mhi_cntrl->mhi_event->task); + mhi_msi_handlr(0, mhi_cntrl->mhi_event); + + if (!notify_client) + return 0; + + /* notify any clients we enter lpm */ + list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, node) { + mutex_lock(&itr->mutex); + if (itr->mhi_dev) + mhi_notify(itr->mhi_dev, MHI_CB_LPM_ENTER); + mutex_unlock(&itr->mutex); + } + + return 0; + +error_suspend: + write_unlock_irq(&mhi_cntrl->pm_lock); + + /* check ctrl event ring for pending work */ + tasklet_enable(&mhi_cntrl->mhi_event->task); + mhi_msi_handlr(0, mhi_cntrl->mhi_event); + + return ret; +} +EXPORT_SYMBOL(mhi_pm_fast_suspend); + int mhi_pm_resume(struct mhi_controller *mhi_cntrl) { enum MHI_PM_STATE cur_state; @@ -1086,6 +1253,81 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl) return 0; } +int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client) +{ + struct mhi_chan *itr, *tmp; + struct mhi_event *mhi_event; + int i; + + MHI_LOG("Entered with pm_state:%s dev_state:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); + + if (mhi_cntrl->pm_state == MHI_PM_DISABLE) + return 0; + + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) + return -EIO; + + MHI_ASSERT(mhi_cntrl->pm_state != MHI_PM_M3, "mhi_pm_state != M3"); + + /* notify any clients we're about to exit lpm */ + if (notify_client) { + list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, + node) { + mutex_lock(&itr->mutex); + if (itr->mhi_dev) + mhi_notify(itr->mhi_dev, MHI_CB_LPM_EXIT); + mutex_unlock(&itr->mutex); + } + } + + write_lock_irq(&mhi_cntrl->pm_lock); + /* restore the states */ + mhi_cntrl->pm_state = mhi_cntrl->saved_pm_state; + mhi_cntrl->dev_state = mhi_cntrl->saved_dev_state; + write_unlock_irq(&mhi_cntrl->pm_lock); + + switch (mhi_cntrl->pm_state) { + case MHI_PM_M0: + mhi_pm_m0_transition(mhi_cntrl); + case MHI_PM_M2: + read_lock_bh(&mhi_cntrl->pm_lock); + /* + * we're doing a double check of pm_state because by the time we + * grab the pm_lock, device may have already initiate a M0 on + * its own. If that's the case we should not be toggling device + * wake. + */ + if (mhi_cntrl->pm_state == MHI_PM_M2) { + mhi_cntrl->wake_get(mhi_cntrl, true); + mhi_cntrl->wake_put(mhi_cntrl, true); + } + read_unlock_bh(&mhi_cntrl->pm_lock); + } + + /* + * In fast suspend/resume case device is not aware host transition + * to suspend state. So, device could be triggering a interrupt while + * host not accepting MSI. We have to manually check each event ring + * upon resume. + */ + mhi_event = mhi_cntrl->mhi_event; + for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) { + if (mhi_event->offload_ev) + continue; + + mhi_msi_handlr(0, mhi_event); + } + + MHI_LOG("Exit with pm_state:%s dev_state:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); + + return 0; +} +EXPORT_SYMBOL(mhi_pm_resume); + int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl) { int ret; @@ -1117,38 +1359,82 @@ int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl) return 0; } -void mhi_device_get(struct mhi_device *mhi_dev) +void mhi_device_get(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; - atomic_inc(&mhi_dev->dev_wake); - read_lock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->wake_get(mhi_cntrl, true); - read_unlock_bh(&mhi_cntrl->pm_lock); + if (vote & MHI_VOTE_DEVICE) { + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_get(mhi_cntrl, true); + read_unlock_bh(&mhi_cntrl->pm_lock); + atomic_inc(&mhi_dev->dev_vote); + } + + if (vote & MHI_VOTE_BUS) { + mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); + atomic_inc(&mhi_dev->bus_vote); + } } EXPORT_SYMBOL(mhi_device_get); -int mhi_device_get_sync(struct mhi_device *mhi_dev) +int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; int ret; + /* + * regardless of any vote we will bring device out lpm and assert + * device wake + */ ret = __mhi_device_get_sync(mhi_cntrl); - if (!ret) - atomic_inc(&mhi_dev->dev_wake); + if (ret) + return ret; - return ret; + if (vote & MHI_VOTE_DEVICE) { + atomic_inc(&mhi_dev->dev_vote); + } else { + /* client did not requested device vote so de-assert dev_wake */ + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_put(mhi_cntrl, false); + read_unlock_bh(&mhi_cntrl->pm_lock); + } + + if (vote & MHI_VOTE_BUS) { + mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); + atomic_inc(&mhi_dev->bus_vote); + } + + return 0; } EXPORT_SYMBOL(mhi_device_get_sync); -void mhi_device_put(struct mhi_device *mhi_dev) +void mhi_device_put(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; - atomic_dec(&mhi_dev->dev_wake); - read_lock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->wake_put(mhi_cntrl, false); - read_unlock_bh(&mhi_cntrl->pm_lock); + if (vote & MHI_VOTE_DEVICE) { + atomic_dec(&mhi_dev->dev_vote); + read_lock_bh(&mhi_cntrl->pm_lock); + if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state)) { + mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + } + mhi_cntrl->wake_put(mhi_cntrl, false); + read_unlock_bh(&mhi_cntrl->pm_lock); + } + + if (vote & MHI_VOTE_BUS) { + atomic_dec(&mhi_dev->bus_vote); + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + + /* + * if counts reach 0, clients release all votes + * send idle cb to to attempt suspend + */ + if (!atomic_read(&mhi_dev->bus_vote)) + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, + MHI_CB_IDLE); + } } EXPORT_SYMBOL(mhi_device_put); @@ -1160,6 +1446,10 @@ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl) to_mhi_pm_state_str(mhi_cntrl->pm_state), TO_MHI_EXEC_STR(mhi_cntrl->ee)); + /* device already in rddm */ + if (mhi_cntrl->ee == MHI_EE_RDDM) + return 0; + MHI_LOG("Triggering SYS_ERR to force rddm state\n"); mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR); diff --git a/drivers/bus/mhi/devices/mhi_netdev.c b/drivers/bus/mhi/devices/mhi_netdev.c index 485d9d430860f46360493c87a80c689211978d41..d32a5f482f36be4cd765e4743ceb15bff9c2c1cb 100644 --- a/drivers/bus/mhi/devices/mhi_netdev.c +++ b/drivers/bus/mhi/devices/mhi_netdev.c @@ -465,12 +465,12 @@ static int mhi_netdev_ioctl_extended(struct net_device *dev, struct ifreq *ifr) /* Request to enable LPM */ MSG_VERB("Enable MHI LPM"); mhi_netdev->wake--; - mhi_device_put(mhi_dev); + mhi_device_put(mhi_dev, MHI_VOTE_DEVICE); } else if (!ext_cmd.u.data && !mhi_netdev->wake) { /* Request to disable LPM */ MSG_VERB("Disable MHI LPM"); mhi_netdev->wake++; - mhi_device_get(mhi_dev); + mhi_device_get(mhi_dev, MHI_VOTE_DEVICE); } break; default: diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 161df9e54d085551483e8ddeb49d34e488fd2474..66de0e2635dbeecea8017dcc84d1386930102fb4 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -380,7 +380,7 @@ config XILINX_HWICAP config R3964 tristate "Siemens R3964 line discipline" - depends on TTY + depends on TTY && BROKEN ---help--- This driver allows synchronous communication with devices using the Siemens R3964 packet protocol. Unless you are dealing with special diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 946d33380be8a7155968b2cbf57f95893db3b6c7..e052a2bf4476f19ca9a9bf9614efc517d8bb8850 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -377,7 +377,7 @@ struct fastrpc_file { int pd; char *spdname; int file_close; - int dsp_process_init; + int dsp_proc_init; struct fastrpc_apps *apps; struct hlist_head perf; struct dentry *debugfs_file; @@ -608,8 +608,13 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { - if (refs) + if (refs) { + if (map->refs + 1 == INT_MAX) { + spin_unlock(&me->hlock); + return -ETOOMANYREFS; + } map->refs++; + } match = map; break; } @@ -620,8 +625,11 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { - if (refs) + if (refs) { + if (map->refs + 1 == INT_MAX) + return -ETOOMANYREFS; map->refs++; + } match = map; break; } @@ -1888,12 +1896,13 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, } } - VERIFY(err, fl->sctx != NULL); - if (err) - goto bail; - VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS); - if (err) + VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS && fl->sctx != NULL); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s domain is not set\n", + __func__, current->comm); + err = -EBADR; goto bail; + } if (!kernel) { VERIFY(err, 0 == context_restore_interrupted(fl, inv, @@ -2227,7 +2236,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, err = -ENOTTY; goto bail; } - fl->dsp_process_init = 1; + fl->dsp_proc_init = 1; bail: kfree(proc_name); if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC)) @@ -2281,7 +2290,7 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) ioctl.crc = NULL; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); - if (err && fl->dsp_process_init) + if (err && fl->dsp_proc_init) pr_err("adsprpc: %s: releasing DSP process failed for %s, returned 0x%x", __func__, current->comm, err); bail: @@ -2572,6 +2581,13 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl, struct fastrpc_buf *rbuf = NULL, *free = NULL; struct hlist_node *n; + VERIFY(err, fl->dsp_proc_init == 1); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s trying to unmap without initialization\n", + __func__, current->comm); + err = -EBADR; + goto bail; + } mutex_lock(&fl->internal_map_mutex); spin_lock(&fl->hlock); @@ -2627,6 +2643,13 @@ static int fastrpc_internal_munmap_fd(struct fastrpc_file *fl, VERIFY(err, (fl && ud)); if (err) goto bail; + VERIFY(err, fl->dsp_proc_init == 1); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s trying to unmap without initialization\n", + __func__, current->comm); + err = -EBADR; + goto bail; + } mutex_lock(&fl->map_mutex); if (fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) { pr_err("adsprpc: mapping not found to unmap fd 0x%x, va 0x%llx, len 0x%x\n", @@ -2653,6 +2676,13 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl, uintptr_t raddr = 0; int err = 0; + VERIFY(err, fl->dsp_proc_init == 1); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s trying to map without initialization\n", + __func__, current->comm); + err = -EBADR; + goto bail; + } mutex_lock(&fl->internal_map_mutex); if (ud->flags == ADSP_MMAP_ADD_PAGES) { if (ud->vaddrin) { @@ -2841,7 +2871,7 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, context_notify_user(me->ctxtable[index], rsp->retval); bail: if (err) - pr_err("adsprpc: invalid response or context\n"); + pr_debug("adsprpc: invalid response or context\n"); return err; } @@ -3183,13 +3213,14 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) int cid, err = 0; - VERIFY(err, fl && fl->sctx); - if (err) + VERIFY(err, fl && fl->sctx && fl->cid >= 0 && fl->cid < NUM_CHANNELS); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s domain is not set\n", + __func__, current->comm); + err = -EBADR; return err; + } cid = fl->cid; - VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); - if (err) - return err; mutex_lock(&me->channel[cid].rpmsg_mutex); VERIFY(err, NULL != me->channel[cid].rpdev); @@ -3286,7 +3317,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->debugfs_file = debugfs_file; memset(&fl->perf, 0, sizeof(fl->perf)); fl->qos_request = 0; - fl->dsp_process_init = 0; + fl->dsp_proc_init = 0; filp->private_data = fl; mutex_init(&fl->internal_map_mutex); mutex_init(&fl->map_mutex); diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 8d67d98e53966af01f7a9e7f3bb1f076ed2f0e11..366eaf2775789100cf339ebd915f1e98be05ef2c 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -726,32 +726,47 @@ int diag_dci_query_event_mask(struct diag_dci_client_tbl *entry, return ((*event_mask_ptr & byte_mask) == byte_mask) ? 1 : 0; } -static int diag_dci_filter_commands(struct diag_pkt_header_t *header) +static int diag_dci_filter_commands(struct diag_pkt_header_t *header, + int header_len) { if (!header) return -ENOMEM; - switch (header->cmd_code) { - case 0x7d: /* Msg Mask Configuration */ - case 0x73: /* Log Mask Configuration */ - case 0x81: /* Event Mask Configuration */ - case 0x82: /* Event Mask Change */ - case 0x60: /* Event Mask Toggle */ - return 1; - } + if (header_len <= 0) + return -EIO; - if (header->cmd_code == 0x4b && header->subsys_id == 0x12) { - switch (header->subsys_cmd_code) { - case 0x60: /* Extended Event Mask Config */ - case 0x61: /* Extended Msg Mask Config */ - case 0x62: /* Extended Log Mask Config */ - case 0x20C: /* Set current Preset ID */ - case 0x20D: /* Get current Preset ID */ - case 0x218: /* HDLC Disabled Command */ + if (header_len) { + switch (header->cmd_code) { + case 0x7d: /* Msg Mask Configuration */ + case 0x73: /* Log Mask Configuration */ + case 0x81: /* Event Mask Configuration */ + case 0x82: /* Event Mask Change */ + case 0x60: /* Event Mask Toggle */ + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: command not supported: %d\n", + header->cmd_code); return 1; } } + if (header_len >= (3*sizeof(uint8_t))) { + if (header->cmd_code == 0x4b && header->subsys_id == 0x12) { + switch (header->subsys_cmd_code) { + case 0x60: /* Extended Event Mask Config */ + case 0x61: /* Extended Msg Mask Config */ + case 0x62: /* Extended Log Mask Config */ + case 0x20C: /* Set current Preset ID */ + case 0x20D: /* Get current Preset ID */ + case 0x218: /* HDLC Disabled Command */ + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: command not supported %d %d %d\n", + header->cmd_code, header->subsys_id, + header->subsys_cmd_code); + return 1; + } + } + } + return 0; } @@ -1800,7 +1815,7 @@ int diag_dci_send_handshake_pkt(int index) static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header, unsigned char *req_buf, int req_len, - int tag) + int tag, int pkt_header_len) { uint8_t cmd_code, subsys_id, i, goto_download = 0; uint8_t header_len = sizeof(struct diag_dci_pkt_header_t); @@ -1810,12 +1825,16 @@ static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header, unsigned char *payload_ptr = driver->apps_dci_buf + header_len; struct diag_dci_pkt_header_t dci_header; - if (!pkt_header || !req_buf || req_len <= 0 || tag < 0) + if (!pkt_header || !req_buf || req_len <= 0 || tag < 0 || + pkt_header_len <= 0) return -EIO; - cmd_code = pkt_header->cmd_code; - subsys_id = pkt_header->subsys_id; - ss_cmd_code = pkt_header->subsys_cmd_code; + if (pkt_header_len >= (sizeof(uint8_t))) + cmd_code = pkt_header->cmd_code; + if (pkt_header_len >= (2 * sizeof(uint8_t))) + subsys_id = pkt_header->subsys_id; + if (pkt_header_len >= (3 * sizeof(uint8_t))) + ss_cmd_code = pkt_header->subsys_cmd_code; if (cmd_code == DIAG_CMD_DOWNLOAD) { *payload_ptr = DIAG_CMD_DOWNLOAD; @@ -1936,7 +1955,7 @@ static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header, static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) { int ret = DIAG_DCI_TABLE_ERR; - int common_cmd = 0; + int common_cmd = 0, header_len = 0; struct diag_pkt_header_t *header = NULL; unsigned char *temp = buf; unsigned char *req_buf = NULL; @@ -1952,8 +1971,7 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) if (!buf) return -EIO; - if (len <= (sizeof(struct dci_pkt_req_t) + - sizeof(struct diag_pkt_header_t)) || + if (len < sizeof(struct dci_pkt_req_t) || len > DCI_REQ_BUF_SIZE) { pr_err("diag: dci: Invalid length %d len in %s", len, __func__); return -EIO; @@ -1964,14 +1982,6 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) read_len += sizeof(struct dci_pkt_req_t); req_len -= sizeof(struct dci_pkt_req_t); req_buf = temp; /* Start of the Request */ - header = (struct diag_pkt_header_t *)temp; - temp += sizeof(struct diag_pkt_header_t); - read_len += sizeof(struct diag_pkt_header_t); - if (read_len >= DCI_REQ_BUF_SIZE) { - pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__, - read_len); - return -EIO; - } mutex_lock(&driver->dci_mutex); dci_entry = diag_dci_get_client_entry(req_hdr.client_id); @@ -1982,11 +1992,40 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) return DIAG_DCI_NO_REG; } + header = (void *)temp; + header_len = len - sizeof(struct dci_pkt_req_t); + if (header_len <= 0) { + mutex_unlock(&driver->dci_mutex); + return -EIO; + } + if (header_len >= sizeof(uint8_t)) { + header->cmd_code = (uint16_t)(*(uint8_t *)temp); + read_len += sizeof(uint8_t); + } + if (header_len >= (2 * sizeof(uint8_t))) { + temp += sizeof(uint8_t); + header->subsys_id = (uint16_t)(*(uint8_t *)temp); + read_len += sizeof(uint8_t); + } + if (header_len == (3 * sizeof(uint8_t))) { + temp += sizeof(uint8_t); + header->subsys_cmd_code = (uint16_t)(*(uint8_t *)temp); + read_len += sizeof(uint8_t); + } else if (header_len >= + (2 * sizeof(uint8_t)) + sizeof(uint16_t)) { + temp += sizeof(uint8_t); + header->subsys_cmd_code = (uint16_t)(*(uint16_t *)temp); + read_len += sizeof(uint16_t); + } + if (read_len > DCI_REQ_BUF_SIZE) { + pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__, + read_len); + mutex_unlock(&driver->dci_mutex); + return -EIO; + } + /* Check if the command is allowed on DCI */ - if (diag_dci_filter_commands(header)) { - pr_debug("diag: command not supported %d %d %d", - header->cmd_code, header->subsys_id, - header->subsys_cmd_code); + if (diag_dci_filter_commands(header, header_len)) { mutex_unlock(&driver->dci_mutex); return DIAG_DCI_SEND_DATA_FAIL; } @@ -2040,14 +2079,18 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) /* Check if it is a dedicated Apps command */ ret = diag_dci_process_apps_pkt(header, req_buf, req_len, - req_entry->tag); + req_entry->tag, header_len); if ((ret == DIAG_DCI_NO_ERROR && !common_cmd) || ret < 0) return ret; - reg_entry.cmd_code = header->cmd_code; - reg_entry.subsys_id = header->subsys_id; - reg_entry.cmd_code_hi = header->subsys_cmd_code; - reg_entry.cmd_code_lo = header->subsys_cmd_code; + if (header_len >= (sizeof(uint8_t))) + reg_entry.cmd_code = header->cmd_code; + if (header_len >= (2 * sizeof(uint8_t))) + reg_entry.subsys_id = header->subsys_id; + if (header_len >= (3 * sizeof(uint8_t))) { + reg_entry.cmd_code_hi = header->subsys_cmd_code; + reg_entry.cmd_code_lo = header->subsys_cmd_code; + } mutex_lock(&driver->cmd_reg_mutex); temp_entry = diag_cmd_search(®_entry, ALL_PROC); diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index 1cbfb97f9a215cdcd49ff601de667d7340e9301e..73b7f194b984f96e03fcbce3393f045a69d79df3 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -553,7 +553,7 @@ static ssize_t diag_dbgfs_read_socketinfo(struct file *file, char __user *ubuf, struct diag_socket_info *info = NULL; struct diagfwd_info *fwd_ctxt = NULL; - if (diag_dbgfs_socketinfo_index >= NUM_PERIPHERALS) { + if (diag_dbgfs_socketinfo_index >= NUM_TYPES) { /* Done. Reset to prepare for future requests */ diag_dbgfs_socketinfo_index = 0; return 0; @@ -659,7 +659,7 @@ static ssize_t diag_dbgfs_read_rpmsginfo(struct file *file, char __user *ubuf, struct diag_rpmsg_info *info = NULL; struct diagfwd_info *fwd_ctxt = NULL; - if (diag_dbgfs_rpmsginfo_index >= NUM_PERIPHERALS) { + if (diag_dbgfs_rpmsginfo_index >= NUM_TYPES) { /* Done. Reset to prepare for future requests */ diag_dbgfs_rpmsginfo_index = 0; return 0; @@ -697,7 +697,7 @@ static ssize_t diag_dbgfs_read_rpmsginfo(struct file *file, char __user *ubuf, bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining, - "name\t\t:\t%s\n" + "name\t\t:\t%s:\t%s\n" "hdl\t\t:\t%pK\n" "inited\t\t:\t%d\n" "opened\t\t:\t%d\n" @@ -712,6 +712,7 @@ static ssize_t diag_dbgfs_read_rpmsginfo(struct file *file, char __user *ubuf, "fwd inited\t:\t%d\n" "fwd opened\t:\t%d\n" "fwd ch_open\t:\t%d\n\n", + info->edge, info->name, info->hdl, info->inited, @@ -793,7 +794,7 @@ static ssize_t diag_dbgfs_read_hsicinfo(struct file *file, char __user *ubuf, unsigned int bytes_in_buffer = 0; struct diag_hsic_info *hsic_info = NULL; - if (diag_dbgfs_hsicinfo_index >= NUM_DIAG_USB_DEV) { + if (diag_dbgfs_hsicinfo_index >= NUM_HSIC_DEV) { /* Done. Reset to prepare for future requests */ diag_dbgfs_hsicinfo_index = 0; return 0; @@ -938,7 +939,7 @@ static ssize_t diag_dbgfs_read_bridge(struct file *file, char __user *ubuf, unsigned int bytes_in_buffer = 0; struct diagfwd_bridge_info *info = NULL; - if (diag_dbgfs_bridgeinfo_index >= NUM_DIAG_USB_DEV) { + if (diag_dbgfs_bridgeinfo_index >= NUM_REMOTE_DEV) { /* Done. Reset to prepare for future requests */ diag_dbgfs_bridgeinfo_index = 0; return 0; diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index eca580ae337ab29fee544aaf0cd3b9a4b12368ee..362597bceba876754f2a855157e40b2a321adf22 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1109,7 +1109,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, rsp.num_bits = driver->last_event_id + 1; memcpy(dest_buf, &rsp, header_len); write_len += header_len; - memcpy(dest_buf + write_len, mask_info->ptr, mask_len); + memcpy(dest_buf + write_len, src_buf + header_len, mask_len); write_len += mask_len; for (i = 0; i < NUM_MD_SESSIONS; i++) { @@ -1206,7 +1206,7 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, int rsp_header_len = sizeof(struct diag_log_config_rsp_t); uint32_t mask_size = 0; struct diag_log_mask_t *log_item = NULL; - struct diag_log_config_req_t *req; + struct diag_log_config_get_req_t *req; struct diag_log_config_rsp_t rsp; struct diag_mask_info *mask_info = NULL; struct diag_md_session_t *info = NULL; @@ -1216,7 +1216,7 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || - src_len < sizeof(struct diag_log_config_req_t)) { + src_len < sizeof(struct diag_log_config_get_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1235,7 +1235,7 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, return 0; } - req = (struct diag_log_config_req_t *)src_buf; + req = (struct diag_log_config_get_req_t *)src_buf; read_len += req_header_len; rsp.cmd_code = DIAG_CMD_LOG_CONFIG; diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h index 0ccadf30f092b4a59833e97ad88c22f7d9c02c0b..53966e58284cbb2d54db667d516ffa86ee5e1af4 100644 --- a/drivers/char/diag/diag_masks.h +++ b/drivers/char/diag/diag_masks.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2017-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,6 +40,13 @@ struct diag_msg_mask_t { uint32_t *ptr; }; +struct diag_log_config_get_req_t { + uint8_t cmd_code; + uint8_t padding[3]; + uint32_t sub_cmd; + uint32_t equip_id; +} __packed; + struct diag_log_config_req_t { uint8_t cmd_code; uint8_t padding[3]; diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index 87e6862ec2aebff4bd8c2b746baf90c9937c8f57..b44410250420fcc040bfd06b0bbb81521d0fde20 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -175,7 +175,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) { int i, peripheral, pid = 0; uint8_t found = 0; - unsigned long flags; + unsigned long flags, flags_sec; struct diag_md_info *ch = NULL; struct diag_md_session_t *session_info = NULL; @@ -207,6 +207,16 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } spin_lock_irqsave(&ch->lock, flags); + if (peripheral == APPS_DATA) { + spin_lock_irqsave(&driver->diagmem_lock, flags_sec); + if (!hdlc_data.allocated && !non_hdlc_data.allocated) { + spin_unlock_irqrestore(&driver->diagmem_lock, + flags_sec); + spin_unlock_irqrestore(&ch->lock, flags); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + } for (i = 0; i < ch->num_tbl_entries && !found; i++) { if (ch->tbl[i].buf != buf) continue; @@ -218,14 +228,16 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) ch->tbl[i].len = 0; ch->tbl[i].ctx = 0; } - spin_unlock_irqrestore(&ch->lock, flags); if (found) { + if (peripheral == APPS_DATA) + spin_unlock_irqrestore(&driver->diagmem_lock, + flags_sec); + spin_unlock_irqrestore(&ch->lock, flags); mutex_unlock(&driver->md_session_lock); return -ENOMEM; } - spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { if (ch->tbl[i].len == 0) { ch->tbl[i].buf = buf; @@ -235,6 +247,8 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) diag_ws_on_read(DIAG_WS_MUX, len); } } + if (peripheral == APPS_DATA) + spin_unlock_irqrestore(&driver->diagmem_lock, flags_sec); spin_unlock_irqrestore(&ch->lock, flags); mutex_unlock(&driver->md_session_lock); @@ -288,19 +302,13 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, if (!ch->md_info_inited) continue; for (j = 0; j < ch->num_tbl_entries && !err; j++) { - spin_lock_irqsave(&ch->lock, flags); entry = &ch->tbl[j]; - if (entry->len <= 0 || entry->buf == NULL) { - spin_unlock_irqrestore(&ch->lock, flags); + if (entry->len <= 0 || entry->buf == NULL) continue; - } peripheral = diag_md_get_peripheral(entry->ctx); - if (peripheral < 0) { - spin_unlock_irqrestore(&ch->lock, flags); + if (peripheral < 0) goto drop_data; - } - spin_unlock_irqrestore(&ch->lock, flags); session_info = diag_md_session_get_peripheral(i, peripheral); if (!session_info) diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 4cc02803b3ff63688a30b783ff91798dfff7a355..441d28c2558e6822505a060290c8064b86144aa5 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -293,20 +293,6 @@ int diag_mux_close_peripheral(int proc, uint8_t peripheral) return 0; } -int diag_mux_close_device(int proc) -{ - struct diag_logger_t *logger = NULL; - - if (!diag_mux) - return -EIO; - - logger = diag_mux->logger[proc]; - - if (logger && logger->log_ops && logger->log_ops->close_device) - logger->log_ops->close_device(proc); - return 0; -} - int diag_mux_switch_logging(int proc, int *req_mode, int *peripheral_mask) { unsigned int new_mask = 0; diff --git a/drivers/char/diag/diag_mux.h b/drivers/char/diag/diag_mux.h index 3bafa8864dce42d27396cbc7fa42d6ea84d45e42..c4d5bbd4c4a72c271c7972849d922a5cb9a85699 100644 --- a/drivers/char/diag/diag_mux.h +++ b/drivers/char/diag/diag_mux.h @@ -71,7 +71,6 @@ int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops); int diag_mux_queue_read(int proc); int diag_mux_write(int proc, unsigned char *buf, int len, int ctx); int diag_mux_close_peripheral(int proc, uint8_t peripheral); -int diag_mux_close_device(int proc); int diag_mux_open_all(struct diag_logger_t *logger); int diag_mux_close_all(void); int diag_pcie_register_ops(int proc, int ctx, struct diag_mux_ops *ops); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index a2e072360830623d1d82c23c68084ea95c5c8f8c..2c49615c55819f14f7713d31cd2af82529119783 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -289,6 +289,10 @@ do { \ #define DIAG_NUM_PROC (1 + NUM_REMOTE_DEV) #endif +#define DIAG_MSM_MASK (0x0001) /* Bit mask for MSM */ +#define DIAG_MDM_MASK (0x0002) /* Bit mask for first mdm device */ +#define DIAG_MDM2_MASK (0x0004) /* Bit mask for second mdm device */ + #define DIAG_WS_DCI 0 #define DIAG_WS_MUX 1 @@ -318,8 +322,7 @@ enum remote_procs { #define DIAG_MD_BRIDGE_BASE DIAG_MD_LOCAL_LAST #define DIAG_MD_MDM (DIAG_MD_BRIDGE_BASE) #define DIAG_MD_MDM2 (DIAG_MD_BRIDGE_BASE + 1) -#define DIAG_MD_SMUX (DIAG_MD_BRIDGE_BASE + 2) -#define DIAG_MD_BRIDGE_LAST (DIAG_MD_BRIDGE_BASE + 3) +#define DIAG_MD_BRIDGE_LAST (DIAG_MD_BRIDGE_BASE + 2) #ifndef CONFIG_DIAGFWD_BRIDGE_CODE #define NUM_DIAG_MD_DEV DIAG_MD_LOCAL_LAST @@ -638,6 +641,7 @@ struct diagchar_dev { unsigned int poolsize_dci; unsigned int poolsize_user; spinlock_t diagmem_lock; + wait_queue_head_t hdlc_wait_q; /* Buffers for masks */ struct mutex diag_cntl_mutex; /* Members for Sending response */ @@ -685,6 +689,7 @@ struct diagchar_dev { int usb_connected; #endif int pcie_connected; + int pcie_switch_pid; struct workqueue_struct *diag_wq; struct work_struct diag_drain_work; struct work_struct update_user_clients; @@ -741,6 +746,17 @@ extern struct diagchar_dev *driver; extern int wrap_enabled; extern uint16_t wrap_count; +struct diag_apps_data_t { + void *buf; + uint32_t len; + int ctxt; + uint8_t allocated; + uint8_t flushed; +}; + +extern struct diag_apps_data_t hdlc_data; +extern struct diag_apps_data_t non_hdlc_data; + void diag_get_timestamp(char *time_str); void check_drain_timer(void); int diag_get_remote(int remote_info); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 37f39bf9a5141d50c7ba9884f7c4a9e0c3f554ec..8c88b006e0a93706014e870c298bff05a05849ac 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -156,14 +156,8 @@ static int timer_in_progress; static int diag_mask_clear_param = 1; module_param(diag_mask_clear_param, int, 0644); -struct diag_apps_data_t { - void *buf; - uint32_t len; - int ctxt; -}; - -static struct diag_apps_data_t hdlc_data; -static struct diag_apps_data_t non_hdlc_data; +struct diag_apps_data_t hdlc_data; +struct diag_apps_data_t non_hdlc_data; static struct mutex apps_data_mutex; #define DIAGPKT_MAX_DELAYED_RSP 0xFFFF @@ -225,14 +219,21 @@ static void diag_drain_apps_data(struct diag_apps_data_t *data) if (!data || !data->buf) return; + spin_lock_irqsave(&driver->diagmem_lock, flags); + data->flushed = 1; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); - spin_lock_irqsave(&driver->diagmem_lock, flags); - if (err) + + if (err) { + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, data->buf, POOL_TYPE_HDLC); - data->buf = NULL; - data->len = 0; - spin_unlock_irqrestore(&driver->diagmem_lock, flags); + data->buf = NULL; + data->len = 0; + data->allocated = 0; + data->flushed = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); + } } void diag_update_user_client_work_fn(struct work_struct *work) @@ -305,6 +306,7 @@ static void diag_mempool_init(void) diagmem_init(driver, POOL_TYPE_DCI); spin_lock_init(&driver->diagmem_lock); + init_waitqueue_head(&driver->hdlc_wait_q); } static void diag_mempool_exit(void) @@ -453,7 +455,7 @@ void diag_clear_masks(int pid) static void diag_close_logging_process(const int pid) { int i, j; - int session_mask; + int session_mask = 0; int device_mask = 0; uint32_t p_mask; struct diag_md_session_t *session_info = NULL; @@ -463,15 +465,20 @@ static void diag_close_logging_process(const int pid) session_info = diag_md_session_get_pid(pid); if (!session_info) { mutex_unlock(&driver->md_session_lock); - if (driver->pcie_transport_def == DIAG_ROUTE_TO_PCIE) - params.req_mode = PCIE_MODE; - else - params.req_mode = USB_MODE; - params.mode_param = 0; - params.pd_mask = 0; - params.peripheral_mask = DIAG_CON_ALL; mutex_lock(&driver->diagchar_mutex); - diag_switch_logging(¶ms); + if (driver->pcie_switch_pid == pid) { + if (driver->pcie_transport_def == + DIAG_ROUTE_TO_PCIE) + params.req_mode = PCIE_MODE; + else + params.req_mode = USB_MODE; + params.mode_param = 0; + params.pd_mask = 0; + params.device_mask = DIAG_MSM_MASK; + params.peripheral_mask = DIAG_CON_ALL; + diag_switch_logging(¶ms); + driver->pcie_switch_pid = 0; + } mutex_unlock(&driver->diagchar_mutex); return; } @@ -487,8 +494,9 @@ static void diag_close_logging_process(const int pid) diag_clear_masks(pid); mutex_lock(&driver->diagchar_mutex); - p_mask = - diag_translate_kernel_to_user_mask(session_mask); + if (session_mask) + p_mask = + diag_translate_kernel_to_user_mask(session_mask); for (i = 0; i < NUM_MD_SESSIONS; i++) if (MD_PERIPHERAL_MASK(i) & session_mask) @@ -515,9 +523,11 @@ static void diag_close_logging_process(const int pid) } } } + mutex_lock(&driver->hdlc_disable_mutex); mutex_lock(&driver->md_session_lock); diag_md_session_close(pid); mutex_unlock(&driver->md_session_lock); + mutex_unlock(&driver->hdlc_disable_mutex); diag_switch_logging(¶ms); mutex_unlock(&driver->diagchar_mutex); } @@ -1435,6 +1445,8 @@ static void diag_md_session_close(int pid) driver->md_session_map[proc][i] = NULL; driver->md_session_mask[proc] &= ~session_info->peripheral_mask[proc]; + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; } } diag_log_mask_free(session_info->log_mask); @@ -1609,7 +1621,8 @@ static int diag_md_session_check(int proc, int curr_mode, int req_mode, *change_mode = 1; return 0; } else if ((req_mode == DIAG_USB_MODE || req_mode == DIAG_PCIE_MODE) - && curr_mode == DIAG_MEMORY_DEVICE_MODE) { + && (curr_mode == DIAG_MEMORY_DEVICE_MODE || + curr_mode == DIAG_MULTI_MODE)) { mutex_lock(&driver->md_session_lock); if (driver->md_session_mode[proc] == DIAG_MD_NONE && driver->md_session_mask[proc] == 0 && @@ -1935,6 +1948,19 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) } driver->logging_mode[proc] = new_mode; driver->logging_mask[proc] = peripheral_mask; + if (((curr_mode == DIAG_PCIE_MODE && + new_mode == DIAG_USB_MODE) || + (curr_mode == DIAG_USB_MODE && + new_mode == DIAG_PCIE_MODE)) && + !driver->pcie_switch_pid) { + /* + * Store the pid of process affecting switch + * from USB to PCIE or vice versa to help + * close only this process while closing + * logging process. + */ + driver->pcie_switch_pid = current->tgid; + } if (new_mode == DIAG_PCIE_MODE) { driver->transport_set = DIAG_ROUTE_TO_PCIE; diagmem_setsize(POOL_TYPE_MUX_APPS, @@ -3041,31 +3067,47 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, send.last = (void *)(buf + len - 1); send.terminate = 1; - if (!data->buf) + wait_event_interruptible(driver->hdlc_wait_q, + (data->flushed == 0)); + if (!data->buf) { + spin_lock_irqsave(&driver->diagmem_lock, flags); data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE + APF_DIAG_PADDING, POOL_TYPE_HDLC); - if (!data->buf) { - ret = PKT_DROP; - goto fail_ret; + if (!data->buf) { + ret = PKT_DROP; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); + goto fail_ret; + } + data->allocated = 1; + data->flushed = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } if ((DIAG_MAX_HDLC_BUF_SIZE - data->len) <= max_encoded_size) { + spin_lock_irqsave(&driver->diagmem_lock, flags); + data->flushed = 1; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); if (err) { ret = -EIO; goto fail_free_buf; } - data->buf = NULL; - data->len = 0; + wait_event_interruptible(driver->hdlc_wait_q, + (data->flushed == 0)); + spin_lock_irqsave(&driver->diagmem_lock, flags); data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE + APF_DIAG_PADDING, POOL_TYPE_HDLC); if (!data->buf) { ret = PKT_DROP; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); goto fail_ret; } + data->allocated = 1; + data->flushed = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } enc.dest = data->buf + data->len; @@ -3080,21 +3122,29 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, */ if ((uintptr_t)enc.dest >= (uintptr_t)(data->buf + DIAG_MAX_HDLC_BUF_SIZE)) { + spin_lock_irqsave(&driver->diagmem_lock, flags); + data->flushed = 1; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); if (err) { ret = -EIO; goto fail_free_buf; } - data->buf = NULL; - data->len = 0; + wait_event_interruptible(driver->hdlc_wait_q, + (data->flushed == 0)); + spin_lock_irqsave(&driver->diagmem_lock, flags); data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE + APF_DIAG_PADDING, POOL_TYPE_HDLC); if (!data->buf) { ret = PKT_DROP; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); goto fail_ret; } + data->allocated = 1; + data->flushed = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); enc.dest = data->buf + data->len; enc.dest_last = (void *)(data->buf + data->len + @@ -3108,23 +3158,27 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, DIAG_MAX_HDLC_BUF_SIZE; if (pkt_type == DATA_TYPE_RESPONSE) { + spin_lock_irqsave(&driver->diagmem_lock, flags); + data->flushed = 1; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); if (err) { ret = -EIO; goto fail_free_buf; } - data->buf = NULL; - data->len = 0; } return PKT_ALLOC; fail_free_buf: spin_lock_irqsave(&driver->diagmem_lock, flags); - diagmem_free(driver, data->buf, POOL_TYPE_HDLC); + if (data->allocated) + diagmem_free(driver, data->buf, POOL_TYPE_HDLC); data->buf = NULL; data->len = 0; + data->allocated = 0; + data->flushed = 0; spin_unlock_irqrestore(&driver->diagmem_lock, flags); fail_ret: return ret; @@ -3150,33 +3204,47 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len, __func__, buf, len); return -EIO; } - + wait_event_interruptible(driver->hdlc_wait_q, + (data->flushed == 0)); if (!data->buf) { + spin_lock_irqsave(&driver->diagmem_lock, flags); data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE + APF_DIAG_PADDING, POOL_TYPE_HDLC); if (!data->buf) { ret = PKT_DROP; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); goto fail_ret; } + data->allocated = 1; + data->flushed = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } - if ((DIAG_MAX_HDLC_BUF_SIZE - data->len) <= max_pkt_size) { + spin_lock_irqsave(&driver->diagmem_lock, flags); + data->flushed = 1; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); if (err) { ret = -EIO; goto fail_free_buf; } - data->buf = NULL; - data->len = 0; + wait_event_interruptible(driver->hdlc_wait_q, + (data->flushed == 0)); + + spin_lock_irqsave(&driver->diagmem_lock, flags); data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE + APF_DIAG_PADDING, POOL_TYPE_HDLC); if (!data->buf) { ret = PKT_DROP; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); goto fail_ret; } + data->allocated = 1; + data->flushed = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } header.start = CONTROL_CHAR; @@ -3189,23 +3257,27 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len, *(uint8_t *)(data->buf + data->len) = CONTROL_CHAR; data->len += sizeof(uint8_t); if (pkt_type == DATA_TYPE_RESPONSE) { + spin_lock_irqsave(&driver->diagmem_lock, flags); + data->flushed = 1; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); if (err) { ret = -EIO; goto fail_free_buf; } - data->buf = NULL; - data->len = 0; } return PKT_ALLOC; fail_free_buf: spin_lock_irqsave(&driver->diagmem_lock, flags); - diagmem_free(driver, data->buf, POOL_TYPE_HDLC); + if (data->allocated) + diagmem_free(driver, data->buf, POOL_TYPE_HDLC); data->buf = NULL; data->len = 0; + data->allocated = 0; + data->flushed = 0; spin_unlock_irqrestore(&driver->diagmem_lock, flags); fail_ret: return ret; @@ -4332,11 +4404,16 @@ static int __init diagchar_init(void) driver->mask_check = 0; driver->in_busy_pktdata = 0; driver->in_busy_dcipktdata = 0; + driver->pcie_switch_pid = 0; driver->rsp_buf_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, TYPE_CMD); hdlc_data.ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_DATA, 1); hdlc_data.len = 0; + hdlc_data.allocated = 0; + hdlc_data.flushed = 0; non_hdlc_data.ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_DATA, 1); non_hdlc_data.len = 0; + non_hdlc_data.allocated = 0; + non_hdlc_data.flushed = 0; mutex_init(&driver->hdlc_disable_mutex); mutex_init(&driver->diagchar_mutex); mutex_init(&driver->diag_notifier_mutex); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index da6d60e56f2e0c519dcb34179a7bddd09d8053e8..fe9027eaf4787bbea8306d77bb37b7dc1650c373 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1835,6 +1835,7 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, int peripheral = -1; int type = -1; int num = -1; + struct diag_apps_data_t *temp = NULL; if (!buf || len < 0) return -EINVAL; @@ -1853,9 +1854,24 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, diag_ws_on_copy(DIAG_WS_MUX); } else if (peripheral == APPS_DATA) { spin_lock_irqsave(&driver->diagmem_lock, flags); - diagmem_free(driver, (unsigned char *)buf, - POOL_TYPE_HDLC); - buf = NULL; + if (hdlc_data.allocated) + temp = &hdlc_data; + else if (non_hdlc_data.allocated) + temp = &non_hdlc_data; + else + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "No apps data buffer is allocated to be freed\n"); + if (temp) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Freeing Apps data buffer after write done hdlc.allocated: %d, non_hdlc.allocated: %d\n", + hdlc_data.allocated, non_hdlc_data.allocated); + diagmem_free(driver, temp->buf, POOL_TYPE_HDLC); + temp->buf = NULL; + temp->len = 0; + temp->allocated = 0; + temp->flushed = 0; + wake_up_interruptible(&driver->hdlc_wait_q); + } spin_unlock_irqrestore(&driver->diagmem_lock, flags); } else { pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n", diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 0caa7405587bb7fe4e1343e88776399041a7eada..27f7aacc48253abae73ccfe0709a509fd3c9e16e 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -176,10 +176,7 @@ int diag_remote_dev_open(int id) void diag_remote_dev_close(int id) { - if (id < 0 || id >= NUM_REMOTE_DEV) - return; - diag_mux_close_device(BRIDGE_TO_MUX(id)); } int diag_remote_dev_read_done(int id, unsigned char *buf, int len) diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index bad35d6ccf7d21232ee44fc4f34df5c7a353bdb3..8228e7d54f609bc6340e0f0374cc9eda2828b6b6 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -632,13 +632,10 @@ static void handle_ctrl_pkt(struct diag_socket_info *info, void *buf, int len) info->name); mutex_lock(&driver->diag_notifier_mutex); - if (bootup_req[info->peripheral] == PERIPHERAL_SSR_UP) { + if (bootup_req[info->peripheral] == PERIPHERAL_SSR_UP) DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: %s is up, stopping cleanup: bootup_req = %d\n", + "diag: %s is up, bootup_req = %d\n", info->name, (int)bootup_req[info->peripheral]); - mutex_unlock(&driver->diag_notifier_mutex); - break; - } mutex_unlock(&driver->diag_notifier_mutex); socket_close_channel(info); } diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 32a8e27c5382fe2677393e9f47f5055f1013c163..cc4e642d3180a89977c1fae3634f3968acb5125b 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -69,6 +69,10 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) if (status < 0) return status; + /* The upper layer does not support incomplete sends. */ + if (status != len) + return -E2BIG; + return 0; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 07a9d39a6fa06cdd569788b8977ac254d5d6df2f..e68700ef36d5e7d01fbb549f3382614320aa6b20 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -572,8 +572,7 @@ static int clk_update_vdd(struct clk_vdd_class *vdd_class) for (i = 0; i < vdd_class->num_regulators; i++) { pr_debug("Set Voltage level Min %d, Max %d\n", uv[new_base + i], uv[max_lvl + i]); - rc = regulator_set_voltage(r[i], uv[new_base + i], - vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + rc = regulator_set_voltage(r[i], uv[new_base + i], INT_MAX); if (rc) goto set_voltage_fail; @@ -594,13 +593,11 @@ static int clk_update_vdd(struct clk_vdd_class *vdd_class) return rc; enable_disable_fail: - regulator_set_voltage(r[i], uv[cur_base + i], - vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + regulator_set_voltage(r[i], uv[cur_base + i], INT_MAX); set_voltage_fail: for (i--; i >= 0; i--) { - regulator_set_voltage(r[i], uv[cur_base + i], - vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + regulator_set_voltage(r[i], uv[cur_base + i], INT_MAX); if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels) regulator_disable(r[i]); else if (level == 0) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 876c9aaca3015c34a504b7a875d3ca91d837efd0..61ffeb6136c58d701ab29ad322aa6f9909b10ef9 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -562,3 +562,9 @@ config QCOM_CLK_VIRT This is the virtual clock frontend driver which is based on HAB for the QTI virtual machine. Say Y if you want to support virtual clock. + +config VIRTIO_CLK + tristate "Virtio clock driver" + depends on VIRTIO + ---help--- + This is the virtual clock driver for virtio. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 8f09f0c72765e867c3a63a67dfc976bb5be8bfd5..157a9f7e2cbbf328de2bdd7785c40b92f6642fdf 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -78,5 +78,6 @@ obj-$(CONFIG_SM_GCC_TRINKET) += gcc-trinket.o obj-$(CONFIG_SM_GPUCC_TRINKET) += gpucc-trinket.o obj-$(CONFIG_SM_VIDEOCC_TRINKET) += videocc-trinket.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o +obj-$(CONFIG_VIRTIO_CLK) += virtio_clk.o virtio_clk_sm8150.o virtio_clk_sm6150.o virtio_clk_sa8195p.o obj-y += mdss/ diff --git a/drivers/clk/qcom/camcc-sm8150.c b/drivers/clk/qcom/camcc-sm8150.c index 7459b40a56c53966de21eddffa3e49c77f66930e..c49ac2115ef24d1f005ea6c95205b66038c03435 100644 --- a/drivers/clk/qcom/camcc-sm8150.c +++ b/drivers/clk/qcom/camcc-sm8150.c @@ -2494,7 +2494,6 @@ static int cam_cc_sm8150_probe(struct platform_device *pdev) "Unable to get vdd_mm regulator\n"); return PTR_ERR(vdd_mm.regulator[0]); } - vdd_mm.use_max_uV = true; camcc_bus_id = msm_bus_scale_register_client(&clk_debugfs_scale_table); if (!camcc_bus_id) { diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 3055c359c167398fdfda721e5a083546f2aa7c81..ed12f6b99393e8f0a6c99da2a37356d55d2f7d6d 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -125,6 +125,12 @@ static int clk_branch_toggle(struct clk_hw *hw, bool en, clk_disable_regmap(hw); } + /* + * Make sure enable/disable request goes through before waiting + * for CLK_OFF status to get updated. + */ + mb(); + return clk_branch_wait(br, en, check_halt); } @@ -136,34 +142,36 @@ static int clk_branch_enable(struct clk_hw *hw) static int clk_cbcr_set_flags(struct regmap *regmap, unsigned int reg, unsigned long flags) { - u32 cbcr_val; - - regmap_read(regmap, reg, &cbcr_val); + u32 cbcr_val = 0; + u32 cbcr_mask; + int ret; switch (flags) { case CLKFLAG_PERIPH_OFF_SET: - cbcr_val |= BIT(12); + cbcr_val = cbcr_mask = BIT(12); break; case CLKFLAG_PERIPH_OFF_CLEAR: - cbcr_val &= ~BIT(12); + cbcr_mask = BIT(12); break; case CLKFLAG_RETAIN_PERIPH: - cbcr_val |= BIT(13); + cbcr_val = cbcr_mask = BIT(13); break; case CLKFLAG_NORETAIN_PERIPH: - cbcr_val &= ~BIT(13); + cbcr_mask = BIT(13); break; case CLKFLAG_RETAIN_MEM: - cbcr_val |= BIT(14); + cbcr_val = cbcr_mask = BIT(14); break; case CLKFLAG_NORETAIN_MEM: - cbcr_val &= ~BIT(14); + cbcr_mask = BIT(14); break; default: return -EINVAL; } - regmap_write(regmap, reg, cbcr_val); + ret = regmap_update_bits(regmap, reg, cbcr_mask, cbcr_val); + if (ret) + return ret; /* Make sure power is enabled/disabled before returning. */ mb(); diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 8d49a370ce99a41c4ae77fd0836a46b7ca0c8013..a397013479f1b4af9ea85d9d5d8597e2b261903e 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -89,6 +89,7 @@ static bool is_sdmshrike; static bool is_sm6150; static bool is_sdmmagpie; static bool is_trinket; +static bool is_atoll; static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw) { @@ -1031,7 +1032,8 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } - if (is_sdmshrike || is_sm6150 || is_sdmmagpie || is_trinket) + if (is_sdmshrike || is_sm6150 || is_sdmmagpie || + is_trinket || is_atoll) return 0; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -1124,9 +1126,13 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev) is_sdmshrike = of_device_is_compatible(pdev->dev.of_node, "qcom,clk-cpu-osm-sdmshrike"); + + is_atoll = of_device_is_compatible(pdev->dev.of_node, + "qcom,clk-cpu-osm-atoll"); + if (is_sdmshrike) clk_cpu_osm_driver_sdmshrike_fixup(); - else if (is_sm6150 || is_sdmmagpie) + else if (is_sm6150 || is_sdmmagpie || is_atoll) clk_cpu_osm_driver_sm6150_fixup(); else if (is_trinket) clk_cpu_osm_driver_trinket_fixup(); @@ -1183,7 +1189,8 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev) return rc; } - if (!is_sdmshrike && !is_sm6150 && !is_sdmmagpie && !is_trinket) { + if (!is_sdmshrike && !is_sm6150 && !is_sdmmagpie && + !is_trinket && !is_atoll) { rc = clk_osm_read_lut(pdev, &perfpcl_clk); if (rc) { dev_err(&pdev->dev, "Unable to read OSM LUT for perf plus cluster, rc=%d\n", @@ -1265,6 +1272,7 @@ static const struct of_device_id match_table[] = { { .compatible = "qcom,clk-cpu-osm-sdmmagpie" }, { .compatible = "qcom,clk-cpu-osm-trinket" }, { .compatible = "qcom,clk-cpu-osm-sdmshrike" }, + { .compatible = "qcom,clk-cpu-osm-atoll" }, {} }; diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 97d761daf08e0170a99bec8f0db6095b9c9176a4..b7e69b449d809c4d3ff8639ca871bd821d8cb6c1 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -522,6 +522,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,rpmh-clk-sdmmagpie", .data = &clk_rpmh_sm6150}, { .compatible = "qcom,rpmh-clk-sdxprairie", .data = &clk_rpmh_sdxprairie}, + { .compatible = "qcom,rpmh-clk-atoll", .data = &clk_rpmh_sm6150}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); diff --git a/drivers/clk/qcom/clk-virt-sm6150.c b/drivers/clk/qcom/clk-virt-sm6150.c index 5af572c6e9ac4da5375eeb913d767634e6cca9f6..bcfcf42c3ad3f83380a63c95e6d1854129338431 100644 --- a/drivers/clk/qcom/clk-virt-sm6150.c +++ b/drivers/clk/qcom/clk-virt-sm6150.c @@ -25,6 +25,8 @@ static struct virt_reset_map sm6150_gcc_virt_resets[] = { [GCC_USB20_SEC_BCR] = { "gcc_usb20_sec_master_clk" }, [GCC_USB3_PHY_PRIM_SP0_BCR] = { "gcc_usb3_phy_prim_sp0_bcr" }, [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { "gcc_usb3phy_phy_prim_sp0_bcr" }, + [GCC_PCIE_0_BCR] = { "gcc_pcie_0_mstr_axi_clk" }, + [GCC_PCIE_0_PHY_BCR] = { "gcc_pcie_0_phy_bcr" }, }; static struct clk_virt gcc_qupv3_wrap0_s0_clk = { @@ -216,6 +218,83 @@ static struct clk_virt gcc_usb3_prim_phy_com_aux_clk = { }, }; +static struct clk_virt gcc_pcie_0_pipe_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_pipe_clk", + }, +}; + +static struct clk_virt gcc_pcie_0_aux_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_aux_clk", + }, +}; + +static struct clk_virt gcc_pcie_0_cfg_ahb_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_cfg_ahb_clk", + }, +}; + +static struct clk_virt gcc_pcie_0_mstr_axi_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_mstr_axi_clk", + }, +}; + +static struct clk_virt gcc_pcie_0_slv_axi_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_slv_axi_clk", + }, +}; + +static struct clk_virt gcc_pcie_0_clkref_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_clkref_en", + }, +}; + +static struct clk_virt gcc_pcie_0_slv_q2a_axi_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_0_slv_q2a_axi_clk", + }, +}; + +static struct clk_virt gcc_pcie0_phy_refgen_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie0_phy_refgen_clk", + }, +}; + +static struct clk_virt gcc_pcie_phy_aux_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_pcie_phy_aux_clk", + }, +}; + +static struct clk_virt gcc_sdcc2_ahb_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_sdcc2_ahb_clk", + }, +}; + +static struct clk_virt gcc_sdcc2_apps_clk = { + .hw.init = &(struct clk_init_data) { + .ops = &clk_virt_ops, + .name = "gcc_sdcc2_apps_clk", + }, +}; + static struct clk_hw *sm6150_gcc_virt_clocks[] = { [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.hw, [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.hw, @@ -244,6 +323,17 @@ static struct clk_hw *sm6150_gcc_virt_clocks[] = { [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.hw, [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.hw, [GCC_AHB2PHY_WEST_CLK] = &gcc_ahb2phy_west_clk.hw, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.hw, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.hw, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.hw, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.hw, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.hw, + [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.hw, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.hw, + [GCC_PCIE0_PHY_REFGEN_CLK] = &gcc_pcie0_phy_refgen_clk.hw, + [GCC_PCIE_PHY_AUX_CLK] = &gcc_pcie_phy_aux_clk.hw, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.hw, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.hw, }; const struct clk_virt_desc clk_virt_sm6150_gcc = { diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 6fa3aa56b5a3dc56e26d8a05917462e3cba78d24..f82a70db381b41e819802f3328362e7b8f9071a9 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -201,6 +201,22 @@ int qcom_cc_register_sleep_clk(struct device *dev) } EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk); +/* Drop 'protected-clocks' from the list of clocks to register */ +static void qcom_cc_drop_protected(struct device *dev, struct qcom_cc *cc) +{ + struct device_node *np = dev->of_node; + struct property *prop; + const __be32 *p; + u32 i; + + of_property_for_each_u32(np, "protected-clocks", prop, p, i) { + if (i >= cc->num_rclks) + continue; + + cc->rclks[i] = NULL; + } +} + static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -249,6 +265,8 @@ int qcom_cc_really_probe(struct platform_device *pdev, return ret; } + qcom_cc_drop_protected(dev, cc); + for (i = 0; i < num_clks; i++) { if (!rclks[i]) continue; diff --git a/drivers/clk/qcom/dispcc-sm8150.c b/drivers/clk/qcom/dispcc-sm8150.c index ecb95bf864e26c4059e374d5acdb5de678fe2d00..343a8c1f084ed72da960820db0acb8ee2b3ecd33 100644 --- a/drivers/clk/qcom/dispcc-sm8150.c +++ b/drivers/clk/qcom/dispcc-sm8150.c @@ -1637,7 +1637,6 @@ static int disp_cc_sm8150_probe(struct platform_device *pdev) "Unable to get vdd_mm regulator\n"); return PTR_ERR(vdd_mm.regulator[0]); } - vdd_mm.use_max_uV = true; dispcc_bus_id = msm_bus_scale_register_client(&clk_debugfs_scale_table); if (!dispcc_bus_id) { diff --git a/drivers/clk/qcom/gcc-sdmshrike.c b/drivers/clk/qcom/gcc-sdmshrike.c index d88f11e7729a00bff9c241c70dad2c9279315ca1..ec5cd2cd6266b335923e6fb69012258f85cc9484 100644 --- a/drivers/clk/qcom/gcc-sdmshrike.c +++ b/drivers/clk/qcom/gcc-sdmshrike.c @@ -2662,6 +2662,19 @@ static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { }, }; +static struct clk_branch gcc_pcie_0_clkref_clk = { + .halt_reg = 0x8c00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_pcie_0_mstr_axi_clk = { .halt_reg = 0x6b018, .halt_check = BRANCH_HALT_VOTED, @@ -2749,6 +2762,19 @@ static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { }, }; +static struct clk_branch gcc_pcie_1_clkref_clk = { + .halt_reg = 0x8c02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_pcie_1_mstr_axi_clk = { .halt_reg = 0x8d018, .halt_check = BRANCH_HALT_VOTED, @@ -4524,6 +4550,19 @@ static struct clk_branch gcc_usb3_mp_phy_pipe_1_clk = { }, }; +static struct clk_branch gcc_usb3_prim_clkref_clk = { + .halt_reg = 0x8c008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_usb3_prim_phy_aux_clk = { .halt_reg = 0xf050, .halt_check = BRANCH_HALT, @@ -4572,6 +4611,19 @@ static struct clk_gate2 gcc_usb3_prim_phy_pipe_clk = { }, }; +static struct clk_branch gcc_usb3_sec_clkref_clk = { + .halt_reg = 0x8c028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_usb3_sec_phy_aux_clk = { .halt_reg = 0x10050, .halt_check = BRANCH_HALT, @@ -4757,6 +4809,7 @@ static struct clk_regmap *gcc_sdmshrike_clocks[] = { [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr, [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, @@ -4764,6 +4817,7 @@ static struct clk_regmap *gcc_sdmshrike_clocks[] = { [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_CLKREF_CLK] = &gcc_pcie_1_clkref_clk.clkr, [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, @@ -4932,10 +4986,12 @@ static struct clk_regmap *gcc_sdmshrike_clocks[] = { [GCC_USB3_MP_PHY_COM_AUX_CLK] = &gcc_usb3_mp_phy_com_aux_clk.clkr, [GCC_USB3_MP_PHY_PIPE_0_CLK] = &gcc_usb3_mp_phy_pipe_0_clk.clkr, [GCC_USB3_MP_PHY_PIPE_1_CLK] = &gcc_usb3_mp_phy_pipe_1_clk.clkr, + [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr, [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_SEC_CLKREF_CLK] = &gcc_usb3_sec_clkref_clk.clkr, [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr, [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr, [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr, @@ -4995,6 +5051,8 @@ static const struct qcom_reset_map gcc_sdmshrike_resets[] = { [GCC_USB30_SEC_BCR] = { 0x10000 }, [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, [GCC_VIDEO_AXIC_CLK_BCR] = { 0xb02c, 2 }, + [GCC_VIDEO_AXI0_CLK_BCR] = { 0xb024, 2 }, + [GCC_VIDEO_AXI1_CLK_BCR] = { 0xb028, 2 }, }; diff --git a/drivers/clk/qcom/gcc-sdxprairie.c b/drivers/clk/qcom/gcc-sdxprairie.c index 869cf9ebf533b34d282929214d62399aa2c52dc4..d36cb221077c5835a8d64999da4d733e615c71ec 100644 --- a/drivers/clk/qcom/gcc-sdxprairie.c +++ b/drivers/clk/qcom/gcc-sdxprairie.c @@ -630,6 +630,13 @@ static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(230400000, P_GPLL5_OUT_MAIN, 3.5, 0, 0), + { } +}; + static struct clk_rcg2 gcc_emac_ptp_clk_src = { .cmd_rcgr = 0x47038, .mnd_width = 0, @@ -840,6 +847,11 @@ static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk_src_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + static struct clk_rcg2 gcc_usb30_mock_utmi_clk_src = { .cmd_rcgr = 0xb03c, .mnd_width = 0, @@ -1882,15 +1894,25 @@ static const struct qcom_cc_desc gcc_sdxprairie_desc = { static const struct of_device_id gcc_sdxprairie_match_table[] = { { .compatible = "qcom,gcc-sdxprairie" }, + { .compatible = "qcom,gcc-sdxprairie-v2" }, { } }; MODULE_DEVICE_TABLE(of, gcc_sdxprairie_match_table); +static void gcc_sdxprairie_fixup_v2(void) +{ + gcc_usb30_mock_utmi_clk_src.freq_tbl = + ftbl_gcc_usb30_mock_utmi_clk_src_v2; + gcc_usb30_mock_utmi_clk_src.clkr.hw.init->rate_max[VDD_MIN] = 19200000; + gcc_emac_ptp_clk_src.freq_tbl = ftbl_gcc_emac_ptp_clk_src_v2; +} + static int gcc_sdxprairie_probe(struct platform_device *pdev) { struct clk *clk; struct device *dev = &pdev->dev; int ret = 0; + bool is_v2; clk = devm_clk_get(dev, "bi_tcxo"); if (IS_ERR(clk)) { @@ -1921,6 +1943,11 @@ static int gcc_sdxprairie_probe(struct platform_device *pdev) return PTR_ERR(vdd_mx.regulator[0]); } + is_v2 = of_device_is_compatible(pdev->dev.of_node, + "qcom,gcc-sdxprairie-v2"); + if (is_v2) + gcc_sdxprairie_fixup_v2(); + ret = qcom_cc_probe(pdev, &gcc_sdxprairie_desc); if (ret) { dev_err(&pdev->dev, "Failed to register GCC clocks\n"); diff --git a/drivers/clk/qcom/gcc-sm6150.c b/drivers/clk/qcom/gcc-sm6150.c index efd47757166b126b31a16017e6319a3e7ea33b4a..4e448681c4d952a1b2607131fc8f8365a2eb1771 100644 --- a/drivers/clk/qcom/gcc-sm6150.c +++ b/drivers/clk/qcom/gcc-sm6150.c @@ -3243,6 +3243,97 @@ static struct clk_branch gcc_usb2_sec_clkref_clk = { }, }; +static struct clk_branch gcc_sdr_core_clk = { + .halt_reg = 0x46004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdr_wr0_mem_clk = { + .halt_reg = 0x46008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_wr0_mem_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdr_wr1_mem_clk = { + .halt_reg = 0x46010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_wr1_mem_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdr_wr2_mem_clk = { + .halt_reg = 0x46018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_wr2_mem_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdr_csr_hclk = { + .halt_reg = 0x46020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_csr_hclk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdr_pri_mi2s_clk = { + .halt_reg = 0x46024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_pri_mi2s_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdr_sec_mi2s_clk = { + .halt_reg = 0x46028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x46028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdr_sec_mi2s_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + /* Measure-only clock for ddrss_gcc_debug_clk. */ static struct clk_dummy measure_only_mccc_clk = { .rrate = 1000, @@ -3465,6 +3556,13 @@ static struct clk_regmap *gcc_sm6150_clocks[] = { [GCC_RX3_USB2_CLKREF_CLK] = &gcc_rx3_usb2_clkref_clk.clkr, [GCC_USB2_PRIM_CLKREF_CLK] = &gcc_usb2_prim_clkref_clk.clkr, [GCC_USB2_SEC_CLKREF_CLK] = &gcc_usb2_sec_clkref_clk.clkr, + [GCC_SDR_CORE_CLK] = &gcc_sdr_core_clk.clkr, + [GCC_SDR_WR0_MEM_CLK] = &gcc_sdr_wr0_mem_clk.clkr, + [GCC_SDR_WR1_MEM_CLK] = &gcc_sdr_wr1_mem_clk.clkr, + [GCC_SDR_WR2_MEM_CLK] = &gcc_sdr_wr2_mem_clk.clkr, + [GCC_SDR_CSR_HCLK] = &gcc_sdr_csr_hclk.clkr, + [GCC_SDR_PRI_MI2S_CLK] = &gcc_sdr_pri_mi2s_clk.clkr, + [GCC_SDR_SEC_MI2S_CLK] = &gcc_sdr_sec_mi2s_clk.clkr, }; static const struct qcom_reset_map gcc_sm6150_resets[] = { diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index 758fd30ac423f4a1e5d797e3829b0e3711714cd2..77d4e6e1a88c24a3435d8485f08d051d0dd6fd2d 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -4262,7 +4262,6 @@ static int gcc_sm8150_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get vdd_mm regulator\n"); return PTR_ERR(vdd_mm.regulator[0]); } - vdd_mm.use_max_uV = true; /* register hardware clocks */ for (i = 0; i < ARRAY_SIZE(gcc_sm8150_hws); i++) { diff --git a/drivers/clk/qcom/gpucc-sm6150.c b/drivers/clk/qcom/gpucc-sm6150.c index 08b95c2c472086e726c956c4af75f89cc47d8552..aa6fd4f4fc49d22880fd481a15eadbcf1f901787 100644 --- a/drivers/clk/qcom/gpucc-sm6150.c +++ b/drivers/clk/qcom/gpucc-sm6150.c @@ -296,14 +296,14 @@ static struct clk_branch gpu_cc_cx_apb_clk = { static struct clk_branch gpu_cc_cx_gfx3d_clk = { .halt_reg = 0x10a4, - .halt_check = BRANCH_HALT, + .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", + "gpu_cc_gx_gfx3d_clk", }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, diff --git a/drivers/clk/qcom/gpucc-trinket.c b/drivers/clk/qcom/gpucc-trinket.c index 15f037af034422109d7d80489e2295a0e90df350..e07d4a9e3f2befdb67470ada1eee62d6c9569823 100644 --- a/drivers/clk/qcom/gpucc-trinket.c +++ b/drivers/clk/qcom/gpucc-trinket.c @@ -259,7 +259,7 @@ static struct clk_branch gpu_cc_cx_gfx3d_clk = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_cx_gfx3d_clk", .parent_names = (const char *[]){ - "gpu_cc_gx_gfx3d_clk_src", + "gpu_cc_gx_gfx3d_clk", }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, diff --git a/drivers/clk/qcom/scc-sm8150.c b/drivers/clk/qcom/scc-sm8150.c index 9cf33169f26864e8a3963c46050bfc42171a8dd6..554d5590eabac98b746813636b4a7c3d43ae66ef 100644 --- a/drivers/clk/qcom/scc-sm8150.c +++ b/drivers/clk/qcom/scc-sm8150.c @@ -576,10 +576,19 @@ static const struct qcom_cc_desc scc_sm8150_desc = { static const struct of_device_id scc_sm8150_match_table[] = { { .compatible = "qcom,scc-sm8150" }, { .compatible = "qcom,scc-sm8150-v2" }, + { .compatible = "qcom,scc-sa8195" }, { } }; MODULE_DEVICE_TABLE(of, scc_sm8150_match_table); +static void scc_sa8195_fixup(struct platform_device *pdev) +{ + if (of_device_is_compatible(pdev->dev.of_node, "qcom,scc-sa8195")) { + vdd_scc_cx.num_levels = VDD_MM_NUM; + vdd_scc_cx.cur_level = VDD_MM_NUM; + } +} + static void scc_sm8150_fixup_sm8150v2(struct regmap *regmap) { scc_pll.config = &scc_pll_config_sm8150_v2; @@ -635,7 +644,8 @@ static int scc_sm8150_fixup(struct platform_device *pdev, struct regmap *regmap) if (!compat || (compatlen <= 0)) return -EINVAL; - if (!strcmp(compat, "qcom,scc-sm8150-v2")) + if (!strcmp(compat, "qcom,scc-sm8150-v2") || + !strcmp(compat, "qcom,scc-sa8195")) scc_sm8150_fixup_sm8150v2(regmap); return 0; @@ -652,6 +662,8 @@ static int scc_sm8150_probe(struct platform_device *pdev) return PTR_ERR(regmap); } + scc_sa8195_fixup(pdev); + vdd_scc_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_scc_cx"); if (IS_ERR(vdd_scc_cx.regulator[0])) { ret = PTR_ERR(vdd_scc_cx.regulator[0]); diff --git a/drivers/clk/qcom/videocc-sm8150.c b/drivers/clk/qcom/videocc-sm8150.c index b896e26a26ab7eba30da0e94d020cae1a75b4e99..e26618f53824225b37e5493e259b8f28df1e0f16 100644 --- a/drivers/clk/qcom/videocc-sm8150.c +++ b/drivers/clk/qcom/videocc-sm8150.c @@ -374,7 +374,6 @@ static int video_cc_sm8150_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get vdd_mm regulator\n"); return PTR_ERR(vdd_mm.regulator[0]); } - vdd_mm.use_max_uV = true; videocc_bus_id = msm_bus_scale_register_client(&clk_debugfs_scale_table); diff --git a/drivers/clk/qcom/virtio_clk.c b/drivers/clk/qcom/virtio_clk.c new file mode 100644 index 0000000000000000000000000000000000000000..3630755e5bcb6cb1356f182bc54ddba02354accb --- /dev/null +++ b/drivers/clk/qcom/virtio_clk.c @@ -0,0 +1,726 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "virtio_clk_common.h" + +#define VIRTIO_CLK_TIMEOUT (200) /* miliseconds */ + +struct virtio_clk { + struct virtio_device *vdev; + struct virtqueue *vq; + struct completion rsp_avail; + struct mutex lock; + struct reset_controller_dev rcdev; + const struct clk_virtio_desc *desc; + struct clk_virtio *clks; + size_t num_clks; + size_t num_resets; +}; + +#define to_clk_virtio(_hw) container_of(_hw, struct clk_virtio, hw) + +struct clk_virtio { + int clk_id; + struct clk_hw hw; + struct virtio_clk *vclk; +}; + +struct virtio_cc_map { + char cc_name[20]; + const struct clk_virtio_desc *desc; +}; + +static int virtio_clk_prepare(struct clk_hw *hw) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_ENABLE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("%s: wait for completion timeout\n", + clk_hw_get_name(hw)); + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static void virtio_clk_unprepare(struct clk_hw *hw) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_DISABLE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("%s: wait for completion timeout\n", + clk_hw_get_name(hw)); + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + goto out; + } + + if (rsp->result) + pr_err("%s: error response (%d)\n", clk_hw_get_name(hw), + rsp->result); + +out: + mutex_unlock(&vclk->lock); + kfree(req); +} + +static int virtio_clk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_SET_RATE); + req->data[0] = cpu_to_virtio32(vclk->vdev, rate); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("%s: wait for completion timeout\n", + clk_hw_get_name(hw)); + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static long virtio_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return 0; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_ROUND_RATE); + req->data[0] = cpu_to_virtio32(vclk->vdev, rate); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("%s: wait for completion timeout\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + if (rsp->result) { + pr_err("%s: error response (%d)\n", clk_hw_get_name(hw), + rsp->result); + ret = 0; + } else + ret = virtio32_to_cpu(vclk->vdev, rsp->data[0]); + +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static unsigned long virtio_clk_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return 0; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_GET_RATE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("%s: wait for completion timeout\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + if (rsp->result) { + pr_err("%s: error response (%d)\n", clk_hw_get_name(hw), + rsp->result); + ret = 0; + } else + ret = virtio32_to_cpu(vclk->vdev, rsp->data[0]); + +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static int virtio_clk_set_flags(struct clk_hw *hw, unsigned int flags) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return 0; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_SET_FLAGS); + req->data[0] = cpu_to_virtio32(vclk->vdev, flags); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("%s: wait for completion timeout\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static const struct clk_ops clk_virtio_ops = { + .prepare = virtio_clk_prepare, + .unprepare = virtio_clk_unprepare, + .set_rate = virtio_clk_set_rate, + .round_rate = virtio_clk_round_rate, + .recalc_rate = virtio_clk_get_rate, + .set_flags = virtio_clk_set_flags, +}; + +static int +__virtio_reset(struct reset_controller_dev *rcdev, unsigned long id, + unsigned int action) +{ + struct virtio_clk *vclk = container_of(rcdev, struct virtio_clk, rcdev); + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + if (vclk->desc && vclk->desc->reset_names[id]) + strlcpy(req->name, vclk->desc->reset_names[id], + sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_RESET); + req->data[0] = cpu_to_virtio32(vclk->vdev, action); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("fail to add output buffer (%d)\n", ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + ret = wait_for_completion_timeout(&vclk->rsp_avail, + msecs_to_jiffies(VIRTIO_CLK_TIMEOUT)); + if (!ret) { + pr_err("wait for completion timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("fail to get virtqueue buffer\n"); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); + +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static int +virtio_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + return __virtio_reset(rcdev, id, 1); +} + +static int +virtio_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + return __virtio_reset(rcdev, id, 0); +} + +static int +virtio_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + rcdev->ops->assert(rcdev, id); + udelay(1); + rcdev->ops->deassert(rcdev, id); + return 0; +} + +static const struct reset_control_ops virtio_reset_ops = { + .reset = virtio_reset, + .assert = virtio_reset_assert, + .deassert = virtio_reset_deassert, +}; + +static void virtclk_isr(struct virtqueue *vq) +{ + struct virtio_clk *vclk = vq->vdev->priv; + + complete(&vclk->rsp_avail); +} + +static int virtclk_init_vqs(struct virtio_clk *vclk) +{ + struct virtqueue *vqs[1]; + vq_callback_t *cbs[] = { virtclk_isr }; + static const char * const names[] = { "clock" }; + int ret; + + ret = virtio_find_vqs(vclk->vdev, 1, vqs, cbs, names, NULL); + if (ret) + return ret; + + vclk->vq = vqs[0]; + + return 0; +} + +static const struct virtio_cc_map clk_virtio_map_table[] = { + { .cc_name = "sm8150-gcc", .desc = &clk_virtio_sm8150_gcc, }, + { .cc_name = "sm8150-scc", .desc = &clk_virtio_sm8150_scc, }, + { .cc_name = "sm6150-gcc", .desc = &clk_virtio_sm6150_gcc, }, + { .cc_name = "sm6150-scc", .desc = &clk_virtio_sm6150_scc, }, + { .cc_name = "sa8195p-gcc", .desc = &clk_virtio_sa8195p_gcc, }, + { } +}; + +static const struct clk_virtio_desc *virtclk_find_desc( + const struct virtio_cc_map *maps, + const char *name) +{ + if (!maps) + return NULL; + + for (; maps->cc_name[0]; maps++) { + if (!strcmp(name, maps->cc_name)) + return maps->desc; + } + + return NULL; +} + +static struct clk_hw * +of_clk_hw_virtio_get(struct of_phandle_args *clkspec, void *data) +{ + struct virtio_clk *vclk = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= vclk->num_clks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &vclk->clks[idx].hw; +} + +static int virtio_clk_probe(struct virtio_device *vdev) +{ + const struct clk_virtio_desc *desc = NULL; + struct virtio_clk *vclk; + struct virtio_clk_config config; + struct clk_virtio *virtio_clks; + char name[40]; + struct clk_init_data init; + static int instance; + unsigned int i; + int ret; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + vclk = devm_kzalloc(&vdev->dev, sizeof(*vclk), GFP_KERNEL); + if (!vclk) + return -ENOMEM; + + vdev->priv = vclk; + vclk->vdev = vdev; + mutex_init(&vclk->lock); + init_completion(&vclk->rsp_avail); + + ret = virtclk_init_vqs(vclk); + if (ret) { + dev_err(&vdev->dev, "failed to initialized virtqueue\n"); + return ret; + } + + virtio_device_ready(vdev); + + memset(&config, 0x0, sizeof(config)); + + virtio_cread(vdev, struct virtio_clk_config, num_clks, + &config.num_clks); + virtio_cread_feature(vdev, VIRTIO_CLK_F_RESET, struct virtio_clk_config, + num_resets, &config.num_resets); + + if (virtio_has_feature(vdev, VIRTIO_CLK_F_NAME)) { + virtio_cread_bytes(vdev, + offsetof(struct virtio_clk_config, name), + &config.name, sizeof(config.name)); + desc = virtclk_find_desc(clk_virtio_map_table, config.name); + if (!desc) { + ret = -ENXIO; + goto err_find_desc; + } + } + + dev_dbg(&vdev->dev, "num_clks=%d, num_resets=%d, name=%s\n", + config.num_clks, config.num_resets, config.name); + + if (desc) { + vclk->desc = desc; + vclk->num_clks = desc->num_clks; + if (desc->num_resets > 0) + vclk->num_resets = desc->num_resets; + } else { + vclk->num_clks = config.num_clks; + if (config.num_resets > 0) + vclk->num_resets = config.num_resets; + } + + virtio_clks = devm_kcalloc(&vdev->dev, vclk->num_clks, + sizeof(struct clk_virtio), GFP_KERNEL); + if (!virtio_clks) { + ret = -ENOMEM; + goto err_kcalloc; + } + + vclk->clks = virtio_clks; + + memset(&init, 0x0, sizeof(init)); + init.ops = &clk_virtio_ops; + + if (desc) { + for (i = 0; i < vclk->num_clks; i++) { + if (!desc->clk_names[i]) + continue; + + virtio_clks[i].clk_id = i; + virtio_clks[i].vclk = vclk; + init.name = desc->clk_names[i]; + virtio_clks[i].hw.init = &init; + ret = devm_clk_hw_register(&vdev->dev, + &virtio_clks[i].hw); + if (ret) { + dev_err(&vdev->dev, "fail to register clock\n"); + goto err_clk_register; + } + } + } else { + init.name = name; + + for (i = 0; i < config.num_clks; i++) { + virtio_clks[i].clk_id = i; + virtio_clks[i].vclk = vclk; + snprintf(name, sizeof(name), "virtio_%d_%d", + instance, i); + virtio_clks[i].hw.init = &init; + ret = devm_clk_hw_register(&vdev->dev, + &virtio_clks[i].hw); + if (ret) { + dev_err(&vdev->dev, "fail to register clock\n"); + goto err_clk_register; + } + } + } + + ret = of_clk_add_hw_provider(vdev->dev.parent->of_node, + of_clk_hw_virtio_get, vclk); + if (ret) { + dev_err(&vdev->dev, "failed to add clock provider\n"); + goto err_clk_register; + } + + if (vclk->num_resets > 0) { + vclk->rcdev.of_node = vdev->dev.parent->of_node; + vclk->rcdev.ops = &virtio_reset_ops; + vclk->rcdev.owner = vdev->dev.driver->owner; + vclk->rcdev.nr_resets = vclk->num_resets; + ret = devm_reset_controller_register(&vdev->dev, &vclk->rcdev); + if (ret) + goto err_rst_register; + } + + instance++; + + dev_info(&vdev->dev, "Registered virtio clocks (%s)\n", config.name); + + return 0; + +err_rst_register: + of_clk_del_provider(vdev->dev.parent->of_node); +err_clk_register: +err_kcalloc: +err_find_desc: + vdev->config->del_vqs(vdev); + return ret; +} + +static const struct virtio_device_id id_table[] = { + { VIRTIO_ID_CLOCK, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { + VIRTIO_CLK_F_RESET, + VIRTIO_CLK_F_NAME, +}; + +static struct virtio_driver virtio_clk_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_clk_probe, +}; + +static int __init virtio_clk_init(void) +{ + return register_virtio_driver(&virtio_clk_driver); +} + +static void __exit virtio_clk_fini(void) +{ + unregister_virtio_driver(&virtio_clk_driver); +} +subsys_initcall_sync(virtio_clk_init); +module_exit(virtio_clk_fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio clock driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/virtio_clk_common.h b/drivers/clk/qcom/virtio_clk_common.h new file mode 100644 index 0000000000000000000000000000000000000000..200fcd9e3784148377f080af5fc0cdda43e9b2cc --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_common.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 __VIRTIO_CLK_COMMON__ +#define __VIRTIO_CLK_COMMON__ + +#include + +/* + * struct clk_virtio_desc - virtio clock descriptor + * clk_names: the pointer of clock name pointer + * num_clks: number of clocks + * reset_names: the pointer of reset name pointer + * num_resets: number of resets + */ +struct clk_virtio_desc { + const char * const *clk_names; + size_t num_clks; + const char * const *reset_names; + size_t num_resets; +}; + +extern const struct clk_virtio_desc clk_virtio_sm8150_gcc; +extern const struct clk_virtio_desc clk_virtio_sm8150_scc; +extern const struct clk_virtio_desc clk_virtio_sm6150_gcc; +extern const struct clk_virtio_desc clk_virtio_sm6150_scc; +extern const struct clk_virtio_desc clk_virtio_sa8195p_gcc; + +#endif diff --git a/drivers/clk/qcom/virtio_clk_sa8195p.c b/drivers/clk/qcom/virtio_clk_sa8195p.c new file mode 100644 index 0000000000000000000000000000000000000000..90c07bf8f7cae16a7bd51c3ea319ffe9bdb18145 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_sa8195p.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "virtio_clk_common.h" + +static const char * const sa8195p_gcc_virtio_clocks[] = { + [GCC_QUPV3_WRAP0_S0_CLK] = "gcc_qupv3_wrap0_s0_clk", + [GCC_QUPV3_WRAP0_S1_CLK] = "gcc_qupv3_wrap0_s1_clk", + [GCC_QUPV3_WRAP0_S2_CLK] = "gcc_qupv3_wrap0_s2_clk", + [GCC_QUPV3_WRAP0_S3_CLK] = "gcc_qupv3_wrap0_s3_clk", + [GCC_QUPV3_WRAP0_S4_CLK] = "gcc_qupv3_wrap0_s4_clk", + [GCC_QUPV3_WRAP0_S5_CLK] = "gcc_qupv3_wrap0_s5_clk", + [GCC_QUPV3_WRAP0_S6_CLK] = "gcc_qupv3_wrap0_s6_clk", + [GCC_QUPV3_WRAP0_S7_CLK] = "gcc_qupv3_wrap0_s7_clk", + [GCC_QUPV3_WRAP1_S0_CLK] = "gcc_qupv3_wrap1_s0_clk", + [GCC_QUPV3_WRAP1_S1_CLK] = "gcc_qupv3_wrap1_s1_clk", + [GCC_QUPV3_WRAP1_S2_CLK] = "gcc_qupv3_wrap1_s2_clk", + [GCC_QUPV3_WRAP1_S3_CLK] = "gcc_qupv3_wrap1_s3_clk", + [GCC_QUPV3_WRAP1_S4_CLK] = "gcc_qupv3_wrap1_s4_clk", + [GCC_QUPV3_WRAP1_S5_CLK] = "gcc_qupv3_wrap1_s5_clk", + [GCC_QUPV3_WRAP2_S0_CLK] = "gcc_qupv3_wrap2_s0_clk", + [GCC_QUPV3_WRAP2_S1_CLK] = "gcc_qupv3_wrap2_s1_clk", + [GCC_QUPV3_WRAP2_S2_CLK] = "gcc_qupv3_wrap2_s2_clk", + [GCC_QUPV3_WRAP2_S3_CLK] = "gcc_qupv3_wrap2_s3_clk", + [GCC_QUPV3_WRAP2_S4_CLK] = "gcc_qupv3_wrap2_s4_clk", + [GCC_QUPV3_WRAP2_S5_CLK] = "gcc_qupv3_wrap2_s5_clk", + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = "gcc_qupv3_wrap_0_m_ahb_clk", + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = "gcc_qupv3_wrap_0_s_ahb_clk", + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = "gcc_qupv3_wrap_1_m_ahb_clk", + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = "gcc_qupv3_wrap_1_s_ahb_clk", + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = "gcc_qupv3_wrap_2_m_ahb_clk", + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = "gcc_qupv3_wrap_2_s_ahb_clk", + [GCC_USB30_PRIM_MASTER_CLK] = "gcc_usb30_prim_master_clk", + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = "gcc_cfg_noc_usb3_prim_axi_clk", + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = "gcc_aggre_usb3_prim_axi_clk", + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = "gcc_usb30_prim_mock_utmi_clk", + [GCC_USB30_PRIM_SLEEP_CLK] = "gcc_usb30_prim_sleep_clk", + [GCC_USB3_PRIM_PHY_AUX_CLK] = "gcc_usb3_prim_phy_aux_clk", + [GCC_USB3_PRIM_PHY_PIPE_CLK] = "gcc_usb3_prim_phy_pipe_clk", + [GCC_USB3_PRIM_CLKREF_CLK] = "gcc_usb3_prim_clkref_en", + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = "gcc_usb3_prim_phy_com_aux_clk", + [GCC_USB30_SEC_MASTER_CLK] = "gcc_usb30_sec_master_clk", + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = "gcc_cfg_noc_usb3_sec_axi_clk", + [GCC_AGGRE_USB3_SEC_AXI_CLK] = "gcc_aggre_usb3_sec_axi_clk", + [GCC_USB30_SEC_MOCK_UTMI_CLK] = "gcc_usb30_sec_mock_utmi_clk", + [GCC_USB30_SEC_SLEEP_CLK] = "gcc_usb30_sec_sleep_clk", + [GCC_USB3_SEC_PHY_AUX_CLK] = "gcc_usb3_sec_phy_aux_clk", + [GCC_USB3_SEC_PHY_PIPE_CLK] = "gcc_usb3_sec_phy_pipe_clk", + [GCC_USB3_SEC_CLKREF_CLK] = "gcc_usb3_sec_clkref_en", + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = "gcc_usb3_sec_phy_com_aux_clk", + [GCC_PCIE_0_PIPE_CLK] = "gcc_pcie_0_pipe_clk", + [GCC_PCIE_0_AUX_CLK] = "gcc_pcie_0_aux_clk", + [GCC_PCIE_0_CFG_AHB_CLK] = "gcc_pcie_0_cfg_ahb_clk", + [GCC_PCIE_0_MSTR_AXI_CLK] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", + [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = "gcc_aggre_noc_pcie_tbu_clk", + [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", + [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", + [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", +}; + +static const char * const sa8195p_gcc_virtio_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = "gcc_qusb2phy_prim_bcr", + [GCC_QUSB2PHY_SEC_BCR] = "gcc_qusb2phy_sec_bcr", + [GCC_USB30_PRIM_BCR] = "gcc_usb30_prim_master_clk", + [GCC_USB30_SEC_BCR] = "gcc_usb30_sec_master_clk", + [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", +}; + +const struct clk_virtio_desc clk_virtio_sa8195p_gcc = { + .clk_names = sa8195p_gcc_virtio_clocks, + .num_clks = ARRAY_SIZE(sa8195p_gcc_virtio_clocks), + .reset_names = sa8195p_gcc_virtio_resets, + .num_resets = ARRAY_SIZE(sa8195p_gcc_virtio_resets), +}; diff --git a/drivers/clk/qcom/virtio_clk_sm6150.c b/drivers/clk/qcom/virtio_clk_sm6150.c new file mode 100644 index 0000000000000000000000000000000000000000..ef49397fe48aecfb1396719ffa3afae922430c75 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_sm6150.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "virtio_clk_common.h" + +static const char * const sm6150_gcc_virtio_clocks[] = { + [GCC_QUPV3_WRAP0_S0_CLK] = "gcc_qupv3_wrap0_s0_clk", + [GCC_QUPV3_WRAP0_S1_CLK] = "gcc_qupv3_wrap0_s1_clk", + [GCC_QUPV3_WRAP0_S2_CLK] = "gcc_qupv3_wrap0_s2_clk", + [GCC_QUPV3_WRAP0_S3_CLK] = "gcc_qupv3_wrap0_s3_clk", + [GCC_QUPV3_WRAP0_S4_CLK] = "gcc_qupv3_wrap0_s4_clk", + [GCC_QUPV3_WRAP0_S5_CLK] = "gcc_qupv3_wrap0_s5_clk", + [GCC_QUPV3_WRAP1_S0_CLK] = "gcc_qupv3_wrap1_s0_clk", + [GCC_QUPV3_WRAP1_S1_CLK] = "gcc_qupv3_wrap1_s1_clk", + [GCC_QUPV3_WRAP1_S2_CLK] = "gcc_qupv3_wrap1_s2_clk", + [GCC_QUPV3_WRAP1_S3_CLK] = "gcc_qupv3_wrap1_s3_clk", + [GCC_QUPV3_WRAP1_S4_CLK] = "gcc_qupv3_wrap1_s4_clk", + [GCC_QUPV3_WRAP1_S5_CLK] = "gcc_qupv3_wrap1_s5_clk", + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = "gcc_qupv3_wrap_0_m_ahb_clk", + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = "gcc_qupv3_wrap_0_s_ahb_clk", + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = "gcc_qupv3_wrap_1_m_ahb_clk", + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = "gcc_qupv3_wrap_1_s_ahb_clk", + [GCC_USB30_PRIM_MASTER_CLK] = "gcc_usb30_prim_master_clk", + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = "gcc_cfg_noc_usb3_prim_axi_clk", + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = "gcc_aggre_usb3_prim_axi_clk", + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = "gcc_usb30_prim_mock_utmi_clk", + [GCC_USB30_PRIM_SLEEP_CLK] = "gcc_usb30_prim_sleep_clk", + [GCC_USB3_SEC_CLKREF_CLK] = "gcc_usb3_sec_clkref_en", + [GCC_USB3_PRIM_PHY_AUX_CLK] = "gcc_usb3_prim_phy_aux_clk", + [GCC_USB3_PRIM_PHY_PIPE_CLK] = "gcc_usb3_prim_phy_pipe_clk", + [GCC_USB3_PRIM_CLKREF_CLK] = "gcc_usb3_prim_clkref_en", + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = "gcc_usb3_prim_phy_com_aux_clk", + [GCC_AHB2PHY_WEST_CLK] = "gcc_ahb2phy_west_clk", + [GCC_PCIE_0_PIPE_CLK] = "gcc_pcie_0_pipe_clk", + [GCC_PCIE_0_AUX_CLK] = "gcc_pcie_0_aux_clk", + [GCC_PCIE_0_CFG_AHB_CLK] = "gcc_pcie_0_cfg_ahb_clk", + [GCC_PCIE_0_MSTR_AXI_CLK] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", + [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", + [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", + [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", +}; + +static const char * const sm6150_gcc_virtio_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = "gcc_qusb2phy_prim_bcr", + [GCC_QUSB2PHY_SEC_BCR] = "gcc_qusb2phy_sec_bcr", + [GCC_USB30_PRIM_BCR] = "gcc_usb30_prim_master_clk", + [GCC_USB2_PHY_SEC_BCR] = "gcc_usb2_phy_sec_bcr", + [GCC_USB3_DP_PHY_SEC_BCR] = "gcc_usb3_dp_phy_sec_bcr", + [GCC_USB3PHY_PHY_SEC_BCR] = "gcc_usb3phy_phy_sec_bcr", + [GCC_USB20_SEC_BCR] = "gcc_usb20_sec_master_clk", + [GCC_USB3_PHY_PRIM_SP0_BCR] = "gcc_usb3_phy_prim_sp0_bcr", + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = "gcc_usb3phy_phy_prim_sp0_bcr", + [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", +}; + +const struct clk_virtio_desc clk_virtio_sm6150_gcc = { + .clk_names = sm6150_gcc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm6150_gcc_virtio_clocks), + .reset_names = sm6150_gcc_virtio_resets, + .num_resets = ARRAY_SIZE(sm6150_gcc_virtio_resets), +}; + +static const char * const sm6150_scc_virtio_clocks[] = { + [SCC_QUPV3_SE0_CLK] = "scc_qupv3_se0_clk", + [SCC_QUPV3_SE1_CLK] = "scc_qupv3_se1_clk", + [SCC_QUPV3_SE2_CLK] = "scc_qupv3_se2_clk", + [SCC_QUPV3_SE3_CLK] = "scc_qupv3_se3_clk", + [SCC_QUPV3_M_HCLK_CLK] = "scc_qupv3_m_hclk_clk", + [SCC_QUPV3_S_HCLK_CLK] = "scc_qupv3_s_hclk_clk", +}; + +const struct clk_virtio_desc clk_virtio_sm6150_scc = { + .clk_names = sm6150_scc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm6150_scc_virtio_clocks), +}; diff --git a/drivers/clk/qcom/virtio_clk_sm8150.c b/drivers/clk/qcom/virtio_clk_sm8150.c new file mode 100644 index 0000000000000000000000000000000000000000..68b0f52d21b239d9449a85e860b8815c18e348bb --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_sm8150.c @@ -0,0 +1,109 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "virtio_clk_common.h" + +static const char * const sm8150_gcc_virtio_clocks[] = { + [GCC_QUPV3_WRAP0_S0_CLK] = "gcc_qupv3_wrap0_s0_clk", + [GCC_QUPV3_WRAP0_S1_CLK] = "gcc_qupv3_wrap0_s1_clk", + [GCC_QUPV3_WRAP0_S2_CLK] = "gcc_qupv3_wrap0_s2_clk", + [GCC_QUPV3_WRAP0_S3_CLK] = "gcc_qupv3_wrap0_s3_clk", + [GCC_QUPV3_WRAP0_S4_CLK] = "gcc_qupv3_wrap0_s4_clk", + [GCC_QUPV3_WRAP0_S5_CLK] = "gcc_qupv3_wrap0_s5_clk", + [GCC_QUPV3_WRAP0_S6_CLK] = "gcc_qupv3_wrap0_s6_clk", + [GCC_QUPV3_WRAP0_S7_CLK] = "gcc_qupv3_wrap0_s7_clk", + [GCC_QUPV3_WRAP1_S0_CLK] = "gcc_qupv3_wrap1_s0_clk", + [GCC_QUPV3_WRAP1_S1_CLK] = "gcc_qupv3_wrap1_s1_clk", + [GCC_QUPV3_WRAP1_S2_CLK] = "gcc_qupv3_wrap1_s2_clk", + [GCC_QUPV3_WRAP1_S3_CLK] = "gcc_qupv3_wrap1_s3_clk", + [GCC_QUPV3_WRAP1_S4_CLK] = "gcc_qupv3_wrap1_s4_clk", + [GCC_QUPV3_WRAP1_S5_CLK] = "gcc_qupv3_wrap1_s5_clk", + [GCC_QUPV3_WRAP2_S0_CLK] = "gcc_qupv3_wrap2_s0_clk", + [GCC_QUPV3_WRAP2_S1_CLK] = "gcc_qupv3_wrap2_s1_clk", + [GCC_QUPV3_WRAP2_S2_CLK] = "gcc_qupv3_wrap2_s2_clk", + [GCC_QUPV3_WRAP2_S3_CLK] = "gcc_qupv3_wrap2_s3_clk", + [GCC_QUPV3_WRAP2_S4_CLK] = "gcc_qupv3_wrap2_s4_clk", + [GCC_QUPV3_WRAP2_S5_CLK] = "gcc_qupv3_wrap2_s5_clk", + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = "gcc_qupv3_wrap_0_m_ahb_clk", + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = "gcc_qupv3_wrap_0_s_ahb_clk", + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = "gcc_qupv3_wrap_1_m_ahb_clk", + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = "gcc_qupv3_wrap_1_s_ahb_clk", + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = "gcc_qupv3_wrap_2_m_ahb_clk", + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = "gcc_qupv3_wrap_2_s_ahb_clk", + [GCC_USB30_PRIM_MASTER_CLK] = "gcc_usb30_prim_master_clk", + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = "gcc_cfg_noc_usb3_prim_axi_clk", + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = "gcc_aggre_usb3_prim_axi_clk", + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = "gcc_usb30_prim_mock_utmi_clk", + [GCC_USB30_PRIM_SLEEP_CLK] = "gcc_usb30_prim_sleep_clk", + [GCC_USB3_SEC_CLKREF_CLK] = "gcc_usb3_sec_clkref_en", + [GCC_USB3_PRIM_PHY_AUX_CLK] = "gcc_usb3_prim_phy_aux_clk", + [GCC_USB3_PRIM_PHY_PIPE_CLK] = "gcc_usb3_prim_phy_pipe_clk", + [GCC_USB3_PRIM_CLKREF_CLK] = "gcc_usb3_prim_clkref_en", + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = "gcc_usb3_prim_phy_com_aux_clk", + [GCC_USB30_SEC_MASTER_CLK] = "gcc_usb30_sec_master_clk", + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = "gcc_cfg_noc_usb3_sec_axi_clk", + [GCC_AGGRE_USB3_SEC_AXI_CLK] = "gcc_aggre_usb3_sec_axi_clk", + [GCC_USB30_SEC_MOCK_UTMI_CLK] = "gcc_usb30_sec_mock_utmi_clk", + [GCC_USB30_SEC_SLEEP_CLK] = "gcc_usb30_sec_sleep_clk", + [GCC_USB3_SEC_PHY_AUX_CLK] = "gcc_usb3_sec_phy_aux_clk", + [GCC_USB3_SEC_PHY_PIPE_CLK] = "gcc_usb3_sec_phy_pipe_clk", + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = "gcc_usb3_sec_phy_com_aux_clk", + [GCC_PCIE_0_PIPE_CLK] = "gcc_pcie_0_pipe_clk", + [GCC_PCIE_0_AUX_CLK] = "gcc_pcie_0_aux_clk", + [GCC_PCIE_0_CFG_AHB_CLK] = "gcc_pcie_0_cfg_ahb_clk", + [GCC_PCIE_0_MSTR_AXI_CLK] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", + [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = "gcc_aggre_noc_pcie_tbu_clk", + [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", + [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", + [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", +}; + +static const char * const sm8150_gcc_virtio_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = "gcc_qusb2phy_prim_bcr", + [GCC_QUSB2PHY_SEC_BCR] = "gcc_qusb2phy_sec_bcr", + [GCC_USB3_PHY_PRIM_BCR] = "gcc_usb3_phy_prim_bcr", + [GCC_USB3_DP_PHY_PRIM_BCR] = "gcc_usb3_dp_phy_prim_bcr", + [GCC_USB3_PHY_SEC_BCR] = "gcc_usb3_phy_sec_bcr", + [GCC_USB3PHY_PHY_SEC_BCR] = "gcc_usb3phy_phy_sec_bcr", + [GCC_USB30_PRIM_BCR] = "gcc_usb30_prim_master_clk", + [GCC_USB30_SEC_BCR] = "gcc_usb30_sec_master_clk", + [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", +}; + +const struct clk_virtio_desc clk_virtio_sm8150_gcc = { + .clk_names = sm8150_gcc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm8150_gcc_virtio_clocks), + .reset_names = sm8150_gcc_virtio_resets, + .num_resets = ARRAY_SIZE(sm8150_gcc_virtio_resets), +}; + +static const char * const sm8150_scc_virtio_clocks[] = { + [SCC_QUPV3_SE0_CLK] = "scc_qupv3_se0_clk", + [SCC_QUPV3_SE1_CLK] = "scc_qupv3_se1_clk", + [SCC_QUPV3_SE2_CLK] = "scc_qupv3_se2_clk", + [SCC_QUPV3_SE3_CLK] = "scc_qupv3_se3_clk", + [SCC_QUPV3_M_HCLK_CLK] = "scc_qupv3_m_hclk_clk", + [SCC_QUPV3_S_HCLK_CLK] = "scc_qupv3_s_hclk_clk", +}; + +const struct clk_virtio_desc clk_virtio_sm8150_scc = { + .clk_names = sm8150_scc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm8150_scc_virtio_clocks), +}; diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c index d977193842dfed1fead553dd2240013c5a0d380a..19174835693b91cd473b59c7fed787f128f268d1 100644 --- a/drivers/clk/x86/clk-pmc-atom.c +++ b/drivers/clk/x86/clk-pmc-atom.c @@ -165,7 +165,7 @@ static const struct clk_ops plt_clk_ops = { }; static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id, - void __iomem *base, + const struct pmc_clk_data *pmc_data, const char **parent_names, int num_parents) { @@ -184,9 +184,17 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id, init.num_parents = num_parents; pclk->hw.init = &init; - pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE; + pclk->reg = pmc_data->base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE; spin_lock_init(&pclk->lock); + /* + * On some systems, the pmc_plt_clocks already enabled by the + * firmware are being marked as critical to avoid them being + * gated by the clock framework. + */ + if (pmc_data->critical && plt_clk_is_enabled(&pclk->hw)) + init.flags |= CLK_IS_CRITICAL; + ret = devm_clk_hw_register(&pdev->dev, &pclk->hw); if (ret) { pclk = ERR_PTR(ret); @@ -332,7 +340,7 @@ static int plt_clk_probe(struct platform_device *pdev) return PTR_ERR(parent_names); for (i = 0; i < PMC_CLK_NUM; i++) { - data->clks[i] = plt_clk_register(pdev, i, pmc_data->base, + data->clks[i] = plt_clk_register(pdev, i, pmc_data, parent_names, data->nparents); if (IS_ERR(data->clks[i])) { err = PTR_ERR(data->clks[i]); diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 7553ee21b6f97a376c26bdaefe7e2e25d535ec7e..ac2c6f7ea8d0511b2d9b1273782753a749321e25 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * Copyright (C) 2006-2007 Adam Belay * Copyright (C) 2009 Intel Corporation * @@ -109,6 +109,7 @@ static DEFINE_PER_CPU(struct lpm_cpu*, cpu_lpm); static bool suspend_in_progress; static struct hrtimer lpm_hrtimer; static DEFINE_PER_CPU(struct hrtimer, histtimer); +static DEFINE_PER_CPU(struct hrtimer, biastimer); static struct lpm_debug *lpm_debug; static phys_addr_t lpm_debug_phys; static const int num_dbg_elements = 0x100; @@ -435,6 +436,34 @@ static void msm_pm_set_timer(uint32_t modified_time_us) hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED); } +static void biastimer_cancel(void) +{ + unsigned int cpu = raw_smp_processor_id(); + struct hrtimer *cpu_biastimer = &per_cpu(biastimer, cpu); + ktime_t time_rem; + + time_rem = hrtimer_get_remaining(cpu_biastimer); + if (ktime_to_us(time_rem) <= 0) + return; + + hrtimer_try_to_cancel(cpu_biastimer); +} + +static enum hrtimer_restart biastimer_fn(struct hrtimer *h) +{ + return HRTIMER_NORESTART; +} + +static void biastimer_start(uint32_t time_ns) +{ + ktime_t bias_ktime = ns_to_ktime(time_ns); + unsigned int cpu = raw_smp_processor_id(); + struct hrtimer *cpu_biastimer = &per_cpu(biastimer, cpu); + + cpu_biastimer->function = biastimer_fn; + hrtimer_start(cpu_biastimer, bias_ktime, HRTIMER_MODE_REL_PINNED); +} + static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, struct lpm_cpu *cpu, int *idx_restrict, uint32_t *idx_restrict_time) @@ -595,15 +624,22 @@ static void clear_predict_history(void) static void update_history(struct cpuidle_device *dev, int idx); -static inline bool is_cpu_biased(int cpu) +static inline bool is_cpu_biased(int cpu, uint64_t *bias_time) { u64 now = sched_clock(); u64 last = sched_get_cpu_last_busy_time(cpu); + u64 diff = 0; if (!last) return false; - return (now - last) < BIAS_HYST; + diff = now - last; + if (diff < BIAS_HYST) { + *bias_time = BIAS_HYST - diff; + return true; + } + + return false; } static int cpu_power_select(struct cpuidle_device *dev, @@ -623,6 +659,7 @@ static int cpu_power_select(struct cpuidle_device *dev, uint32_t next_wakeup_us = (uint32_t)sleep_us; uint32_t min_residency, max_residency; struct power_params *pwr_params; + uint64_t bias_time = 0; if ((sleep_disabled && !cpu_isolated(dev->cpu)) || sleep_us < 0) return best_level; @@ -631,8 +668,10 @@ static int cpu_power_select(struct cpuidle_device *dev, next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu))); - if (is_cpu_biased(dev->cpu) && (!cpu_isolated(dev->cpu))) + if (is_cpu_biased(dev->cpu, &bias_time) && (!cpu_isolated(dev->cpu))) { + cpu->bias = bias_time; goto done_select; + } for (i = 0; i < cpu->nlevels; i++) { bool allow; @@ -1310,6 +1349,8 @@ static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle) */ if (!idx) { + if (cpu->bias) + biastimer_start(cpu->bias); stop_critical_timings(); wfi(); start_critical_timings(); @@ -1420,6 +1461,10 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, histtimer_cancel(); clusttimer_cancel(); } + if (cpu->bias) { + biastimer_cancel(); + cpu->bias = 0; + } local_irq_enable(); return idx; } @@ -1723,6 +1768,8 @@ static int lpm_probe(struct platform_device *pdev) for_each_possible_cpu(cpu) { cpu_histtimer = &per_cpu(histtimer, cpu); hrtimer_init(cpu_histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cpu_histtimer = &per_cpu(biastimer, cpu); + hrtimer_init(cpu_histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); } cluster_timer_init(lpm_root_node); diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index ae336d26c37b1f6a08bd90fcb9d575ad83e4dab1..e6207e5ecd89116e88f1ebb0a7881d839b0923fd 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -52,6 +52,7 @@ struct lpm_cpu { uint32_t ref_premature_cnt; uint32_t tmr_add; bool lpm_prediction; + uint64_t bias; struct cpuidle_driver *drv; struct lpm_cluster *parent; }; diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index 4afca396877335653ae8f6f902d1bcdf5b3b9db3..e3b8bebfdd304b6356aa87d8104f4cb9fc1a5121 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -138,7 +138,8 @@ static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, sa = (struct dynamic_sa_ctl *) ctx->sa_in; ctx->hash_final = 0; - set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV, + set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, (cm == CRYPTO_MODE_CBC ? + SA_SAVE_IV : SA_NOT_SAVE_IV), SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE, SA_NO_HEADER_PROC, SA_HASH_ALG_NULL, SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO, diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 3f9eee7e555fe921a8e4af9d3d5fee7063e5a711..8d4d8db244e997408b71bbcfd9ac1c51769d9661 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -645,6 +645,15 @@ static u32 crypto4xx_ablkcipher_done(struct crypto4xx_device *dev, addr = dma_map_page(dev->core_dev->device, sg_page(dst), dst->offset, dst->length, DMA_FROM_DEVICE); } + + if (pd_uinfo->sa_va->sa_command_0.bf.save_iv == SA_SAVE_IV) { + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + + crypto4xx_memcpy_from_le32((u32 *)req->iv, + pd_uinfo->sr_va->save_iv, + crypto_skcipher_ivsize(skcipher)); + } + crypto4xx_ret_sg_desc(dev, pd_uinfo); if (ablk_req->base.complete != NULL) ablk_req->base.complete(&ablk_req->base, 0); diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 6eb5cb92b9863d2800717fb996bcd0353332e78a..9f82e14983f65677b02fc56df85d5f4fb28a0e34 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -284,6 +284,7 @@ enum artpec6_crypto_hash_flags { struct artpec6_crypto_req_common { struct list_head list; + struct list_head complete_in_progress; struct artpec6_crypto_dma_descriptors *dma; struct crypto_async_request *req; void (*complete)(struct crypto_async_request *req); @@ -2046,7 +2047,8 @@ static int artpec6_crypto_prepare_aead(struct aead_request *areq) return artpec6_crypto_dma_map_descs(common); } -static void artpec6_crypto_process_queue(struct artpec6_crypto *ac) +static void artpec6_crypto_process_queue(struct artpec6_crypto *ac, + struct list_head *completions) { struct artpec6_crypto_req_common *req; @@ -2057,7 +2059,7 @@ static void artpec6_crypto_process_queue(struct artpec6_crypto *ac) list_move_tail(&req->list, &ac->pending); artpec6_crypto_start_dma(req); - req->req->complete(req->req, -EINPROGRESS); + list_add_tail(&req->complete_in_progress, completions); } /* @@ -2087,6 +2089,11 @@ static void artpec6_crypto_task(unsigned long data) struct artpec6_crypto *ac = (struct artpec6_crypto *)data; struct artpec6_crypto_req_common *req; struct artpec6_crypto_req_common *n; + struct list_head complete_done; + struct list_head complete_in_progress; + + INIT_LIST_HEAD(&complete_done); + INIT_LIST_HEAD(&complete_in_progress); if (list_empty(&ac->pending)) { pr_debug("Spurious IRQ\n"); @@ -2120,19 +2127,30 @@ static void artpec6_crypto_task(unsigned long data) pr_debug("Completing request %p\n", req); - list_del(&req->list); + list_move_tail(&req->list, &complete_done); artpec6_crypto_dma_unmap_all(req); artpec6_crypto_copy_bounce_buffers(req); ac->pending_count--; artpec6_crypto_common_destroy(req); - req->complete(req->req); } - artpec6_crypto_process_queue(ac); + artpec6_crypto_process_queue(ac, &complete_in_progress); spin_unlock_bh(&ac->queue_lock); + + /* Perform the completion callbacks without holding the queue lock + * to allow new request submissions from the callbacks. + */ + list_for_each_entry_safe(req, n, &complete_done, list) { + req->complete(req->req); + } + + list_for_each_entry_safe(req, n, &complete_in_progress, + complete_in_progress) { + req->req->complete(req->req, -EINPROGRESS); + } } static void artpec6_crypto_complete_crypto(struct crypto_async_request *req) diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c index 698c60000fe80c6d3fdedf8a66289f2e565fb606..af19be8c6628ad4ed208537238c2119d7c0fb477 100644 --- a/drivers/devfreq/bimc-bwmon.c +++ b/drivers/devfreq/bimc-bwmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ #include #include #include +#include #include "governor_bw_hwmon.h" #define GLB_INT_STATUS(m) ((m)->global_base + 0x100) @@ -99,6 +100,8 @@ struct bwmon { void __iomem *global_base; unsigned int mport; int irq; + int nr_clks; + struct clk **clks; const struct bwmon_spec *spec; struct device *dev; struct bw_hwmon hw; @@ -588,15 +591,16 @@ unsigned long get_zone_count(struct bwmon *m, unsigned int zone, WARN(1, "Invalid\n"); return 0; case MON2: - count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1; + count = readl_relaxed(MON2_ZONE_MAX(m, zone)); break; case MON3: count = readl_relaxed(MON3_ZONE_MAX(m, zone)); - if (count) - count++; break; } + if (count) + count++; + return count; } @@ -782,6 +786,27 @@ void mon_set_byte_count_filter(struct bwmon *m, enum mon_reg_type type) } } +static __always_inline int mon_clk_enable(struct bwmon *m) +{ + int ret; + int i; + + for (i = 0; i < m->nr_clks; i++) { + ret = clk_prepare_enable(m->clks[i]); + if (ret) { + dev_err(m->dev, "BWMON clk not enabled %d\n", ret); + goto err; + } + } + + return 0; +err: + for (i--; i >= 0; i--) + clk_disable_unprepare(m->clks[i]); + + return ret; +} + static __always_inline int __start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum mon_reg_type type) { @@ -790,6 +815,12 @@ static __always_inline int __start_bw_hwmon(struct bw_hwmon *hw, int ret; irq_handler_t handler; + ret = mon_clk_enable(m); + if (ret) { + dev_err(m->dev, "Unable to turn on bwmon clks! (%d)\n", ret); + return ret; + } + switch (type) { case MON1: handler = bwmon_intr_handler; @@ -856,6 +887,14 @@ static int start_bw_hwmon3(struct bw_hwmon *hw, unsigned long mbps) return __start_bw_hwmon(hw, mbps, MON3); } +static __always_inline void mon_clk_disable(struct bwmon *m) +{ + int i; + + for (i = m->nr_clks - 1; i >= 0; i--) + clk_disable_unprepare(m->clks[i]); +} + static __always_inline void __stop_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) { @@ -866,6 +905,7 @@ void __stop_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) mon_disable(m, type); mon_clear(m, true, type); mon_irq_clear(m, type); + mon_clk_disable(m); } static void stop_bw_hwmon(struct bw_hwmon *hw) @@ -918,6 +958,12 @@ int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) int ret; irq_handler_t handler; + ret = mon_clk_enable(m); + if (ret) { + dev_err(m->dev, "Unable to turn on bwmon clks! (%d)\n", ret); + return ret; + } + switch (type) { case MON1: handler = bwmon_intr_handler; @@ -1021,6 +1067,7 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) struct bwmon *m; int ret; u32 data, count_unit; + unsigned int len, i; m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL); if (!m) @@ -1066,6 +1113,42 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) m->mport = data; } + if (of_find_property(dev->of_node, "qcom,bwmon_clks", &len)) { + m->nr_clks = of_property_count_strings(dev->of_node, + "qcom,bwmon_clks"); + if (!m->nr_clks) { + dev_err(dev, "Failed to get clock names\n"); + return -EINVAL; + } + + m->clks = devm_kzalloc(dev, sizeof(struct clk *) * m->nr_clks, + GFP_KERNEL); + if (!m->clks) + return -ENOMEM; + + for (i = 0; i < m->nr_clks; i++) { + const char *clock_name; + + ret = of_property_read_string_index(dev->of_node, + "qcom,bwmon_clks", i, + &clock_name); + if (ret) { + pr_err("failed to read clk index %d ret %d\n", + i, ret); + return ret; + } + m->clks[i] = devm_clk_get(dev, clock_name); + if (IS_ERR(m->clks[i])) { + ret = PTR_ERR(m->clks[i]); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error to get %s clk %d\n", + clock_name, ret); + return ret; + } + } + } else + m->nr_clks = 0; + m->irq = platform_get_irq(pdev, 0); if (m->irq < 0) { dev_err(dev, "Unable to get IRQ number\n"); diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index 164d622c3a5034e3e826680b0da2c3ba7a793fe7..330c45a8c1fe30a5994761b1c29b925c59f8447b 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -617,7 +617,8 @@ static int gov_start(struct devfreq *df) node->orig_data = df->data; df->data = node; - if (start_monitor(df, true)) + ret = start_monitor(df, true); + if (ret) goto err_start; ret = sysfs_create_group(&df->dev.kobj, node->attr_grp); diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index 779c37836ff3eb20b5c5b71966e0f84f8198cd79..9c4cce1e9656e4eb32fcf17fedff744242559bd4 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -519,6 +519,37 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) return result; } +int msm_adreno_devfreq_init_tz(struct devfreq *devfreq) +{ + struct devfreq_msm_adreno_tz_data *priv; + unsigned int tz_pwrlevels[MSM_ADRENO_MAX_PWRLEVELS + 1]; + int i, out = 1, ret; + unsigned int version; + + if (!devfreq) + return -EINVAL; + + priv = devfreq->data; + + if (devfreq->profile->max_state < MSM_ADRENO_MAX_PWRLEVELS) { + for (i = 0; i < devfreq->profile->max_state; i++) + tz_pwrlevels[out++] = devfreq->profile->freq_table[i]; + tz_pwrlevels[0] = i; + } else { + pr_err(TAG "tz_pwrlevels[] is too short\n"); + return -EINVAL; + } + + ret = tz_init(priv, tz_pwrlevels, sizeof(tz_pwrlevels), &version, + sizeof(version)); + if (ret != 0 || version > MAX_TZ_VERSION) { + pr_err(TAG "tz_init failed\n"); + return ret ? ret : -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(msm_adreno_devfreq_init_tz); static struct devfreq_governor msm_adreno_tz = { .name = "msm-adreno-tz", diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index eab48c682d850a14ee43e61289dae30a9a34fe38..ca1028e7ab455abf1c3c06ada249c0097f707eb9 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -441,6 +441,7 @@ struct gpi_dev { struct device *dev; struct resource *res; void __iomem *regs; + void __iomem *ee_base; /*ee register base address*/ u32 max_gpii; /* maximum # of gpii instances available per gpi block */ u32 gpii_mask; /* gpii instances available for apps */ u32 ev_factor; /* ev ring length factor */ @@ -2649,6 +2650,7 @@ static int gpi_probe(struct platform_device *pdev) { struct gpi_dev *gpi_dev; int ret, i; + u32 gpi_ee_offset; gpi_dev = devm_kzalloc(&pdev->dev, sizeof(*gpi_dev), GFP_KERNEL); if (!gpi_dev) @@ -2669,6 +2671,8 @@ static int gpi_probe(struct platform_device *pdev) return -EFAULT; } + gpi_dev->ee_base = gpi_dev->regs; + ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,max-num-gpii", &gpi_dev->max_gpii); if (ret) { @@ -2683,6 +2687,14 @@ static int gpi_probe(struct platform_device *pdev) return ret; } + ret = of_property_read_u32(gpi_dev->dev->of_node, + "qcom,gpi-ee-offset", &gpi_ee_offset); + if (ret) + GPI_LOG(gpi_dev, "No variable ee offset present\n"); + else + gpi_dev->ee_base = + gpi_dev->ee_base - gpi_ee_offset; + ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,ev-factor", &gpi_dev->ev_factor); if (ret) { @@ -2732,7 +2744,6 @@ static int gpi_probe(struct platform_device *pdev) if (!gpi_dev->gpiis) return -ENOMEM; - /* setup all the supported gpii */ INIT_LIST_HEAD(&gpi_dev->dma_device.channels); for (i = 0; i < gpi_dev->max_gpii; i++) { @@ -2743,9 +2754,9 @@ static int gpi_probe(struct platform_device *pdev) continue; /* set up ev cntxt register map */ - gpii->ev_cntxt_base_reg = gpi_dev->regs + + gpii->ev_cntxt_base_reg = gpi_dev->ee_base + GPI_GPII_n_EV_CH_k_CNTXT_0_OFFS(i, 0); - gpii->ev_cntxt_db_reg = gpi_dev->regs + + gpii->ev_cntxt_db_reg = gpi_dev->ee_base + GPI_GPII_n_EV_CH_k_DOORBELL_0_OFFS(i, 0); gpii->ev_ring_base_lsb_reg = gpii->ev_cntxt_base_reg + CNTXT_2_RING_BASE_LSB; @@ -2753,11 +2764,11 @@ static int gpi_probe(struct platform_device *pdev) CNTXT_4_RING_RP_LSB; gpii->ev_ring_wp_lsb_reg = gpii->ev_cntxt_base_reg + CNTXT_6_RING_WP_LSB; - gpii->ev_cmd_reg = gpi_dev->regs + + gpii->ev_cmd_reg = gpi_dev->ee_base + GPI_GPII_n_EV_CH_CMD_OFFS(i); - gpii->ieob_src_reg = gpi_dev->regs + + gpii->ieob_src_reg = gpi_dev->ee_base + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_OFFS(i); - gpii->ieob_clr_reg = gpi_dev->regs + + gpii->ieob_clr_reg = gpi_dev->ee_base + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(i); /* set up irq */ @@ -2774,9 +2785,9 @@ static int gpi_probe(struct platform_device *pdev) struct gpii_chan *gpii_chan = &gpii->gpii_chan[chan]; /* set up ch cntxt register map */ - gpii_chan->ch_cntxt_base_reg = gpi_dev->regs + + gpii_chan->ch_cntxt_base_reg = gpi_dev->ee_base + GPI_GPII_n_CH_k_CNTXT_0_OFFS(i, chan); - gpii_chan->ch_cntxt_db_reg = gpi_dev->regs + + gpii_chan->ch_cntxt_db_reg = gpi_dev->ee_base + GPI_GPII_n_CH_k_DOORBELL_0_OFFS(i, chan); gpii_chan->ch_ring_base_lsb_reg = gpii_chan->ch_cntxt_base_reg + @@ -2787,7 +2798,7 @@ static int gpi_probe(struct platform_device *pdev) gpii_chan->ch_ring_wp_lsb_reg = gpii_chan->ch_cntxt_base_reg + CNTXT_6_RING_WP_LSB; - gpii_chan->ch_cmd_reg = gpi_dev->regs + + gpii_chan->ch_cmd_reg = gpi_dev->ee_base + GPI_GPII_n_CH_CMD_OFFS(i); /* vchan setup */ @@ -2803,7 +2814,7 @@ static int gpi_probe(struct platform_device *pdev) (unsigned long)gpii); init_completion(&gpii->cmd_completion); gpii->gpii_id = i; - gpii->regs = gpi_dev->regs; + gpii->regs = gpi_dev->ee_base; gpii->gpi_dev = gpi_dev; atomic_set(&gpii->dbg_index, 0); } diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 9d6ce5051d8f580ed3fd7a14d47e80a1a2eb03de..77b126525daca47799d04eb630e0e83f9240258d 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1332,6 +1332,7 @@ static enum dma_status rcar_dmac_tx_status(struct dma_chan *chan, enum dma_status status; unsigned long flags; unsigned int residue; + bool cyclic; status = dma_cookie_status(chan, cookie, txstate); if (status == DMA_COMPLETE || !txstate) @@ -1339,10 +1340,11 @@ static enum dma_status rcar_dmac_tx_status(struct dma_chan *chan, spin_lock_irqsave(&rchan->lock, flags); residue = rcar_dmac_chan_get_residue(rchan, cookie); + cyclic = rchan->desc.running ? rchan->desc.running->cyclic : false; spin_unlock_irqrestore(&rchan->lock, flags); /* if there's no residue, the cookie is complete */ - if (!residue) + if (!residue && !cyclic) return DMA_COMPLETE; dma_set_residue(txstate, residue); diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index 1645d10bd781df64f88fe67e37a7045b0c273dc8..9fe5a8c23de83d7958150e0c2f43bcbab0eec086 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -20,25 +20,11 @@ #include "mdm-dbg.h" /* Default number of powerup trial requests per session */ -#define ESOC_DEF_PON_REQ 2 -static unsigned int n_pon_tries = ESOC_DEF_PON_REQ; -module_param(n_pon_tries, uint, 0644); -MODULE_PARM_DESC(n_pon_tries, -"Number of power-on retrials allowed upon boot failure"); - -enum esoc_boot_fail_action { - BOOT_FAIL_ACTION_RETRY, - BOOT_FAIL_ACTION_COLD_RESET, - BOOT_FAIL_ACTION_SHUTDOWN, - BOOT_FAIL_ACTION_PANIC, - BOOT_FAIL_ACTION_NOP, - BOOT_FAIL_ACTION_S3_RESET, -}; +#define ESOC_DEF_PON_REQ 3 + +#define ESOC_MAX_PON_TRIES 5 -static unsigned int boot_fail_action = BOOT_FAIL_ACTION_PANIC; -module_param(boot_fail_action, uint, 0644); -MODULE_PARM_DESC(boot_fail_action, -"Actions: 0:Retry PON; 1:Cold reset; 2:Power-down; 3:APQ Panic; 4:No action"); +#define BOOT_FAIL_ACTION_DEF BOOT_FAIL_ACTION_PANIC enum esoc_pon_state { PON_INIT, @@ -70,13 +56,58 @@ struct mdm_drv { struct work_struct ssr_work; struct notifier_block esoc_restart; struct mutex poff_lock; + atomic_t boot_fail_action; + atomic_t n_pon_tries; }; #define to_mdm_drv(d) container_of(d, struct mdm_drv, cmd_eng) -#define S3_RESET_DELAY_MS 2100 +#define S3_RESET_DELAY_MS 2000 static void esoc_client_link_power_off(struct esoc_clink *esoc_clink, unsigned int flags); +static void esoc_client_link_mdm_crash(struct esoc_clink *esoc_clink); + +int esoc_set_boot_fail_action(struct esoc_clink *esoc_clink, u32 action) +{ + struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); + + if (action >= BOOT_FAIL_ACTION_LAST) { + esoc_mdm_log("Unknown boot fail action requested: %u\n", + action); + return -EINVAL; + } + + if (!mdm_drv) { + esoc_mdm_log("esoc-mdm driver not present\n"); + return -EAGAIN; + } + + atomic_set(&mdm_drv->boot_fail_action, action); + esoc_mdm_log("Boot fail action configured to %u\n", action); + + return 0; +} + +int esoc_set_n_pon_tries(struct esoc_clink *esoc_clink, u32 n_tries) +{ + struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); + + if (n_tries > ESOC_MAX_PON_TRIES) { + esoc_mdm_log( + "Num PON tries requested (%u) is over the limit: %u\n", + n_tries, ESOC_MAX_PON_TRIES); + } + + if (!mdm_drv) { + esoc_mdm_log("esoc-mdm driver not present\n"); + return -EAGAIN; + } + + atomic_set(&mdm_drv->n_pon_tries, n_tries); + esoc_mdm_log("Num PON tries configured to %u\n", n_tries); + + return 0; +} static int esoc_msm_restart_handler(struct notifier_block *nb, unsigned long action, void *data) @@ -171,10 +202,11 @@ static void mdm_ssr_fn(struct work_struct *work) struct mdm_drv *mdm_drv = container_of(work, struct mdm_drv, ssr_work); struct mdm_ctrl *mdm = get_esoc_clink_data(mdm_drv->esoc_clink); + esoc_client_link_mdm_crash(mdm_drv->esoc_clink); + mdm_wait_for_status_low(mdm, false); esoc_mdm_log("Starting SSR work\n"); - /* * If restarting esoc fails, the SSR framework triggers a kernel panic */ @@ -218,6 +250,21 @@ static void esoc_client_link_power_off(struct esoc_clink *esoc_clink, } } +static void esoc_client_link_mdm_crash(struct esoc_clink *esoc_clink) +{ + int i; + struct esoc_client_hook *client_hook; + + dev_dbg(&esoc_clink->dev, "Calling mdm_crash hooks\n"); + esoc_mdm_log("Calling mdm_crash hooks\n"); + + for (i = 0; i < ESOC_MAX_HOOKS; i++) { + client_hook = esoc_clink->client_hook[i]; + if (client_hook && client_hook->esoc_link_mdm_crash) + client_hook->esoc_link_mdm_crash(client_hook->priv); + } +} + static void mdm_crash_shutdown(const struct subsys_desc *mdm_subsys) { struct esoc_clink *esoc_clink = @@ -327,8 +374,15 @@ static void mdm_subsys_retry_powerup_cleanup(struct esoc_clink *esoc_clink, static int mdm_handle_boot_fail(struct esoc_clink *esoc_clink, u8 *pon_trial) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); + struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); + + if (*pon_trial == atomic_read(&mdm_drv->n_pon_tries)) { + esoc_mdm_log("Reached max. number of boot trials\n"); + atomic_set(&mdm_drv->boot_fail_action, + BOOT_FAIL_ACTION_PANIC); + } - switch (boot_fail_action) { + switch (atomic_read(&mdm_drv->boot_fail_action)) { case BOOT_FAIL_ACTION_RETRY: mdm_subsys_retry_powerup_cleanup(esoc_clink, 0); esoc_mdm_log("Request to retry a warm reset\n"); @@ -382,7 +436,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops; int timeout = INT_MAX; - u8 pon_trial = 1; + u8 pon_trial = 0; esoc_mdm_log("Powerup request from SSR\n"); @@ -456,7 +510,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) } else if (mdm_drv->pon_state == PON_SUCCESS) { break; } - } while (pon_trial <= n_pon_tries); + } while (pon_trial <= atomic_read(&mdm_drv->n_pon_tries)); return 0; } @@ -528,6 +582,8 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv) mdm_drv->esoc_clink = esoc_clink; mdm_drv->mode = PWR_OFF; mdm_drv->pon_state = PON_INIT; + atomic_set(&mdm_drv->boot_fail_action, BOOT_FAIL_ACTION_DEF); + atomic_set(&mdm_drv->n_pon_tries, ESOC_DEF_PON_REQ); mdm_drv->esoc_restart.notifier_call = esoc_msm_restart_handler; ret = register_reboot_notifier(&mdm_drv->esoc_restart); if (ret) diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c index e1e335226867e9ef1b44519da51235aa5531726f..6e75fb5a4dbd80f971fb32e21e276ba97b7a79e4 100644 --- a/drivers/esoc/esoc-mdm-pon.c +++ b/drivers/esoc/esoc-mdm-pon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -62,7 +62,7 @@ static int sdx50m_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) * Allow PS hold assert to be detected */ if (!atomic) - usleep_range(80000,180000); + usleep_range(120000, 180000); else /* * The flow falls through this path as a part of the diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h index 81dd0dfe1cadf3c6ccf7397b6b42f660a77b8889..46403c371698e73dc065ce06868efd014b97e417 100644 --- a/drivers/esoc/esoc.h +++ b/drivers/esoc/esoc.h @@ -193,3 +193,7 @@ static inline void notify_esoc_clients(struct esoc_clink *esoc_clink, bool esoc_req_eng_enabled(struct esoc_clink *esoc_clink); bool esoc_cmd_eng_enabled(struct esoc_clink *esoc_clink); #endif + +/* Modem boot fail actions */ +int esoc_set_boot_fail_action(struct esoc_clink *esoc_clink, u32 action); +int esoc_set_n_pon_tries(struct esoc_clink *esoc_clink, u32 n_tries); diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c index 6777627daee5fbbdf579b212725dc9e9cc249936..bd3929074eea04a1c6b4532c62860818916813fd 100644 --- a/drivers/esoc/esoc_dev.c +++ b/drivers/esoc/esoc_dev.c @@ -330,6 +330,12 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd, return err; case ESOC_GET_LINK_ID: return esoc_get_link_id(esoc_clink, arg); + case ESOC_SET_BOOT_FAIL_ACT: + get_user(esoc_cmd, (u32 __user *) arg); + return esoc_set_boot_fail_action(esoc_clink, esoc_cmd); + case ESOC_SET_N_PON_TRIES: + get_user(esoc_cmd, (u32 __user *) arg); + return esoc_set_n_pon_tries(esoc_clink, esoc_cmd); default: return -EINVAL; }; diff --git a/drivers/gnsssirf/Kconfig b/drivers/gnsssirf/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..559a6b62f815abb61167c2ad9b60eb15696577b8 --- /dev/null +++ b/drivers/gnsssirf/Kconfig @@ -0,0 +1,11 @@ +# +# SIRF GNSS receiver configuration +# + +menu "GNSS SIRF controls" +config GNSS_SIRF + bool "GNSS SIRF" + help + Driver for ports of GNSS SIRF functionality + +endmenu diff --git a/drivers/gnsssirf/Makefile b/drivers/gnsssirf/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e8400ec13ea2b53f4c0d65a088571ebb7ddb0bf0 --- /dev/null +++ b/drivers/gnsssirf/Makefile @@ -0,0 +1,3 @@ +# SIRF GNSS driver makefile. + +obj-$(CONFIG_GNSS_SIRF) += gnss_sirf.o \ No newline at end of file diff --git a/drivers/gnsssirf/gnss_sirf.c b/drivers/gnsssirf/gnss_sirf.c new file mode 100644 index 0000000000000000000000000000000000000000..5281cecb6f15073d15d72feba2df452a8d55450a --- /dev/null +++ b/drivers/gnsssirf/gnss_sirf.c @@ -0,0 +1,267 @@ +/* + * + * SiRF GNSS Driver + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "gnss_sirf.h" + + +static int resetPin; +static int onOffPin; + +static dev_t gnssDev; +static struct cdev c_dev; +static struct class *devClass; + +static int gnss_sirf_driver_open(struct inode *inode, struct file *filp); +static ssize_t gnss_sirf_driver_read(struct file *filp, char *buf, + size_t count, loff_t *f_pos); +static ssize_t gnss_sirf_driver_write(struct file *filp, const char *buf, + size_t count, loff_t *f_pos); +static int gnss_sirf_driver_release(struct inode *inode, struct file *filp); +static long gnss_sirf_driver_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + +static int gnss_sirf_probe(struct platform_device *pdev); +static int gnss_sirf_remove(struct platform_device *pdev); + + +static const struct of_device_id gnss_sirf_match_table[] = { + { .compatible = "gnss_sirf" }, + { } +}; + +static const struct file_operations gnss_sirf_fops = { + .open = gnss_sirf_driver_open, + .read = gnss_sirf_driver_read, + .write = gnss_sirf_driver_write, + .release = gnss_sirf_driver_release, + .unlocked_ioctl = gnss_sirf_driver_ioctl, + .owner = THIS_MODULE +}; + +static struct platform_driver gnss_sirf_drv = { + .driver = { + .name = "gnss_sirf", + .of_match_table = gnss_sirf_match_table, + .owner = THIS_MODULE, + }, + .probe = gnss_sirf_probe, + .remove = gnss_sirf_remove, +}; + +static int gnss_sirf_driver_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t gnss_sirf_driver_read(struct file *filp, + char *buf, + size_t count, + loff_t *f_pos) +{ + return 0; +} + +static ssize_t gnss_sirf_driver_write(struct file *filp, + const char *buf, + size_t count, + loff_t *f_pos) +{ + return count; +} + +static int gnss_sirf_driver_release(struct inode *inode, + struct file *filp) +{ + return 0; +} + +static long gnss_sirf_driver_ioctl(struct file *file, + unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case IO_CONTROL_SIRF_RESET_CLEAR: + gpio_direction_output(resetPin, 0); + break; + case IO_CONTROL_SIRF_RESET_SET: + gpio_direction_output(resetPin, 1); + break; + case IO_CONTROL_SIRF_ON_OFF_CLEAR: + gpio_direction_output(onOffPin, 0); + break; + case IO_CONTROL_SIRF_ON_OFF_SET: + gpio_direction_output(onOffPin, 1); + break; + default: + break; + } + return 0; +} + + +static int gnss_sirf_init_ports(void) +{ + gpio_direction_output(resetPin, 1); + gpio_direction_output(onOffPin, 1); + return 0; +} + +static int gnss_sirf_deInit_sirf_ports(void) +{ + gpio_direction_output(resetPin, 0); + gpio_direction_output(onOffPin, 0); + return 0; +} + + +static int gnss_sirf_cteate_device(void) +{ + if (alloc_chrdev_region(&gnssDev, 0, 1, "gnss_sirf") < 0) + return -ENODEV; + devClass = class_create(THIS_MODULE, "gnssdevClass"); + if (devClass == NULL) { + unregister_chrdev_region(gnssDev, 1); + return -ENODEV; + } + if (device_create(devClass, NULL, gnssDev, NULL, "gnss_sirf") == NULL) { + class_destroy(devClass); + unregister_chrdev_region(gnssDev, 1); + return -ENODEV; + } + cdev_init(&c_dev, &gnss_sirf_fops); + if (cdev_add(&c_dev, gnssDev, 1) == -1) { + device_destroy(devClass, gnssDev); + class_destroy(devClass); + unregister_chrdev_region(gnssDev, 1); + return -ENODEV; + } + return 0; +} + +static int gnss_sirf_delete_device(void) +{ + /* Remove Char device */ + cdev_del(&c_dev); + device_destroy(devClass, gnssDev); + class_destroy(devClass); + unregister_chrdev_region(gnssDev, 1); + return 0; +} + +static int gnss_sirf_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct device *dev; + + dev = &pdev->dev; + dev_info(dev, "%s", __func__); + if (pdev != NULL) { + if (pdev->name) { + resetPin = of_get_named_gpio(pdev->dev.of_node, + "ssVreset-gpio", 0); + onOffPin = of_get_named_gpio(pdev->dev.of_node, + "ssVonoff-gpio", 0); + if (gpio_is_valid(resetPin)) { + ret = gpio_request(resetPin, "ssVreset-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + resetPin, ret); + return ret; + } + } + if (gpio_is_valid(onOffPin)) { + ret = gpio_request(onOffPin, "ssVonoff-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + onOffPin, ret); + return ret; + } + } + gpio_direction_output(resetPin, 1); + gpio_direction_output(onOffPin, 1); + if (gnss_sirf_init_ports() < 0) + pr_err("gnss_sirf_init_ports failed\n"); + else + ret = 0; + } + } + return ret; +} + + +static int gnss_sirf_remove(struct platform_device *pdev) +{ + gnss_sirf_delete_device(); + + if (gnss_sirf_deInit_sirf_ports() < 0) { + pr_err("gnss_sirf_deInit_sirf_ports failed\n"); + return -ENODEV; + } + return 0; +} + + +static int __init gnss_sirf_init(void) +{ + int retVal; + + retVal = platform_driver_register(&gnss_sirf_drv); + if (retVal) { + pr_err("GNSS platform driver registation Failed !!!!\n"); + return retVal; + } + + retVal = gnss_sirf_cteate_device(); + return retVal; +} + + +static void __exit gnss_sirf_exit(void) +{ + platform_driver_unregister(&gnss_sirf_drv); +} + + +module_init(gnss_sirf_init); +module_exit(gnss_sirf_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SIRF GNSS reciver control driver"); diff --git a/drivers/gnsssirf/gnss_sirf.h b/drivers/gnsssirf/gnss_sirf.h new file mode 100644 index 0000000000000000000000000000000000000000..ad87709f65d2e06bd9a5207715971370ebefbe6f --- /dev/null +++ b/drivers/gnsssirf/gnss_sirf.h @@ -0,0 +1,31 @@ +/* + * + * SiRF GNSS Driver + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 _GNSS_SIRF_H_ +#define _GNSS_SIRF_H_ + +#include + + +/* IO Control used to interface with SiRF GNSS receiver */ +#define IO_CONTROL_SIRF_MAGIC_CODE 'Q' +#define IO_CONTROL_SIRF_RESET_CLEAR _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 0, int) +#define IO_CONTROL_SIRF_RESET_SET _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 1, int) +#define IO_CONTROL_SIRF_ON_OFF_CLEAR _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 2, int) +#define IO_CONTROL_SIRF_ON_OFF_SET _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 3, int) + +#endif //_GNSS_SIRF_H_ diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index f03fe916eb9d0c38c575d31ab5e96ec88620106f..f6d1bda8a80255890e7a2c817a359e43fb47f6c3 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -861,6 +861,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->offset_timer = devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL); + if (!gpio->offset_timer) + return -ENOMEM; return aspeed_gpio_setup_irqs(gpio, pdev); } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 2943dfc4c470742511c190dedce079a10066ce94..822ad220f0af9476157d5a4e5bed5670eff5b989 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -776,6 +776,9 @@ static int pxa_gpio_suspend(void) struct pxa_gpio_bank *c; int gpio; + if (!pchip) + return 0; + for_each_gpio_bank(gpio, c, pchip) { c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); @@ -794,6 +797,9 @@ static void pxa_gpio_resume(void) struct pxa_gpio_bank *c; int gpio; + if (!pchip) + return; + for_each_gpio_bank(gpio, c, pchip) { /* restore level with set/clear */ writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index ee8c046cab62ede7ab7c0b70d5a87285a5c6a79a..d6ed4e891b3483e2b14122aa73d11104b5140123 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -499,7 +499,13 @@ int of_gpiochip_add(struct gpio_chip *chip) of_node_get(chip->of_node); - return of_gpiochip_scan_gpios(chip); + status = of_gpiochip_scan_gpios(chip); + if (status) { + of_node_put(chip->of_node); + gpiochip_remove_pin_ranges(chip); + } + + return status; } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 164fa4b1f9a9d7c4305cb69320fe20d4ca858d15..732b8fbbca68946b694a9ffbce988643df538508 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -285,57 +285,7 @@ static int init_mqd_hiq(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) { - uint64_t addr; - struct cik_mqd *m; - int retval; - - retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd), - mqd_mem_obj); - - if (retval != 0) - return -ENOMEM; - - m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr; - addr = (*mqd_mem_obj)->gpu_addr; - - memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256)); - - m->header = 0xC0310800; - m->compute_pipelinestat_enable = 1; - m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; - - m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE | - PRELOAD_REQ; - m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS | - QUANTUM_DURATION(10); - - m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN; - m->cp_mqd_base_addr_lo = lower_32_bits(addr); - m->cp_mqd_base_addr_hi = upper_32_bits(addr); - - m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE; - - /* - * Pipe Priority - * Identifies the pipe relative priority when this queue is connected - * to the pipeline. The pipe priority is against the GFX pipe and HP3D. - * In KFD we are using a fixed pipe priority set to CS_MEDIUM. - * 0 = CS_LOW (typically below GFX) - * 1 = CS_MEDIUM (typically between HP3D and GFX - * 2 = CS_HIGH (typically above HP3D) - */ - m->cp_hqd_pipe_priority = 1; - m->cp_hqd_queue_priority = 15; - - *mqd = m; - if (gart_addr) - *gart_addr = addr; - retval = mm->update_mqd(mm, m, q); - - return retval; + return init_mqd(mm, mqd, mqd_mem_obj, gart_addr, q); } static int update_mqd_hiq(struct mqd_manager *mm, void *mqd, diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index dadacbe558abedc75fa5d847e3a451841c02ec19..1a1f7eb46d1eaa287ae8b699259438f9f914bdf2 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1629,7 +1629,7 @@ void intel_vgpu_unpin_mm(struct intel_vgpu_mm *mm) if (WARN_ON(mm->type != INTEL_GVT_MM_PPGTT)) return; - atomic_dec(&mm->pincount); + atomic_dec_if_positive(&mm->pincount); } /** diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 14eb8a0645622d98b5319ee6b16d534bde718526..da2d309574ba94de2e6351afd1c52e0a06e0ba80 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -326,8 +326,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, bool *enabled, int width, int height) { struct drm_i915_private *dev_priv = to_i915(fb_helper->dev); + unsigned long conn_configured, conn_seq, mask; unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG); - unsigned long conn_configured, conn_seq; int i, j; bool *save_enabled; bool fallback = true, ret = true; @@ -345,9 +345,10 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, drm_modeset_backoff(&ctx); memcpy(save_enabled, enabled, count); - conn_seq = GENMASK(count - 1, 0); + mask = GENMASK(count - 1, 0); conn_configured = 0; retry: + conn_seq = conn_configured; for (i = 0; i < count; i++) { struct drm_fb_helper_connector *fb_conn; struct drm_connector *connector; @@ -360,8 +361,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, if (conn_configured & BIT(i)) continue; - /* First pass, only consider tiled connectors */ - if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile) + if (conn_seq == 0 && !connector->has_tile) continue; if (connector->status == connector_status_connected) @@ -465,10 +465,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, conn_configured |= BIT(i); } - if (conn_configured != conn_seq) { /* repeat until no more are found */ - conn_seq = conn_configured; + if ((conn_configured & mask) != mask && conn_configured != conn_seq) goto retry; - } /* * If the BIOS didn't enable everything it could, fall back to have the diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 5deb44ac67915dc9d410b21823d78aa3d5be9d56..0608243c33874c77408dc05685decd847f98a5e8 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -277,10 +277,12 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) ret = drm_dev_register(drm, 0); if (ret) - goto free_drm; + goto uninstall_irq; return 0; +uninstall_irq: + drm_irq_uninstall(drm); free_drm: drm_dev_unref(drm); @@ -294,10 +296,11 @@ static int meson_drv_bind(struct device *dev) static void meson_drv_unbind(struct device *dev) { - struct drm_device *drm = dev_get_drvdata(dev); - struct meson_drm *priv = drm->dev_private; + struct meson_drm *priv = dev_get_drvdata(dev); + struct drm_device *drm = priv->drm; drm_dev_unregister(drm); + drm_irq_uninstall(drm); drm_kms_helper_poll_fini(drm); drm_fbdev_cma_fini(priv->fbdev); drm_mode_config_cleanup(drm); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h index 95cb9776cf096c428956cf49e9662b79fcbfe5d2..213142263d58958e60a95840c947e2e11071901f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h @@ -18,6 +18,9 @@ #include #include "msm_drv.h" +#define MAX_EXT_BRIDGE_PORT_CONFIG 16 +#define MAX_DSI_CTRLS_PER_DISPLAY 2 + #define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \ ((t)->h_sync_width) + ((t)->h_front_porch)) @@ -452,7 +455,9 @@ struct dsi_split_link_config { * @ignore_rx_eot: Ignore Rx EOT packets if set to true. * @append_tx_eot: Append EOT packets for forward transmissions if set to * true. - * @ext_bridge_mode: External bridge is connected. + * @ext_bridge_num: Connected external bridge count. + * @ext_bridge_map: External bridge config reg needs to match with the port + * reg config. * @force_hs_clk_lane: Send continuous clock to the panel. * @dsi_split_link_config: Split Link Configuration. */ @@ -473,7 +478,8 @@ struct dsi_host_common_cfg { u32 t_clk_pre; bool ignore_rx_eot; bool append_tx_eot; - bool ext_bridge_mode; + u32 ext_bridge_num; + u32 ext_bridge_map[MAX_DSI_CTRLS_PER_DISPLAY]; bool force_hs_clk_lane; struct dsi_split_link_config split_link; }; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index c965a3c545bff8b8e3adaa8e7effd90f423c7ff5..a4c4e957f10b847e6c8dee035949fea38b523c9b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -3606,13 +3606,11 @@ static int dsi_display_parse_dt(struct dsi_display *display) /* Parse TE data */ dsi_display_parse_te_data(display); - /* Parse all external bridges from port 0 */ - display_for_each_ctrl(i, display) { + /* Parse all external bridges config, endpoint0 */ + for (i = 0; i < MAX_EXT_BRIDGE_PORT_CONFIG; i++) { display->ext_bridge[i].node_of = of_graph_get_remote_node(of_node, 0, i); - if (display->ext_bridge[i].node_of) - display->ext_bridge_cnt++; - else + if (!display->ext_bridge[i].node_of) break; } @@ -4898,7 +4896,7 @@ static int dsi_display_bind(struct device *dev, char *client1 = "dsi_clk_client"; char *client2 = "mdp_event_client"; char dsi_client_name[DSI_CLIENT_NAME_SIZE]; - int i, rc = 0; + int i, j, rc = 0; if (!dev || !pdev || !master) { pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n", @@ -4919,14 +4917,17 @@ static int dsi_display_bind(struct device *dev, return 0; /* defer bind if ext bridge driver is not loaded */ - if (display->panel && display->panel->host_config.ext_bridge_mode) { - for (i = 0; i < display->ext_bridge_cnt; i++) { - if (!of_drm_find_bridge( - display->ext_bridge[i].node_of)) { - pr_debug("defer for bridge[%d] %s\n", i, - display->ext_bridge[i].node_of->full_name); - return -EPROBE_DEFER; - } + for (i = 0; i < display->panel->host_config.ext_bridge_num; i++) { + j = display->panel->host_config.ext_bridge_map[i]; + if (!display->ext_bridge[j].node_of) { + pr_err("invalid ext bridge node\n"); + return -EINVAL; + } + + if (!of_drm_find_bridge(display->ext_bridge[j].node_of)) { + pr_debug("defer for bridge[%d] %s\n", j, + display->ext_bridge[j].node_of->full_name); + return -EPROBE_DEFER; } } @@ -5585,11 +5586,9 @@ static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge( { struct msm_drm_private *priv; struct sde_kms *sde_kms; - struct list_head *connector_list; - struct drm_connector *conn_iter; - struct sde_connector *sde_conn; struct dsi_display *display; - int i; + int i, j, k; + u32 bridge_num; if (!bridge || !bridge->encoder) { SDE_ERROR("invalid argument\n"); @@ -5598,16 +5597,14 @@ static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge( priv = bridge->dev->dev_private; sde_kms = to_sde_kms(priv->kms); - connector_list = &sde_kms->dev->mode_config.connector_list; - - list_for_each_entry(conn_iter, connector_list, head) { - sde_conn = to_sde_connector(conn_iter); - if (sde_conn->encoder == bridge->encoder) { - display = sde_conn->display; - display_for_each_ctrl(i, display) { - if (display->ext_bridge[i].bridge == bridge) - return &display->ext_bridge[i]; - } + + for (i = 0; i < sde_kms->dsi_display_count; i++) { + display = sde_kms->dsi_displays[i]; + bridge_num = display->panel->host_config.ext_bridge_num; + for (j = 0; j < bridge_num; j++) { + k = display->panel->host_config.ext_bridge_map[j]; + if (display->ext_bridge[k].bridge == bridge) + return &display->ext_bridge[k]; } } @@ -5771,12 +5768,10 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, struct drm_bridge *prev_bridge = bridge; int rc = 0, i; - if (display->panel && !display->panel->host_config.ext_bridge_mode) - return 0; - - for (i = 0; i < display->ext_bridge_cnt; i++) { + for (i = 0; i < display->panel->host_config.ext_bridge_num; i++) { + int j = display->panel->host_config.ext_bridge_map[i]; struct dsi_display_ext_bridge *ext_bridge_info = - &display->ext_bridge[i]; + &display->ext_bridge[j]; /* return if ext bridge is already initialized */ if (ext_bridge_info->bridge) @@ -5790,7 +5785,7 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, } /* override functions for mode adjustment */ - if (display->ext_bridge_cnt > 1) { + if (display->panel->host_config.ext_bridge_num > 1) { ext_bridge_info->bridge_funcs = *ext_bridge->funcs; if (ext_bridge->funcs->mode_fixup) ext_bridge_info->bridge_funcs.mode_fixup = @@ -5835,7 +5830,7 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, if (!display->ext_conn || !display->ext_conn->funcs || !display->ext_conn->helper_private || - display->ext_bridge_cnt > 1) { + display->panel->host_config.ext_bridge_num > 1) { display->ext_conn = NULL; continue; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index 1eef2fa5aa030804e6ef55c7f93b9d3b37e9e8cc..4cf3cebb7d02e404cd6b8e433b663c1501f93e8c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -29,7 +29,6 @@ #include "dsi_phy.h" #include "dsi_panel.h" -#define MAX_DSI_CTRLS_PER_DISPLAY 2 #define DSI_CLIENT_NAME_SIZE 20 #define MAX_CMDLINE_PARAM_LEN 512 #define MAX_CMD_PAYLOAD_SIZE 256 @@ -160,7 +159,6 @@ struct dsi_display_ext_bridge { * @panel: Handle to DSI panel. * @panel_of: pHandle to DSI panel. * @ext_bridge: External bridge information for DSI display. - * @ext_bridge_cnt: Number of external bridges * @modes: Array of probed DSI modes * @type: DSI display type. * @clk_master_idx: The master controller for controlling clocks. This is an @@ -216,8 +214,7 @@ struct dsi_display { struct device_node *parser_node; /* external bridge */ - struct dsi_display_ext_bridge ext_bridge[MAX_DSI_CTRLS_PER_DISPLAY]; - u32 ext_bridge_cnt; + struct dsi_display_ext_bridge ext_bridge[MAX_EXT_BRIDGE_PORT_CONFIG]; struct dsi_display_mode *modes; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 9097044ac4d83af3f04082135e1700b7adb3cc5f..de28a2e8964dc1700c987e1e9a14d1d2e23a3970 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -414,7 +414,7 @@ static int dsi_panel_set_pinctrl_state(struct dsi_panel *panel, bool enable) int rc = 0; struct pinctrl_state *state; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; if (enable) @@ -548,7 +548,7 @@ static int dsi_panel_pinctrl_deinit(struct dsi_panel *panel) { int rc = 0; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; devm_pinctrl_put(panel->pinctrl.pinctrl); @@ -560,7 +560,7 @@ static int dsi_panel_pinctrl_init(struct dsi_panel *panel) { int rc = 0; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; /* TODO: pinctrl is defined in dsi dt node */ @@ -683,7 +683,7 @@ int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl) int rc = 0; struct dsi_backlight_config *bl = &panel->bl_config; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl); @@ -764,7 +764,7 @@ static int dsi_panel_bl_register(struct dsi_panel *panel) int rc = 0; struct dsi_backlight_config *bl = &panel->bl_config; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; switch (bl->type) { @@ -800,7 +800,7 @@ static int dsi_panel_bl_unregister(struct dsi_panel *panel) int rc = 0; struct dsi_backlight_config *bl = &panel->bl_config; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; switch (bl->type) { @@ -1134,6 +1134,51 @@ static int dsi_panel_parse_triggers(struct dsi_host_common_cfg *host, return rc; } +static int dsi_panel_parse_ext_bridge_config(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + u32 len = 0, i = 0; + int rc = 0; + + host->ext_bridge_num = 0; + + len = utils->count_u32_elems(utils->data, "qcom,mdss-dsi-ext-bridge"); + + if (len > MAX_DSI_CTRLS_PER_DISPLAY) { + pr_debug("[%s] Invalid ext bridge count set\n", name); + return -EINVAL; + } + + if (len == 0) { + pr_debug("[%s] It's a DSI panel, not bridge\n", name); + return rc; + } + + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-ext-bridge", + host->ext_bridge_map, + len); + + if (rc) { + pr_debug("[%s] Did not get ext bridge set\n", name); + return rc; + } + + for (i = 0; i < len; i++) { + if (host->ext_bridge_map[i] >= MAX_EXT_BRIDGE_PORT_CONFIG) { + pr_debug("[%s] Invalid bridge port value %d\n", + name, host->ext_bridge_map[i]); + return -EINVAL; + } + } + + host->ext_bridge_num = len; + + pr_debug("[%s] ext bridge count is %d\n", name, host->ext_bridge_num); + + return rc; +} + static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, struct dsi_parser_utils *utils, const char *name) @@ -1160,9 +1205,6 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, host->append_tx_eot = utils->read_bool(utils->data, "qcom,mdss-dsi-tx-eot-append"); - host->ext_bridge_mode = utils->read_bool(utils->data, - "qcom,mdss-dsi-ext-bridge-mode"); - host->force_hs_clk_lane = utils->read_bool(utils->data, "qcom,mdss-dsi-force-clock-lane-hs"); return 0; @@ -1251,6 +1293,13 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel) goto error; } + dsi_panel_parse_ext_bridge_config(&panel->host_config, utils, + panel->name); + if (rc) { + pr_err("[%s] failed to parse ext bridge config, rc=%d\n", + panel->name, rc); + } + dsi_panel_parse_split_link_config(&panel->host_config, utils, panel->name); @@ -1893,7 +1942,7 @@ static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel) struct dsi_parser_utils *utils = &panel->utils; struct dsi_reset_seq *seq; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; arr = utils->get_property(utils->data, @@ -2030,7 +2079,7 @@ static int dsi_panel_parse_power_cfg(struct dsi_panel *panel) int rc = 0; char *supply_name; - if (panel->host_config.ext_bridge_mode) + if (panel->host_config.ext_bridge_num) return 0; if (!strcmp(panel->type, "primary")) @@ -2067,7 +2116,7 @@ static int dsi_panel_parse_gpios(struct dsi_panel *panel) panel->reset_config.reset_gpio = utils->get_named_gpio(utils->data, reset_gpio_name, 0); if (!gpio_is_valid(panel->reset_config.reset_gpio) && - !panel->host_config.ext_bridge_mode) { + !panel->host_config.ext_bridge_num) { rc = panel->reset_config.reset_gpio; pr_err("[%s] failed get reset gpio, rc=%d\n", panel->name, rc); goto error; @@ -3392,14 +3441,14 @@ int dsi_panel_get_mode_count(struct dsi_panel *panel) timings_np = utils->get_child_by_name(utils->data, "qcom,mdss-dsi-display-timings"); - if (!timings_np && !panel->host_config.ext_bridge_mode) { + if (!timings_np && !panel->host_config.ext_bridge_num) { pr_err("no display timing nodes defined\n"); rc = -EINVAL; goto error; } count = utils->get_child_count(timings_np); - if ((!count && !panel->host_config.ext_bridge_mode) || + if ((!count && !panel->host_config.ext_bridge_num) || count > DSI_MODE_MAX) { pr_err("invalid count of timing nodes: %d\n", count); rc = -EINVAL; @@ -3408,7 +3457,7 @@ int dsi_panel_get_mode_count(struct dsi_panel *panel) /* No multiresolution support is available for video mode panels */ if (panel->panel_mode != DSI_OP_CMD_MODE && - !panel->host_config.ext_bridge_mode) + !panel->host_config.ext_bridge_num) count = SINGLE_MODE_SUPPORT; panel->num_timing_nodes = count; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index 8a0f85f5fc1a86b4e47b4e06411c80a89c891bc1..6a765682fbfa2a61d252fcd880978745b922322c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -38,6 +38,7 @@ int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp, int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **); int gf100_volt_new(struct nvkm_device *, int, struct nvkm_volt **); +int gf117_volt_new(struct nvkm_device *, int, struct nvkm_volt **); int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **); int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **); int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **); diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 9109b69cd052958bbc126b4bad4f490720e11f4a..9635704a1d8647b116bb1c42b65bf536f39f4905 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -161,7 +161,7 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf, } ret = pm_runtime_get_sync(drm->dev); - if (IS_ERR_VALUE(ret) && ret != -EACCES) + if (ret < 0 && ret != -EACCES) return ret; ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args)); pm_runtime_put_autosuspend(drm->dev); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e096a5d9c292f60377d8b072d0d741e975dc2297..f8dd78e2145619617b9ef3b5e6b064aa478af834 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1612,7 +1612,7 @@ nvd7_chipset = { .pci = gf106_pci_new, .therm = gf119_therm_new, .timer = nv41_timer_new, - .volt = gf100_volt_new, + .volt = gf117_volt_new, .ce[0] = gf100_ce_new, .disp = gf119_disp_new, .dma = gf119_dma_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild index bcd179ba11d0d2cd11fa40ef1c7559843a8a1881..146adcdd316a40fc6265aa572fddeb73425e7ac9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild @@ -2,6 +2,7 @@ nvkm-y += nvkm/subdev/volt/base.o nvkm-y += nvkm/subdev/volt/gpio.o nvkm-y += nvkm/subdev/volt/nv40.o nvkm-y += nvkm/subdev/volt/gf100.o +nvkm-y += nvkm/subdev/volt/gf117.o nvkm-y += nvkm/subdev/volt/gk104.o nvkm-y += nvkm/subdev/volt/gk20a.o nvkm-y += nvkm/subdev/volt/gm20b.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c new file mode 100644 index 0000000000000000000000000000000000000000..547a58f0aeac326b3b7685d5a04fa1956e77b1c6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c @@ -0,0 +1,60 @@ +/* + * Copyright 2019 Ilia Mirkin + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ilia Mirkin + */ +#include "priv.h" + +#include + +static int +gf117_volt_speedo_read(struct nvkm_volt *volt) +{ + struct nvkm_device *device = volt->subdev.device; + struct nvkm_fuse *fuse = device->fuse; + + if (!fuse) + return -EINVAL; + + return nvkm_fuse_read(fuse, 0x3a8); +} + +static const struct nvkm_volt_func +gf117_volt = { + .oneinit = gf100_volt_oneinit, + .vid_get = nvkm_voltgpio_get, + .vid_set = nvkm_voltgpio_set, + .speedo_read = gf117_volt_speedo_read, +}; + +int +gf117_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) +{ + struct nvkm_volt *volt; + int ret; + + ret = nvkm_volt_new_(&gf117_volt, device, index, &volt); + *pvolt = volt; + if (ret) + return ret; + + return nvkm_voltgpio_init(volt); +} diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba93449fcfbd5c74a25949880e5bc82d80ff10a..58b67e0cc3859b9ceebe6a140ee824c50265f19f 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -40,7 +40,6 @@ static inline struct innolux_panel *to_innolux_panel(struct drm_panel *panel) static int innolux_panel_disable(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err; if (!innolux->enabled) return 0; @@ -48,11 +47,6 @@ static int innolux_panel_disable(struct drm_panel *panel) innolux->backlight->props.power = FB_BLANK_POWERDOWN; backlight_update_status(innolux->backlight); - err = mipi_dsi_dcs_set_display_off(innolux->link); - if (err < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - err); - innolux->enabled = false; return 0; @@ -66,6 +60,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel) if (!innolux->prepared) return 0; + err = mipi_dsi_dcs_set_display_off(innolux->link); + if (err < 0) + DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", + err); + err = mipi_dsi_dcs_enter_sleep_mode(innolux->link); if (err < 0) { DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 31421b6b586e76f07b2721b5dfd23c0862cdb4fa..b45ac6bc8addbe9538fece0b44d7dd5a2311e7f3 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -47,6 +47,7 @@ static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = udl_driver_load, .unload = udl_driver_unload, + .release = udl_driver_release, /* gem hooks */ .gem_free_object = udl_gem_free_object, diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 2c149b841cf1edcc4e86032a73753ffefad53d25..307455dd65263b311f79dae1f15ec706436df671 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -101,6 +101,7 @@ void udl_urb_completion(struct urb *urb); int udl_driver_load(struct drm_device *dev, unsigned long flags); void udl_driver_unload(struct drm_device *dev); +void udl_driver_release(struct drm_device *dev); int udl_fbdev_init(struct drm_device *dev); void udl_fbdev_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index f8ea3c99b523234273f705a3884a383df0949ae1..60866b422f81d2d9ae82cac37c60fba24ec6d758 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -378,6 +378,12 @@ void udl_driver_unload(struct drm_device *dev) udl_free_urb_list(dev); udl_fbdev_cleanup(dev); - udl_modeset_cleanup(dev); kfree(udl); } + +void udl_driver_release(struct drm_device *dev) +{ + udl_modeset_cleanup(dev); + drm_dev_fini(dev); + kfree(dev); +} diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index ce1e3b9e14c9ac2e676ad760f653fd6d7091f964..7747f160c740a1586764682395cb32b7d00e8c62 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -867,7 +867,7 @@ static void vc4_crtc_reset(struct drm_crtc *crtc) { if (crtc->state) - __drm_atomic_helper_crtc_destroy_state(crtc->state); + vc4_crtc_destroy_state(crtc, crtc->state); crtc->state = kzalloc(sizeof(struct vc4_crtc_state), GFP_KERNEL); if (crtc->state) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 63c6b515470677ac3ccd25a73959b35dcc84059f..be83edf8f1479e1cb0363f3137fabe19093f3338 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -834,7 +834,10 @@ adreno_identify_gpu(struct adreno_device *adreno_dev) */ adreno_dev->gmem_size = adreno_dev->gpucore->gmem_size; - adreno_dev->uche_gmem_base = ALIGN(adreno_dev->gmem_size, SZ_4K); + + /* UCHE to GMEM base address requires 1MB alignment */ + adreno_dev->uche_gmem_base = ALIGN(adreno_dev->gmem_size, SZ_1M); + /* * Initialize uninitialzed gpu registers, only needs to be done once * Make all offsets that are not initialized to ADRENO_REG_UNUSED @@ -1379,6 +1382,13 @@ static int adreno_probe(struct platform_device *pdev) /* Default to 4K alignment (in other words, no additional padding) */ device->mmu.va_padding = PAGE_SIZE; + /* + * SVM start va can be calculated based on UCHE GMEM size. + * UCHE_GMEM_MAX < (SP LOCAL & PRIVATE) < MMU SVA + */ + device->mmu.svm_base32 = KGSL_IOMMU_SVM_BASE32 + + ((ALIGN(adreno_dev->gmem_size, SZ_1M) - SZ_1M) << 1); + if (adreno_dev->gpucore->va_padding) { device->mmu.features |= KGSL_MMU_PAD_VA; device->mmu.va_padding = adreno_dev->gpucore->va_padding; @@ -1751,19 +1761,6 @@ static int adreno_init(struct kgsl_device *device) } - if (nopreempt == false && - ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) { - int r = 0; - - if (gpudev->preemption_init) - r = gpudev->preemption_init(adreno_dev); - - if (r == 0) - set_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); - else - WARN(1, "adreno: GPU preemption is disabled\n"); - } - return 0; } @@ -1944,6 +1941,17 @@ static int _adreno_start(struct adreno_device *adreno_dev) if (regulator_left_on) _soft_reset(adreno_dev); + /* + * During adreno_stop, GBIF halt is asserted to ensure + * no further transaction can go through GPU before GPU + * headswitch is turned off. + * + * This halt is deasserted once headswitch goes off but + * incase headswitch doesn't goes off clear GBIF halt + * here to ensure GPU wake-up doesn't fail because of + * halted GPU transactions. + */ + adreno_deassert_gbif_halt(adreno_dev); if (adreno_is_a640v1(adreno_dev)) { ret = adreno_program_smmu_aperture(device); @@ -2302,8 +2310,15 @@ static int adreno_stop(struct kgsl_device *device) adreno_clear_pending_transactions(device); - /* The halt is not cleared in the above function if we have GBIF */ - adreno_deassert_gbif_halt(adreno_dev); + /* + * The halt is not cleared in the above function if we have GBIF. + * Clear it here if GMU is enabled as GMU stop needs access to + * system memory to stop. For non-GMU targets, we don't need to + * clear it as it will get cleared automatically once headswitch + * goes OFF immediately after adreno_stop. + */ + if (gmu_core_gpmu_isenabled(device)) + adreno_deassert_gbif_halt(adreno_dev); kgsl_mmu_stop(&device->mmu); @@ -3961,6 +3976,9 @@ static void adreno_iommu_sync(struct kgsl_device *device, bool sync) struct scm_desc desc = {0}; int ret; + if (!ADRENO_QUIRK(ADRENO_DEVICE(device), ADRENO_QUIRK_IOMMU_SYNC)) + return; + if (sync == true) { mutex_lock(&kgsl_mmu_sync); desc.args[0] = true; @@ -3977,25 +3995,29 @@ static void adreno_iommu_sync(struct kgsl_device *device, bool sync) } } -static void _regulator_disable(struct kgsl_regulator *regulator, bool poll) +static void +_regulator_disable(struct kgsl_regulator *regulator, unsigned int timeout) { - unsigned long wait_time = jiffies + msecs_to_jiffies(200); + unsigned long wait_time; if (IS_ERR_OR_NULL(regulator->reg)) return; regulator_disable(regulator->reg); - if (poll == false) - return; + wait_time = jiffies + msecs_to_jiffies(timeout); + /* Poll for regulator status to ensure it's OFF */ while (!time_after(jiffies, wait_time)) { if (!regulator_is_enabled(regulator->reg)) return; - cpu_relax(); + usleep_range(10, 100); } - KGSL_CORE_ERR("regulator '%s' still on after 200ms\n", regulator->name); + if (!regulator_is_enabled(regulator->reg)) + return; + + KGSL_CORE_ERR("regulator '%s' disable timed out\n", regulator->name); } static void adreno_regulator_disable_poll(struct kgsl_device *device) @@ -4003,18 +4025,13 @@ static void adreno_regulator_disable_poll(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; int i; - - /* Fast path - hopefully we don't need this quirk */ - if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_IOMMU_SYNC)) { - for (i = KGSL_MAX_REGULATORS - 1; i >= 0; i--) - _regulator_disable(&pwr->regulators[i], false); - return; - } + unsigned int timeout = + ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_IOMMU_SYNC) ? 200 : 5000; adreno_iommu_sync(device, true); - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - _regulator_disable(&pwr->regulators[i], true); + for (i = KGSL_MAX_REGULATORS - 1; i >= 0; i--) + _regulator_disable(&pwr->regulators[i], timeout); adreno_iommu_sync(device, false); } @@ -4046,12 +4063,6 @@ static int adreno_suspend_device(struct kgsl_device *device, if (gpudev->zap_shader_unload != NULL) gpudev->zap_shader_unload(adreno_dev); - if (gmu_core_isenabled(device)) { - clear_bit(GMU_BOOT_INIT_DONE, &device->gmu_core.flags); - clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, - &device->gmu_core.flags); - } - if (gpudev->secure_pt_hibernate != NULL) ret = gpudev->secure_pt_hibernate(adreno_dev); } @@ -4080,6 +4091,22 @@ static int adreno_resume_device(struct kgsl_device *device, if (ret) return ret; } + + if (gmu_core_isenabled(device)) { + if (!gmu_core_is_initialized(device)) { + clear_bit(GMU_BOOT_INIT_DONE, + &device->gmu_core.flags); + clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, + &device->gmu_core.flags); + } + } + + if (device->pwrscale.devfreqptr) { + ret = msm_adreno_devfreq_init_tz( + device->pwrscale.devfreqptr); + if (ret) + return ret; + } } if (device->state == KGSL_STATE_SUSPEND) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 5b1981e70fb5ecdc2c894db41336541c62610156..69f7235decbf373f49e83f3562e5ae97396ab8d6 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1013,6 +1013,7 @@ struct adreno_gpudev { struct adreno_device *adreno_dev, unsigned int *cmds); int (*preemption_init)(struct adreno_device *); + void (*preemption_close)(struct adreno_device *); void (*preemption_schedule)(struct adreno_device *); int (*preemption_context_init)(struct kgsl_context *); void (*preemption_context_destroy)(struct kgsl_context *); diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 100f34edf2696ce1013b835997a0557ff2806046..6570d84bfb8aea463c08829d0f4da2dd4a75aa33 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -3642,6 +3642,7 @@ struct adreno_gpudev adreno_a5xx_gpudev = { .preemption_post_ibsubmit = a5xx_preemption_post_ibsubmit, .preemption_init = a5xx_preemption_init, + .preemption_close = a5xx_preemption_close, .preemption_schedule = a5xx_preemption_schedule, .enable_64bit = a5xx_enable_64bit, .clk_set_options = a5xx_clk_set_options, diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h index 510eff2f94f2a439e958bbfe5c98f551bd53192b..08f56d6701f28ea0cb941e2a191b246303375f61 100644 --- a/drivers/gpu/msm/adreno_a5xx.h +++ b/drivers/gpu/msm/adreno_a5xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017,2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -226,6 +226,7 @@ void a5xx_preemption_trigger(struct adreno_device *adreno_dev); void a5xx_preemption_schedule(struct adreno_device *adreno_dev); void a5xx_preemption_start(struct adreno_device *adreno_dev); int a5xx_preemption_init(struct adreno_device *adreno_dev); +void a5xx_preemption_close(struct adreno_device *adreno_dev); int a5xx_preemption_yield_enable(unsigned int *cmds); unsigned int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index d5da56261d3947c94880b363d9f95bdaf16b9b61..cb7a65f92135255032029f41746ef080741bd63f 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017,2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -567,9 +567,9 @@ static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev) } #endif -static void a5xx_preemption_close(struct kgsl_device *device) +static void _preemption_close(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_preemption *preempt = &adreno_dev->preempt; struct adreno_ringbuffer *rb; unsigned int i; @@ -583,6 +583,15 @@ static void a5xx_preemption_close(struct kgsl_device *device) } } +void a5xx_preemption_close(struct adreno_device *adreno_dev) +{ + if (!test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv)) + return; + + _preemption_close(adreno_dev); +} + + int a5xx_preemption_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -624,7 +633,7 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) err: if (ret) - a5xx_preemption_close(device); + _preemption_close(adreno_dev); return ret; } diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 8cc7a45bb9e2bf4f1c17c391cbc941d0d00e8dfe..0724bda629e03c5bcf47267bbd26320638c05e3f 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -30,6 +30,7 @@ #include "kgsl.h" #include "kgsl_hfi.h" #include "kgsl_trace.h" +#include "kgsl_gmu.h" #define MIN_HBB 13 @@ -427,6 +428,7 @@ static struct reg_list_pair { /* IFPC only static powerup restore list */ static struct reg_list_pair a6xx_ifpc_pwrup_reglist[] = { { A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x0 }, + { A6XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x0 }, { A6XX_CP_CHICKEN_DBG, 0x0 }, { A6XX_CP_DBG_ECO_CNTL, 0x0 }, { A6XX_CP_PROTECT_CNTL, 0x0 }, @@ -1444,6 +1446,11 @@ static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev) int64_t adj = -1; uint32_t counts[ADRENO_GPMU_THROTTLE_COUNTERS]; struct adreno_busy_data *busy = &adreno_dev->busy_data; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + if (!gmu_core_isenabled(device)) + return 0; for (i = 0; i < ARRAY_SIZE(counts); i++) { if (!adreno_dev->gpmu_throttle_counters[i]) @@ -1457,12 +1464,18 @@ static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev) /* * The adjustment is the number of cycles lost to throttling, which * is calculated as a weighted average of the cycles throttled - * at 15%, 50%, and 90%. The adjustment is negative because in A6XX, + * at 5% or 15% based on GMU FW version, 50%, and 90%. + * The adjustment is negative because in A6XX, * the busy count includes the throttled cycles. Therefore, we want * to remove them to prevent appearing to be busier than * we actually are. */ - adj *= ((counts[0] * 15) + (counts[1] * 50) + (counts[2] * 90)) / 100; + if (GMU_VER_STEP(gmu->ver) > 0x104) + adj *= ((counts[0] * 5) + (counts[1] * 50) + (counts[2] * 90)) + / 100; + else + adj *= ((counts[0] * 15) + (counts[1] * 50) + (counts[2] * 90)) + / 100; trace_kgsl_clock_throttling(0, counts[1], counts[2], counts[0], adj); @@ -1627,7 +1640,7 @@ static void a6xx_llc_configure_gpu_scid(struct adreno_device *adreno_dev) | gpu_scid; if (adreno_is_a640(adreno_dev) || adreno_is_a612(adreno_dev) || - adreno_is_a610(adreno_dev)) { + adreno_is_a610(adreno_dev) || adreno_is_a680(adreno_dev)) { kgsl_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GBIF_SCACHE_CNTL1, A6XX_GPU_LLC_SCID_MASK, gpu_cntl1_val); } else { @@ -1650,7 +1663,7 @@ static void a6xx_llc_configure_gpuhtw_scid(struct adreno_device *adreno_dev) * XBL image. */ if (adreno_is_a640(adreno_dev) || adreno_is_a612(adreno_dev) || - adreno_is_a610(adreno_dev)) + adreno_is_a610(adreno_dev) || adreno_is_a680(adreno_dev)) return; gpuhtw_scid = adreno_llc_get_scid(adreno_dev->gpuhtw_llc_slice); @@ -1672,7 +1685,7 @@ static void a6xx_llc_enable_overrides(struct adreno_device *adreno_dev) * Attributes are used as configured through SMMU pagetable entries. */ if (adreno_is_a640(adreno_dev) || adreno_is_a612(adreno_dev) || - adreno_is_a610(adreno_dev)) + adreno_is_a610(adreno_dev) || adreno_is_a680(adreno_dev)) return; /* @@ -3328,6 +3341,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit, .preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit, .preemption_init = a6xx_preemption_init, + .preemption_close = a6xx_preemption_close, .preemption_schedule = a6xx_preemption_schedule, .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index f2869b6bc4fec134497e0f4b6d979f783b094882..bd1b916b638a3e284cb74f016094a46e4cdead5f 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -173,6 +173,7 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev); void a6xx_preemption_schedule(struct adreno_device *adreno_dev); void a6xx_preemption_start(struct adreno_device *adreno_dev); int a6xx_preemption_init(struct adreno_device *adreno_dev); +void a6xx_preemption_close(struct adreno_device *adreno_dev); unsigned int a6xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, unsigned int *cmds); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 28cf1812d2ac371ebf2fb45eebfc66b520b15021..3a9bd76c439567267e060064046ff7ff245033eb 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -71,6 +71,8 @@ static const unsigned int a6xx_gmu_registers[] = { #define RSC_CMD_OFFSET 2 #define PDC_CMD_OFFSET 4 +#define PDC_ENABLE_REG_VALUE 0x80000001 + static void _regwrite(void __iomem *regbase, unsigned int offsetwords, unsigned int value) { @@ -80,17 +82,11 @@ static void _regwrite(void __iomem *regbase, __raw_writel(value, reg); } -/* - * _load_gmu_rpmh_ucode() - Load the ucode into the GPU PDC/RSC blocks - * PDC and RSC execute GPU power on/off RPMh sequence - * @device: Pointer to KGSL device - */ -static int _load_gmu_rpmh_ucode(struct kgsl_device *device) +static int _map_pdc_iomem(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct resource *res_pdc, *res_cfg, *res_seq; - void __iomem *cfg = NULL, *seq = NULL; unsigned int cfg_offset, seq_offset; /* Offsets from the base PDC (if no PDC subsections in the DTSI) */ @@ -125,31 +121,59 @@ static int _load_gmu_rpmh_ucode(struct kgsl_device *device) * Map the starting address for pdc_cfg programming. If the pdc_cfg * resource is not available use an offset from the base PDC resource. */ - if (res_cfg) - cfg = ioremap(res_cfg->start, resource_size(res_cfg)); - else if (res_pdc) - cfg = ioremap(res_pdc->start + cfg_offset, 0x10000); - - if (!cfg) { - dev_err(&gmu->pdev->dev, "Failed to map PDC CFG\n"); - return -ENODEV; + if (gmu->pdc_cfg_base == NULL) { + if (res_cfg) + gmu->pdc_cfg_base = devm_ioremap(&gmu->pdev->dev, + res_cfg->start, resource_size(res_cfg)); + else if (res_pdc) + gmu->pdc_cfg_base = devm_ioremap(&gmu->pdev->dev, + res_pdc->start + cfg_offset, 0x10000); + + if (gmu->pdc_cfg_base == NULL) { + dev_err(&gmu->pdev->dev, "Failed to map PDC CFG\n"); + return -ENODEV; + } } /* * Map the starting address for pdc_seq programming. If the pdc_seq * resource is not available use an offset from the base PDC resource. */ - if (res_seq) - seq = ioremap(res_seq->start, resource_size(res_seq)); - else if (res_pdc) - seq = ioremap(res_pdc->start + seq_offset, 0x10000); - - if (!seq) { - dev_err(&gmu->pdev->dev, "Failed to map PDC SEQ\n"); - iounmap(cfg); - return -ENODEV; + if (gmu->pdc_seq_base == NULL) { + if (res_seq) + gmu->pdc_seq_base = devm_ioremap(&gmu->pdev->dev, + res_seq->start, resource_size(res_seq)); + else if (res_pdc) + gmu->pdc_seq_base = devm_ioremap(&gmu->pdev->dev, + res_pdc->start + seq_offset, 0x10000); + + if (gmu->pdc_seq_base == NULL) { + dev_err(&gmu->pdev->dev, "Failed to map PDC SEQ\n"); + return -ENODEV; + } } + return 0; +} + +/* + * _load_gmu_rpmh_ucode() - Load the ucode into the GPU PDC/RSC blocks + * PDC and RSC execute GPU power on/off RPMh sequence + * @device: Pointer to KGSL device + */ +static int _load_gmu_rpmh_ucode(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + void __iomem *cfg, *seq; + int ret = _map_pdc_iomem(device); + + if (ret) + return ret; + + cfg = gmu->pdc_cfg_base; + seq = gmu->pdc_seq_base; + /* Disable SDE clock gating */ gmu_core_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); @@ -238,14 +262,11 @@ static int _load_gmu_rpmh_ucode(struct kgsl_device *device) /* Setup GPU PDC */ _regwrite(cfg, PDC_GPU_SEQ_START_ADDR, 0); - _regwrite(cfg, PDC_GPU_ENABLE_PDC, 0x80000001); + _regwrite(cfg, PDC_GPU_ENABLE_PDC, PDC_ENABLE_REG_VALUE); /* ensure no writes happen before the uCode is fully written */ wmb(); - iounmap(seq); - iounmap(cfg); - return 0; } @@ -478,15 +499,12 @@ static int _load_legacy_gmu_fw(struct kgsl_device *device, struct gmu_device *gmu) { const struct firmware *fw = gmu->fw_image; - u32 *fwptr = (u32 *)fw->data; - int i; if (fw->size > MAX_GMUFW_SIZE) return -EINVAL; - for (i = 0; i < (fw->size >> 2); i++) - gmu_core_regwrite(device, - A6XX_GMU_CM3_ITCM_START + i, fwptr[i]); + gmu_core_blkwrite(device, A6XX_GMU_CM3_ITCM_START, fw->data, + fw->size); /* Proceed only after the FW is written */ wmb(); @@ -497,7 +515,6 @@ static int load_gmu_fw(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); uint8_t *fw = (uint8_t *)gmu->fw_image->data; - int j; int tcm_addr; struct gmu_block_header *blk; struct gmu_memdesc *md; @@ -523,8 +540,6 @@ static int load_gmu_fw(struct kgsl_device *device) } 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); @@ -533,9 +548,7 @@ static int load_gmu_fw(struct kgsl_device *device) else tcm_addr += A6XX_GMU_CM3_DTCM_START; - for (j = 0; j < blk->size / sizeof(uint32_t); j++) - gmu_core_regwrite(device, tcm_addr + j, - fwptr[j]); + gmu_core_blkwrite(device, tcm_addr, fw, blk->size); } else { uint32_t offset = blk->addr - (uint32_t)md->gmuaddr; @@ -1316,7 +1329,7 @@ static uint32_t lm_limit(struct adreno_device *adreno_dev) } static int a640_throttling_counters[ADRENO_GPMU_THROTTLE_COUNTERS] = { - 0x11, 0x15, 0x19 + 0x11, 0x15, 0x19, }; static void _setup_throttling_counters(struct adreno_device *adreno_dev) @@ -1325,6 +1338,10 @@ static void _setup_throttling_counters(struct adreno_device *adreno_dev) struct gmu_device *gmu = KGSL_GMU_DEVICE(device); int i, ret; + /* Select counter for 5% throttling instead of 15% */ + if (GMU_VER_STEP(gmu->ver) > 0x104) + a640_throttling_counters[0] = 0x10; + for (i = 0; i < ARRAY_SIZE(a640_throttling_counters); i++) { adreno_dev->busy_data.throttle_cycles[i] = 0; @@ -1399,6 +1416,7 @@ static int a6xx_gmu_ifpc_store(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct gmu_device *gmu = KGSL_GMU_DEVICE(device); unsigned int requested_idle_level; + int ret; if (!gmu_core_gpmu_isenabled(device) || !ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) @@ -1420,13 +1438,15 @@ static int a6xx_gmu_ifpc_store(struct adreno_device *adreno_dev, mutex_lock(&device->mutex); /* Power down the GPU before changing the idle level */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - gmu->idle_level = requested_idle_level; - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (!ret) { + gmu->idle_level = requested_idle_level; + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + } mutex_unlock(&device->mutex); - return 0; + return ret; } static unsigned int a6xx_gmu_ifpc_show(struct adreno_device *adreno_dev) @@ -1597,6 +1617,23 @@ static int a6xx_gmu_wait_for_active_transition( return -ETIMEDOUT; } +static bool a6xx_gmu_is_initialized(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + u32 val; + + if (_map_pdc_iomem(device)) + return false; + + val = __raw_readl(gmu->pdc_cfg_base + (PDC_GPU_ENABLE_PDC << 2)); + + /* ensure this read operation is done before the next one */ + rmb(); + + return (val == PDC_ENABLE_REG_VALUE); +} + struct gmu_dev_ops adreno_a6xx_gmudev = { .load_firmware = a6xx_gmu_load_firmware, .oob_set = a6xx_gmu_oob_set, @@ -1613,6 +1650,7 @@ struct gmu_dev_ops adreno_a6xx_gmudev = { .ifpc_show = a6xx_gmu_ifpc_show, .snapshot = a6xx_gmu_snapshot, .wait_for_active_transition = a6xx_gmu_wait_for_active_transition, + .is_initialized = a6xx_gmu_is_initialized, .gmu2host_intr_mask = HFI_IRQ_MASK, .gmu_ao_intr_mask = GMU_AO_INT_MASK, }; diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 53e2a1afaecd8cd9b671f08f537e6e13b73da3a1..651306eb0ea5e9d70eb1e64756d890a9e550e4cc 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -694,9 +694,9 @@ static void a6xx_preemption_iommu_close(struct adreno_device *adreno_dev) } #endif -static void a6xx_preemption_close(struct kgsl_device *device) +static void _preemption_close(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_preemption *preempt = &adreno_dev->preempt; struct adreno_ringbuffer *rb; unsigned int i; @@ -714,6 +714,15 @@ static void a6xx_preemption_close(struct kgsl_device *device) } } +void a6xx_preemption_close(struct adreno_device *adreno_dev) +{ + if (!test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv)) + return; + + _preemption_close(adreno_dev); +} + + int a6xx_preemption_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -755,7 +764,7 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) err: if (ret) - a6xx_preemption_close(device); + _preemption_close(adreno_dev); return ret; } diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 7035223d68d4bc5888fbb0f78bb409c84461cafd..29eec8cf9fc94c7ae6a6a4a618691411b1bb694e 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -217,6 +217,7 @@ static int a6xx_rgmu_ifpc_store(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); unsigned int requested_idle_level; + int ret; if (!gmu_core_gpmu_isenabled(device) || !ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) @@ -233,13 +234,15 @@ static int a6xx_rgmu_ifpc_store(struct adreno_device *adreno_dev, mutex_lock(&device->mutex); /* Power down the GPU before changing the idle level */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - rgmu->idle_level = requested_idle_level; - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (!ret) { + rgmu->idle_level = requested_idle_level; + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + } mutex_unlock(&device->mutex); - return 0; + return ret; } static unsigned int a6xx_rgmu_ifpc_show(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index 2a75c75492d84661d5cc9293a92015c67f23e785..472c933aecb1ccc7eca47476ed81cbfa9fb98109 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -1856,6 +1856,10 @@ void a6xx_crashdump_init(struct adreno_device *adreno_dev) for (i = 0; i < ARRAY_SIZE(a6xx_clusters); i++) { struct a6xx_cluster_registers *cluster = &a6xx_clusters[i]; + /* 16 bytes if cluster sel exists */ + if (cluster->sel) + script_size += 16; + for (j = 0; j < A6XX_NUM_CTXTS; j++) { /* 16 bytes for programming the aperture */ diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 1b05411913bcae7cda926a6cfc7a1eb9cada3cc0..2dd651a446b1437123e16368bdf9750de71d7aa4 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -30,19 +30,8 @@ static int _isdb_set(void *data, u64 val) if (test_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv)) return 0; - mutex_lock(&device->mutex); - - /* - * Bring down the GPU so we can bring it back up with the correct power - * and clock settings - */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - set_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv); - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - - return 0; + return kgsl_change_flag(device, ADRENO_DEVICE_ISDB_ENABLED, + &adreno_dev->priv); } static int _isdb_get(void *data, u64 *val) @@ -60,6 +49,7 @@ static int _lm_limit_set(void *data, u64 val) { struct kgsl_device *device = data; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + int ret; if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM)) return 0; @@ -74,7 +64,11 @@ static int _lm_limit_set(void *data, u64 val) if (test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) { mutex_lock(&device->mutex); - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (ret) { + mutex_unlock(&device->mutex); + return ret; + } kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); mutex_unlock(&device->mutex); } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index d791ee485736e91f4689ee29c91ea2a8860a96fb..41d993362a8bf7522d24abf6d109e5a111dab61f 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -317,7 +317,7 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - int i; + int i, r = 0; int status = -ENOMEM; if (!adreno_is_a3xx(adreno_dev)) { @@ -338,6 +338,19 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) break; } + if (!status && (nopreempt == false) && + ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) { + + if (gpudev->preemption_init) + r = gpudev->preemption_init(adreno_dev); + + if (r == 0) + set_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); + else + WARN(1, "adreno: GPU preemption is disabled\n"); + + } + if (status) adreno_ringbuffer_close(adreno_dev); else @@ -352,7 +365,6 @@ static void _adreno_ringbuffer_close(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); kgsl_free_global(device, &rb->pagetable_desc); - kgsl_free_global(device, &rb->preemption_desc); kgsl_free_global(device, &rb->buffer_desc); kgsl_del_event_group(&rb->events); @@ -362,6 +374,7 @@ static void _adreno_ringbuffer_close(struct adreno_device *adreno_dev, void adreno_ringbuffer_close(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_ringbuffer *rb; int i; @@ -370,6 +383,9 @@ void adreno_ringbuffer_close(struct adreno_device *adreno_dev) FOR_EACH_RINGBUFFER(adreno_dev, rb, i) _adreno_ringbuffer_close(adreno_dev, rb); + + if (gpudev->preemption_close) + gpudev->preemption_close(adreno_dev); } /* diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 3ed79af8982daaeb6c1cbb70ecca6b4cc26d7a38..ab53ff396c63da29fb2465398e8f4f28897ba941 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -70,6 +70,19 @@ void kgsl_snapshot_push_object(struct kgsl_process_private *process, for (index = 0; index < objbufptr; index++) { if (objbuf[index].gpuaddr == gpuaddr && objbuf[index].entry->priv == process) { + /* + * Check if newly requested size is within the + * allocated range or not, otherwise continue + * with previous size. + */ + if (!kgsl_gpuaddr_in_memdesc( + &objbuf[index].entry->memdesc, + gpuaddr, dwords << 2)) { + KGSL_CORE_ERR( + "snapshot: IB 0x%016llx size is not within the memdesc range\n", + gpuaddr); + return; + } objbuf[index].size = max_t(uint64_t, objbuf[index].size, diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index c0f92e511e3825a9659ecb885189b09dcaad9059..407c05b79bd3afc46505585b64b309895e19003c 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -208,16 +208,7 @@ static int _pwrctrl_store(struct adreno_device *adreno_dev, if (val == test_bit(flag, &adreno_dev->pwrctrl_flag)) return 0; - mutex_lock(&device->mutex); - - /* Power down the GPU before changing the state */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - change_bit(flag, &adreno_dev->pwrctrl_flag); - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - - return 0; + return kgsl_change_flag(device, flag, &adreno_dev->pwrctrl_flag); } static int _preemption_store(struct adreno_device *adreno_dev, @@ -226,7 +217,7 @@ static int _preemption_store(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_context *context; struct adreno_context *drawctxt; - int id; + int id, ret; mutex_lock(&device->mutex); @@ -237,7 +228,11 @@ static int _preemption_store(struct adreno_device *adreno_dev, return 0; } - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (ret) { + mutex_unlock(&device->mutex); + return ret; + } change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); adreno_dev->cur_rb = &(adreno_dev->ringbuffers[0]); @@ -717,14 +712,9 @@ static ssize_t ppd_enable_store(struct kgsl_device *device, if (ppd_on == test_bit(ADRENO_PPD_CTRL, &adreno_dev->pwrctrl_flag)) return count; - mutex_lock(&device->mutex); - - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - change_bit(ADRENO_PPD_CTRL, &adreno_dev->pwrctrl_flag); - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - return count; + ret = kgsl_change_flag(device, ADRENO_PPD_CTRL, + &adreno_dev->pwrctrl_flag); + return ret ? ret : count; } static ssize_t ppd_enable_show(struct kgsl_device *device, diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index b743594b015831faa649695681f77c5412c3c0aa..bbf4c8e7b3365c4195de1968ee326f3a5eba1bd9 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -341,6 +341,8 @@ static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta) { if (meta != NULL) { remove_dmabuf_list(meta); + dma_buf_unmap_attachment(meta->attach, meta->table, + DMA_FROM_DEVICE); dma_buf_detach(meta->dmabuf, meta->attach); dma_buf_put(meta->dmabuf); kfree(meta); @@ -2804,8 +2806,6 @@ static int kgsl_setup_dma_buf(struct kgsl_device *device, goto out; } - dma_buf_unmap_attachment(attach, sg_table, DMA_FROM_DEVICE); - meta->table = sg_table; entry->priv_data = meta; entry->memdesc.sgt = sg_table; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index dfb5050c734b69f6e5c7b209e29da4e7db5d3838..d668d4561e05c663d2defef6dc87fd14ae9ad2c8 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -319,7 +319,7 @@ struct kgsl_event { void *priv; struct list_head node; unsigned int created; - struct kthread_work work; + struct work_struct work; int result; struct kgsl_event_group *group; }; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 4cdbb8c67ede99c8408f72a8b9dd24c5e84e6319..dea7ebe8298652fefb6a8600929dc4d64d7c212b 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -697,6 +697,26 @@ static inline int kgsl_state_is_awake(struct kgsl_device *device) return false; } +static inline int kgsl_change_flag(struct kgsl_device *device, + unsigned long flag, unsigned long *val) +{ + int ret; + + mutex_lock(&device->mutex); + /* + * Bring down the GPU, so that we can bring it back up with the correct + * power and clock settings + */ + ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (!ret) { + change_bit(flag, val); + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + } + + mutex_unlock(&device->mutex); + return ret; +} + int kgsl_readtimestamp(struct kgsl_device *device, void *priv, enum kgsl_timestamp_type type, unsigned int *timestamp); diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index dc6d835867f889c63680e14713413e66acde538b..c927fdccb66d9236289313003ef5173f9d527d22 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -223,8 +223,13 @@ static void drawobj_sync_func(struct kgsl_device *device, trace_syncpoint_timestamp_expire(event->syncobj, event->context, event->timestamp); - drawobj_sync_expire(device, event); - kgsl_context_put(event->context); + /* + * Put down the context ref count only if + * this thread successfully clears the pending bit mask. + */ + if (drawobj_sync_expire(device, event)) + kgsl_context_put(event->context); + kgsl_drawobj_put(&event->syncobj->base); } @@ -254,24 +259,11 @@ static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj) static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) { struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); - unsigned long pending = 0; unsigned int i; /* Zap the canary timer */ del_timer_sync(&syncobj->timer); - /* - * Copy off the pending list and clear each pending event atomically - - * this will render any subsequent asynchronous callback harmless. - * This marks each event for deletion. If any pending fence callbacks - * run between now and the actual cancel, the associated structures - * are kfreed only in the cancel call. - */ - for_each_set_bit(i, &syncobj->pending, KGSL_MAX_SYNCPOINTS) { - if (test_and_clear_bit(i, &syncobj->pending)) - __set_bit(i, &pending); - } - /* * Clear all pending events - this will render any subsequent async * callbacks harmless @@ -279,8 +271,12 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) for (i = 0; i < syncobj->numsyncs; i++) { struct kgsl_drawobj_sync_event *event = &syncobj->synclist[i]; - /* Don't do anything if the event has already expired */ - if (!test_bit(i, &pending)) + /* + * Don't do anything if the event has already expired. + * If this thread clears the pending bit mask then it is + * responsible for doing context put. + */ + if (!test_and_clear_bit(i, &syncobj->pending)) continue; switch (event->type) { @@ -288,6 +284,11 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) kgsl_cancel_event(drawobj->device, &event->context->events, event->timestamp, drawobj_sync_func, event); + /* + * Do context put here to make sure the context is alive + * till this thread cancels kgsl event. + */ + kgsl_context_put(event->context); break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: kgsl_sync_fence_async_cancel(event->handle); @@ -300,7 +301,7 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) * If we cancelled an event, there's a good chance that the context is * on a dispatcher queue, so schedule to get it removed. */ - if (!bitmap_empty(&pending, KGSL_MAX_SYNCPOINTS) && + if (!bitmap_empty(&syncobj->pending, KGSL_MAX_SYNCPOINTS) && drawobj->device->ftbl->drawctxt_sched) drawobj->device->ftbl->drawctxt_sched(drawobj->device, drawobj->context); diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index 9bdd05a2b9dfa7be7f510376856673f5fdb3c371..d4f4a618d8950537878a95cb1694774617f3d3d6 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -32,7 +32,7 @@ static inline void signal_event(struct kgsl_device *device, { list_del(&event->node); event->result = result; - kthread_queue_work(&kgsl_driver.worker, &event->work); + queue_work(device->events_wq, &event->work); } /** @@ -42,7 +42,7 @@ static inline void signal_event(struct kgsl_device *device, * Each event callback has its own work struct and is run on a event specific * workqeuue. This is the worker that queues up the event callback function. */ -static void _kgsl_event_worker(struct kthread_work *work) +static void _kgsl_event_worker(struct work_struct *work) { struct kgsl_event *event = container_of(work, struct kgsl_event, work); int id = KGSL_CONTEXT_ID(event->context); @@ -286,7 +286,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, event->created = jiffies; event->group = group; - kthread_init_work(&event->work, _kgsl_event_worker); + INIT_WORK(&event->work, _kgsl_event_worker); trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func); @@ -301,7 +301,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, if (timestamp_cmp(retired, timestamp) >= 0) { event->result = KGSL_EVENT_RETIRED; - kthread_queue_work(&kgsl_driver.worker, &event->work); + queue_work(device->events_wq, &event->work); spin_unlock(&group->lock); return 0; } diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 41cb7d75242fa1cab0bb0c64d824754fb35520d6..11ec6fa448dffedfff4a8d04dd0ff83080d23dfd 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1241,22 +1241,30 @@ 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 kgsl_mailbox *mailbox = &gmu->mailbox; 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) + if (!mailbox->client) + return; + + if (state == mailbox->enabled) 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) + ret = mbox_send_message(mailbox->channel, &msg); + if (ret < 0) { dev_err(&gmu->pdev->dev, "AOP mbox send message failed: %d\n", ret); + return; + } + + mailbox->enabled = state; } static void gmu_aop_mailbox_destroy(struct kgsl_device *device) @@ -1268,13 +1276,15 @@ static void gmu_aop_mailbox_destroy(struct kgsl_device *device) if (!mailbox->client) return; + /* Turn off ACD in AOP */ + clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + gmu_aop_send_acd_state(device); + 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, @@ -1316,18 +1326,8 @@ static int gmu_acd_set(struct kgsl_device *device, unsigned int val) 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; + return kgsl_change_flag(device, ADRENO_ACD_CTRL, + &adreno_dev->pwrctrl_flag); } /* Do not access any GMU registers in GMU probe function */ @@ -1851,6 +1851,24 @@ static bool gmu_regulator_isenabled(struct kgsl_device *device) return (gmu->gx_gdsc && regulator_is_enabled(gmu->gx_gdsc)); } +static bool gmu_is_initialized(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + bool ret; + + gmu_enable_gdsc(gmu); + gmu_enable_clks(device); + + ret = gmu_dev_ops->is_initialized(adreno_dev); + + gmu_disable_clks(device); + gmu_disable_gdsc(gmu); + + return ret; +} + struct gmu_core_ops gmu_ops = { .probe = gmu_probe, .remove = gmu_remove, @@ -1861,4 +1879,5 @@ struct gmu_core_ops gmu_ops = { .regulator_isenabled = gmu_regulator_isenabled, .suspend = gmu_suspend, .acd_set = gmu_acd_set, + .is_initialized = gmu_is_initialized, }; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 24d5f547fb7e401927d4c90122650ae8ed57cba3..3ed6582eabfa3f59fd60ebcac23726d4ee0ad37a 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -120,6 +120,7 @@ enum gmu_load_mode { }; struct kgsl_mailbox { + bool enabled; struct mbox_client *client; struct mbox_chan *channel; }; @@ -161,6 +162,8 @@ struct kgsl_mailbox { * @idle_level: Minimal GPU idle power level * @fault_count: GMU fault count * @mailbox: Messages to AOP for ACD enable/disable go through this + * @pdc_cfg_base: Base address of PDC cfg registers + * @pdc_seq_base: Base address of PDC seq registers */ struct gmu_device { unsigned int ver; @@ -196,6 +199,8 @@ struct gmu_device { unsigned int idle_level; unsigned int fault_count; struct kgsl_mailbox mailbox; + void __iomem *pdc_cfg_base; + void __iomem *pdc_seq_base; }; struct gmu_memdesc *gmu_get_memdesc(unsigned int addr, unsigned int size); diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 6e98bb5eead18f4da2c5a2f9d254137f5f655999..a0749012c789b732f4244dd854e0e95e6e80cdb6 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -243,6 +243,22 @@ void gmu_core_regwrite(struct kgsl_device *device, unsigned int offsetwords, __raw_writel(value, reg); } +void gmu_core_blkwrite(struct kgsl_device *device, unsigned int offsetwords, + const void *buffer, size_t size) +{ + void __iomem *base; + + if (!gmu_core_is_register_offset(device, offsetwords)) { + WARN(1, "Out of bounds register write: 0x%x\n", offsetwords); + return; + } + + offsetwords -= device->gmu_core.gmu2gpu_offset; + base = device->gmu_core.reg_virt + (offsetwords << 2); + + memcpy_toio(base, buffer, size); +} + void gmu_core_regrmw(struct kgsl_device *device, unsigned int offsetwords, unsigned int mask, unsigned int bits) @@ -258,3 +274,14 @@ void gmu_core_regrmw(struct kgsl_device *device, val &= ~mask; gmu_core_regwrite(device, offsetwords, val | bits); } + +bool gmu_core_is_initialized(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->is_initialized) + return gmu_core_ops->is_initialized(device); + + return false; +} + diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 52395b76b995c29457b83018e8d002b1e4f6c57b..f84475b15de22517a268ef3a7b1e3f131cc39243 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,12 @@ (((_devops) != NULL) && \ ((_devops)->_field != NULL)) +#define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF) +#define GMU_VER_MINOR(ver) (((ver) >> 16) & 0xFFF) +#define GMU_VER_STEP(ver) (((ver) >> 0) & 0xFFFF) +#define GMU_VERSION(major, minor) \ + ((((major) & 0xF) << 28) | (((minor) & 0xFFF) << 16)) + #define NUM_BW_LEVELS 100 #define MAX_GX_LEVELS 16 #define MAX_CX_LEVELS 4 @@ -134,6 +140,7 @@ struct gmu_core_ops { bool (*regulator_isenabled)(struct kgsl_device *device); int (*suspend)(struct kgsl_device *device); int (*acd_set)(struct kgsl_device *device, unsigned int val); + bool (*is_initialized)(struct kgsl_device *device); }; struct gmu_dev_ops { @@ -159,6 +166,7 @@ struct gmu_dev_ops { void (*snapshot)(struct adreno_device *, struct kgsl_snapshot *); void (*halt_execution)(struct kgsl_device *device); int (*wait_for_active_transition)(struct adreno_device *adreno_dev); + bool (*is_initialized)(struct adreno_device *adreno_dev); const unsigned int gmu2host_intr_mask; const unsigned int gmu_ao_intr_mask; }; @@ -209,7 +217,18 @@ void gmu_core_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value); void gmu_core_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value); + +/** + * gmu_core_blkwrite() - Do a bulk I/O write to GMU + * @device: Pointer to the kgsl device + * @offsetwords: Destination dword offset + * @buffer: Pointer to the source buffer + * @size: Number of bytes to copy + */ +void gmu_core_blkwrite(struct kgsl_device *device, unsigned int offsetwords, + const void *buffer, size_t size); void gmu_core_regrmw(struct kgsl_device *device, unsigned int offsetwords, unsigned int mask, unsigned int bits); const char *gmu_core_oob_type_str(enum oob_request req); +bool gmu_core_is_initialized(struct kgsl_device *device); #endif /* __KGSL_GMU_CORE_H */ diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index aa0c9cc8d1bbc6725eb53141a451a11a44d69666..2810644a592b3f4523e8d6028ab7c12e773333db 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -628,11 +628,6 @@ void hfi_receiver(unsigned long data) hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL); } -#define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF) -#define GMU_VER_MINOR(ver) (((ver) >> 16) & 0xFFF) -#define GMU_VERSION(major, minor) \ - ((((major) & 0xF) << 28) | (((minor) & 0xFFF) << 16)) - static int hfi_verify_fw_version(struct kgsl_device *device, struct gmu_device *gmu) { diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index abfe984b1c266293ee6205a3ba7116d1f8d16b99..6a387eca1d3c10816642a4c5120b27253b056344 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1081,7 +1081,7 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu); pt->va_end = KGSL_IOMMU_SECURE_END(mmu); } else { - pt->compat_va_start = KGSL_IOMMU_SVM_BASE32; + pt->compat_va_start = mmu->svm_base32; pt->compat_va_end = KGSL_IOMMU_SECURE_BASE(mmu); pt->va_start = KGSL_IOMMU_VA_BASE64; pt->va_end = KGSL_IOMMU_VA_END64; @@ -1090,7 +1090,7 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, if (pagetable->name != KGSL_MMU_GLOBAL_PT && pagetable->name != KGSL_MMU_SECURE_PT) { if (kgsl_is_compat_task()) { - pt->svm_start = KGSL_IOMMU_SVM_BASE32; + pt->svm_start = mmu->svm_base32; pt->svm_end = KGSL_IOMMU_SECURE_BASE(mmu); } else { pt->svm_start = KGSL_IOMMU_SVM_BASE64; @@ -1110,13 +1110,13 @@ static void setup_32bit_pagetable(struct kgsl_mmu *mmu, pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu); pt->va_end = KGSL_IOMMU_SECURE_END(mmu); } else { - pt->va_start = KGSL_IOMMU_SVM_BASE32; + pt->va_start = mmu->svm_base32; pt->va_end = KGSL_IOMMU_SECURE_BASE(mmu); pt->compat_va_start = pt->va_start; pt->compat_va_end = pt->va_end; } } else { - pt->va_start = KGSL_IOMMU_SVM_BASE32; + pt->va_start = mmu->svm_base32; pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu); pt->compat_va_start = pt->va_start; pt->compat_va_end = pt->va_end; @@ -1124,7 +1124,7 @@ static void setup_32bit_pagetable(struct kgsl_mmu *mmu, if (pagetable->name != KGSL_MMU_GLOBAL_PT && pagetable->name != KGSL_MMU_SECURE_PT) { - pt->svm_start = KGSL_IOMMU_SVM_BASE32; + pt->svm_start = mmu->svm_base32; pt->svm_end = KGSL_IOMMU_SVM_END32; } } @@ -1192,7 +1192,8 @@ void _enable_gpuhtw_llc(struct kgsl_mmu *mmu, struct kgsl_iommu_pt *iommu_pt) return; /* Domain attribute to enable system cache for GPU pagetable walks */ - if (adreno_is_a640(adreno_dev) || adreno_is_a612(adreno_dev)) + if (adreno_is_a640(adreno_dev) || adreno_is_a612(adreno_dev) || + adreno_is_a680(adreno_dev)) ret = iommu_domain_set_attr(iommu_pt->domain, DOMAIN_ATTR_USE_LLC_NWA, &gpuhtw_llc_enable); else diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 4b06654fc21ae3079f7edc294373fb835866c3f4..a0d6785f09870bcf36c7131f04b2b06bd317b6a8 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -154,6 +154,7 @@ struct kgsl_mmu_pt_ops { * @feature: Static list of MMU features * @secure_aligned_mask: Mask that secure buffers need to be aligned to * @va_padding: Size to pad VA mappings to + * @svm_base32: MMU 32bit VA start address * @priv: Union of sub-device specific members */ struct kgsl_mmu { @@ -166,6 +167,7 @@ struct kgsl_mmu { unsigned long features; unsigned int secure_align_mask; uint64_t va_padding; + unsigned int svm_base32; union { struct kgsl_iommu iommu; } priv; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index eac0933e4f4c79a2674fd0dba2dfcd0c1e2d777b..1332749eb63e621d4cb6b16572220c74de0de2a6 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -65,7 +65,7 @@ static const char * const clocks[] = { "smmu_vote", }; -static unsigned int ib_votes[KGSL_MAX_BUSLEVELS]; +static unsigned long ib_votes[KGSL_MAX_BUSLEVELS]; static int last_vote_buslevel; static int max_vote_buslevel; @@ -129,7 +129,7 @@ static void _record_pwrevent(struct kgsl_device *device, /** * kgsl_get_bw() - Return latest msm bus IB vote */ -static unsigned int kgsl_get_bw(void) +static unsigned long kgsl_get_bw(void) { return ib_votes[last_vote_buslevel]; } @@ -143,8 +143,8 @@ static unsigned int kgsl_get_bw(void) static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr, unsigned long *ab) { - unsigned int ib = ib_votes[last_vote_buslevel]; - unsigned int max_bw = ib_votes[max_vote_buslevel]; + unsigned long ib = ib_votes[last_vote_buslevel]; + unsigned long max_bw = ib_votes[max_vote_buslevel]; if (!ab) return; @@ -178,6 +178,12 @@ static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level, pwr->thermal_pwrlevel_floor, pwr->min_pwrlevel); + /* Ensure that max/min pwrlevels are within thermal max/min limits */ + max_pwrlevel = min_t(unsigned int, max_pwrlevel, + pwr->thermal_pwrlevel_floor); + min_pwrlevel = max_t(unsigned int, min_pwrlevel, + pwr->thermal_pwrlevel); + switch (pwrc->type) { case KGSL_CONSTRAINT_PWRLEVEL: { switch (pwrc->sub_type) { @@ -2984,7 +2990,6 @@ _slumber(struct kgsl_device *device) kgsl_pwrctrl_clk_set_options(device, false); kgsl_pwrctrl_disable(device); kgsl_pwrscale_sleep(device); - kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, PM_QOS_DEFAULT_VALUE); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index a90967cd49870ec0375828e18b170d7ec04644b5..a0bcbb633b670236b6b734cf85ce6df4eac8d5a3 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1060,10 +1060,15 @@ static int hid_debug_rdesc_show(struct seq_file *f, void *p) seq_printf(f, "\n\n"); /* dump parsed data and input mappings */ + if (down_interruptible(&hdev->driver_input_lock)) + return 0; + hid_dump_device(hdev, f); seq_printf(f, "\n"); hid_dump_input_mapping(hdev, f); + up(&hdev->driver_input_lock); + return 0; } diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d146a9b545eed7a9563e23263a36e67fe3ebc00f..1aa7d268686b969b76b3712a5cc27ad92d1fffe8 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -973,6 +973,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x1b8: map_key_clear(KEY_VIDEO); break; case 0x1bc: map_key_clear(KEY_MESSENGER); break; case 0x1bd: map_key_clear(KEY_INFO); break; + case 0x1cb: map_key_clear(KEY_ASSISTANT); break; case 0x201: map_key_clear(KEY_NEW); break; case 0x202: map_key_clear(KEY_OPEN); break; case 0x203: map_key_clear(KEY_CLOSE); break; diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 614054af904a853b6060232df74c062bde22a249..b83d4173fc7f5da00bef4576677b648ab6beab32 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -1907,6 +1907,13 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) kfree(data); return -ENOMEM; } + data->wq = create_singlethread_workqueue("hidpp-ff-sendqueue"); + if (!data->wq) { + kfree(data->effect_ids); + kfree(data); + return -ENOMEM; + } + data->hidpp = hidpp; data->feature_index = feature_index; data->version = version; @@ -1951,7 +1958,6 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) /* ignore boost value at response.fap.params[2] */ /* init the hardware command queue */ - data->wq = create_singlethread_workqueue("hidpp-ff-sendqueue"); atomic_set(&data->workqueue_size, 0); /* initialize with zero autocenter to get wheel in usable state */ diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile index 832d8f9aaba27fed7926177383f96ec1edaf9666..099e1ce2f2347592f8cf00cff8f620cc4d170301 100644 --- a/drivers/hid/i2c-hid/Makefile +++ b/drivers/hid/i2c-hid/Makefile @@ -3,3 +3,6 @@ # obj-$(CONFIG_I2C_HID) += i2c-hid.o + +i2c-hid-objs = i2c-hid-core.o +i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c similarity index 96% rename from drivers/hid/i2c-hid/i2c-hid.c rename to drivers/hid/i2c-hid/i2c-hid-core.c index 136a34dc31b8e23fbea60fdda7968c81e65adfab..7842d76aa813b5025105ecdc24d183078a352e5c 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -43,6 +43,7 @@ #include #include "../hid-ids.h" +#include "i2c-hid.h" /* quirks to control the device */ #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) @@ -663,6 +664,7 @@ static int i2c_hid_parse(struct hid_device *hid) char *rdesc; int ret; int tries = 3; + char *use_override; i2c_hid_dbg(ihid, "entering %s\n", __func__); @@ -681,26 +683,37 @@ static int i2c_hid_parse(struct hid_device *hid) if (ret) return ret; - rdesc = kzalloc(rsize, GFP_KERNEL); + use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name, + &rsize); - if (!rdesc) { - dbg_hid("couldn't allocate rdesc memory\n"); - return -ENOMEM; - } + if (use_override) { + rdesc = use_override; + i2c_hid_dbg(ihid, "Using a HID report descriptor override\n"); + } else { + rdesc = kzalloc(rsize, GFP_KERNEL); - i2c_hid_dbg(ihid, "asking HID report descriptor\n"); + if (!rdesc) { + dbg_hid("couldn't allocate rdesc memory\n"); + return -ENOMEM; + } - ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize); - if (ret) { - hid_err(hid, "reading report descriptor failed\n"); - kfree(rdesc); - return -EIO; + i2c_hid_dbg(ihid, "asking HID report descriptor\n"); + + ret = i2c_hid_command(client, &hid_report_descr_cmd, + rdesc, rsize); + if (ret) { + hid_err(hid, "reading report descriptor failed\n"); + kfree(rdesc); + return -EIO; + } } i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); ret = hid_parse_report(hid, rdesc, rsize); - kfree(rdesc); + if (!use_override) + kfree(rdesc); + if (ret) { dbg_hid("parsing report descriptor failed\n"); return ret; @@ -827,12 +840,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) int ret; /* i2c hid fetch using a fixed descriptor size (30 bytes) */ - i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); - ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, - sizeof(struct i2c_hid_desc)); - if (ret) { - dev_err(&client->dev, "hid_descr_cmd failed\n"); - return -ENODEV; + if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) { + i2c_hid_dbg(ihid, "Using a HID descriptor override\n"); + ihid->hdesc = + *i2c_hid_get_dmi_i2c_hid_desc_override(client->name); + } else { + i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); + ret = i2c_hid_command(client, &hid_descr_cmd, + ihid->hdesc_buffer, + sizeof(struct i2c_hid_desc)); + if (ret) { + dev_err(&client->dev, "hid_descr_cmd failed\n"); + return -ENODEV; + } } /* Validate the length of HID descriptor, the 4 first bytes: diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c new file mode 100644 index 0000000000000000000000000000000000000000..cac262a912c1248747d2814fa9e3b3d3512f8c76 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Quirks for I2C-HID devices that do not supply proper descriptors + * + * Copyright (c) 2018 Julian Sax + * + */ + +#include +#include +#include + +#include "i2c-hid.h" + + +struct i2c_hid_desc_override { + union { + struct i2c_hid_desc *i2c_hid_desc; + uint8_t *i2c_hid_desc_buffer; + }; + uint8_t *hid_report_desc; + unsigned int hid_report_desc_size; + uint8_t *i2c_name; +}; + + +/* + * descriptors for the SIPODEV SP1064 touchpad + * + * This device does not supply any descriptors and on windows a filter + * driver operates between the i2c-hid layer and the device and injects + * these descriptors when the device is prompted. The descriptors were + * extracted by listening to the i2c-hid traffic that occurs between the + * windows filter driver and the windows i2c-hid driver. + */ + +static const struct i2c_hid_desc_override sipodev_desc = { + .i2c_hid_desc_buffer = (uint8_t []) + {0x1e, 0x00, /* Length of descriptor */ + 0x00, 0x01, /* Version of descriptor */ + 0xdb, 0x01, /* Length of report descriptor */ + 0x21, 0x00, /* Location of report descriptor */ + 0x24, 0x00, /* Location of input report */ + 0x1b, 0x00, /* Max input report length */ + 0x25, 0x00, /* Location of output report */ + 0x11, 0x00, /* Max output report length */ + 0x22, 0x00, /* Location of command register */ + 0x23, 0x00, /* Location of data register */ + 0x11, 0x09, /* Vendor ID */ + 0x88, 0x52, /* Product ID */ + 0x06, 0x00, /* Version ID */ + 0x00, 0x00, 0x00, 0x00 /* Reserved */ + }, + + .hid_report_desc = (uint8_t []) + {0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x02, /* Usage (Mouse), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x01, /* Report ID (1), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x02, /* Usage Maximum (02h), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x15, 0x81, /* Logical Minimum (-127), */ + 0x25, 0x7F, /* Logical Maximum (127), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0xC0, /* End Collection, */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x05, /* Usage (Touchpad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x04, /* Report ID (4), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x55, 0x0E, /* Unit Exponent (14), */ + 0x65, 0x11, /* Unit (Centimeter), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x55, 0x0C, /* Unit Exponent (12), */ + 0x66, 0x01, 0x10, /* Unit (Seconds), */ + 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */ + 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x01, /* Report Count (1), */ + 0x09, 0x56, /* Usage (Scan Time), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x54, /* Usage (Contact Count), */ + 0x25, 0x7F, /* Logical Maximum (127), */ + 0x75, 0x08, /* Report Size (8), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x09, 0x01, /* Usage (01h), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x85, 0x02, /* Report ID (2), */ + 0x09, 0x55, /* Usage (Contact Count Maximum), */ + 0x09, 0x59, /* Usage (59h), */ + 0x75, 0x04, /* Report Size (4), */ + 0x95, 0x02, /* Report Count (2), */ + 0x25, 0x0F, /* Logical Maximum (15), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x85, 0x07, /* Report ID (7), */ + 0x09, 0x60, /* Usage (60h), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x01, /* Report Count (1), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0xB1, 0x03, /* Feature (Constant, Variable), */ + 0x85, 0x06, /* Report ID (6), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0xC5, /* Usage (C5h), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x75, 0x08, /* Report Size (8), */ + 0x96, 0x00, 0x01, /* Report Count (256), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0x01, /* Usage (01h), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x0D, /* Report ID (13), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x02, /* Usage Maximum (02h), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x0E, /* Usage (Configuration), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x03, /* Report ID (3), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x09, 0x52, /* Usage (Device Mode), */ + 0x25, 0x0A, /* Logical Maximum (10), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x85, 0x05, /* Report ID (5), */ + 0x09, 0x57, /* Usage (57h), */ + 0x09, 0x58, /* Usage (58h), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x03, /* Feature (Constant, Variable),*/ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ + }, + .hid_report_desc_size = 475, + .i2c_name = "SYNA3602:00" +}; + + +static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { + { + .ident = "Teclast F6 Pro", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Teclast F7", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Trekstor Primebook C13", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Trekstor Primebook C11", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Direkt-Tek DTLAPY116-2", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Mediacom Flexbook Edge 11", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"), + }, + .driver_data = (void *)&sipodev_desc + }, + { } /* Terminate list */ +}; + + +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) +{ + struct i2c_hid_desc_override *override; + const struct dmi_system_id *system_id; + + system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); + if (!system_id) + return NULL; + + override = system_id->driver_data; + if (strcmp(override->i2c_name, i2c_name)) + return NULL; + + return override->i2c_hid_desc; +} + +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, + unsigned int *size) +{ + struct i2c_hid_desc_override *override; + const struct dmi_system_id *system_id; + + system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); + if (!system_id) + return NULL; + + override = system_id->driver_data; + if (strcmp(override->i2c_name, i2c_name)) + return NULL; + + *size = override->hid_report_desc_size; + return override->hid_report_desc; +} diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h new file mode 100644 index 0000000000000000000000000000000000000000..a8c19aef5824c5fd0f592cd84a596fc435c4bff2 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef I2C_HID_H +#define I2C_HID_H + + +#ifdef CONFIG_DMI +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, + unsigned int *size); +#else +static inline struct i2c_hid_desc + *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) +{ return NULL; } +static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, + unsigned int *size) +{ return NULL; } +#endif + +#endif diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index 1a4c7419178909c4b33320a60e85d50366a87814..ecf92b7756b01f2ab4ecd2511badd73ae80a7c33 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -143,13 +143,15 @@ static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data, { struct byte_cntr *byte_cntr_data = fp->private_data; char *bufp; - + int ret = 0; if (!data) return -EINVAL; mutex_lock(&byte_cntr_data->byte_cntr_lock); - if (!byte_cntr_data->read_active) + if (!byte_cntr_data->read_active) { + ret = -EINVAL; goto err0; + } bufp = (char *)(tmcdrvdata->buf + *ppos); @@ -157,11 +159,15 @@ static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data, if (!atomic_read(&byte_cntr_data->irq_cnt)) { mutex_unlock(&byte_cntr_data->byte_cntr_lock); if (wait_event_interruptible(byte_cntr_data->wq, - atomic_read(&byte_cntr_data->irq_cnt) > 0)) + atomic_read(&byte_cntr_data->irq_cnt) > 0 + || !byte_cntr_data->enable)) return -ERESTARTSYS; mutex_lock(&byte_cntr_data->byte_cntr_lock); - if (!byte_cntr_data->read_active) + if (!byte_cntr_data->read_active) { + ret = -EINVAL; goto err0; + } + } if (tmcdrvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) @@ -183,8 +189,10 @@ static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data, byte_cntr_data->block_size, 1, &len, &bufp); - if (!len) + if (!len) { + ret = -EINVAL; goto err0; + } } else { if (tmcdrvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) tmc_etr_read_bytes(byte_cntr_data, ppos, @@ -208,9 +216,14 @@ static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data, *ppos = 0; else *ppos += len; + + goto out; + err0: mutex_unlock(&byte_cntr_data->byte_cntr_lock); - + return ret; +out: + mutex_unlock(&byte_cntr_data->byte_cntr_lock); return len; } @@ -221,7 +234,8 @@ void tmc_etr_byte_cntr_start(struct byte_cntr *byte_cntr_data) mutex_lock(&byte_cntr_data->byte_cntr_lock); - if (byte_cntr_data->block_size == 0) { + if (byte_cntr_data->block_size == 0 + || byte_cntr_data->read_active) { mutex_unlock(&byte_cntr_data->byte_cntr_lock); return; } @@ -239,6 +253,8 @@ void tmc_etr_byte_cntr_stop(struct byte_cntr *byte_cntr_data) mutex_lock(&byte_cntr_data->byte_cntr_lock); byte_cntr_data->enable = false; + byte_cntr_data->read_active = false; + wake_up(&byte_cntr_data->wq); coresight_csr_set_byte_cntr(byte_cntr_data->csr, 0); mutex_unlock(&byte_cntr_data->byte_cntr_lock); @@ -266,7 +282,7 @@ static int tmc_etr_byte_cntr_open(struct inode *in, struct file *fp) mutex_lock(&byte_cntr_data->byte_cntr_lock); - if (!tmcdrvdata->enable || !byte_cntr_data->block_size) { + if (!byte_cntr_data->enable || !byte_cntr_data->block_size) { mutex_unlock(&byte_cntr_data->byte_cntr_lock); return -EINVAL; } @@ -279,10 +295,8 @@ static int tmc_etr_byte_cntr_open(struct inode *in, struct file *fp) fp->private_data = byte_cntr_data; nonseekable_open(in, fp); - byte_cntr_data->enable = true; byte_cntr_data->read_active = true; mutex_unlock(&byte_cntr_data->byte_cntr_lock); - return 0; } diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index c13eed61752941bdfb4cf5736b563d84653b5185..46df4870e3f9442210b384ff042e3cfd21fb8ef0 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -683,6 +683,10 @@ static const struct amba_id debug_ids[] = { .id = 0x000bbd08, .mask = 0x000fffff, }, + { /* Debug for Cortex-A73 */ + .id = 0x000bbd09, + .mask = 0x000fffff, + }, { 0, 0 }, }; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 6c036bc666dcfb045d78babd790d2f1536b1c66f..0d1d334f8de6ef70ac07f519e21ee8e6078f7a15 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -382,20 +382,27 @@ int coresight_cti_map_trigin(struct coresight_cti *cti, int trig, int ch) ret = pm_runtime_get_sync(drvdata->dev); if (ret) goto err1; + ret = coresight_enable_reg_clk(drvdata->csdev); + if (ret) + goto err2; } spin_lock_irqsave(&drvdata->spinlock, flag); ret = cti_cpu_verify_access(drvdata); if (ret) - goto err2; + goto err3; __cti_map_trigin(drvdata, trig, ch); spin_unlock_irqrestore(&drvdata->spinlock, flag); mutex_unlock(&drvdata->mutex); return 0; -err2: +err3: spin_unlock_irqrestore(&drvdata->spinlock, flag); + + if (drvdata->refcnt == 0) + coresight_disable_reg_clk(drvdata->csdev); +err2: /* * We come here before refcnt is potentially modified in * __cti_map_trigin so it is safe to check it against 0 without @@ -466,20 +473,27 @@ int coresight_cti_map_trigout(struct coresight_cti *cti, int trig, int ch) ret = pm_runtime_get_sync(drvdata->dev); if (ret) goto err1; + ret = coresight_enable_reg_clk(drvdata->csdev); + if (ret) + goto err2; } spin_lock_irqsave(&drvdata->spinlock, flag); ret = cti_cpu_verify_access(drvdata); if (ret) - goto err2; + goto err3; __cti_map_trigout(drvdata, trig, ch); spin_unlock_irqrestore(&drvdata->spinlock, flag); mutex_unlock(&drvdata->mutex); return 0; -err2: +err3: spin_unlock_irqrestore(&drvdata->spinlock, flag); + + if (drvdata->refcnt == 0) + coresight_disable_reg_clk(drvdata->csdev); +err2: /* * We come here before refcnt is potentially incremented in * __cti_map_trigout so it is safe to check it against 0. @@ -562,8 +576,10 @@ void coresight_cti_unmap_trigin(struct coresight_cti *cti, int trig, int ch) * refcnt can be used here since in all cases its value is modified only * within the mutex lock region in addition to within the spinlock. */ - if (drvdata->refcnt == 0) + if (drvdata->refcnt == 0) { pm_runtime_put(drvdata->dev); + coresight_disable_reg_clk(drvdata->csdev); + } if (drvdata->gpio_trigin->trig == trig) cti_trigin_gpio_disable(drvdata); @@ -631,8 +647,10 @@ void coresight_cti_unmap_trigout(struct coresight_cti *cti, int trig, int ch) * refcnt can be used here since in all cases its value is modified only * within the mutex lock region in addition to within the spinlock. */ - if (drvdata->refcnt == 0) + if (drvdata->refcnt == 0) { pm_runtime_put(drvdata->dev); + coresight_disable_reg_clk(drvdata->csdev); + } if (drvdata->gpio_trigout->trig == trig) cti_trigout_gpio_disable(drvdata); @@ -694,8 +712,10 @@ void coresight_cti_reset(struct coresight_cti *cti) cti_trigout_gpio_disable(drvdata); } - if (refcnt) + if (refcnt) { pm_runtime_put(drvdata->dev); + coresight_disable_reg_clk(drvdata->csdev); + } mutex_unlock(&drvdata->mutex); return; err: diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 1c3015db920839107307fd3ecde84551011b2073..d90d74ff36a0362f1eec9c56696a91f07488d5c9 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -120,14 +120,14 @@ static void coresight_reset_all_sink(void) bus_for_each_dev(&coresight_bustype, NULL, NULL, coresight_reset_sink); } -void coresight_enable_reg_clk(struct coresight_device *csdev) +int coresight_enable_reg_clk(struct coresight_device *csdev) { struct coresight_reg_clk *reg_clk = csdev->reg_clk; int ret; int i, j; if (IS_ERR_OR_NULL(reg_clk)) - return; + return -EINVAL; for (i = 0; i < reg_clk->nr_reg; i++) { ret = regulator_enable(reg_clk->reg[i]); @@ -141,7 +141,7 @@ void coresight_enable_reg_clk(struct coresight_device *csdev) goto err_clks; } - return; + return 0; err_clks: for (j--; j >= 0; j--) @@ -149,6 +149,8 @@ void coresight_enable_reg_clk(struct coresight_device *csdev) err_regs: for (i--; i >= 0; i--) regulator_disable(reg_clk->reg[i]); + + return ret; } EXPORT_SYMBOL(coresight_enable_reg_clk); diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c index bb27a31505633b835c339527b98e6cbc4de220ee..2a3ae9006c58279182c3e5577c3682baab21b1f7 100644 --- a/drivers/hwtracing/intel_th/gth.c +++ b/drivers/hwtracing/intel_th/gth.c @@ -624,7 +624,7 @@ static void intel_th_gth_unassign(struct intel_th_device *thdev, othdev->output.port = -1; othdev->output.active = false; gth->output[port].output = NULL; - for (master = 0; master < TH_CONFIGURABLE_MASTERS; master++) + for (master = 0; master <= TH_CONFIGURABLE_MASTERS; master++) if (gth->master[master] == port) gth->master[master] = -1; spin_unlock(>h->gth_lock); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 1ba1b89a0a5274c9a2c4f0ca87cc87b22545bf20..5113fff4bd2258d87eb1eb7e080f876e2b55ede8 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1347,4 +1347,10 @@ config I2C_ZX2967 This driver can also be built as a module. If so, the module will be called i2c-zx2967. +config VIRTIO_I2C + tristate "VIRTIO_I2C" + depends on VIRTIO + help + If you say yes to this option, the virtio i2c will be supported. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 7fe0174c01f678a8a51d5d0ec222c6fee764584f..b2ddaf18d13453dac1927912762a02d2f21a9af4 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o obj-$(CONFIG_I2C_MSM_V2) += i2c-msm-v2.o obj-$(CONFIG_I2C_ZX2967) += i2c-zx2967.o +obj-$(CONFIG_VIRTIO_I2C) += virtio-i2c.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 124f9b1cf1b034499c5108f1969cd5a31755f9bb..d8cbe149925b5cb2a976d0ecc5d13560d5a6d7bb 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -340,7 +340,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); dnf_delay = setup->dnf * i2cclk; - sdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min - + sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - af_delay_min - (setup->dnf + 3) * i2cclk; sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - diff --git a/drivers/i2c/busses/virtio-i2c.c b/drivers/i2c/busses/virtio-i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..b10ddd03ec1ea7ef490091d2b230841a0194f42a --- /dev/null +++ b/drivers/i2c/busses/virtio-i2c.c @@ -0,0 +1,348 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include + +#define I2C_ADAPTER_NR 0x00 + +#define I2C_VIRTIO_RD 0x01 +#define I2C_VIRTIO_WR 0x02 +#define I2C_VIRTIO_RDWR 0x03 + +struct i2c_transfer_head { + u32 type; /* read or write from or to slave */ + u32 addr; /* slave addr */ + u32 length; /* buffer length */ + u32 total_length; /* merge write and read will use this segment */ +}; + +struct i2c_transfer_end { + u32 result; /* return value from backend */ +}; + +struct virtio_i2c_req { + struct i2c_transfer_head head; + char *buf; + struct i2c_transfer_end end; +}; + +/** + * struct virtio_i2c - virtio i2c device + * @adapter: i2c adapter + * @vdev: the virtio device + * @i2c_req: description of the fromat of transfer data + * @vq: i2c virtqueue + */ +struct virtio_i2c { + struct i2c_adapter adapter; + struct virtio_device *vdev; + struct virtio_i2c_req i2c_req; + struct virtqueue *vq; + wait_queue_head_t inq; +}; + +static int virti2c_transfer(struct virtio_i2c *vi2c, + struct virtio_i2c_req *i2c_req) +{ + struct virtqueue *vq = vi2c->vq; + struct scatterlist outhdr, bufhdr, inhdr, *sgs[3]; + unsigned int num_out = 0, num_in = 0, err, len; + struct virtio_i2c_req *req_handled = NULL; + + /* send the head queue to the backend */ + sg_init_one(&outhdr, &i2c_req->head, sizeof(i2c_req->head)); + sgs[num_out++] = &outhdr; + + /* send the buffer queue to the backend */ + sg_init_one(&bufhdr, i2c_req->buf, + (i2c_req->head.type == I2C_VIRTIO_RDWR) ? + i2c_req->head.total_length : i2c_req->head.length); + if (i2c_req->head.type & I2C_VIRTIO_WR) + sgs[num_out++] = &bufhdr; + else + sgs[num_out + num_in++] = &bufhdr; + + /* send the result queue to the backend */ + sg_init_one(&inhdr, &i2c_req->end, sizeof(i2c_req->end)); + sgs[num_out + num_in++] = &inhdr; + + /* call the virtqueue function */ + err = virtqueue_add_sgs(vq, sgs, num_out, num_in, i2c_req, GFP_KERNEL); + if (err) + goto req_exit; + + /* Tell Host to go! */ + err = virtqueue_kick(vq); + + wait_event(vi2c->inq, + (req_handled = virtqueue_get_buf(vq, &len))); + + if (i2c_req->head.type == I2C_VIRTIO_RDWR) { + if (i2c_req->end.result == + i2c_req->head.total_length - i2c_req->head.length) + err = 0; + else + err = -EINVAL; + } else { + if (i2c_req->end.result == i2c_req->head.length) + err = 0; + else + err = -EINVAL; + } +req_exit: + return err; +} + +/* prepare the transfer req */ +static int virti2c_transfer_prepare(struct i2c_msg *msg_1, + struct i2c_msg *msg_2, struct virtio_i2c_req *i2c_req) +{ + if (IS_ERR_OR_NULL(msg_1) || !msg_1->len || + IS_ERR_OR_NULL(msg_1->buf)) + return -EINVAL; + + i2c_req->head.addr = msg_1->addr; + i2c_req->head.length = msg_1->len; + + if (IS_ERR_OR_NULL(msg_2)) { + i2c_req->buf = kzalloc(msg_1->len, GFP_KERNEL); + if (!i2c_req->buf) + return -ENOMEM; + + if (msg_1->flags & I2C_M_RD) { + i2c_req->head.type = I2C_VIRTIO_RD; + } else { + i2c_req->head.type = I2C_VIRTIO_WR; + memcpy(i2c_req->buf, msg_1->buf, msg_1->len); + } + + } else { + if (!msg_2->len || IS_ERR_OR_NULL(msg_2->buf)) + return -EINVAL; + + i2c_req->buf = kzalloc((msg_1->len + msg_2->len), GFP_KERNEL); + if (!i2c_req->buf) + return -ENOMEM; + + i2c_req->head.type = I2C_VIRTIO_RDWR; + i2c_req->head.total_length = msg_1->len + msg_2->len; + + memcpy(i2c_req->buf, msg_1->buf, msg_1->len); + } + + return 0; +} + +static void virti2c_transfer_end(struct virtio_i2c_req *req, + struct i2c_msg *msg) +{ + if (req->head.type == I2C_VIRTIO_RDWR) + memcpy(msg->buf, req->buf + req->head.length, msg->len); + else if (req->head.type == I2C_VIRTIO_RD) + memcpy(msg->buf, req->buf, msg->len); + kfree(req->buf); + req->buf = NULL; +} + +static int virtio_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + int i, ret; + struct virtio_i2c *vi2c = i2c_get_adapdata(adap); + struct virtio_i2c_req *i2c_req = &vi2c->i2c_req; + + if (num < 1) { + dev_err(&vi2c->vdev->dev, + "error on number of msgs(%d) received\n", num); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(msgs)) { + dev_err(&vi2c->vdev->dev, " error no msgs Accessing invalid pointer location\n"); + return PTR_ERR(msgs); + } + + for (i = 0; i < num; i++) { + + if (msgs[i].flags & I2C_M_RD) { + /* read the data from slave to master*/ + ret = virti2c_transfer_prepare(&msgs[i], NULL, i2c_req); + + } else if ((i + 1 < num) && (msgs[i + 1].flags & I2C_M_RD) && + (msgs[i].addr == msgs[i + 1].addr)) { + /* write then read from same address*/ + ret = virti2c_transfer_prepare(&msgs[i], + &msgs[i+1], i2c_req); + i += 1; + + } else { + /* write the data to slave */ + ret = virti2c_transfer_prepare(&msgs[i], NULL, i2c_req); + } + + if (ret) + goto err; + ret = virti2c_transfer(vi2c, i2c_req); + virti2c_transfer_end(i2c_req, &msgs[i]); + if (ret) + goto err; + } + return num; +err: + return ret; +} + +static u32 virtio_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm virtio_i2c_algorithm = { + .master_xfer = virtio_i2c_master_xfer, + .functionality = virtio_i2c_functionality, +}; + +/* virtqueue incoming data interrupt IRQ */ +static void virti2c_vq_isr(struct virtqueue *vq) +{ + struct virtio_i2c *vi2c = vq->vdev->priv; + + wake_up(&vi2c->inq); +} + +static int virti2c_init_vqs(struct virtio_i2c *vi2c) +{ + struct virtqueue *vqs[1]; + vq_callback_t *cbs[] = { virti2c_vq_isr }; + static const char * const names[] = { "virti2c_vq_isr" }; + int err; + + err = virtio_find_vqs(vi2c->vdev, 1, vqs, cbs, names, NULL); + if (err) + return err; + vi2c->vq = vqs[0]; + + return 0; +} + +static void virti2c_del_vqs(struct virtio_i2c *vi2c) +{ + vi2c->vdev->config->del_vqs(vi2c->vdev); +} + +static int virti2c_init_hw(struct virtio_device *vdev, + struct virtio_i2c *vi2c) +{ + int err; + + i2c_set_adapdata(&vi2c->adapter, vi2c); + vi2c->adapter.algo = &virtio_i2c_algorithm; + + vi2c->adapter.owner = THIS_MODULE; + vi2c->adapter.dev.parent = &vdev->dev; + vi2c->adapter.dev.of_node = vdev->dev.parent->of_node; + + /* read virtio i2c config info */ + vi2c->adapter.nr = virtio_cread32(vdev, I2C_ADAPTER_NR); + snprintf(vi2c->adapter.name, sizeof(vi2c->adapter.name), + "virtio_i2c_%d", vi2c->adapter.nr); + + err = i2c_add_numbered_adapter(&vi2c->adapter); + if (err) + return err; + return 0; +} + +static int virti2c_probe(struct virtio_device *vdev) +{ + struct virtio_i2c *vi2c; + int err = 0; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + vi2c = kzalloc(sizeof(*vi2c), GFP_KERNEL); + if (!vi2c) + return -ENOMEM; + + vi2c->vdev = vdev; + vdev->priv = vi2c; + init_waitqueue_head(&vi2c->inq); + + err = virti2c_init_vqs(vi2c); + if (err) + goto err_init_vq; + + err = virti2c_init_hw(vdev, vi2c); + if (err) + goto err_init_hw; + + virtio_device_ready(vdev); + + virtqueue_enable_cb(vi2c->vq); + return 0; + +err_init_hw: + virti2c_del_vqs(vi2c); +err_init_vq: + kfree(vi2c); + return err; +} +static void virti2c_remove(struct virtio_device *vdev) +{ + struct virtio_i2c *vi2c = vdev->priv; + + i2c_del_adapter(&vi2c->adapter); + vdev->config->reset(vdev); + virti2c_del_vqs(vi2c); + kfree(vi2c); +} + +static unsigned int features[] = { + /* none */ +}; +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_I2C, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtio_i2c_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .id_table = id_table, + .probe = virti2c_probe, + .remove = virti2c_remove, +}; + +module_virtio_driver(virtio_i2c_driver); +MODULE_DEVICE_TABLE(virtio, id_table); + +MODULE_DESCRIPTION("Virtio i2c frontend driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 7846368003616e08b4bd2cc67f2cdc9859e738c3..780f886ccbfe918537d24125ab7db0f6efeedc97 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1340,6 +1340,8 @@ static int kxcjk1013_resume(struct device *dev) mutex_lock(&data->mutex); ret = kxcjk1013_set_mode(data, OPERATION); + if (ret == 0) + ret = kxcjk1013_set_range(data, data->range); mutex_unlock(&data->mutex); return ret; diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 22c4c17cd9969486fe1ef80b68eaa99e51c43032..a1d072ecb7171b254c29c84d63110ad57125027d 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -121,6 +121,7 @@ static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta, if (sigma_delta->info->has_registers) { data[0] = reg << sigma_delta->info->addr_shift; data[0] |= sigma_delta->info->read_mask; + data[0] |= sigma_delta->comm; spi_message_add_tail(&t[0], &m); } spi_message_add_tail(&t[1], &m); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index cd686179aa925dcfa3d734cc7821d739f3bc1550..492f6c8ba735c78a30ee854bb02ed7e25e9990c3 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -705,23 +705,29 @@ static int at91_adc_read_raw(struct iio_dev *idev, ret = wait_event_interruptible_timeout(st->wq_data_avail, st->done, msecs_to_jiffies(1000)); - if (ret == 0) - ret = -ETIMEDOUT; - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - - *val = st->last_value; + /* Disable interrupts, regardless if adc conversion was + * successful or not + */ at91_adc_writel(st, AT91_ADC_CHDR, AT91_ADC_CH(chan->channel)); at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel)); - st->last_value = 0; - st->done = false; + if (ret > 0) { + /* a valid conversion took place */ + *val = st->last_value; + st->last_value = 0; + st->done = false; + ret = IIO_VAL_INT; + } else if (ret == 0) { + /* conversion timeout */ + dev_err(&idev->dev, "ADC Channel %d timeout.\n", + chan->channel); + ret = -ETIMEDOUT; + } + mutex_unlock(&st->lock); - return IIO_VAL_INT; + return ret; case IIO_CHAN_INFO_SCALE: *val = st->vref_mv; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 38e8783e4b05e217090b0affff9326b8d536f23d..287fbe08264dd21b0a581b58aef1294c8df354f2 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -104,9 +104,10 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev, * Do not use IIO_DEGREE_TO_RAD to avoid precision * loss. Round to the nearest integer. */ - *val = div_s64(val64 * 314159 + 9000000ULL, 1000); - *val2 = 18000 << (CROS_EC_SENSOR_BITS - 1); - ret = IIO_VAL_FRACTIONAL; + *val = 0; + *val2 = div_s64(val64 * 3141592653ULL, + 180 << (CROS_EC_SENSOR_BITS - 1)); + ret = IIO_VAL_INT_PLUS_NANO; break; case MOTIONSENSE_TYPE_MAG: /* diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 6ab1f23e5a7980c2da0cbed5dff3998047b913e9..fe3e42defb33e881fad4bc430bcf230984d874b1 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -98,6 +98,7 @@ static ssize_t mcp4725_store_eeprom(struct device *dev, inoutbuf[0] = 0x60; /* write EEPROM */ inoutbuf[0] |= data->ref_mode << 3; + inoutbuf[0] |= data->powerdown ? ((data->powerdown_mode + 1) << 1) : 0; inoutbuf[1] = data->dac_value >> 4; inoutbuf[2] = (data->dac_value & 0xf) << 4; diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 821919dd245bc8597ce901fffe26001382a9a71c..b5a5517e3ce1a141c3af94c64d506ca00b305172 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -583,11 +583,10 @@ static int bmg160_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: return bmg160_get_filter(data, val); case IIO_CHAN_INFO_SCALE: - *val = 0; switch (chan->type) { case IIO_TEMP: - *val2 = 500000; - return IIO_VAL_INT_PLUS_MICRO; + *val = 500; + return IIO_VAL_INT; case IIO_ANGL_VEL: { int i; @@ -595,6 +594,7 @@ static int bmg160_read_raw(struct iio_dev *indio_dev, for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) { if (bmg160_scale_table[i].dps_range == data->dps_range) { + *val = 0; *val2 = bmg160_scale_table[i].scale; return IIO_VAL_INT_PLUS_MICRO; } diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index e0d241a9aa3033a532eb228baeb7f149b95e4c6f..a7be4670bf8f6637006e195f345c5b3a81725bd5 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -29,7 +29,8 @@ #include "mpu3050.h" -#define MPU3050_CHIP_ID 0x69 +#define MPU3050_CHIP_ID 0x68 +#define MPU3050_CHIP_ID_MASK 0x7E /* * Register map: anything suffixed *_H is a big-endian high byte and always @@ -1178,8 +1179,9 @@ int mpu3050_common_probe(struct device *dev, goto err_power_down; } - if (val != MPU3050_CHIP_ID) { - dev_err(dev, "unsupported chip id %02x\n", (u8)val); + if ((val & MPU3050_CHIP_ID_MASK) != MPU3050_CHIP_ID) { + dev_err(dev, "unsupported chip id %02x\n", + (u8)(val & MPU3050_CHIP_ID_MASK)); ret = -ENODEV; goto err_power_down; } diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 78482d456c3bf8cfb1530752553b448c14e46f93..d501257660937187280dcc106a93e5c9ab379bff 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -320,9 +320,8 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, const unsigned long *mask; unsigned long *trialmask; - trialmask = kmalloc_array(BITS_TO_LONGS(indio_dev->masklength), - sizeof(*trialmask), - GFP_KERNEL); + trialmask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), + sizeof(*trialmask), GFP_KERNEL); if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index e565fd4fc414c2ed18c7cd041de7ba068530a113..97b7266ee0ffadeef900093d795865175256568b 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1741,10 +1741,10 @@ EXPORT_SYMBOL(iio_device_register); **/ void iio_device_unregister(struct iio_dev *indio_dev) { - mutex_lock(&indio_dev->info_exist_lock); - cdev_device_del(&indio_dev->chrdev, &indio_dev->dev); + mutex_lock(&indio_dev->info_exist_lock); + iio_device_unregister_debugfs(indio_dev); iio_disable_all_buffers(indio_dev); diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c index 59b2f96d986aa2b86491d29b8d7c3e25f244ba6f..a3dd88c57be78295ee23bd538013ddc275cfbd1d 100644 --- a/drivers/infiniband/core/security.c +++ b/drivers/infiniband/core/security.c @@ -715,16 +715,20 @@ int ib_mad_agent_security_setup(struct ib_mad_agent *agent, agent->device->name, agent->port_num); if (ret) - return ret; + goto free_security; agent->lsm_nb.notifier_call = ib_mad_agent_security_change; ret = register_lsm_notifier(&agent->lsm_nb); if (ret) - return ret; + goto free_security; agent->smp_allowed = true; agent->lsm_nb_reg = true; return 0; + +free_security: + security_ib_free_security(agent->security); + return ret; } void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent) @@ -732,9 +736,10 @@ void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent) if (!rdma_protocol_ib(agent->device, agent->port_num)) return; - security_ib_free_security(agent->security); if (agent->lsm_nb_reg) unregister_lsm_notifier(&agent->lsm_nb); + + security_ib_free_security(agent->security); } int ib_mad_enforce_security(struct ib_mad_agent_private *map, u16 pkey_index) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 6d59af07d3387a415a5cd03af526fa11ea80afa3..d21c86dd27d863ee824da3b792589ad78f717227 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -766,8 +766,8 @@ struct ib_qp *ib_open_qp(struct ib_xrcd *xrcd, } EXPORT_SYMBOL(ib_open_qp); -static struct ib_qp *ib_create_xrc_qp(struct ib_qp *qp, - struct ib_qp_init_attr *qp_init_attr) +static struct ib_qp *create_xrc_qp(struct ib_qp *qp, + struct ib_qp_init_attr *qp_init_attr) { struct ib_qp *real_qp = qp; @@ -782,10 +782,10 @@ static struct ib_qp *ib_create_xrc_qp(struct ib_qp *qp, qp = __ib_open_qp(real_qp, qp_init_attr->event_handler, qp_init_attr->qp_context); - if (!IS_ERR(qp)) - __ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp); - else - real_qp->device->destroy_qp(real_qp); + if (IS_ERR(qp)) + return qp; + + __ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp); return qp; } @@ -816,10 +816,8 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, return qp; ret = ib_create_qp_security(qp, device); - if (ret) { - ib_destroy_qp(qp); - return ERR_PTR(ret); - } + if (ret) + goto err; qp->device = device; qp->real_qp = qp; @@ -834,8 +832,15 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, INIT_LIST_HEAD(&qp->sig_mrs); qp->port = 0; - if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) - return ib_create_xrc_qp(qp, qp_init_attr); + if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) { + struct ib_qp *xrc_qp = create_xrc_qp(qp, qp_init_attr); + + if (IS_ERR(xrc_qp)) { + ret = PTR_ERR(xrc_qp); + goto err; + } + return xrc_qp; + } qp->event_handler = qp_init_attr->event_handler; qp->qp_context = qp_init_attr->qp_context; @@ -863,11 +868,8 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, if (qp_init_attr->cap.max_rdma_ctxs) { ret = rdma_rw_init_mrs(qp, qp_init_attr); - if (ret) { - pr_err("failed to init MR pool ret= %d\n", ret); - ib_destroy_qp(qp); - return ERR_PTR(ret); - } + if (ret) + goto err; } /* @@ -880,6 +882,11 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, device->attrs.max_sge_rd); return qp; + +err: + ib_destroy_qp(qp); + return ERR_PTR(ret); + } EXPORT_SYMBOL(ib_create_qp); diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c index 155b4dfc0ae837392d0db8d2d07a9b551634d777..baab9afa9174b60989ed95443a7ca8602dfc501d 100644 --- a/drivers/infiniband/hw/mlx4/alias_GUID.c +++ b/drivers/infiniband/hw/mlx4/alias_GUID.c @@ -804,8 +804,8 @@ void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) unsigned long flags; for (i = 0 ; i < dev->num_ports; i++) { - cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work); det = &sriov->alias_guid.ports_guid[i]; + cancel_delayed_work_sync(&det->alias_guid_work); spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); while (!list_empty(&det->cb_list)) { cb_ctx = list_entry(det->cb_list.next, diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c index 524e6134642e4630de0dbab3cff7ead1730f4e8e..e7013d2d4f0ef3dbb035bb8af0196842f978e5d6 100644 --- a/drivers/infiniband/sw/rdmavt/mr.c +++ b/drivers/infiniband/sw/rdmavt/mr.c @@ -611,11 +611,6 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr) if (unlikely(mapped_segs == mr->mr.max_segs)) return -ENOMEM; - if (mr->mr.length == 0) { - mr->mr.user_base = addr; - mr->mr.iova = addr; - } - m = mapped_segs / RVT_SEGSZ; n = mapped_segs % RVT_SEGSZ; mr->mr.map[m]->segs[n].vaddr = (void *)addr; @@ -633,17 +628,24 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr) * @sg_nents: number of entries in sg * @sg_offset: offset in bytes into sg * + * Overwrite rvt_mr length with mr length calculated by ib_sg_to_pages. + * * Return: number of sg elements mapped to the memory region */ int rvt_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, unsigned int *sg_offset) { struct rvt_mr *mr = to_imr(ibmr); + int ret; mr->mr.length = 0; mr->mr.page_shift = PAGE_SHIFT; - return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, - rvt_set_page); + ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, rvt_set_page); + mr->mr.user_base = ibmr->iova; + mr->mr.iova = ibmr->iova; + mr->mr.offset = ibmr->iova - (u64)mr->mr.map[0]->segs[0].vaddr; + mr->mr.length = (size_t)ibmr->length; + return ret; } /** @@ -674,6 +676,7 @@ int rvt_fast_reg_mr(struct rvt_qp *qp, struct ib_mr *ibmr, u32 key, ibmr->rkey = key; mr->mr.lkey = key; mr->mr.access_flags = access; + mr->mr.iova = ibmr->iova; atomic_set(&mr->mr.lkey_invalid, 0); return 0; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 0835e073fcecc2accc56b5acaa33a44b665b2f53..181deb6f05b0cf86d6a8f811918b92d39a3f1244 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2381,8 +2381,19 @@ static void srpt_queue_tm_rsp(struct se_cmd *cmd) srpt_queue_response(cmd); } +/* + * This function is called for aborted commands if no response is sent to the + * initiator. Make sure that the credits freed by aborting a command are + * returned to the initiator the next time a response is sent by incrementing + * ch->req_lim_delta. + */ static void srpt_aborted_task(struct se_cmd *cmd) { + struct srpt_send_ioctx *ioctx = container_of(cmd, + struct srpt_send_ioctx, cmd); + struct srpt_rdma_ch *ch = ioctx->ch; + + atomic_inc(&ch->req_lim_delta); } static int srpt_queue_status(struct se_cmd *cmd) diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 7544888c47494ef96030be6990d58d0b8aa3f2c3..b8dbde746b4ed81ffb7767014d9bce0e42005c8b 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -156,6 +156,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) return error; } + pdata->input = input; + platform_set_drvdata(pdev, pdata); + error = devm_request_irq(&pdev->dev, pdata->irq, imx_snvs_pwrkey_interrupt, 0, pdev->name, pdev); @@ -171,9 +174,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) return error; } - pdata->input = input; - platform_set_drvdata(pdev, pdata); - device_init_wakeup(&pdev->dev, pdata->wakeup); return 0; diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 8f25279903ec6040f948d0e8bfc0b05eb980f899..bee8be0066c736a22479ae6cc41290ad34a1be98 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -167,6 +167,12 @@ enum pon_type { PON_KPDPWR_RESIN = PON_POWER_ON_TYPE_KPDPWR_RESIN, }; +struct pon_reg { + unsigned int val; + u16 addr; + struct list_head list; +}; + struct qpnp_pon_config { u32 pon_type; u32 support_reset; @@ -199,7 +205,9 @@ struct qpnp_pon { struct input_dev *pon_input; struct qpnp_pon_config *pon_cfg; struct pon_regulator *pon_reg_cfg; + struct list_head restore_regs; struct list_head list; + struct mutex restore_lock; struct delayed_work bark_work; struct dentry *debugfs; u16 base; @@ -305,6 +313,42 @@ static const char * const qpnp_poff_reason[] = { [39] = "Triggered from S3_RESET_KPDPWR_ANDOR_RESIN", }; +static int qpnp_pon_store_reg(struct qpnp_pon *pon, u16 addr) +{ + int rc; + unsigned int val; + struct pon_reg *reg, *pos = NULL; + + mutex_lock(&pon->restore_lock); + rc = regmap_read(pon->regmap, addr, &val); + if (rc < 0) { + dev_info(pon->dev, "Register read failed, addr=0x%04X, rc=%d\n", + addr, rc); + } else { + list_for_each_entry(pos, &pon->restore_regs, list) { + if (pos->addr == addr) { + pos->val = val; + goto done; + } + } + + reg = devm_kzalloc(pon->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) { + rc = -ENOMEM; + goto done; + } + + reg->addr = addr; + reg->val = val; + INIT_LIST_HEAD(®->list); + list_add_tail(®->list, &pon->restore_regs); + } + +done: + mutex_unlock(&pon->restore_lock); + return rc; +} + static int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { @@ -317,6 +361,18 @@ qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) return rc; } +static int +qpnp_pon_masked_write_backup(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) +{ + int rc; + + rc = qpnp_pon_masked_write(pon, addr, mask, val); + if (rc < 0) + return rc; + + return qpnp_pon_store_reg(pon, addr); +} + static int qpnp_pon_read(struct qpnp_pon *pon, u16 addr, unsigned int *val) { int rc; @@ -416,7 +472,7 @@ static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) } val = ilog2(val); - rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon), + rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_DBC_CTL(pon), QPNP_PON_DBC_DELAY_MASK(pon), val); if (!rc) pon->dbc_time_us = delay; @@ -794,10 +850,10 @@ int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable) } if (is_pon_gen2(pon) && pon_src == PON_SMPL) - rc = qpnp_pon_masked_write(pon, QPNP_PON_SMPL_CTL(pon), + rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_SMPL_CTL(pon), QPNP_PON_SMPL_EN, enable ? QPNP_PON_SMPL_EN : 0); else - rc = qpnp_pon_masked_write(pon, QPNP_PON_TRIGGER_EN(pon), + rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_TRIGGER_EN(pon), BIT(pon_src), enable ? BIT(pon_src) : 0); return rc; @@ -834,6 +890,7 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) QPNP_PON_WARM_RESET_REASON1(pon), rc); return rc; } + qpnp_pon_store_reg(pon, QPNP_PON_WARM_RESET_REASON1(pon)); } return 0; @@ -1122,8 +1179,8 @@ static int qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) return -EINVAL; } - return qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon), pull_bit, - cfg->pull_up ? pull_bit : 0); + return qpnp_pon_masked_write_backup(pon, QPNP_PON_PULL_CTL(pon), + pull_bit, cfg->pull_up ? pull_bit : 0); } static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) @@ -1150,8 +1207,8 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) } /* Disable S2 reset */ - rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, - 0); + rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, + QPNP_PON_S2_CNTL_EN, 0); if (rc) return rc; @@ -1162,7 +1219,7 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) if (cfg->s1_timer <= s1_delay[i]) break; } - rc = qpnp_pon_masked_write(pon, s1_timer_addr, + rc = qpnp_pon_masked_write_backup(pon, s1_timer_addr, QPNP_PON_S1_TIMER_MASK, i); if (rc) return rc; @@ -1173,18 +1230,18 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) i = ilog2(i + 1); } - rc = qpnp_pon_masked_write(pon, s2_timer_addr, QPNP_PON_S2_TIMER_MASK, - i); + rc = qpnp_pon_masked_write_backup(pon, s2_timer_addr, + QPNP_PON_S2_TIMER_MASK, i); if (rc) return rc; - rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, + rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl_addr, QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type); if (rc) return rc; /* Enable S2 reset */ - return qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, + return qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN); } @@ -1277,6 +1334,18 @@ qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) return 0; } +static int +qpnp_pon_free_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) +{ + if (cfg->state_irq > 0) + devm_free_irq(pon->dev, cfg->state_irq, pon); + + if (cfg->use_bark && cfg->bark_irq > 0) + devm_free_irq(pon->dev, cfg->bark_irq, pon); + + return 0; +} + static int qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) { @@ -1632,7 +1701,7 @@ static int qpnp_pon_config_init(struct qpnp_pon *pon, return rc; } else if (cfg->pon_type != PON_CBLPWR) { /* Disable S2 reset */ - rc = qpnp_pon_masked_write(pon, + rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); if (rc) @@ -1847,7 +1916,7 @@ qpnp_pon_uvlo_dload_set(const char *val, const struct kernel_param *kp) reg = *(bool *)kp->arg ? QPNP_PON_UVLO_DLOAD_EN : 0; - return qpnp_pon_masked_write(pon, QPNP_PON_XVDD_RB_SPARE(pon), + return qpnp_pon_masked_write_backup(pon, QPNP_PON_XVDD_RB_SPARE(pon), QPNP_PON_UVLO_DLOAD_EN, reg); } @@ -1970,12 +2039,12 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) debounce = ilog2(debounce); /* S3 debounce is a SEC_ACCESS register */ - rc = qpnp_pon_masked_write(pon, QPNP_PON_SEC_ACCESS(pon), + rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_SEC_ACCESS(pon), 0xFF, QPNP_PON_SEC_UNLOCK); if (rc) return rc; - rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_DBC_CTL(pon), + rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_S3_DBC_CTL(pon), QPNP_PON_S3_DBC_DELAY_MASK, debounce); if (rc) return rc; @@ -2003,7 +2072,7 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) * been configured by the bootloader then this operation will * not have an effect. */ - rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_SRC(pon), + rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_S3_SRC(pon), QPNP_PON_S3_SRC_MASK, src_val); if (rc) return rc; @@ -2224,6 +2293,9 @@ static int qpnp_pon_probe(struct platform_device *pdev) return -EINVAL; } + INIT_LIST_HEAD(&pon->restore_regs); + mutex_init(&pon->restore_lock); + /* Get the total number of pon configurations and regulators */ for_each_available_child_of_node(dev->of_node, node) { if (of_find_property(node, "regulator-name", NULL)) { @@ -2325,10 +2397,60 @@ static int qpnp_pon_remove(struct platform_device *pdev) list_del(&pon->list); spin_unlock_irqrestore(&spon_list_slock, flags); } + mutex_destroy(&pon->restore_lock); return 0; } +#ifdef CONFIG_PM +static int qpnp_pon_restore(struct device *dev) +{ + int i, rc = 0; + struct qpnp_pon_config *cfg; + struct qpnp_pon *pon = dev_get_drvdata(dev); + struct pon_reg *pos = NULL; + + list_for_each_entry(pos, &pon->restore_regs, list) { + rc = regmap_write(pon->regmap, pos->addr, pos->val); + if (rc < 0) { + dev_err(dev, "Failed to restore reg addr=0x%04X rc=%d\n", + pos->addr, rc); + return rc; + } + } + + for (i = 0; i < pon->num_pon_config; i++) { + cfg = &pon->pon_cfg[i]; + rc = qpnp_pon_request_irqs(pon, cfg); + if (rc < 0) + return rc; + } + + return rc; +} + +static int qpnp_pon_freeze(struct device *dev) +{ + int i, rc = 0; + struct qpnp_pon_config *cfg; + struct qpnp_pon *pon = dev_get_drvdata(dev); + + for (i = 0; i < pon->num_pon_config; i++) { + cfg = &pon->pon_cfg[i]; + rc = qpnp_pon_free_irqs(pon, cfg); + if (rc < 0) + return rc; + } + + return rc; +} + +static const struct dev_pm_ops qpnp_pon_pm_ops = { + .freeze = qpnp_pon_freeze, + .restore = qpnp_pon_restore, +}; +#endif + static const struct of_device_id qpnp_pon_match_table[] = { { .compatible = "qcom,qpnp-power-on" }, {} @@ -2338,6 +2460,9 @@ static struct platform_driver qpnp_pon_driver = { .driver = { .name = "qcom,qpnp-power-on", .of_match_table = qpnp_pon_match_table, +#ifdef CONFIG_PM + .pm = &qpnp_pon_pm_ops, +#endif }, .probe = qpnp_pon_probe, .remove = qpnp_pon_remove, diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index bc5e37f30ac1cf4022ac5a8a17f63fb1793d2ce0..bb63b8823d623e0a45c5dd7a815e5302241c913a 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1239,7 +1239,7 @@ static int rmi_f11_initialize(struct rmi_function *fn) } rc = f11_write_control_regs(fn, &f11->sens_query, - &f11->dev_controls, fn->fd.query_base_addr); + &f11->dev_controls, fn->fd.control_base_addr); if (rc) dev_warn(&fn->dev, "Failed to write control registers\n"); diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 025bae3853cc974bfd0eb56077d548f40fb4bf2a..c72662c979e79f99277138543815b4ac0674ce83 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -111,27 +111,29 @@ struct stmfts_data { bool running; }; -static void stmfts_brightness_set(struct led_classdev *led_cdev, +static int stmfts_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { struct stmfts_data *sdata = container_of(led_cdev, struct stmfts_data, led_cdev); int err; - if (value == sdata->led_status || !sdata->ledvdd) - return; - - if (!value) { - regulator_disable(sdata->ledvdd); - } else { - err = regulator_enable(sdata->ledvdd); - if (err) - dev_warn(&sdata->client->dev, - "failed to disable ledvdd regulator: %d\n", - err); + if (value != sdata->led_status && sdata->ledvdd) { + if (!value) { + regulator_disable(sdata->ledvdd); + } else { + err = regulator_enable(sdata->ledvdd); + if (err) { + dev_warn(&sdata->client->dev, + "failed to disable ledvdd regulator: %d\n", + err); + return err; + } + } + sdata->led_status = value; } - sdata->led_status = value; + return 0; } static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev) @@ -613,7 +615,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata) sdata->led_cdev.name = STMFTS_DEV_NAME; sdata->led_cdev.max_brightness = LED_ON; sdata->led_cdev.brightness = LED_OFF; - sdata->led_cdev.brightness_set = stmfts_brightness_set; + sdata->led_cdev.brightness_set_blocking = stmfts_brightness_set; sdata->led_cdev.brightness_get = stmfts_brightness_get; err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 9f0df503cd7627bf733a5e230784d12723fe5a9e..88a038bada6f53feac2bef3488529fc86f31edc3 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -462,6 +462,7 @@ config IOMMU_DEBUG_TRACKING config IOMMU_TESTS bool "Interactive IOMMU performance/functional tests" select IOMMU_API + select ARM64_PTDUMP_CORE help Enables a suite of IOMMU unit tests. The tests are runnable through debugfs. Unlike the IOMMU_DEBUG_TRACKING option, the diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index bd339bfe0d154850be042b9f8db450e35a1b3cd8..684f7cdd814b64350b01632a0aa77a2427e8879e 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3127,21 +3127,24 @@ static void amd_iommu_get_resv_regions(struct device *dev, return; list_for_each_entry(entry, &amd_iommu_unity_map, list) { + int type, prot = 0; size_t length; - int prot = 0; if (devid < entry->devid_start || devid > entry->devid_end) continue; + type = IOMMU_RESV_DIRECT; length = entry->address_end - entry->address_start; if (entry->prot & IOMMU_PROT_IR) prot |= IOMMU_READ; if (entry->prot & IOMMU_PROT_IW) prot |= IOMMU_WRITE; + if (entry->prot & IOMMU_UNITY_MAP_FLAG_EXCL_RANGE) + /* Exclusion range */ + type = IOMMU_RESV_RESERVED; region = iommu_alloc_resv_region(entry->address_start, - length, prot, - IOMMU_RESV_DIRECT); + length, prot, type); if (!region) { pr_err("Out of memory allocating dm-regions for %s\n", dev_name(dev)); diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b97984a5ddad24ff56e4f79a957788470d6859cf..91d7718625a67768429cba307656bad0ffc23ed0 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1980,6 +1980,9 @@ static int __init init_unity_map_range(struct ivmd_header *m) if (e == NULL) return -ENOMEM; + if (m->flags & IVMD_FLAG_EXCL_RANGE) + init_exclusion_range(m); + switch (m->type) { default: kfree(e); @@ -2026,9 +2029,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table) while (p < end) { m = (struct ivmd_header *)p; - if (m->flags & IVMD_FLAG_EXCL_RANGE) - init_exclusion_range(m); - else if (m->flags & IVMD_FLAG_UNITY_MAP) + if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE)) init_unity_map_range(m); p += m->length; diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index f6b24c7d8b70e335d94992fe54ccd4d72b062be2..3054c0971759fb6dede7411c7a93aaa2d9407e43 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -369,6 +369,8 @@ #define IOMMU_PROT_IR 0x01 #define IOMMU_PROT_IW 0x02 +#define IOMMU_UNITY_MAP_FLAG_EXCL_RANGE (1 << 2) + /* IOMMU capabilities */ #define IOMMU_CAP_IOTLB 24 #define IOMMU_CAP_NPCACHE 26 diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index cb3ac4f793a80f4981c7ae9d54061240812c2b12..0b5502856bb4cde13d41935086f17b901ac497e9 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -524,11 +524,6 @@ static void arm_smmu_secure_domain_unlock(struct arm_smmu_domain *smmu_domain) mutex_unlock(&smmu_domain->assign_lock); } -static bool arm_smmu_opt_hibernation(struct arm_smmu_device *smmu) -{ - return IS_ENABLED(CONFIG_HIBERNATION); -} - #ifdef CONFIG_ARM_SMMU_SELFTEST static int selftest; @@ -1915,14 +1910,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, goto out_unlock; } - if (arm_smmu_has_secure_vmid(smmu_domain) && - arm_smmu_opt_hibernation(smmu)) { - dev_err(smmu->dev, - "Secure usecases not supported with hibernation\n"); - ret = -EPERM; - goto out_unlock; - } - /* * Mapping the requested stage onto what we support is surprisingly * complicated, mainly because the spec allows S1+S2 SMMUs without @@ -5010,7 +4997,11 @@ static int __maybe_unused arm_smmu_pm_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(arm_smmu_pm_ops, NULL, arm_smmu_pm_resume); +static const struct dev_pm_ops arm_smmu_pm_ops = { + .resume = arm_smmu_pm_resume, + .thaw_early = arm_smmu_pm_resume, + .restore_early = arm_smmu_pm_resume, +}; static struct platform_driver arm_smmu_driver = { .driver = { diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index c0d1c4db5794482c384b4bb6a5f5bd0dde1dab50..38d0128b8135d2f5a727ae93a375d1094367d195 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -144,7 +144,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) for (tmp = dev; tmp; tmp = tmp->bus->self) level++; - size = sizeof(*info) + level * sizeof(struct acpi_dmar_pci_path); + size = sizeof(*info) + level * sizeof(info->path[0]); if (size <= sizeof(dmar_pci_notify_info_buf)) { info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf; } else { diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 802ba7b16e09d337020a298cc89af5e736bd5ce2..fe935293fa7bddcefec29ff9b7349f89431c7cc5 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1646,6 +1646,9 @@ static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) u32 pmen; unsigned long flags; + if (!cap_plmr(iommu->cap) && !cap_phmr(iommu->cap)) + return; + raw_spin_lock_irqsave(&iommu->register_lock, flags); pmen = readl(iommu->reg + DMAR_PMEN_REG); pmen &= ~DMA_PMEN_EPM; diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 8ee91150f488fca6b3b325f12511cae9f8d20063..009ab23cc0973bce970d739d8f0d5919e8975d5b 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -694,6 +694,12 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova, ms.num_pte * sizeof(*ms.pte_start), DMA_TO_DEVICE); + /* + * Synchronise all PTE updates for the new mapping before there's + * a chance for anything to kick off a table walk for the new iova. + */ + wmb(); + return mapped; out_err: diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index a4b35c3a37820da53489f7ee3a395ad0f6654f92..3c2f2a447d5327d403c2f6b54938d3833a23e4a5 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -28,6 +28,10 @@ #include #include +#ifdef CONFIG_ARM64_PTDUMP_CORE +#include +#endif + #if defined(CONFIG_IOMMU_TESTS) static const char *iommu_debug_attr_to_string(enum iommu_attr attr) @@ -173,6 +177,9 @@ struct iommu_debug_device { struct mutex clk_lock; unsigned int clk_count; struct mutex debug_dev_lock; +#ifdef CONFIG_ARM64_PTDUMP_CORE + struct ptdump_info pt_info; +#endif }; static int iommu_debug_build_phoney_sg_table(struct device *dev, @@ -2271,6 +2278,43 @@ static const struct file_operations iommu_debug_trigger_fault_fops = { .write = iommu_debug_trigger_fault_write, }; +#ifdef CONFIG_ARM64_PTDUMP_CORE +static int ptdump_show(struct seq_file *s, void *v) +{ + struct iommu_debug_device *ddev = s->private; + struct ptdump_info *info = &(ddev->pt_info); + struct mm_struct mm; + phys_addr_t phys; + + info->markers = (struct addr_marker[]){ + { 0, "start" }, + }; + info->base_addr = 0; + info->mm = &mm; + + if (ddev->domain) { + iommu_domain_get_attr(ddev->domain, DOMAIN_ATTR_PT_BASE_ADDR, + &(phys)); + + info->mm->pgd = (pgd_t *)phys_to_virt(phys); + ptdump_walk_pgd(s, info); + } + return 0; +} + +static int ptdump_open(struct inode *inode, struct file *file) +{ + return single_open(file, ptdump_show, inode->i_private); +} + +static const struct file_operations ptdump_fops = { + .open = ptdump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + /* * The following will only work for drivers that implement the generic * device tree bindings described in @@ -2445,6 +2489,15 @@ static int snarf_iommu_devices(struct device *dev, void *ignored) goto err_rmdir; } +#ifdef CONFIG_ARM64_PTDUMP_CORE + if (!debugfs_create_file("iommu_page_tables", 0200, dir, ddev, + &ptdump_fops)) { + pr_err_ratelimited("Couldn't create iommu/devices/%s/trigger-fault debugfs file\n", + dev_name(dev)); + goto err_rmdir; + } +#endif + list_add(&ddev->list, &iommu_debug_devices); return 0; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index dae3bddaa7fd560debea17332b3411256e9b41ae..d0a199e96e447f55d3ebef06a74b401550eb0ddd 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -41,6 +41,8 @@ #include #include +#include +#include #include "irq-gic-common.h" @@ -60,6 +62,14 @@ struct gic_chip_data { u32 nr_redist_regions; unsigned int irq_nr; struct partition_desc *ppi_descs[16]; +#ifdef CONFIG_HIBERNATION + unsigned int enabled_irqs[32]; + unsigned int active_irqs[32]; + unsigned int irq_edg_lvl[64]; + unsigned int ppi_edg_lvl; + unsigned int enabled_sgis; + unsigned int pending_sgis; +#endif }; static struct gic_chip_data gic_data __read_mostly; @@ -74,6 +84,9 @@ static struct gic_kvm_info gic_v3_kvm_info; /* Our default, arbitrary priority value. Linux only uses one anyway. */ #define DEFAULT_PMR_VALUE 0xf0 +static void gic_dist_init(void); +static void gic_cpu_init(void); + static inline unsigned int gic_irq(struct irq_data *d) { return d->hwirq; @@ -334,9 +347,54 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) } #ifdef CONFIG_PM +#ifdef CONFIG_HIBERNATION +extern int in_suspend; +static bool hibernation; + +static int gic_suspend_notifier(struct notifier_block *nb, + unsigned long event, + void *dummy) +{ + if (event == PM_HIBERNATION_PREPARE) + hibernation = true; + else if (event == PM_POST_HIBERNATION) + hibernation = false; + return NOTIFY_OK; +} +static struct notifier_block gic_notif_block = { + .notifier_call = gic_suspend_notifier, +}; + +static void gic_hibernation_suspend(void) +{ + int i; + void __iomem *base = gic_data.dist_base; + void __iomem *rdist_base = gic_data_rdist_sgi_base(); + + gic_data.enabled_sgis = readl_relaxed(rdist_base + GICD_ISENABLER); + gic_data.pending_sgis = readl_relaxed(rdist_base + GICD_ISPENDR); + /* Store edge level for PPIs by reading GICR_ICFGR1 */ + gic_data.ppi_edg_lvl = readl_relaxed(rdist_base + GICR_ICFGR0 + 4); + + for (i = 0; i * 32 < gic_data.irq_nr; i++) { + gic_data.enabled_irqs[i] = readl_relaxed(base + + GICD_ISENABLER + i * 4); + gic_data.active_irqs[i] = readl_relaxed(base + + GICD_ISPENDR + i * 4); + } + + for (i = 2; i < gic_data.irq_nr / 16; i++) + gic_data.irq_edg_lvl[i] = readl_relaxed(base + + GICD_ICFGR + i * 4); +} +#endif static int gic_suspend(void) { +#ifdef CONFIG_HIBERNATION + if (unlikely(hibernation)) + gic_hibernation_suspend(); +#endif return 0; } @@ -379,6 +437,48 @@ static void gic_resume_one(struct gic_chip_data *gic) static void gic_resume(void) { +#ifdef CONFIG_HIBERNATION + int i; + void __iomem *base = gic_data.dist_base; + void __iomem *rdist_base = gic_data_rdist_sgi_base(); + + /* + * in_suspend is defined in hibernate.c and will be 0 during + * hibernation restore case. Also it willl be 0 for suspend to ram case + * and similar cases. Underlying code will not get executed in regular + * cases and will be executed only for hibernation restore. + */ + if (unlikely((in_suspend == 0 && hibernation))) { + pr_info("Re-initializing gic in hibernation restore\n"); + gic_dist_init(); + gic_cpu_init(); + + /* Activate and enable SGIs and PPIs */ + writel_relaxed(gic_data.enabled_sgis, + rdist_base + GICD_ISENABLER); + writel_relaxed(gic_data.pending_sgis, + rdist_base + GICD_ISPENDR); + /* Restore edge and level triggers for PPIs from GICR_ICFGR1 */ + writel_relaxed(gic_data.ppi_edg_lvl, + rdist_base + GICR_ICFGR0 + 4); + + /* Restore edge and level triggers */ + for (i = 2; i < gic_data.irq_nr / 16; i++) + writel_relaxed(gic_data.irq_edg_lvl[i], + base + GICD_ICFGR + i * 4); + gic_dist_wait_for_rwp(); + + /* Activate and enable interupts from backup */ + for (i = 0; i * 32 < gic_data.irq_nr; i++) { + writel_relaxed(gic_data.active_irqs[i], + base + GICD_ISPENDR + i * 4); + + writel_relaxed(gic_data.enabled_irqs[i], + base + GICD_ISENABLER + i * 4); + } + gic_dist_wait_for_rwp(); + } +#endif gic_resume_one(&gic_data); } @@ -458,7 +558,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs } while (irqnr != ICC_IAR1_EL1_SPURIOUS); } -static void __init gic_dist_init(void) +static void gic_dist_init(void) { unsigned int i; u64 affinity; @@ -1278,7 +1378,11 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare redist_stride, &node->fwnode); if (err) goto out_unmap_rdist; - +#ifdef CONFIG_HIBERNATION + err = register_pm_notifier(&gic_notif_block); + if (err) + goto out_unmap_rdist; +#endif gic_populate_ppi_partitions(node); gic_of_setup_kvm_info(node); return 0; diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c index 567b29c476081056232f13eed15a27c8d8d4fa64..98b6e1d4b1a68cf8a247f4c75a67d09fd11b6b08 100644 --- a/drivers/irqchip/irq-mbigen.c +++ b/drivers/irqchip/irq-mbigen.c @@ -161,6 +161,9 @@ static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg) void __iomem *base = d->chip_data; u32 val; + if (!msg->address_lo && !msg->address_hi) + return; + base += get_mbigen_vec_reg(d->hwirq); val = readl_relaxed(base); diff --git a/drivers/irqchip/qcom/pdc.c b/drivers/irqchip/qcom/pdc.c index ac2b6380a27a6f1cc1461ea542713354854b3032..3f8e8aa5bb1246c5184e4d8dbf58e7ceb24cd313 100644 --- a/drivers/irqchip/qcom/pdc.c +++ b/drivers/irqchip/qcom/pdc.c @@ -33,7 +33,8 @@ #include "trace/events/pdc.h" #define MAX_IRQS 126 -#define MAX_ENABLE_REGS ((MAX_IRQS/32) + 1) +#define IRQS_PER_REG 32 +#define MAX_ENABLE_REGS ((MAX_IRQS/IRQS_PER_REG) + 1) #define CLEAR_INTR(reg, intr) (reg & ~(1 << intr)) #define ENABLE_INTR(reg, intr) (reg | (1 << intr)) @@ -48,7 +49,7 @@ struct pdc_type_info { }; static struct pdc_type_info pdc_type_config[MAX_IRQS]; static u32 pdc_enabled[MAX_ENABLE_REGS]; - +static u32 max_enable_regs; static DEFINE_SPINLOCK(pdc_lock); static void __iomem *pdc_base; @@ -292,7 +293,7 @@ static int pdc_suspend(void) { int i; - for (i = 0; i < MAX_ENABLE_REGS; i++) + for (i = 0; i < max_enable_regs; i++) pdc_enabled[i] = readl_relaxed(pdc_base + IRQ_ENABLE_BANK + (i * sizeof(uint32_t))); @@ -319,7 +320,7 @@ static void pdc_resume(void) } } - for (i = 0; i < MAX_ENABLE_REGS; i++) + for (i = 0; i < max_enable_regs; i++) writel_relaxed(pdc_enabled[i], pdc_base + IRQ_ENABLE_BANK + (i * sizeof(uint32_t))); } @@ -340,8 +341,9 @@ int qcom_pdc_init(struct device_node *node, struct device_node *parent, void *data) { struct irq_domain *parent_domain; - int ret; + int i, ret, pin_count = 0; struct irq_domain *pdc_domain; + struct pdc_pin *pdc_data = (struct pdc_pin *) data; pdc_base = of_iomap(node, 0); if (!pdc_base) { @@ -364,6 +366,13 @@ int qcom_pdc_init(struct device_node *node, goto failure; } + for (i = 0; pdc_data[i].pin >= 0; i++) + pin_count++; + + max_enable_regs = pin_count / IRQS_PER_REG; + if (pin_count % IRQS_PER_REG) + max_enable_regs++; + pdc_domain->name = "qcom,pdc"; return 0; diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 7fea18b0c15d115178c874163232fa6c2e3706ce..7cb4d685a1f107f335c7cf475d06aae6688ab6bc 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -513,6 +513,7 @@ static int pca9532_probe(struct i2c_client *client, const struct i2c_device_id *id) { int devid; + const struct of_device_id *of_id; struct pca9532_data *data = i2c_get_clientdata(client); struct pca9532_platform_data *pca9532_pdata = dev_get_platdata(&client->dev); @@ -528,8 +529,11 @@ static int pca9532_probe(struct i2c_client *client, dev_err(&client->dev, "no platform data\n"); return -EINVAL; } - devid = (int)(uintptr_t)of_match_device( - of_pca9532_leds_match, &client->dev)->data; + of_id = of_match_device(of_pca9532_leds_match, + &client->dev); + if (unlikely(!of_id)) + return -EINVAL; + devid = (int)(uintptr_t) of_id->data; } else { devid = id->driver_data; } diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c index 4ba32ea3bf1485295304c2549e2c81fe3cab7413..ceb57d48d9337cb695a65edf33042fb20186c81a 100644 --- a/drivers/mailbox/msm_qmp.c +++ b/drivers/mailbox/msm_qmp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -168,6 +168,7 @@ struct qmp_mbox { struct completion ch_complete; struct delayed_work dwork; struct qmp_device *mdev; + bool suspend_flag; }; /** @@ -208,6 +209,7 @@ struct qmp_device { u32 rx_irq_count; void *ilc; + bool early_boot; }; /** @@ -376,8 +378,14 @@ static int qmp_send_data(struct mbox_chan *chan, void *data) unsigned long flags; int i; - if (!mbox || !data || mbox->local_state != CHANNEL_CONNECTED) + if (!mbox || !data) return -EINVAL; + /* + * Return -EAGAIN if client tried to send data after hibernation + * and channel is not yet opened + */ + if (!completion_done(&mbox->ch_complete)) + return -EAGAIN; mdev = mbox->mdev; @@ -568,6 +576,16 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) mbox->local_state = LINK_CONNECTED; complete_all(&mbox->link_complete); QMP_INFO(mdev->ilc, "Set to link connected\n"); + /* + * If link connection happened after hibernation + * manualy trigger the channel open procedure since client + * won't try to re-open the channel + */ + if (mbox->suspend_flag == true) { + set_mcore_ch(mbox, QMP_MBOX_CH_CONNECTED); + mbox->local_state = LOCAL_CONNECTING; + send_irq(mbox->mdev); + } break; case LINK_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { @@ -851,6 +869,7 @@ static int qmp_mbox_init(struct device_node *n, struct qmp_device *mdev) mbox->tx_sent = false; mbox->num_assigned = 0; INIT_DELAYED_WORK(&mbox->dwork, qmp_notify_timeout); + mbox->suspend_flag = false; mdev_add_mbox(mdev, mbox); return 0; @@ -938,6 +957,8 @@ static int qmp_mbox_probe(struct platform_device *pdev) if (ret) return ret; + dev_set_drvdata(&pdev->dev, mdev); + mdev->ilc = ipc_log_context_create(QMP_IPC_LOG_PAGE_CNT, mdev->name, 0); kthread_init_work(&mdev->kwork, rx_worker); @@ -960,12 +981,53 @@ static int qmp_mbox_probe(struct platform_device *pdev) mdev->rx_irq_line, ret); /* Trigger fake RX in case of missed interrupt */ - if (of_property_read_bool(edge_node, "qcom,early-boot")) + if (of_property_read_bool(edge_node, "qcom,early-boot")) { + mdev->early_boot = true; qmp_irq_handler(0, mdev); + } return 0; } +static int qmp_mbox_suspend(struct device *dev) +{ + struct qmp_device *mdev = dev_get_drvdata(dev); + struct qmp_mbox *mbox; + + list_for_each_entry(mbox, &mdev->mboxes, list) { + mbox->local_state = LINK_DISCONNECTED; + init_completion(&mbox->link_complete); + init_completion(&mbox->ch_complete); + mbox->tx_sent = false; + /* + * set suspend flag to indicate self channel open is required + * after restore operation + */ + mbox->suspend_flag = true; + /* Release rx packet buffer */ + if (mbox->rx_pkt.data) { + devm_kfree(mdev->dev, mbox->rx_pkt.data); + mbox->rx_pkt.data = NULL; + } + } + return 0; +} + +static int qmp_mbox_resume(struct device *dev) +{ + struct qmp_device *mdev = dev_get_drvdata(dev); + + if (mdev->early_boot) + qmp_irq_handler(0, mdev); + + return 0; +} + +static const struct dev_pm_ops qmp_mbox_pm_ops = { + .freeze = qmp_mbox_suspend, + .restore = qmp_mbox_resume, +}; + static struct platform_driver qmp_mbox_driver = { .probe = qmp_mbox_probe, .remove = qmp_mbox_remove, @@ -973,6 +1035,7 @@ static struct platform_driver qmp_mbox_driver = { .name = "qmp_mbox", .owner = THIS_MODULE, .of_match_table = qmp_mbox_match_table, + .pm = &qmp_mbox_pm_ops, }, }; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 02e7588ef0b561e739c3199175b1a29b93885ab0..3985210d8ab18fa37f8277ddd7689c06c1e0a9e6 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -335,7 +335,7 @@ static int crypt_iv_essiv_init(struct crypt_config *cc) sg_init_one(&sg, cc->key, cc->key_size); ahash_request_set_tfm(req, essiv->hash_tfm); - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); + ahash_request_set_callback(req, 0, NULL, NULL); ahash_request_set_crypt(req, &sg, essiv->salt, cc->key_size); err = crypto_ahash_digest(req); @@ -610,7 +610,7 @@ static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv, int i, r; desc->tfm = lmk->hash_tfm; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + desc->flags = 0; r = crypto_shash_init(desc); if (r) @@ -772,7 +772,7 @@ static int crypt_iv_tcw_whitening(struct crypt_config *cc, /* calculate crc32 for every 32bit part and xor it */ desc->tfm = tcw->crc32_tfm; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + desc->flags = 0; for (i = 0; i < 4; i++) { r = crypto_shash_init(desc); if (r) @@ -1255,7 +1255,7 @@ static void crypt_alloc_req_skcipher(struct crypt_config *cc, * requests if driver request queue is full. */ skcipher_request_set_callback(ctx->r.req, - CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + CRYPTO_TFM_REQ_MAY_BACKLOG, kcryptd_async_done, dmreq_of_req(cc, ctx->r.req)); } @@ -1272,7 +1272,7 @@ static void crypt_alloc_req_aead(struct crypt_config *cc, * requests if driver request queue is full. */ aead_request_set_callback(ctx->r.req_aead, - CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + CRYPTO_TFM_REQ_MAY_BACKLOG, kcryptd_async_done, dmreq_of_req(cc, ctx->r.req_aead)); } diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index da4baea9cf836e76c82899b5c4c8ea77c745439e..23f0f4eaaa2e7b7a70376bc90e6188dde2e36079 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -493,7 +493,7 @@ static void section_mac(struct dm_integrity_c *ic, unsigned section, __u8 result unsigned j, size; desc->tfm = ic->journal_mac; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + desc->flags = 0; r = crypto_shash_init(desc); if (unlikely(r)) { @@ -637,7 +637,7 @@ static void complete_journal_encrypt(struct crypto_async_request *req, int err) static bool do_crypt(bool encrypt, struct skcipher_request *req, struct journal_completion *comp) { int r; - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, complete_journal_encrypt, comp); if (likely(encrypt)) r = crypto_skcipher_encrypt(req); @@ -2917,17 +2917,17 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } ic->sectors_per_block = val >> SECTOR_SHIFT; - } else if (!memcmp(opt_string, "internal_hash:", strlen("internal_hash:"))) { + } else if (!strncmp(opt_string, "internal_hash:", strlen("internal_hash:"))) { r = get_alg_and_key(opt_string, &ic->internal_hash_alg, &ti->error, "Invalid internal_hash argument"); if (r) goto bad; - } else if (!memcmp(opt_string, "journal_crypt:", strlen("journal_crypt:"))) { + } else if (!strncmp(opt_string, "journal_crypt:", strlen("journal_crypt:"))) { r = get_alg_and_key(opt_string, &ic->journal_crypt_alg, &ti->error, "Invalid journal_crypt argument"); if (r) goto bad; - } else if (!memcmp(opt_string, "journal_mac:", strlen("journal_mac:"))) { + } else if (!strncmp(opt_string, "journal_mac:", strlen("journal_mac:"))) { r = get_alg_and_key(opt_string, &ic->journal_mac_alg, &ti->error, "Invalid journal_mac argument"); if (r) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 787afba77b2e6a4f0e503d7c90c0b35cbeac8e8c..33d6011ac4617a08918772083e19560124738c20 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -6,6 +6,7 @@ */ #include "dm-core.h" +#include "dm-ioctrl.h" #include #include @@ -2056,3 +2057,37 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid) return r; } + +int __init dm_ioctrl(uint cmd, struct dm_ioctl *param) +{ + int r = 0; + int ioctl_flags; + ioctl_fn fn = NULL; + size_t input_param_size; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + DMDEBUG("dm_ctl_ioctl: command 0x%x", cmd); + + fn = lookup_ioctl(cmd, &ioctl_flags); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", cmd); + return -ENOTTY; + } + + input_param_size = param->data_size; + param->data_size = sizeof(*param); + + r = fn(NULL, param, input_param_size); + + if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) && + unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS)) + DMERR("ioctl %d but has IOCTL_FLAGS_NO_PARAMS set", cmd); + + return r; +} +EXPORT_SYMBOL(dm_ioctrl); diff --git a/drivers/md/dm-ioctrl.h b/drivers/md/dm-ioctrl.h new file mode 100644 index 0000000000000000000000000000000000000000..d331fcd83df411f20d658526c4f01d48fd9ab0fc --- /dev/null +++ b/drivers/md/dm-ioctrl.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 DM_IOCTRL_INTERNAL_H +#define DM_IOCTRL_INTERNAL_H + +#include + +int dm_ioctrl(uint cmd, struct dm_ioctl *param); + +#endif diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index c9996a744ba40f7b9068cad82cbc62fafdc046b7..7d9a23ddf2a4f4b70c2191716bf3f711d2e16658 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1800,6 +1800,36 @@ static bool dm_table_supports_discards(struct dm_table *t) return true; } +static int device_requires_stable_pages(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 && bdi_cap_stable_pages_required(q->backing_dev_info); +} + +/* + * If any underlying device requires stable pages, a table must require + * them as well. Only targets that support iterate_devices are considered: + * don't want error, zero, etc to require stable pages. + */ +static bool dm_table_requires_stable_pages(struct dm_table *t) +{ + struct dm_target *ti; + unsigned i; + + for (i = 0; i < dm_table_get_num_targets(t); i++) { + ti = dm_table_get_target(t, i); + + if (ti->type->iterate_devices && + ti->type->iterate_devices(ti, device_requires_stable_pages, NULL)) + return true; + } + + return false; +} + void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, struct queue_limits *limits) { @@ -1853,6 +1883,15 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, dm_table_verify_integrity(t); + /* + * Some devices don't use blk_integrity but still want stable pages + * because they do their own checksumming. + */ + if (dm_table_requires_stable_pages(t)) + q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES; + else + q->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES; + /* * Determine whether or not this queue's I/O timings contribute * to the entropy pool, Only request-based targets use this. diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 39ff73a6a807938f5e2ecca177f610e0bcb22135..6925749864a8807fc590ce0319b3dec645a4b816 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -158,10 +158,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define REG_GFIX 0x69 /* Fix gain control */ #define REG_DBLV 0x6b /* PLL control an debugging */ -#define DBLV_BYPASS 0x00 /* Bypass PLL */ -#define DBLV_X4 0x01 /* clock x4 */ -#define DBLV_X6 0x10 /* clock x6 */ -#define DBLV_X8 0x11 /* clock x8 */ +#define DBLV_BYPASS 0x0a /* Bypass PLL */ +#define DBLV_X4 0x4a /* clock x4 */ +#define DBLV_X6 0x8a /* clock x6 */ +#define DBLV_X8 0xca /* clock x8 */ #define REG_REG76 0x76 /* OV's name */ #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ @@ -837,7 +837,7 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd, if (ret < 0) return ret; - return ov7670_write(sd, REG_DBLV, DBLV_X4); + return 0; } static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd, @@ -1601,11 +1601,7 @@ static int ov7670_probe(struct i2c_client *client, if (config->clock_speed) info->clock_speed = config->clock_speed; - /* - * It should be allowed for ov7670 too when it is migrated to - * the new frame rate formula. - */ - if (config->pll_bypass && id->driver_data != MODEL_OV7670) + if (config->pll_bypass) info->pll_bypass = true; if (config->pclk_hb_disable) diff --git a/drivers/media/platform/msm/ais/cam_cdm/cam_cdm.h b/drivers/media/platform/msm/ais/cam_cdm/cam_cdm.h index ff8be3570bc5bf1af303a96abf798c0cee01668b..178d33dee3083c779fd173c5f0ac4af9c9bb396d 100644 --- a/drivers/media/platform/msm/ais/cam_cdm/cam_cdm.h +++ b/drivers/media/platform/msm/ais/cam_cdm/cam_cdm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -251,6 +251,17 @@ struct cam_cdm_intf_mgr { int32_t refcount; }; +/** + * struct cam_cdm_debugfs_entry : debugfs entry struct + * + * @dentry : entry of debugfs + * @dump_register : flag to dump registers + */ +struct cam_cdm_debugfs_entry { + struct dentry *dentry; + bool dump_register; +}; + int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, uint32_t *index); diff --git a/drivers/media/platform/msm/ais/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/ais/cam_cdm/cam_cdm_hw_core.c index 19413d6ebbc14e96ea72da89dc3e6e49361f2280..af83aba7a0bcd881185105b3cf10663c7e492cbf 100644 --- a/drivers/media/platform/msm/ais/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/ais/cam_cdm/cam_cdm_hw_core.c @@ -38,6 +38,8 @@ static void cam_hw_cdm_work(struct work_struct *work); +static struct cam_cdm_debugfs_entry debugfs_entry; + /* DT match table entry for all CDM variants*/ static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { { @@ -69,6 +71,31 @@ int cam_hw_cdm_bl_fifo_pending_bl_rb(struct cam_hw_info *cdm_hw, return rc; } +static int cam_hw_cdm_create_debugfs_entry(void) +{ + int rc = 0; + + debugfs_entry.dentry = debugfs_create_dir("camera_cdm", NULL); + if (!debugfs_entry.dentry) + return -ENOMEM; + + if (!debugfs_create_bool("dump_register", + 0644, + debugfs_entry.dentry, + &debugfs_entry.dump_register)) { + CAM_ERR(CAM_CDM, + "failed to create dump_register entry"); + rc = -ENOMEM; + goto err; + } + + return rc; +err: + debugfs_remove_recursive(debugfs_entry.dentry); + debugfs_entry.dentry = NULL; + return rc; +} + static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, bool enable) { @@ -186,6 +213,9 @@ void cam_hw_cdm_dump_core_debug_registers( { uint32_t dump_reg, core_dbg, loop_cnt; + if (!debugfs_entry.dump_register) + return; + mutex_lock(&cdm_hw->hw_mutex); cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); @@ -482,6 +512,14 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if ((!rc) && (hw_vaddr_ptr) && (len) && (len >= cdm_cmd->cmd[i].offset)) { + + if ((len - cdm_cmd->cmd[i].offset) < + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, "Not enough buffer"); + rc = -EINVAL; + break; + } + CAM_DBG(CAM_CDM, "Got the HW VA"); if (core->bl_tag >= (CAM_CDM_HWFIFO_SIZE - 1)) @@ -1012,6 +1050,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) } cdm_hw->open_count--; mutex_unlock(&cdm_hw->hw_mutex); + cam_hw_cdm_create_debugfs_entry(); CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); diff --git a/drivers/media/platform/msm/ais/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/ais/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 54f82eef44a5e6ea0be6312a422ef8c3d2af0eb8..b2838b4a902f7b5d4c3f7ed13de87b47eeede2f4 100644 --- a/drivers/media/platform/msm/ais/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/ais/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -596,6 +596,15 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, return -ENOMEM; } + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane); + rc = -EINVAL; + goto rel_cpu_buf; + } + io_addr[plane] += io_cfg[i].offsets[plane]; } diff --git a/drivers/media/platform/msm/ais/cam_icp/cam_icp_context.c b/drivers/media/platform/msm/ais/cam_icp/cam_icp_context.c index fa9b44289803f0e3d1bde4e245927360093e696c..41d175188d85ac30ebd86a63dca7b7ee5374cdb1 100644 --- a/drivers/media/platform/msm/ais/cam_icp/cam_icp_context.c +++ b/drivers/media/platform/msm/ais/cam_icp/cam_icp_context.c @@ -45,6 +45,14 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); + + if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { + CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", + ctx->ctx_id, ctx->state); + goto end; + } + CAM_INFO(CAM_ICP, "iommu fault for icp ctx %d state %d", ctx->ctx_id, ctx->state); @@ -63,6 +71,8 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, req->request_id, rc); } +end: + mutex_unlock(&ctx->ctx_mutex); return rc; } @@ -137,6 +147,12 @@ static int __cam_icp_config_dev_in_ready(struct cam_context *ctx, return rc; } + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf"); + return -EINVAL; + } + packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); diff --git a/drivers/media/platform/msm/ais/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/ais/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index cf4e93c07a278369c3cb9094c817344c64806915..4ffb3aa052edd6f2de2abc287bbd22adcfeb6ed6 100644 --- a/drivers/media/platform/msm/ais/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/ais/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -64,6 +64,37 @@ static struct cam_icp_hw_mgr icp_hw_mgr; static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); +static int cam_icp_dump_io_cfg(struct cam_icp_hw_ctx_data *ctx_data, + int32_t buf_handle) +{ + uintptr_t vaddr_ptr; + uint32_t *ptr; + size_t len; + int rc, i; + char buf[512]; + int used = 0; + + rc = cam_mem_get_cpu_buf(buf_handle, &vaddr_ptr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get io_cfg buf address for %d", + ctx_data->ctx_id); + return rc; + } + + len = len / sizeof(uint32_t); + ptr = (uint32_t *)vaddr_ptr; + for (i = 0; i < len; i++) { + used += snprintf(buf + used, + sizeof(buf) - used, "0X%08X-", ptr[i]); + if (!(i % 8)) { + CAM_INFO(CAM_ICP, "%s: %s", __func__, buf); + used = 0; + } + } + + return rc; +} + static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) { struct cam_hw_intf *a5_dev_intf = NULL; @@ -1262,6 +1293,44 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, return rc; } +static int cam_icp_mgr_ipe_bps_get_gdsc_control( + struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong"); + return -EINVAL; + } + + if (icp_hw_mgr.ipe_bps_pc_flag) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + NULL, 0); + } + } + + return rc; +} + static int cam_icp_set_dbg_default_clk(void *data, u64 val) { icp_hw_mgr.icp_debug_clk = val; @@ -1786,27 +1855,31 @@ static int cam_icp_ipebps_reset(struct cam_icp_hw_mgr *hw_mgr) ipe1_dev_intf = hw_mgr->ipe1_dev_intf; bps_dev_intf = hw_mgr->bps_dev_intf; - rc = bps_dev_intf->hw_ops.process_cmd( - bps_dev_intf->hw_priv, - CAM_ICP_BPS_CMD_RESET, - NULL, 0); - if (rc) - CAM_ERR(CAM_ICP, "bps reset failed"); - - rc = ipe0_dev_intf->hw_ops.process_cmd( - ipe0_dev_intf->hw_priv, - CAM_ICP_IPE_CMD_RESET, - NULL, 0); - if (rc) - CAM_ERR(CAM_ICP, "ipe0 reset failed"); + if (hw_mgr->bps_ctxt_cnt) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "bps reset failed"); + } - if (ipe1_dev_intf) { - rc = ipe1_dev_intf->hw_ops.process_cmd( - ipe1_dev_intf->hw_priv, + if (hw_mgr->ipe_ctxt_cnt) { + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, CAM_ICP_IPE_CMD_RESET, NULL, 0); if (rc) - CAM_ERR(CAM_ICP, "ipe1 reset failed"); + CAM_ERR(CAM_ICP, "ipe0 reset failed"); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe1 reset failed"); + } } return 0; @@ -1827,6 +1900,7 @@ static int cam_icp_mgr_trigger_recovery(struct cam_icp_hw_mgr *hw_mgr) sfr_buffer = (struct sfr_buf *)icp_hw_mgr.hfi_mem.sfr_buf.kva; CAM_WARN(CAM_ICP, "SFR:%s", sfr_buffer->msg); + cam_icp_mgr_ipe_bps_get_gdsc_control(hw_mgr); cam_icp_ipebps_reset(hw_mgr); atomic_set(&hw_mgr->recovery, 1); @@ -3449,6 +3523,17 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, goto rel_cmd_buf; } *fw_cmd_buf_iova_addr = addr; + + if (cmd_desc[i].offset >= len || + ((len - cmd_desc[i].offset) < + cmd_desc[i].size)){ + CAM_ERR(CAM_ICP, + "Invalid offset/length, i %d offset 0x%x len 0x%x size 0x%x", + i, cmd_desc[i].offset, + len, cmd_desc[i].size); + goto rel_cmd_buf; + } + *fw_cmd_buf_iova_addr = (*fw_cmd_buf_iova_addr + cmd_desc[i].offset); rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, @@ -4052,8 +4137,12 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, packet = prepare_args->packet; - if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_ICP, "ctx id: %u packet req id %lld validate fail", + ctx_data->ctx_id, packet->header.request_id); return -EINVAL; + } rc = cam_icp_mgr_pkt_validation(packet); if (rc) { @@ -4674,6 +4763,8 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) rc = cam_icp_mgr_send_config_io(ctx_data, io_buf_addr); if (rc) { CAM_ERR(CAM_ICP, "IO Config command failed %d", rc); + cam_icp_dump_io_cfg(ctx_data, + icp_dev_acquire_info->io_config_cmd_handle); goto ioconfig_failed; } diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 38ce6386c57d0005d370d24d2331478de1970ca6..779f5f5264a50cc015fdb922ab948f5e4b23836b 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2968,6 +2968,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } + ctx->dual_ife_irq_mismatch_cnt = 0; /* Start IFE root node: do nothing */ CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); @@ -3050,6 +3051,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->is_rdi_only_context = 0; ctx->cdm_handle = 0; ctx->cdm_ops = NULL; + ctx->dual_ife_irq_mismatch_cnt = 0; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; @@ -4062,6 +4064,36 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } } +static void cam_ife_mgr_ctx_irq_dump(struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_hw_get_cmd_update cmd_update; + int i = 0; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + cmd_update.res = hw_mgr_res->hw_res[i]; + cmd_update.cmd_type = + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, + &cmd_update, sizeof(cmd_update)); + break; + default: + break; + } + } + } +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -4732,11 +4764,26 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( (event_cnt[core_idx1] && (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { + if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt > 10) { + rc = -1; + return rc; + } + CAM_ERR_RATE_LIMIT(CAM_ISP, "One of the VFE could not generate hw event %d", hw_event_type); - rc = -1; - return rc; + if (event_cnt[core_idx0] >= 2) { + event_cnt[core_idx0]--; + ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++; + } + if (event_cnt[core_idx1] >= 2) { + event_cnt[core_idx1]--; + ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++; + } + + if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt == 1) + cam_ife_mgr_ctx_irq_dump(ife_hw_mgr_ctx); + rc = 0; } CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d", diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index bf5f1527caa44e101882e96fc2a016d041139e5b..0e6d79b75232418d07157d448940fd10c3c31176 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -102,38 +102,42 @@ struct cam_ife_hw_mgr_debug { /** * struct cam_vfe_hw_mgr_ctx - IFE HW manager Context object * - * @list: used by the ctx list. - * @common: common acquired context data - * @ctx_index: acquired context id. - * @hw_mgr: IFE hw mgr which owns this context - * @ctx_in_use: flag to tell whether context is active - * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be - * one. - * @res_list_csid: CSID resource list - * @res_list_ife_src: IFE input resource list - * @res_list_ife_in_rd IFE input resource list for read path - * @res_list_ife_out: IFE output resoruces array - * @free_res_list: Free resources list for the branch node - * @res_pool: memory storage for the free resource list - * @irq_status0_mask: irq_status0_mask for the context - * @irq_status1_mask: irq_status1_mask for the context - * @base device base index array contain the all IFE HW - * instance associated with this context. - * @num_base number of valid base data in the base array - * @cdm_handle cdm hw acquire handle - * @cdm_ops cdm util operation pointer for building - * cdm commands - * @cdm_cmd cdm base and length request pointer - * @sof_cnt sof count value per core, used for dual VFE - * @epoch_cnt epoch count value per core, used for dual VFE - * @eof_cnt eof count value per core, used for dual VFE - * @overflow_pending flat to specify the overflow is pending for the - * context - * @is_rdi_only_context flag to specify the context has only rdi resource - * @config_done_complete indicator for configuration complete - * @init_done indicate whether init hw is done - * @is_fe_enable indicate whether fetch engine\read path is enabled - * @res_bitmap fill resource bitmap for which rup to be set + * @list: used by the ctx list. + * @common: common acquired context data + * @ctx_index: acquired context id. + * @hw_mgr: IFE hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be + * one. + * @res_list_csid: CSID resource list + * @res_list_ife_src: IFE input resource list + * @res_list_ife_in_rd IFE input resource list for read path + * @res_list_ife_out: IFE output resoruces array + * @free_res_list: Free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @irq_status0_mask: irq_status0_mask for the context + * @irq_status1_mask: irq_status1_mask for the context + * @base device base index array contain the all IFE HW + * instance associated with this context. + * @num_base number of valid base data in the base array + * @cdm_handle cdm hw acquire handle + * @cdm_ops cdm util operation pointer for building + * cdm commands + * @cdm_cmd cdm base and length request pointer + * @sof_cnt sof count value per core, used for dual VFE + * @epoch_cnt epoch count value per core, used for dual VFE + * @eof_cnt eof count value per core, used for dual VFE + * @overflow_pending flat to specify the overflow is pending + * for the context + * @is_rdi_only_context flag to specify the context has only rdi + * resource + * @config_done_complete indicator for configuration complete + * @init_done indicate whether init hw is done + * @is_fe_enable indicate whether fetch engine\read path + * is enabled + * @res_bitmap fill resource bitmap for which rup to be set + * @dual_ife_irq_mismatch_cnt irq mismatch count value per core, used for + * dual VFE */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -171,6 +175,7 @@ struct cam_ife_hw_mgr_ctx { bool init_done; bool is_fe_enable; unsigned long res_bitmap; + uint32_t dual_ife_irq_mismatch_cnt; }; /** diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 1b64913f091918eb7a1668c5b5b7f41fb799649a..21b0d03075d18a5dafdfa196800812ec6b457f21 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -686,7 +686,52 @@ int cam_isp_add_io_buffers( rc = -ENOMEM; return rc; } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_HFR_UPDATE; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.hfr_update->framedrop_pattern = + io_cfg[i].framedrop_pattern; + update_buf.hfr_update->framedrop_period = + io_cfg[i].framedrop_period; + update_buf.hfr_update->subsample_pattern = + io_cfg[i].subsample_pattern; + update_buf.hfr_update->subsample_period = + io_cfg[i].subsample_period; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_HFR_UPDATE, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && io_cfg[i].direction == CAM_BUF_INPUT; j++) { diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index e2f7ae4d5d59e2ed87d4306e482187e3d43af130..bbcf9af641507e37c7a2497affba28d42654b62d 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -46,7 +46,7 @@ #define CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX 12 /* Max CSI Rx irq error count threshold value */ -#define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 +#define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 5 static int cam_ife_csid_is_ipp_ppp_format_supported( uint32_t in_format) @@ -1477,15 +1477,13 @@ static void cam_ife_csid_halt_csi2( csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; - CAM_INFO(CAM_ISP, "CSID: %d cnt: %d Halt csi2 rx", - csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); /* Disable the CSI2 rx inerrupts */ - cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + cam_io_w(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); /* Reset the Rx CFG registers */ - cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + cam_io_w(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); @@ -3046,13 +3044,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); - CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); - CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); - CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); - CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x", irq_status_rdi[0]); - 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]); + CAM_DBG(CAM_ISP, + "CSID %d irq status 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + csid_hw->hw_intf->hw_idx, irq_status_top, + irq_status_rx, irq_status_ipp, irq_status_ppp, + irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); @@ -3062,71 +3058,38 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_lock_irqsave(&csid_hw->lock_state, flags); if (csid_hw->device_enabled == 1) { if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); - } if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } } - spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT) { @@ -3134,8 +3097,15 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count = 0; } - if (fatal_err_detected) +handle_fatal_error: + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + if (fatal_err_detected) { + CAM_INFO(CAM_ISP, + "CSID: %d cnt: %d Halt csi2 rx irq_status_rx:0x%x", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt, + irq_status_rx); cam_ife_csid_halt_csi2(csid_hw); + } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { @@ -3236,7 +3206,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /* IPP reset done bit */ if (irq_status_ipp & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { - CAM_DBG(CAM_ISP, "CSID IPP reset complete"); complete(&csid_hw->csid_ipp_complete); } @@ -3253,19 +3222,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID:%d IPP CCIF violation", - csid_hw->hw_intf->hw_idx); - - if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION) || + (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d IPP fifo over flow", - csid_hw->hw_intf->hw_idx); - /* Stop IPP path immediately */ - cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, - soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_pxl_ctrl_addr); + "CSID:%d irq_status_ipp:0x%x", + csid_hw->hw_intf->hw_idx, irq_status_ipp); + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + /* Stop IPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + } } } @@ -3274,7 +3241,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /* PPP reset done bit */ if (irq_status_ppp & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { - CAM_DBG(CAM_ISP, "CSID PPP reset complete"); complete(&csid_hw->csid_ppp_complete); } @@ -3291,26 +3257,23 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID:%d PPP CCIF violation", - csid_hw->hw_intf->hw_idx); - - if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION) || + (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d PPP fifo over flow", - csid_hw->hw_intf->hw_idx); - /* Stop PPP path immediately */ - cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, - soc_info->reg_map[0].mem_base + - csid_reg->ppp_reg->csid_pxl_ctrl_addr); + "CSID:%d irq_status_ppp:0x%x", + csid_hw->hw_intf->hw_idx, irq_status_ppp); + if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + /* Stop PPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_ctrl_addr); + } } } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { if (irq_status_rdi[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { - CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); complete(&csid_hw->csid_rdin_complete[i]); } @@ -3327,14 +3290,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); - if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSIDi RDI :%d CCIF violation", i); - - if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION) || + (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d RDI fifo over flow", - csid_hw->hw_intf->hw_idx); + "CSID:%d irq_status_rdi[%d]:0x%x", + csid_hw->hw_intf->hw_idx, i, + irq_status_rdi[i]); + } + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { /* Stop RDI path immediately */ cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, soc_info->reg_map[0].mem_base + diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 9792ac5f0f98ddaf64bcf544db7003e9b02862f4..185d0f59567306bf9b2b89cb9aa6622ae9112858 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -103,6 +103,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 2bd6db9954f1a38ca8ce5fee3eb99a24cf63400b..43531c173f89b3e19a6f9b8044ffaa49f367801e 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -23,6 +23,7 @@ #include "cam_vfe_top.h" #include "cam_ife_hw_mgr.h" #include "cam_debug_util.h" +#include "cam_vfe_hw_intf.h" static const char drv_name[] = "vfe"; static uint32_t irq_reg_offset[CAM_IFE_IRQ_REGISTERS_MAX] = { @@ -51,6 +52,26 @@ static uint32_t rdi_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x00000000, }; +static uint32_t rdi0_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x08000020, + 0x00000000, +}; + +static uint32_t rdi1_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x10000040, + 0x00000000, +}; + +static uint32_t rdi2_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x20000080, + 0x00000000, +}; + +static uint32_t rdi3_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x40000100, + 0x00000000, +}; + static uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x80000000, 0x00000000, @@ -579,6 +600,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) struct cam_vfe_hw_core_info *core_info = NULL; struct cam_hw_info *vfe_hw = hw_priv; struct cam_isp_resource_node *isp_res; + uint32_t *evt_bit_mask_arr = NULL; int rc = 0; if (!hw_priv || !start_args || @@ -620,16 +642,35 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) if (isp_res->irq_handle < 1) rc = -ENOMEM; } else if (isp_res->rdi_only_ctx) { + switch (isp_res->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + evt_bit_mask_arr = rdi0_irq_reg_mask; + break; + case CAM_ISP_HW_VFE_IN_RDI1: + evt_bit_mask_arr = rdi1_irq_reg_mask; + break; + case CAM_ISP_HW_VFE_IN_RDI2: + evt_bit_mask_arr = rdi2_irq_reg_mask; + break; + case CAM_ISP_HW_VFE_IN_RDI3: + evt_bit_mask_arr = rdi3_irq_reg_mask; + break; + default: + evt_bit_mask_arr = rdi_irq_reg_mask; + break; + } + isp_res->irq_handle = cam_irq_controller_subscribe_irq( core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_1, - rdi_irq_reg_mask, + evt_bit_mask_arr, &core_info->irq_payload, cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet, isp_res->tasklet_info, &tasklet_bh_api); + if (isp_res->irq_handle < 1) rc = -ENOMEM; } @@ -760,6 +801,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CLOCK_UPDATE: case CAM_ISP_HW_CMD_BW_UPDATE: case CAM_ISP_HW_CMD_BW_CONTROL: + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 61c1e9e01ba25193fa747aafc9663229c14f88a5..4c525ff1b5f76d0c29b413bdb4b4905aa4d42bf3 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -246,6 +246,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .debug_status_0 = 0x00002270, }, .num_client = 20, + .is_lite = 0, .bus_client_reg = { /* BUS Client 0 */ { diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index edb595e70ad9c29682a44dcd8bd62a9d8138f824..0d0d593bd1083d295483bc3a9ca2d88cd030e790 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -309,6 +309,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { .debug_status_0 = 0x00002270, }, .num_client = 24, + .is_lite = 0, .bus_client_reg = { /* BUS Client 0 */ { diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 3ca5bec711137abc2c4c71f9fd6fe8a5d5c5e67c..eb4c62a632a7399d71e1389d4e55b2236349b179 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -410,6 +410,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { .addr_sync_no_sync = 0x00002084, }, .num_client = 24, + .is_lite = 0, .bus_client_reg = { /* BUS Client 0 */ { diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h index 9767f97165818437c0dd99e8944d950d13ee0227..9733a1fe7515c0faa0fe7d3d38e6e270f61ed5d2 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -153,6 +153,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe17x_bus_hw_info = { .addr_sync_no_sync = 0x00002084, }, .num_client = 4, + .is_lite = 1, .bus_client_reg = { /* BUS Client 0 */ { diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 61e17ab465651a206e2e03d05a03386804ea70ec..dcb77bee29c0e56abc2ce549e7a0686b19f249c1 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -153,6 +153,7 @@ struct cam_vfe_bus_ver2_wm_resource_data { uint32_t en_cfg; uint32_t is_dual; + uint32_t is_lite; }; struct cam_vfe_bus_ver2_comp_grp_data { @@ -199,6 +200,7 @@ struct cam_vfe_bus_ver2_priv { struct cam_vfe_bus_ver2_common_data common_data; uint32_t num_client; uint32_t num_out; + uint32_t is_lite; struct cam_isp_resource_node bus_client[CAM_VFE_BUS_VER2_MAX_CLIENTS]; struct cam_isp_resource_node comp_grp[CAM_VFE_BUS_VER2_COMP_GRP_MAX]; @@ -917,12 +919,14 @@ static int cam_vfe_bus_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; rsrc_data->is_dual = is_dual; + rsrc_data->is_lite = ver2_bus_priv->is_lite; /* Set WM offset value to default */ rsrc_data->offset = 0; CAM_DBG(CAM_ISP, "WM %d width %d height %d", rsrc_data->index, rsrc_data->width, rsrc_data->height); - if (rsrc_data->index < 3) { + if (rsrc_data->index < 3 || + (rsrc_data->is_lite && rsrc_data->index == 3)) { /* Write master 0-2 refers to RDI 0/ RDI 1/RDI 2 */ if ((out_port_info->reserved >> 8) & 0x01) { /* frame based mode as default */ @@ -943,24 +947,17 @@ static int cam_vfe_bus_acquire_wm( case CAM_FORMAT_MIPI_RAW_14: case CAM_FORMAT_MIPI_RAW_16: case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: case CAM_FORMAT_PLAIN128: + /*repacking is done in CSID for PLAIN*/ rsrc_data->pack_fmt = 0x0; break; case CAM_FORMAT_PLAIN8: rsrc_data->pack_fmt = 0x1; break; - case CAM_FORMAT_PLAIN16_10: - rsrc_data->pack_fmt = 0x2; - break; - case CAM_FORMAT_PLAIN16_12: - rsrc_data->pack_fmt = 0x3; - break; - case CAM_FORMAT_PLAIN16_14: - rsrc_data->pack_fmt = 0x4; - break; - case CAM_FORMAT_PLAIN16_16: - rsrc_data->pack_fmt = 0x5; - break; case CAM_FORMAT_PLAIN64: rsrc_data->pack_fmt = 0xA; break; @@ -1159,7 +1156,8 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) common_data->mem_base + rsrc_data->hw_regs->packer_cfg); /* Configure stride for RDIs */ - if (rsrc_data->index < 3) + if (rsrc_data->index < 3 || + (rsrc_data->is_lite && rsrc_data->index == 3)) cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + rsrc_data->hw_regs->stride)); @@ -3420,6 +3418,7 @@ int cam_vfe_bus_ver2_init( bus_priv->num_client = ver2_hw_info->num_client; bus_priv->num_out = ver2_hw_info->num_out; + bus_priv->is_lite = ver2_hw_info->is_lite; bus_priv->common_data.num_sec_out = 0; bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; bus_priv->common_data.core_index = soc_info->index; diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index 39d8fa561590efb0c8524cd6fdb1468138203e87..7d267fc000f7e4af387e4108aec2180ae9545619 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -203,6 +203,7 @@ struct cam_vfe_bus_ver2_reg_data { struct cam_vfe_bus_ver2_hw_info { struct cam_vfe_bus_ver2_reg_offset_common common_reg; uint32_t num_client; + uint32_t is_lite; struct cam_vfe_bus_ver2_reg_offset_bus_client bus_client_reg[CAM_VFE_BUS_VER2_MAX_CLIENTS]; struct cam_vfe_bus_ver2_reg_offset_comp_grp diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 13b588fe34d12e93da6daae9eec4530c63eb5fd4..3ed45ee530e8683fed33e733432dadc6caaf4a36 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -422,6 +422,40 @@ static int cam_vfe_camif_reg_dump_bh( return 0; } +static int cam_vfe_camif_irq_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments\n"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + CAM_ERR(CAM_ISP, "Error! Invalid state\n"); + return 0; + } + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + soc_private = camif_priv->soc_info->soc_private; + + CAM_INFO(CAM_ISP, + "Core Id =%d Mask reg: offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + 0x5c, cam_io_r_mb(camif_priv->mem_base + 0x5c), + 0x60, cam_io_r_mb(camif_priv->mem_base + 0x60)); + CAM_INFO(CAM_ISP, + "Core Id =%d Status reg: offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + 0x6c, cam_io_r_mb(camif_priv->mem_base + 0x6c), + 0x70, cam_io_r_mb(camif_priv->mem_base + 0x70)); + return rc; +} + static int cam_vfe_camif_resource_stop( struct cam_isp_resource_node *camif_res) { @@ -509,6 +543,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_camif_irq_reg_dump(rsrc_node); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 4dcad9cfc5d03dfafa15c5859b31589a93511d77..d512128b28e56644f24f4dad110573971e194125 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -438,6 +438,19 @@ static int cam_vfe_top_mux_get_reg_update( return -EINVAL; } +static int cam_vfe_get_irq_register_dump( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, cmd_args, arg_size); + + return 0; +} + int cam_vfe_top_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -723,6 +736,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_BW_CONTROL: rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_get_irq_register_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); diff --git a/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 9e4578d294d8c22b38154e070176bf979b661890..9ea8e3f5b7d1c3907f12c64628cea4086fef8207 100644 --- a/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -157,6 +157,12 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) cmd_buf_kaddr = (uint32_t *)kaddr; + if ((p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset / + sizeof(uint32_t)) >= cmd_buf_len) { + CAM_ERR(CAM_JPEG, "Not enough buf"); + return -EINVAL; + } + cmd_buf_kaddr = (cmd_buf_kaddr + (p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset diff --git a/drivers/media/platform/msm/ais/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/ais/cam_req_mgr/cam_req_mgr_dev.c index 5cf1d844f5e2a9314f119851092b61f3113ca2a4..5e800ae8c5aadd9b83425e1310c960798269c361 100644 --- a/drivers/media/platform/msm/ais/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/ais/cam_req_mgr/cam_req_mgr_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -103,10 +103,6 @@ static int cam_req_mgr_open(struct file *filep) int rc; mutex_lock(&g_dev.cam_lock); - if (g_dev.open_cnt >= 1) { - rc = -EALREADY; - goto end; - } rc = v4l2_fh_open(filep); if (rc) { @@ -114,11 +110,18 @@ static int cam_req_mgr_open(struct file *filep) goto end; } + g_dev.open_cnt++; + + /* return if already initialized before */ + if (g_dev.open_cnt > 1) { + CAM_ERR(CAM_CRM, "Already opened", rc); + goto end; + } + spin_lock_bh(&g_dev.cam_eventq_lock); g_dev.cam_eventq = filep->private_data; spin_unlock_bh(&g_dev.cam_eventq_lock); - g_dev.open_cnt++; rc = cam_mem_mgr_init(); if (rc) { g_dev.open_cnt--; @@ -165,27 +168,34 @@ static int cam_req_mgr_close(struct file *filep) return -EINVAL; } - cam_req_mgr_handle_core_shutdown(); + g_dev.open_cnt--; - list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) - continue; - if (sd->internal_ops && sd->internal_ops->close) { - CAM_DBG(CAM_CRM, "Invoke subdev close for device %s", - sd->name); - sd->internal_ops->close(sd, subdev_fh); + if (g_dev.open_cnt == 0) { + cam_req_mgr_handle_core_shutdown(); + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + continue; + if (sd->internal_ops && sd->internal_ops->close) { + CAM_DBG(CAM_CRM, + "Invoke subdev close for device %s", + sd->name); + sd->internal_ops->close(sd, subdev_fh); + } } } - g_dev.open_cnt--; v4l2_fh_release(filep); - spin_lock_bh(&g_dev.cam_eventq_lock); - g_dev.cam_eventq = NULL; - spin_unlock_bh(&g_dev.cam_eventq_lock); + if (g_dev.open_cnt == 0) { + spin_lock_bh(&g_dev.cam_eventq_lock); + g_dev.cam_eventq = NULL; + spin_unlock_bh(&g_dev.cam_eventq_lock); + + cam_req_mgr_util_free_hdls(); + cam_mem_mgr_deinit(); + } - cam_req_mgr_util_free_hdls(); - cam_mem_mgr_deinit(); mutex_unlock(&g_dev.cam_lock); return 0; diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index ab83346c1f54c072603373c8f2dd24e2fa0df12f..a8088caa73e010673182fc354e7fbf2c377fa259 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -232,13 +232,18 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, csiphy_dev->csiphy_info.csiphy_3phase = cam_cmd_csiphy_info->csiphy_3phase; csiphy_dev->csiphy_info.combo_mode |= cam_cmd_csiphy_info->combo_mode; - if (cam_cmd_csiphy_info->combo_mode == 1) + if (cam_cmd_csiphy_info->combo_mode == 1) { csiphy_dev->csiphy_info.settle_time_combo_sensor = cam_cmd_csiphy_info->settle_time; - else + csiphy_dev->csiphy_info.data_rate_combo_sensor = + cam_cmd_csiphy_info->data_rate; + } else { csiphy_dev->csiphy_info.settle_time = cam_cmd_csiphy_info->settle_time; - csiphy_dev->csiphy_info.data_rate = cam_cmd_csiphy_info->data_rate; + csiphy_dev->csiphy_info.data_rate = + cam_cmd_csiphy_info->data_rate; + } + if (cam_cmd_csiphy_info->secure_mode == 1) cam_csiphy_update_secure_info(csiphy_dev, @@ -269,6 +274,65 @@ void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev) csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); } +void cam_csiphy_cphy_data_rate_config(struct csiphy_device *csiphy_device) +{ + int i = 0, j = 0; + uint64_t phy_data_rate = 0; + void __iomem *csiphybase = NULL; + ssize_t num_table_entries = 0; + struct data_rate_settings_t *settings_table = NULL; + + if ((csiphy_device == NULL) || + (csiphy_device->ctrl_reg == NULL) || + (csiphy_device->ctrl_reg->data_rates_settings_table == NULL)) { + CAM_DBG(CAM_CSIPHY, + "Data rate specific register table not found"); + return; + } + + phy_data_rate = csiphy_device->csiphy_info.data_rate; + csiphybase = + csiphy_device->soc_info.reg_map[0].mem_base; + settings_table = + csiphy_device->ctrl_reg->data_rates_settings_table; + num_table_entries = + settings_table->num_data_rate_settings; + + CAM_DBG(CAM_CSIPHY, "required data rate : %llu", phy_data_rate); + for (i = 0; i < num_table_entries; i++) { + struct data_rate_reg_info_t *drate_settings = + settings_table->data_rate_settings; + uint64_t bandwidth = + drate_settings[i].bandwidth; + ssize_t num_reg_entries = + drate_settings[i].data_rate_reg_array_size; + + if (phy_data_rate > bandwidth) { + CAM_DBG(CAM_CSIPHY, + "Skipping table [%d] %llu required: %llu", + i, bandwidth, phy_data_rate); + continue; + } + + CAM_DBG(CAM_CSIPHY, + "table[%d] BW : %llu Selected", i, bandwidth); + for (j = 0; j < num_reg_entries; j++) { + uint32_t reg_addr = + drate_settings[i].csiphy_data_rate_regs[j].reg_addr; + + uint32_t reg_data = + drate_settings[i].csiphy_data_rate_regs[j].reg_data; + + CAM_DBG(CAM_CSIPHY, + "writing reg : %x val : %x", + reg_addr, reg_data); + cam_io_w_mb(reg_data, + csiphybase + reg_addr); + } + break; + } +} + void cam_csiphy_cphy_irq_disable(struct csiphy_device *csiphy_dev) { int32_t i; @@ -475,6 +539,9 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) lane_pos++; } + if (csiphy_dev->csiphy_info.csiphy_3phase) + cam_csiphy_cphy_data_rate_config(csiphy_dev); + cam_csiphy_cphy_irq_config(csiphy_dev); return rc; diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 51cf9e953a4145347a74a66e80fe93a420bc58a0..cf81924d970a0377a5cd45bcb6f459d2252d2400 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -44,8 +44,10 @@ #define MAX_CSIPHY_REG_ARRAY 70 #define MAX_CSIPHY_CMN_REG_ARRAY 5 -#define MAX_LANES 5 -#define MAX_SETTINGS_PER_LANE 43 +#define MAX_LANES 5 +#define MAX_SETTINGS_PER_LANE 43 +#define MAX_DATA_RATES 3 +#define MAX_DATA_RATE_REGS 30 #define MAX_REGULATOR 5 #define CAMX_CSIPHY_DEV_NAME "cam-csiphy-driver" @@ -155,6 +157,32 @@ struct csiphy_reg_t { uint32_t csiphy_param_type; }; +struct csiphy_device; + +/* + * struct data_rate_reg_info_t + * @bandwidth: max bandwidth supported by this reg settings + * @data_rate_reg_array_size: number of reg value pairs in the array + * @csiphy_data_rate_regs: array of data rate specific reg value pairs + */ +struct data_rate_reg_info_t { + uint64_t bandwidth; + ssize_t data_rate_reg_array_size; + struct csiphy_reg_t csiphy_data_rate_regs[MAX_DATA_RATE_REGS]; +}; + +/** + * struct data_rate_settings_t + * @num_data_rate_settings: number of valid settings + * present in the data rate settings array + * @data_rate_settings: array of regsettings which are specific to + * data rate + */ +struct data_rate_settings_t { + ssize_t num_data_rate_settings; + struct data_rate_reg_info_t data_rate_settings[MAX_DATA_RATES]; +}; + /** * struct csiphy_ctrl_t * @csiphy_reg: Register address @@ -166,6 +194,12 @@ struct csiphy_reg_t { * @csiphy_3ph_reg: 3phase register set * @csiphy_2ph_3ph_mode_reg: * 2 phase 3phase combo register set + * @getclockvoting: function pointer which + * is used to find the clock voting + * for the sensor output data rate + * @data_rate_settings_table: + * Table which maintains the resgister + * settings specific to data rate */ struct csiphy_ctrl_t { struct csiphy_reg_parms_t csiphy_reg; @@ -176,6 +210,8 @@ struct csiphy_ctrl_t { struct csiphy_reg_t (*csiphy_2ph_combo_mode_reg)[MAX_SETTINGS_PER_LANE]; struct csiphy_reg_t (*csiphy_3ph_reg)[MAX_SETTINGS_PER_LANE]; struct csiphy_reg_t (*csiphy_2ph_3ph_mode_reg)[MAX_SETTINGS_PER_LANE]; + enum cam_vote_level (*getclockvoting)(struct csiphy_device *phy_dev); + struct data_rate_settings_t *data_rates_settings_table; }; /** @@ -190,6 +226,8 @@ struct csiphy_ctrl_t { * @settle_time : Settling time in ms * @settle_time_combo_sensor : Settling time in ms * @data_rate : Data rate in mbps + * @data_rate_combo_sensor: data rate of combo sensor + * in the the same phy * */ struct cam_csiphy_param { @@ -202,6 +240,7 @@ struct cam_csiphy_param { uint64_t settle_time; uint64_t settle_time_combo_sensor; uint64_t data_rate; + uint64_t data_rate_combo_sensor; }; /** diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 0902601cebd57dc8c1f030bf65a8c800a92c21cf..0bf5aac2f0900ae7cd25b54f4cfa99350f46a64f 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,9 @@ #include "include/cam_csiphy_1_2_hwreg.h" #include "include/cam_csiphy_2_0_hwreg.h" +#define CSIPHY_3PH_DIVISOR 16 +#define CSIPHY_3PH_DIVISOR_12 32 +#define CSIPHY_2PH_DIVISOR 8 #define BYTES_PER_REGISTER 4 #define NUM_REGISTER_PER_LINE 4 #define REG_OFFSET(__start, __i) ((__start) + ((__i) * BYTES_PER_REGISTER)) @@ -79,10 +82,62 @@ int32_t cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info) return rc; } +enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) +{ + CAM_DBG(CAM_CSIPHY, "voting for SVS"); + return CAM_SVS_VOTE; +} + +enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) +{ + uint32_t cam_vote_level = 0; + uint32_t last_valid_vote = 0; + struct cam_hw_soc_info *soc_info; + uint64_t phy_data_rate = csiphy_dev->csiphy_info.data_rate; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->is_acquired_dev_combo_mode) + phy_data_rate = max(phy_data_rate, + csiphy_dev->csiphy_info.data_rate_combo_sensor); + + if (csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->is_csiphy_3phase_hw == CSI_3PHASE_HW_12) + do_div(phy_data_rate, CSIPHY_3PH_DIVISOR_12); + else + do_div(phy_data_rate, CSIPHY_3PH_DIVISOR); + } else { + do_div(phy_data_rate, CSIPHY_2PH_DIVISOR); + } + + /* round off to next integer */ + phy_data_rate += 1; + + for (cam_vote_level = 0; + cam_vote_level < CAM_MAX_VOTE; cam_vote_level++) { + if (soc_info->clk_level_valid[cam_vote_level] != true) + continue; + + if (soc_info->clk_rate[cam_vote_level][0] > + phy_data_rate) { + CAM_DBG(CAM_CSIPHY, + "match detected %s : %llu:%d level : %d", + soc_info->clk_name[0], + phy_data_rate, + soc_info->clk_rate[cam_vote_level][0], + cam_vote_level); + return cam_vote_level; + } + last_valid_vote = cam_vote_level; + } + return last_valid_vote; +} + int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) { int32_t rc = 0; struct cam_hw_soc_info *soc_info; + enum cam_vote_level vote_level = CAM_SVS_VOTE; soc_info = &csiphy_dev->soc_info; @@ -92,8 +147,9 @@ int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) return rc; } + vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev); rc = cam_soc_util_enable_platform_resource(soc_info, true, - CAM_SVS_VOTE, ENABLE_IRQ); + vote_level, ENABLE_IRQ); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "failed to enable platform resources %d", rc); @@ -174,9 +230,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_1_0; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_0; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->hw_version = CSIPHY_VERSION_V10; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v1.1")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_1_reg; @@ -191,9 +249,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_1; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_1; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->hw_version = CSIPHY_VERSION_V11; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v1.2")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; @@ -206,10 +266,13 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_common_reg_1_2; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; - csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW_12; csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table; } 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; @@ -221,9 +284,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, 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->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->hw_version = CSIPHY_VERSION_V20; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else { CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", csiphy_dev->hw_version); diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index 68ca68ced31b6466a13cbe92858e699c0f6e567a..64d05616d2e309f008f32075f6d96cab557e583a 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -34,6 +34,7 @@ #define CDBG(fmt, args...) pr_debug(fmt, ##args) #define CSI_3PHASE_HW 1 +#define CSI_3PHASE_HW_12 0x12 #define CSIPHY_VERSION_V35 0x35 #define CSIPHY_VERSION_V10 0x10 #define CSIPHY_VERSION_V11 0x11 diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 945910e96a55b4d864919b3d1580d3bb2ed46ea5..67653e81fde123570822b17afb340ea1cb929c41 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -19,10 +19,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 4, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 21, - .csiphy_3ph_config_array_size = 31, + .csiphy_3ph_config_array_size = 38, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -30,8 +30,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { struct csiphy_reg_t csiphy_common_reg_1_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { @@ -297,7 +299,7 @@ struct csiphy_reg_t struct csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { - {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -305,10 +307,10 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -321,27 +323,34 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0144, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -354,16 +363,23 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0344, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB0, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -371,10 +387,10 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -387,14 +403,107 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0544, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB0, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; +struct data_rate_settings_t data_rate_delta_table = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 12, + .csiphy_data_rate_regs = { + {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; #endif /* _CAM_CSIPHY_1_2_HWREG_H_ */ diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index faece709dea41d4d299dfa80817d9396ae2063a1..3683fc73501b7ea8ca03918bfb91af5303b7cd50 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -438,17 +438,32 @@ static int32_t cam_eeprom_parse_memory_map( else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) validate_size = sizeof(struct cam_cmd_unconditional_wait); - if (remain_buf_len < validate_size) { + if (remain_buf_len < validate_size || + *num_map >= (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { CAM_ERR(CAM_EEPROM, "not enough buffer"); return -EINVAL; } switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if (i2c_random_wr->header.count == 0 || + i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || + (size_t)*num_map >= ((MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE) - + i2c_random_wr->header.count)) { + CAM_ERR(CAM_EEPROM, "OOB Error"); + return -EINVAL; + } cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) + ((i2c_random_wr->header.count - 1) * sizeof(struct i2c_random_wr_payload)); + if (cmd_length_in_bytes > remain_buf_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer remaining"); + return -EINVAL; + } for (cnt = 0; cnt < (i2c_random_wr->header.count); cnt++) { map[*num_map + cnt].page.addr = @@ -471,6 +486,11 @@ static int32_t cam_eeprom_parse_memory_map( i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf; cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + if (i2c_cont_rd->header.count >= U32_MAX - data->num_data) { + CAM_ERR(CAM_EEPROM, + "int overflow on eeprom memory block"); + return -EINVAL; + } map[*num_map].mem.addr = i2c_cont_rd->reg_addr; map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type; map[*num_map].mem.data_type = i2c_cont_rd->header.data_type; diff --git a/drivers/media/platform/msm/ais/cam_sync/cam_sync.c b/drivers/media/platform/msm/ais/cam_sync/cam_sync.c index d3f62d6a3e20567719fd0086e3a6347c572f41f5..a1518e464884f0ac3c7d5253b5adcdded1345983 100644 --- a/drivers/media/platform/msm/ais/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/ais/cam_sync/cam_sync.c @@ -29,6 +29,20 @@ struct sync_device *sync_dev; */ static bool trigger_cb_without_switch; +void cam_sync_print_fence_table(void) +{ + int cnt; + + for (cnt = 0; cnt < CAM_SYNC_MAX_OBJS; cnt++) { + CAM_INFO(CAM_SYNC, "%d, %s, %d, %d, %d", + sync_dev->sync_table[cnt].sync_id, + sync_dev->sync_table[cnt].name, + sync_dev->sync_table[cnt].type, + sync_dev->sync_table[cnt].state, + sync_dev->sync_table[cnt].ref_cnt); + } +} + int cam_sync_create(int32_t *sync_obj, const char *name) { int rc; @@ -37,8 +51,15 @@ int cam_sync_create(int32_t *sync_obj, const char *name) do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); - if (idx >= CAM_SYNC_MAX_OBJS) + if (idx >= CAM_SYNC_MAX_OBJS) { + CAM_ERR(CAM_SYNC, + "Error: Unable to Create Sync Idx = %d Reached Max!!", + idx); + sync_dev->err_cnt++; + if (sync_dev->err_cnt == 1) + cam_sync_print_fence_table(); return -ENOMEM; + } CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx); bit = test_and_set_bit(idx, sync_dev->bitmap); } while (bit); @@ -418,9 +439,10 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) k_ioctl->size)) return -EFAULT; + mutex_lock(&sync_dev->table_lock); result = cam_sync_create(&sync_create.sync_obj, sync_create.name); - + mutex_unlock(&sync_dev->table_lock); if (!result) if (copy_to_user( u64_to_user_ptr(k_ioctl->ioctl_ptr), @@ -539,6 +561,7 @@ static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl) static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl) { struct cam_sync_info sync_create; + int rc; if (k_ioctl->size != sizeof(struct cam_sync_info)) return -EINVAL; @@ -551,7 +574,11 @@ static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl) k_ioctl->size)) return -EFAULT; - return cam_sync_destroy(sync_create.sync_obj); + mutex_lock(&sync_dev->table_lock); + rc = cam_sync_destroy(sync_create.sync_obj); + mutex_unlock(&sync_dev->table_lock); + + return rc; } static int cam_sync_handle_register_user_payload( @@ -765,22 +792,29 @@ static int cam_sync_open(struct file *filep) CAM_ERR(CAM_SYNC, "Sync device NULL"); return -ENODEV; } + sync_dev->err_cnt = 0; mutex_lock(&sync_dev->table_lock); - if (sync_dev->open_cnt >= 1) { - mutex_unlock(&sync_dev->table_lock); - return -EALREADY; - } rc = v4l2_fh_open(filep); - if (!rc) { - sync_dev->open_cnt++; - spin_lock_bh(&sync_dev->cam_sync_eventq_lock); - sync_dev->cam_sync_eventq = filep->private_data; - spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); - } else { - CAM_ERR(CAM_SYNC, "v4l2_fh_open failed : %d", rc); + if (rc) { + CAM_ERR(CAM_SYNC, "v4l2_fh_open failed: %d", rc); + goto end; } + + sync_dev->open_cnt++; + + /* return if already initialized before */ + if (sync_dev->open_cnt > 1) { + CAM_ERR(CAM_SYNC, "Already opened", rc); + goto end; + } + + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + sync_dev->cam_sync_eventq = filep->private_data; + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + +end: mutex_unlock(&sync_dev->table_lock); return rc; @@ -797,6 +831,7 @@ static int cam_sync_close(struct file *filep) rc = -ENODEV; return rc; } + sync_dev->err_cnt = 0; mutex_lock(&sync_dev->table_lock); sync_dev->open_cnt--; if (!sync_dev->open_cnt) { @@ -841,11 +876,13 @@ static int cam_sync_close(struct file *filep) i); } } + + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + sync_dev->cam_sync_eventq = NULL; + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); } mutex_unlock(&sync_dev->table_lock); - spin_lock_bh(&sync_dev->cam_sync_eventq_lock); - sync_dev->cam_sync_eventq = NULL; - spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + v4l2_fh_release(filep); return rc; @@ -972,6 +1009,7 @@ static int cam_sync_probe(struct platform_device *pdev) if (!sync_dev) return -ENOMEM; + sync_dev->err_cnt = 0; mutex_init(&sync_dev->table_lock); spin_lock_init(&sync_dev->cam_sync_eventq_lock); diff --git a/drivers/media/platform/msm/ais/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/ais/cam_sync/cam_sync_private.h index eb2fb34fc33c1980e321f50cd7ad2404b3c0a0c0..c3cb345a13fa2ad877f797575e455cc5c6cc6850 100644 --- a/drivers/media/platform/msm/ais/cam_sync/cam_sync_private.h +++ b/drivers/media/platform/msm/ais/cam_sync/cam_sync_private.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -184,6 +184,7 @@ struct cam_signalable_info { * @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 + * @err_cnt : Error counter to dump fence table */ struct sync_device { struct video_device *vdev; @@ -197,6 +198,7 @@ struct sync_device { struct v4l2_fh *cam_sync_eventq; spinlock_t cam_sync_eventq_lock; DECLARE_BITMAP(bitmap, CAM_SYNC_MAX_OBJS); + int err_cnt; }; 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 f79af9b0c71f3824a69b4a9c2282b30dcb9322f2..50c2d8d84b2488226492dd6a18deace130ea58c9 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 @@ -459,6 +459,17 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, "[%s][%d] : Moving req[%llu] from free_list to pending_list", ctx->dev_name, ctx->ctx_id, req->request_id); + for (j = 0; j < req->num_in_map_entries; j++) { + rc = cam_sync_check_valid( + req->in_map_entries[j].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, + "invalid in map sync object %d", + req->in_map_entries[j].sync_id); + goto put_ref; + } + } + for (j = 0; j < req->num_in_map_entries; j++) { cam_context_getref(ctx); rc = cam_sync_register_callback( @@ -480,7 +491,9 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id, req->request_id); - goto put_ctx_ref; + cam_context_putref(ctx); + goto put_ref; + } CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", req->in_map_entries[j].sync_id, rc); @@ -492,9 +505,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id); return rc; -put_ctx_ref: - for (j; j >= 0; j--) - cam_context_putref(ctx); + put_ref: for (--i; i >= 0; i--) { if (cam_sync_put_obj_ref(req->out_map_entries[i].sync_id)) @@ -578,7 +589,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, req_hdl_param.media_entity_flag = 0; req_hdl_param.priv = ctx; req_hdl_param.ops = ctx->crm_ctx_intf; - + req_hdl_param.dev_id = ctx->dev_id; ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { rc = -EFAULT; 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 a05901afba71c0365b0fa8ca0b78a79d27f0cb53..a68e20745b1aa575842d2a41c2b01b293569a885 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 @@ -568,7 +568,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( struct cam_cpas_axi_port *curr_axi_port = NULL; struct cam_cpas_axi_port *temp_axi_port = NULL; uint64_t required_camnoc_bw = 0; - int32_t clk_rate = 0; + int64_t clk_rate = 0; list_for_each_entry_safe(curr_axi_port, temp_axi_port, &cpas_core->axi_ports_list_head, sibling_port) { @@ -596,13 +596,13 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; - CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %lld", required_camnoc_bw, clk_rate); rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_CPAS, - "Failed in setting camnoc axi clk %llu %d %d", + "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); } @@ -980,8 +980,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, return -EINVAL; } - if (!CAM_CPAS_CLIENT_VALID(client_indx)) + if (!CAM_CPAS_CLIENT_VALID(client_indx)) { + CAM_ERR(CAM_CPAS, "Client index invalid %d", client_indx); return -EINVAL; + } mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); @@ -1099,8 +1101,10 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, cmd_hw_stop = (struct cam_cpas_hw_cmd_stop *)stop_args; client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_stop->client_handle); - if (!CAM_CPAS_CLIENT_VALID(client_indx)) + if (!CAM_CPAS_CLIENT_VALID(client_indx)) { + CAM_ERR(CAM_CPAS, "Client index invalid %d", client_indx); return -EINVAL; + } mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); @@ -1162,14 +1166,20 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, ahb_vote.vote.level = CAM_SUSPEND_VOTE; rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, &ahb_vote, NULL); - if (rc) + if (rc) { + CAM_ERR(CAM_CPAS, "ahb vote failed for %s rc %d", + cpas_client->data.identifier, rc); goto done; + } axi_vote.uncompressed_bw = 0; axi_vote.compressed_bw = 0; axi_vote.compressed_bw_ab = 0; rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); + if (rc) + CAM_ERR(CAM_CPAS, "axi vote failed for %s rc %d", + cpas_client->data.identifier, rc); done: mutex_unlock(&cpas_core->client_mutex[client_indx]); @@ -1234,6 +1244,13 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, rc = cam_common_util_get_string_index(soc_private->client_name, soc_private->num_clients, client_name, &client_indx); + if (rc) { + CAM_ERR(CAM_CPAS, "No match found for client %s", + client_name); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; + } + mutex_lock(&cpas_core->client_mutex[client_indx]); if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) || 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 aa970f83424df2d240f7cf5326bfee05f4635405..a21803ee59457382583eb35de140fa9b24df1afd 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -406,6 +406,12 @@ static void cam_cpastop_work(struct work_struct *work) return; } + mutex_lock(&cpas_hw->hw_mutex); + if (cpas_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_CPAS, "CPAS CORE is off"); + mutex_unlock(&cpas_hw->hw_mutex); + return; + } for (i = 0; i < camnoc_info->irq_err_size; i++) { if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) && (camnoc_info->irq_err[i].enable)) { @@ -451,6 +457,7 @@ static void cam_cpastop_work(struct work_struct *work) ~camnoc_info->irq_err[i].sbm_port; } } + mutex_unlock(&cpas_hw->hw_mutex); atomic_dec(&cpas_core->irq_count); wake_up(&cpas_core->irq_count_wq); CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); 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 8a84c0ee7e99bf08a200b30b482d38f91614a1be..083041c21dffa57d4b832202f936c88dbc494462 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -206,10 +206,6 @@ static const struct of_device_id cam_fd_hw_dt_match[] = { .compatible = "qcom,fd501", .data = &cam_fd_wrapper200_core501_info, }, - { - .compatible = "qcom,fd501", - .data = &cam_fd_wrapper200_core501_info, - }, {} }; MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h index 311886ffd6da1bb372c651921ba55dcc9e1fba79..d60a25e8b925de9c8ce33695edcb57aee02cbcd5 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -215,6 +215,27 @@ #define HFI_DEV_VERSION_MAX 0x5 +/* General errors and HFI Specific errors. */ +enum hfi_errors { + CAMERAICP_SUCCESS, + CAMERAICP_EFAILED, + CAMERAICP_ENOMEMORY, + CAMERAICP_EBADSTATE, + CAMERAICP_EBADPARM, + CAMERAICP_EBADITEM, + CAMERAICP_EINVALIDFORMAT, + CAMERAICP_EUNSUPPORTED, + CAMERAICP_EOUTOFBOUND, + CAMERAICP_ETIMEDOUT, + CAMERAICP_EABORTED, + CAMERAICP_EHWVIOLATION, + CAMERAICP_ECDMERROR, + CAMERAICP_HFI_ERR_COMMAND_SIZE = 1000, + CAMERAICP_HFI_ERR_MESSAGE_SIZE, + CAMERAICP_HFI_QUEUE_EMPTY, + CAMERAICP_HFI_QUEUE_FULL, +}; + /** * start of sys command packet types * These commands are used to get system level information diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c index e13d7f2edceed4e9c20d329e82b68a41df6a9726..4dbc8f1bd991392ef424cc64edac172b2a78f14d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c @@ -464,7 +464,11 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ICP_A5_CMD_CPAS_STOP: if (core_info->cpas_start) { - cam_cpas_stop(core_info->cpas_handle); + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) { + CAM_ERR(CAM_ICP, "cpas stop failed %d", rc); + return rc; + } core_info->cpas_start = false; } break; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c index c94276ce877848dc844d56af60c0848795bf276c..f522f713876583ed8a8a35d96f796b8846563d82 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c @@ -347,7 +347,11 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ICP_BPS_CMD_CPAS_STOP: if (core_info->cpas_start) { - cam_cpas_stop(core_info->cpas_handle); + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) { + CAM_ERR(CAM_ICP, "cpas stop failed %d", rc); + return rc; + } core_info->cpas_start = false; } break; 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 eec56c74d8161a0355c68de7bcc91409e996d7a4..370768a0609daab7fac2cd0ced056652fe449534 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 @@ -1601,7 +1601,69 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) return 0; } +static const char *cam_icp_error_handle_id_to_type( + uint32_t error_handle) +{ + const char *name = NULL; + switch (error_handle) { + case CAMERAICP_SUCCESS: + name = "SUCCESS"; + break; + case CAMERAICP_EFAILED: + name = "EFAILED"; + break; + case CAMERAICP_ENOMEMORY: + name = "ENOMEMORY"; + break; + case CAMERAICP_EBADSTATE: + name = "EBADSTATE"; + break; + case CAMERAICP_EBADPARM: + name = "EBADPARM"; + break; + case CAMERAICP_EBADITEM: + name = "EBADITEM"; + break; + case CAMERAICP_EINVALIDFORMAT: + name = "EINVALIDFORMAT"; + break; + case CAMERAICP_EUNSUPPORTED: + name = "EUNSUPPORTED"; + break; + case CAMERAICP_EOUTOFBOUND: + name = "EOUTOFBOUND"; + break; + case CAMERAICP_ETIMEDOUT: + name = "ETIMEDOUT"; + break; + case CAMERAICP_EABORTED: + name = "EABORTED"; + break; + case CAMERAICP_EHWVIOLATION: + name = "EHWVIOLATION"; + break; + case CAMERAICP_ECDMERROR: + name = "ECDMERROR"; + break; + case CAMERAICP_HFI_ERR_COMMAND_SIZE: + name = "HFI_ERR_COMMAND_SIZE"; + break; + case CAMERAICP_HFI_ERR_MESSAGE_SIZE: + name = "HFI_ERR_MESSAGE_SIZE"; + break; + case CAMERAICP_HFI_QUEUE_EMPTY: + name = "HFI_QUEUE_EMPTY"; + break; + case CAMERAICP_HFI_QUEUE_FULL: + name = "HFI_QUEUE_FULL"; + break; + default: + name = NULL; + break; + } + return name; +} static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) { struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; @@ -1614,8 +1676,11 @@ static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) { - CAM_ERR(CAM_ICP, "failed with error : %u", - ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, + "failed with err_no= [%u] err_type= [%s]", + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); cam_icp_mgr_handle_frame_process(msg_ptr, ICP_FRAME_PROCESS_FAILURE); return -EIO; @@ -1655,8 +1720,12 @@ static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) ipe_config_ack = (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); if (ipe_config_ack->rc) { - CAM_ERR(CAM_ICP, "rc = %d err = %u", - ipe_config_ack->rc, ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, "rc = %d failed with\n" + "err_no = [%u] err_type = [%s]", + ipe_config_ack->rc, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); return -EIO; } ctx_data = (struct cam_icp_hw_ctx_data *) @@ -1821,9 +1890,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, "received IPE/BPS\n" + "MAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; @@ -1831,9 +1904,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, + "received IPE/BPS UNMAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; default: CAM_ERR(CAM_ICP, "Invalid opcode : %u", @@ -4004,8 +4081,13 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, for (i = 0; i < packet->num_io_configs; i++) { for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { - if (!io_cfg[i].mem_handle[j]) + if (!io_cfg[i].mem_handle[j]) { + CAM_ERR(CAM_ICP, + "Mem Handle %d is NULL for %d io config", + j, i); break; + } + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == GET_FD_FROM_HANDLE(pf_buf_info)) { @@ -4613,6 +4695,13 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return -EFAULT; } + /* To make sure num_out_res is same as allocated */ + if (ctx_data->icp_dev_acquire_info->num_out_res != + icp_dev_acquire_info.num_out_res) { + CAM_ERR(CAM_ICP, "num_out_res got changed"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x", ctx_data->icp_dev_acquire_info->dev_type, ctx_data->icp_dev_acquire_info->in_res.format, diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c index ae3d1343c1c44e88e92ade2e2b5176e8b0eec430..ae58b34062d6f2552378013c4ffb711db08688b5 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -342,7 +342,11 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ICP_IPE_CMD_CPAS_STOP: if (core_info->cpas_start) { - cam_cpas_stop(core_info->cpas_handle); + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) { + CAM_ERR(CAM_ICP, "CPAS stop failed %d", rc); + return rc; + } core_info->cpas_start = false; } break; 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 43e08611cd18aa8ffa402ea4bc234ab6fdcb98c9..0d0ce4210ae4734591db3322266180de9b436864 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 @@ -38,18 +38,26 @@ static int cam_isp_context_dump_active_request(void *data, unsigned long iova, static void __cam_isp_ctx_update_state_monitor_array( struct cam_isp_context *ctx_isp, - enum cam_isp_state_change_trigger trigger_type, - uint32_t req_id) + enum cam_isp_hw_event_type hw_event, + enum cam_isp_ctx_activated_substate curr_state, + enum cam_isp_ctx_activated_substate next_state) { int iterator = 0; iterator = INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head); ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = - ctx_isp->substate_activated; - ctx_isp->cam_isp_ctx_state_monitor[iterator].trigger = - trigger_type; - ctx_isp->cam_isp_ctx_state_monitor[iterator].req_id = - req_id; + curr_state; + ctx_isp->cam_isp_ctx_state_monitor[iterator].next_state = + next_state; + ctx_isp->cam_isp_ctx_state_monitor[iterator].hw_event = + hw_event; + ctx_isp->cam_isp_ctx_state_monitor[iterator].last_reported_id = + ctx_isp->req_info.reported_req_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].last_applied_req_id = + ctx_isp->req_info.last_applied_req_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].frame_id = + ctx_isp->frame_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].evt_time_stamp = jiffies_to_msecs(jiffies); } @@ -79,17 +87,17 @@ static const char *__cam_isp_hw_evt_val_to_type( uint32_t evt_id) { switch (evt_id) { - case CAM_ISP_STATE_CHANGE_TRIGGER_ERROR: + case CAM_ISP_HW_EVENT_ERROR: return "ERROR"; - case CAM_ISP_STATE_CHANGE_TRIGGER_SOF: + case CAM_ISP_HW_EVENT_SOF: return "SOF"; - case CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE: + case CAM_ISP_HW_EVENT_REG_UPDATE: return "REG_UPDATE"; - case CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH: + case CAM_ISP_HW_EVENT_EPOCH: return "EPOCH"; - case CAM_ISP_STATE_CHANGE_TRIGGER_EOF: + case CAM_ISP_HW_EVENT_EOF: return "EOF"; - case CAM_ISP_STATE_CHANGE_TRIGGER_DONE: + case CAM_ISP_HW_EVENT_DONE: return "DONE"; default: return "CAM_ISP_EVENT_INVALID"; @@ -97,29 +105,58 @@ static const char *__cam_isp_hw_evt_val_to_type( } static void __cam_isp_ctx_dump_state_monitor_array( - struct cam_isp_context *ctx_isp) + struct cam_isp_context *ctx_isp, bool log_rate_limit) { int i = 0; uint64_t state_head = 0; uint64_t index; + struct cam_isp_context_state_monitor *ctx_monitor; state_head = atomic64_read(&ctx_isp->state_monitor_head); - CAM_ERR_RATE_LIMIT(CAM_ISP, - "Dumping state information for preceding requests"); + + ctx_monitor = ctx_isp->cam_isp_ctx_state_monitor; + + if (log_rate_limit) + CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + "Dumping state information for preceding requests"); + else + CAM_INFO(CAM_ISP, + "Dumping state information for preceding requests"); for (i = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES - 1; i >= 0; i--) { index = (((state_head - i) + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) % CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES); - CAM_ERR_RATE_LIMIT(CAM_ISP, - "time[0x%llx] req_id[%u] state[%s] evt_type[%s]", - ctx_isp->cam_isp_ctx_state_monitor[index].evt_time_stamp, - ctx_isp->cam_isp_ctx_state_monitor[index].req_id, - __cam_isp_ctx_substate_val_to_type( - ctx_isp->cam_isp_ctx_state_monitor[index].curr_state), - __cam_isp_hw_evt_val_to_type( - ctx_isp->cam_isp_ctx_state_monitor[index].trigger)); + + if (log_rate_limit) { + CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + "time[%lld] last reported req_id[%u] frame id[%lld] applied id[%lld] current state[%s] next state[%s] hw_event[%s]", + ctx_monitor[index].evt_time_stamp, + ctx_monitor[index].last_reported_id, + ctx_monitor[index].frame_id, + ctx_monitor[index].last_applied_req_id, + __cam_isp_ctx_substate_val_to_type( + ctx_monitor[index].curr_state), + __cam_isp_ctx_substate_val_to_type( + ctx_monitor[index].next_state), + __cam_isp_hw_evt_val_to_type( + ctx_monitor[index].hw_event)); + + } else { + CAM_INFO(CAM_ISP, + "time[%lld] last reported req_id[%u] frame id[%lld] applied id[%lld] current state[%s] next state[%s] hw_event[%s]", + ctx_monitor[index].evt_time_stamp, + ctx_monitor[index].last_reported_id, + ctx_monitor[index].frame_id, + ctx_monitor[index].last_applied_req_id, + __cam_isp_ctx_substate_val_to_type( + ctx_monitor[index].curr_state), + __cam_isp_ctx_substate_val_to_type( + ctx_monitor[index].next_state), + __cam_isp_hw_evt_val_to_type( + ctx_monitor[index].hw_event)); + } } } @@ -403,7 +440,7 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( struct cam_context *ctx = ctx_isp->base; if (list_empty(&ctx->active_req_list)) { - CAM_DBG(CAM_ISP, "Buf done with no active request!"); + CAM_WARN(CAM_ISP, "Buf done with no active request!"); goto end; } @@ -508,6 +545,10 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_DBG(CAM_REQ, "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_HW_EVENT_DONE, + ctx_isp->substate_activated, + ctx_isp->substate_activated); } else { list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); @@ -515,32 +556,39 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + ctx_isp->req_info.last_bufdone_req_id = req->request_id; + ctx_isp->req_info.last_bufdone_time_stamp = + jiffies_to_msecs(jiffies); + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_HW_EVENT_DONE, + ctx_isp->substate_activated, + ctx_isp->substate_activated); } end: - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_DONE, - ctx_isp->base->req_list->request_id); return rc; } static void __cam_isp_ctx_send_sof_boot_timestamp( struct cam_isp_context *ctx_isp, uint64_t request_id, - uint32_t sof_event_status) + uint32_t sof_event_status, uint64_t delta_ts) { struct cam_req_mgr_message req_msg; req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; req_msg.u.frame_msg.request_id = request_id; - req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.frame_msg.sof_status = sof_event_status; + req_msg.u.frame_msg.timestamp = ctx_isp->prev_boot_timestamp + delta_ts; + CAM_DBG(CAM_ISP, - "request id:%lld frame number:%lld boot time stamp:0x%llx", - request_id, ctx_isp->frame_id, - ctx_isp->boot_timestamp); + "req id:%lld frame num:%lld bt_ts:0x%llx pre_bt_ts:0x%llx diff:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->boot_timestamp, ctx_isp->prev_boot_timestamp, + delta_ts); + if (cam_req_mgr_notify_message(&req_msg, V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS, @@ -548,6 +596,8 @@ static void __cam_isp_ctx_send_sof_boot_timestamp( CAM_ERR(CAM_ISP, "Error in notifying the boot time for req id:%lld", request_id); + + ctx_isp->prev_boot_timestamp = req_msg.u.frame_msg.timestamp; } @@ -556,6 +606,7 @@ static void __cam_isp_ctx_send_sof_timestamp( uint32_t sof_event_status) { struct cam_req_mgr_message req_msg; + uint64_t delta_ts; req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; @@ -565,9 +616,9 @@ static void __cam_isp_ctx_send_sof_timestamp( req_msg.u.frame_msg.sof_status = sof_event_status; CAM_DBG(CAM_ISP, - "request id:%lld frame number:%lld SOF time stamp:0x%llx", + "request id:%lld frame number:%lld SOF time stamp:0x%llx, Prev SOF time:0x%llx", request_id, ctx_isp->frame_id, - ctx_isp->sof_timestamp_val); + ctx_isp->sof_timestamp_val, ctx_isp->prev_sof_timestamp_val); CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status); if (cam_req_mgr_notify_message(&req_msg, @@ -575,9 +626,17 @@ static void __cam_isp_ctx_send_sof_timestamp( CAM_ERR(CAM_ISP, "Error in notifying the sof time for req id:%lld", request_id); + delta_ts = ctx_isp->sof_timestamp_val - + ctx_isp->prev_sof_timestamp_val; __cam_isp_ctx_send_sof_boot_timestamp(ctx_isp, - request_id, sof_event_status); + request_id, sof_event_status, + (ctx_isp->prev_sof_timestamp_val == 0) ? + ctx_isp->boot_timestamp : + delta_ts); + + ctx_isp->prev_sof_timestamp_val = + ctx_isp->sof_timestamp_val; } @@ -658,6 +717,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", @@ -665,9 +725,12 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( } list_for_each_entry(req, &ctx->active_req_list, list) { - if (req->request_id > ctx_isp->reported_req_id) { + if (req->request_id > + ctx_isp->req_info.reported_req_id) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); break; } } @@ -675,6 +738,17 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE) request_id = 0; + if (request_id && ctx_isp->req_info.reported_req_id && + ((request_id - ctx_isp->req_info.reported_req_id) > + 1)){ + CAM_INFO(CAM_ISP, + "ctx:%d curr req id: %u last reported id:%u", + ctx->ctx_id, request_id, + ctx_isp->req_info.reported_req_id); + + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); + } + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } else { @@ -742,8 +816,7 @@ static int __cam_isp_ctx_sof_in_activated_state( ctx_isp->frame_id++; ctx_isp->sof_timestamp_val = sof_event_data->timestamp; ctx_isp->boot_timestamp = sof_event_data->boot_time; - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u", ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id); @@ -778,11 +851,7 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, CAM_ERR(CAM_ISP, "receive rup in unexpected state"); } - if (req != NULL) { - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, - req->request_id); - } + end: return rc; } @@ -800,7 +869,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, * 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 wait request"); + CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; /* Send SOF event as empty frame*/ @@ -815,7 +885,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; - CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; @@ -842,9 +914,11 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); - if (req->request_id > ctx_isp->reported_req_id) { + if (req->request_id > ctx_isp->req_info.reported_req_id) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); } __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); @@ -853,15 +927,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: - if (request_id == 0) { - req = list_last_entry(&ctx->active_req_list, - struct cam_ctx_request, list); - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id); - } else { - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, request_id); - } + return 0; } @@ -884,7 +950,6 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, int rc = 0; struct cam_context *ctx = ctx_isp->base; struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; - struct cam_ctx_request *req; if (!evt_data) { CAM_ERR(CAM_ISP, "in valid sof event data"); @@ -900,12 +965,6 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, else CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); - req = list_last_entry(&ctx->active_req_list, - struct cam_ctx_request, list); - if (req) - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_SOF, - ctx->req_list->request_id); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); @@ -952,7 +1011,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( * If no pending req in epoch, this is an error case. * Just go back to the bubble state. */ - CAM_ERR(CAM_ISP, "No pending request."); + CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -964,6 +1024,9 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { @@ -992,9 +1055,11 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( list_add_tail(&req->list, &ctx->active_req_list); if (!req_isp->bubble_report) { - if (req->request_id > ctx_isp->reported_req_id) { + if (req->request_id > ctx_isp->req_info.reported_req_id) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); } else @@ -1007,11 +1072,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: - req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, - list); - if (req) - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id); + return 0; } @@ -1023,9 +1084,7 @@ static int __cam_isp_ctx_buf_done_in_bubble_applied( (struct cam_isp_hw_done_event_data *) evt_data; rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_DONE, - ctx_isp->base->req_list->request_id); + return rc; } @@ -1083,9 +1142,6 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, if (error_event_data->enable_reg_dump) cam_isp_ctx_dump_req(req_isp); - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); - list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) { req_isp = (struct cam_isp_ctx_req *) req->req_priv; @@ -1176,14 +1232,15 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, end: do { if (list_empty(&ctx->pending_req_list)) { - error_request_id = ctx_isp->last_applied_req_id + 1; + error_request_id = + ctx_isp->req_info.last_applied_req_id + 1; req_isp = NULL; break; } req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); req_isp = (struct cam_isp_ctx_req *) req->req_priv; - error_request_id = ctx_isp->last_applied_req_id; + error_request_id = ctx_isp->req_info.last_applied_req_id; if (req_isp->bubble_report) { req_to_report = req; @@ -1201,7 +1258,8 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); - } while (req->request_id < ctx_isp->last_applied_req_id); + } while (req->request_id < + ctx_isp->req_info.last_applied_req_id); if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { notify.link_hdl = ctx->link_hdl; @@ -1240,8 +1298,8 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, V4L_EVENT_CAM_REQ_MGR_EVENT)) CAM_ERR(CAM_ISP, "Error in notifying the error time for req id:%lld ctx %u", - ctx_isp->last_applied_req_id, - ctx->ctx_id); + ctx_isp->req_info.last_applied_req_id, + ctx->ctx_id); } ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR; } else { @@ -1278,8 +1336,7 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state( ctx_isp->frame_id++; ctx_isp->sof_timestamp_val = sof_event_data->timestamp; ctx_isp->boot_timestamp = sof_event_data->boot_time; - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", ctx_isp->frame_id, ctx_isp->sof_timestamp_val); @@ -1293,6 +1350,7 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -1300,9 +1358,12 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state( } list_for_each_entry(req, &ctx->active_req_list, list) { - if (req->request_id > ctx_isp->reported_req_id) { + if (req->request_id > + ctx_isp->req_info.reported_req_id) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); break; } } @@ -1343,8 +1404,10 @@ static int __cam_isp_ctx_fs2_buf_done(struct cam_isp_context *ctx_isp, CAM_DBG(CAM_ISP, "No request, move to SOF"); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - if (ctx_isp->reported_req_id < curr_req_id) { - ctx_isp->reported_req_id = curr_req_id; + if (ctx_isp->req_info.reported_req_id < curr_req_id) { + ctx_isp->req_info.reported_req_id = curr_req_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); __cam_isp_ctx_send_sof_timestamp(ctx_isp, curr_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -1402,11 +1465,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp, CAM_ERR(CAM_ISP, "receive rup in unexpected state"); } - if (req != NULL) { - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, - req->request_id); - } + end: return rc; } @@ -1451,9 +1510,12 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && ctx_isp->active_req_cnt <= 2) { list_for_each_entry(req, &ctx->active_req_list, list) { - if (req->request_id > ctx_isp->reported_req_id) { + if (req->request_id > + ctx_isp->req_info.reported_req_id) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); break; } } @@ -1466,6 +1528,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -1478,11 +1541,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: - if (req != NULL && !rc) { - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, - req->request_id); - } + return rc; } @@ -1729,19 +1788,19 @@ static int __cam_isp_ctx_apply_req_in_activated_state( } else { spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = next_state; - ctx_isp->last_applied_req_id = apply->request_id; + ctx_isp->req_info.last_applied_req_id = + apply->request_id; + ctx_isp->req_info.last_applied_time_stamp = + jiffies_to_msecs(jiffies); list_del_init(&req->list); list_add_tail(&req->list, &ctx->wait_req_list); CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld", - next_state, ctx_isp->last_applied_req_id); + next_state, + ctx_isp->req_info.last_applied_req_id); spin_unlock_bh(&ctx->lock); } end: - if (ctx_isp != NULL) { - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_SOF, - ctx->req_list->request_id); - } + return rc; } @@ -1875,6 +1934,23 @@ static int __cam_isp_ctx_flush_req_in_top_state( 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); + + if (!list_empty(&ctx->active_req_list)) { + CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + "ctx:%d last applied id:%lld, reported req id:%lld, buf done id:%lld", + ctx->ctx_id, + ctx_isp->req_info.last_applied_req_id, + ctx_isp->req_info.reported_req_id, + ctx_isp->req_info.last_bufdone_req_id); + CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + "current time:%lld last apply time:%lld, reported req time:%lld, buf done time:%lld", + jiffies_to_msecs(jiffies), + ctx_isp->req_info.last_applied_time_stamp, + ctx_isp->req_info.last_reported_id_time_stamp, + ctx_isp->req_info.last_bufdone_time_stamp); + + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); + } spin_unlock_bh(&ctx->lock); atomic_set(&ctx_isp->process_bubble, 0); @@ -2041,6 +2117,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -2133,8 +2210,10 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); - CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; @@ -2161,9 +2240,11 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( req->request_id, ctx_isp->active_req_cnt); if (!req_isp->bubble_report) { - if (req->request_id > ctx_isp->reported_req_id) { + if (req->request_id > ctx_isp->req_info.reported_req_id) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); } else @@ -2228,6 +2309,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -2298,6 +2380,7 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -2305,8 +2388,11 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( } else { CAM_ERR(CAM_ISP, "Can not notify SOF to CRM"); } - if (request_id) - ctx_isp->reported_req_id = request_id; + if (request_id) { + ctx_isp->req_info.reported_req_id = request_id; + ctx_isp->req_info.last_reported_id_time_stamp = + jiffies_to_msecs(jiffies); + } __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -2481,9 +2567,14 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx->last_flush_req = 0; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; - ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; + ctx_isp->req_info.reported_req_id = 0; + ctx_isp->req_info.last_applied_req_id = 0; + ctx_isp->req_info.last_bufdone_req_id = 0; + ctx_isp->req_info.last_applied_time_stamp = 0; + ctx_isp->req_info.last_bufdone_time_stamp = 0; + ctx_isp->req_info.last_reported_id_time_stamp = 0; /* * Ideally, we should never have any active request here. @@ -2538,11 +2629,16 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx->last_flush_req = 0; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; - ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; ctx_isp->rdi_only_context = false; ctx_isp->split_acquire = false; + ctx_isp->req_info.reported_req_id = 0; + ctx_isp->req_info.last_applied_req_id = 0; + ctx_isp->req_info.last_bufdone_req_id = 0; + ctx_isp->req_info.last_applied_time_stamp = 0; + ctx_isp->req_info.last_bufdone_time_stamp = 0; + ctx_isp->req_info.last_reported_id_time_stamp = 0; /* * Ideally, we should never have any active request here. @@ -2875,7 +2971,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, req_hdl_param.media_entity_flag = 0; req_hdl_param.ops = ctx->crm_ctx_intf; req_hdl_param.priv = ctx; - + req_hdl_param.dev_id = CAM_ISP; CAM_DBG(CAM_ISP, "get device handle form bridge"); ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { @@ -3169,7 +3265,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, atomic_set(&ctx_isp->process_bubble, 0); ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; - ctx_isp->reported_req_id = 0; + ctx_isp->req_info.reported_req_id = 0; ctx_isp->substate_activated = ctx_isp->rdi_only_context ? CAM_ISP_CTX_ACTIVATED_APPLIED : (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : @@ -3301,7 +3397,15 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( } ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; - ctx_isp->reported_req_id = 0; + ctx_isp->req_info.reported_req_id = 0; + ctx_isp->req_info.last_applied_req_id = 0; + ctx_isp->req_info.last_bufdone_req_id = 0; + ctx_isp->req_info.last_applied_time_stamp = 0; + ctx_isp->req_info.last_bufdone_time_stamp = 0; + ctx_isp->req_info.last_reported_id_time_stamp = 0; + ctx_isp->prev_sof_timestamp_val = 0; + ctx_isp->prev_boot_timestamp = 0; + atomic_set(&ctx_isp->process_bubble, 0); CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", @@ -3478,8 +3582,9 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx, rc = ctx_ops->crm_ops.apply_req(ctx, apply); } else { CAM_ERR_RATE_LIMIT(CAM_ISP, - "No handle function in activated substate %d", - ctx_isp->substate_activated); + "Ctx:%d No handle function in activated substate %d", + ctx->ctx_id, ctx_isp->substate_activated); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); rc = -EFAULT; } @@ -3500,22 +3605,27 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context, struct cam_context *ctx = (struct cam_context *)context; struct cam_isp_context *ctx_isp = (struct cam_isp_context *)ctx->ctx_priv; + enum cam_isp_ctx_activated_substate curr_state; spin_lock(&ctx->lock); trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id, __cam_isp_ctx_get_event_ts(evt_id, evt_data)); + curr_state = ctx_isp->substate_activated; CAM_DBG(CAM_ISP, "Enter: State %d, Substate %d, evt id %d", ctx->state, ctx_isp->substate_activated, evt_id); irq_ops = &ctx_isp->substate_machine_irq[ctx_isp->substate_activated]; if (irq_ops->irq_ops[evt_id]) { rc = irq_ops->irq_ops[evt_id](ctx_isp, evt_data); } else { - CAM_DBG(CAM_ISP, "No handle function for substate %d", - ctx_isp->substate_activated); - __cam_isp_ctx_dump_state_monitor_array(ctx_isp); + CAM_INFO(CAM_ISP, "Ctx:%d No handle function for substate %d", + ctx->ctx_id, ctx_isp->substate_activated); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); } + if (evt_id != CAM_ISP_HW_EVENT_DONE) + __cam_isp_ctx_update_state_monitor_array(ctx_isp, evt_id, + curr_state, ctx_isp->substate_activated); CAM_DBG(CAM_ISP, "Exit: State %d Substate %d", ctx->state, ctx_isp->substate_activated); @@ -3677,7 +3787,13 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->base = ctx_base; ctx->frame_id = 0; ctx->active_req_cnt = 0; - ctx->reported_req_id = 0; + ctx->req_info.reported_req_id = 0; + ctx->req_info.last_applied_req_id = 0; + ctx->req_info.last_bufdone_req_id = 0; + ctx->req_info.last_applied_time_stamp = 0; + ctx->req_info.last_bufdone_time_stamp = 0; + ctx->req_info.last_reported_id_time_stamp = 0; + ctx->hw_ctx = NULL; ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; ctx->substate_machine = cam_isp_ctx_activated_state_machine; diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h index 9bc6411011f976086dece3b048536e8a8461146b..a4f4e5ae0ee95cca74646f19b8c117eb35eb1b43 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -61,20 +61,6 @@ enum cam_isp_ctx_activated_substate { CAM_ISP_CTX_ACTIVATED_MAX, }; -/** - * enum cam_isp_state_change_trigger - Different types of ISP events - * - */ -enum cam_isp_state_change_trigger { - CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, - CAM_ISP_STATE_CHANGE_TRIGGER_SOF, - CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, - CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, - CAM_ISP_STATE_CHANGE_TRIGGER_EOF, - CAM_ISP_STATE_CHANGE_TRIGGER_DONE, - CAM_ISP_STATE_CHANGE_TRIGGER_MAX -}; - /** * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks * @@ -125,19 +111,46 @@ struct cam_isp_ctx_req { * debug purposes * *@curr_state: Current sub state that received req - *@req_type: Event type of incoming req - *@req_id: Request id - *@evt_time_stamp Current time stamp + *@next_state: Next sub state that received req + *@hw_event: Hw Event type of incoming req + *@last_reported_id: Last_reported_id to userspace + *@last_applied_req_id Last applied request id to hardware + *@frame_id: Current Frame id + *@evt_time_stamp Current time stamp of this event logged * */ struct cam_isp_context_state_monitor { enum cam_isp_ctx_activated_substate curr_state; - enum cam_isp_state_change_trigger trigger; - uint32_t req_id; + enum cam_isp_ctx_activated_substate next_state; + enum cam_isp_hw_event_type hw_event; + int64_t last_reported_id; + int64_t last_applied_req_id; int64_t frame_id; uint64_t evt_time_stamp; }; +/** + * struct cam_isp_context_req_id_info - ISP context request id + * information for last applied, reported and bufdone. + * + *@last_applied_req_id: Last applied request id + *@last_bufdone_req_id: Last bufdone request id + *@reported_req_id: Last reported request id to userspace + *@last_applied_time_stamp: Last applied request time stamp information + *@last_bufdone_time_stamp Last bufdone request time stamp information + *@last_reported_id_time_stamp: Last reported request time stamp information + * + */ + +struct cam_isp_context_req_id_info { + int64_t last_applied_req_id; + int64_t last_bufdone_req_id; + int64_t reported_req_id; + int64_t last_applied_time_stamp; + int64_t last_bufdone_time_stamp; + int64_t last_reported_id_time_stamp; + +}; /** * struct cam_isp_context - ISP context object * @@ -152,13 +165,15 @@ struct cam_isp_context_state_monitor { * @req_isp: ISP private request object storage * @hw_ctx: HW object returned by the acquire device command * @sof_timestamp_val: Captured time stamp value at sof hw event + * @prev_sof_timestamp_val Holds last notified sof time stamp * @boot_timestamp: Boot time stamp for a given req_id + * @prev_boot_timestamp Holds last notified boot time stamp * @active_req_cnt: Counter for the active request - * @reported_req_id: Last reported request id * @subscribe_event: The irq event mask that CRM subscribes to, IFE * will invoke CRM cb at those event. - * @last_applied_req_id: Last applied request id * @state_monitor_head: Write index to the state monitoring array + * @req_info Request id information about last applied, + * reported and buf done * @cam_isp_ctx_state_monitor: State monitoring array * @rdi_only_context: Get context type information. * true, if context is rdi only context @@ -181,14 +196,15 @@ struct cam_isp_context { void *hw_ctx; uint64_t sof_timestamp_val; + uint64_t prev_sof_timestamp_val; uint64_t boot_timestamp; + uint64_t prev_boot_timestamp; int32_t active_req_cnt; - int64_t reported_req_id; uint32_t subscribe_event; - int64_t last_applied_req_id; atomic64_t state_monitor_head; struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; + struct cam_isp_context_req_id_info req_info; bool rdi_only_context; bool hw_acquired; bool init_received; 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 5f23e87d1c3f79cadac0b208bfec9e3da46be55d..3b6d04a302ed8b327143a4dfa12c479fa43d9746 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 @@ -2637,7 +2637,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* Stop the master CSID path first */ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, - master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + master_base_idx, csid_halt_type); /* stop rest of the CSID paths */ for (i = 0; i < ctx->num_base; i++) { @@ -2647,7 +2647,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, i, master_base_idx); cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, - ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + ctx->base[i].idx, csid_halt_type); } CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); @@ -3575,6 +3575,38 @@ void fill_res_bitmap(uint32_t resource_type, unsigned long *res_bitmap) } } +static int cam_isp_blob_init_frame_drop( + struct cam_isp_init_frame_drop_config *frame_drop_cfg, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + uint32_t hw_idx = UINT_MAX; + uint32_t i; + int rc = 0; + + ctx = prepare->ctxt_to_hw_map; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_idx == hw_idx) + continue; + + rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_IFE_CSID_SET_INIT_FRAME_DROP, + frame_drop_cfg, + sizeof( + struct cam_isp_init_frame_drop_config *)); + hw_idx = hw_intf->hw_idx; + } + } + return rc; +} + static int cam_isp_packet_generic_blob_handler(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) { @@ -3709,10 +3741,33 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { - struct cam_isp_bw_config_ab *bw_config_ab = - (struct cam_isp_bw_config_ab *)blob_data; + struct cam_isp_bw_config_ab *bw_config_ab; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + if (blob_size < sizeof(struct cam_isp_bw_config_ab)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config_ab = (struct cam_isp_bw_config_ab *)blob_data; + + if (bw_config_ab->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config ab", + bw_config_ab->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + + (bw_config_ab->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %u", + blob_size, + sizeof(uint32_t) * 2 + + (bw_config_ab->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } CAM_DBG(CAM_ISP, "AB L:%lld R:%lld usage_type %d", bw_config_ab->left_pix_vote_ab, bw_config_ab->right_pix_vote_ab, @@ -3797,7 +3852,22 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP: { + struct cam_isp_init_frame_drop_config *frame_drop_cfg = + (struct cam_isp_init_frame_drop_config *)blob_data; + + if (blob_size < sizeof(struct cam_isp_init_frame_drop_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %u", + blob_size, + sizeof(struct cam_isp_init_frame_drop_config)); + return -EINVAL; + } + rc = cam_isp_blob_init_frame_drop(frame_drop_cfg, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Init Frame drop Update Failed"); + } + break; default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; @@ -4027,8 +4097,12 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, for (i = 0; i < packet->num_io_configs; i++) { for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { - if (!io_cfg[i].mem_handle[j]) + if (!io_cfg[i].mem_handle[j]) { + CAM_ERR(CAM_ISP, + "Mem Handle %d is NULL for %d io config", + j, i); break; + } if (pf_buf_info && GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == @@ -4191,45 +4265,44 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_hw_intf *hw_intf; struct cam_csid_get_time_stamp_args csid_get_time; - list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i]) - continue; + hw_mgr_res = list_first_entry(&ife_ctx->res_list_ife_csid, + struct cam_ife_hw_mgr_res, list); + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual vfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { /* - * Get the SOF time stamp from left resource only. - * Left resource is master for dual vfe case and - * Rdi only context case left resource only hold - * the RDI resource + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient */ - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf->hw_ops.process_cmd) { - /* - * Single VFE case, Get the time stamp from - * available one csid hw in the context - * Dual VFE case, get the time stamp from - * master(left) would be sufficient - */ - - csid_get_time.node_res = - hw_mgr_res->hw_res[i]; - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_IFE_CSID_CMD_GET_TIME_STAMP, - &csid_get_time, - sizeof( - struct cam_csid_get_time_stamp_args)); - if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { - *time_stamp = - csid_get_time.time_stamp_val; - *boot_time_stamp = - csid_get_time.boot_timestamp; - } + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof( + struct cam_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; } } } - if (rc) CAM_ERR(CAM_ISP, "Getting sof time stamp failed"); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 1b64913f091918eb7a1668c5b5b7f41fb799649a..8c38a3071608138616b7af8095122fa5120dfc4a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -473,6 +473,7 @@ int cam_isp_add_io_buffers( int32_t hdl; int mmu_hdl; bool mode, is_buf_secure; + uint64_t req_id; io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) &prepare->packet->payload + @@ -481,6 +482,7 @@ int cam_isp_add_io_buffers( num_in_buf = 0; io_cfg_used_bytes = 0; prepare->pf_data->packet = prepare->packet; + req_id = prepare->packet->header.request_id; /* Max one hw entries required for each base */ if (prepare->num_hw_update_entries + 1 >= @@ -495,7 +497,7 @@ int cam_isp_add_io_buffers( CAM_DBG(CAM_ISP, "======= io config idx %d ============", i); CAM_DBG(CAM_REQ, "i %d req_id %llu resource_type:%d fence:%d direction %d", - i, prepare->packet->header.request_id, + i, req_id, io_cfg[i].resource_type, io_cfg[i].fence, io_cfg[i].direction); CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); @@ -622,12 +624,37 @@ int cam_isp_add_io_buffers( mmu_hdl, &io_addr[plane_id], &size); if (rc) { CAM_ERR(CAM_ISP, - "no io addr for plane%d", - plane_id); + "no io addr for plane%d Bufhdl:%d, Size =%d", + plane_id, + io_cfg[i].mem_handle[plane_id], + (int)size); + CAM_ERR(CAM_ISP, + "Port i %d Reqid %llu res_type:%d fence:%d dir %d", + i, req_id, + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].direction); rc = -ENOMEM; return rc; } + if (j == 0) { + rc = cam_packet_validate_plane_size( + &io_cfg[i], + plane_id, + size); + if (rc) { + CAM_ERR(CAM_ISP, + "Invalid buffer size, port 0x%x plane %d req_id %llu format %d memh 0x%x", + io_cfg[i].resource_type, + plane_id, + req_id, + io_cfg[i].format, + io_cfg[i].mem_handle[plane_id]); + return -EINVAL; + } + } + /* need to update with offset */ io_addr[plane_id] += io_cfg[i].offsets[plane_id]; 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 a6564151e645f070f91179c3afebf3f48885772c..a0811abc57d1c6b62c8c87904e1b3f6995dd69c9 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 @@ -467,6 +467,10 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; + csid_hw->first_sof_ts = 0; + + for (i = 0 ; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; return rc; } @@ -838,7 +842,6 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, return rc; } - static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *reserve) { @@ -953,7 +956,7 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->height = reserve->in_port->height; path_data->start_line = reserve->in_port->line_start; path_data->end_line = reserve->in_port->line_stop; - + path_data->usage_type = reserve->in_port->usage_type; /* Enable RDI crop for single ife use case only */ switch (reserve->res_id) { case CAM_IFE_PIX_PATH_RES_RDI_0: @@ -1120,6 +1123,7 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) { int rc = -EINVAL; + uint32_t i; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; unsigned long flags; @@ -1160,12 +1164,96 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; + csid_hw->first_sof_ts = 0; return rc; } +static int cam_ife_csid_check_path_active(struct cam_ife_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i, path_status = 1; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* check the IPP path status */ + if (csid_reg->cmn_reg->num_pix) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d IPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d PPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + /* Check the RDI path status */ + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d RDI:%d path status:%d", + csid_hw->hw_intf->hw_idx, i, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + +end: + return path_status; +} + +static void cam_ife_csid_reset_init_frame_drop( + struct cam_ife_csid_hw *csid_hw) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i = 0; + + /* + * Reset CSID init frame drop value only if all resources are + * released + */ + csid_reg = csid_hw->csid_info->csid_reg; + if (csid_reg->cmn_reg->num_pix) { + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + if (csid_hw->rdi_res[i].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + /* All CSID resources are available reset the init frame drop */ + csid_hw->init_frame_drop = 0; +end: + return; + +} static int cam_ife_csid_tpg_start(struct cam_ife_csid_hw *csid_hw, struct cam_isp_resource_node *res) @@ -1725,7 +1813,7 @@ static int cam_ife_csid_enable_pxl_path( struct cam_ife_csid_path_cfg *path_data; const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; bool is_ipp; - uint32_t val = 0; + uint32_t val = 0, path_status; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -1768,14 +1856,15 @@ static int cam_ife_csid_enable_pxl_path( /* Default is internal halt mode */ val = 0; - /* - * Resume at frame boundary if Master or No Sync. - * Slave will get resume command from Master. - */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || - path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) - val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; - + /* Resume at frame boundary */ + path_status = cam_ife_csid_check_path_active(csid_hw); + if (!csid_hw->init_frame_drop || + (csid_hw->init_frame_drop && !path_status)) { + CAM_DBG(CAM_ISP, "start pixel path"); + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + } cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_ctrl_addr); @@ -1789,8 +1878,10 @@ static int cam_ife_csid_enable_pxl_path( if (pxl_reg->ccif_violation_en) val |= CSID_PATH_ERROR_CCIF_VIOLATION; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (csid_hw->init_frame_drop && path_status)) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2087,8 +2178,10 @@ static int cam_ife_csid_enable_rdi_path( { const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; - uint32_t id, val; + struct cam_ife_csid_path_cfg *path_data; + uint32_t id, val, path_status; + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; @@ -2103,19 +2196,28 @@ static int cam_ife_csid_enable_rdi_path( return -EINVAL; } - /*resume at frame boundary */ - cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, - soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + if (path_data->usage_type) + path_data->init_frame_drop = csid_hw->init_frame_drop + 1; + /*resume at frame boundary */ + path_status = cam_ife_csid_check_path_active(csid_hw); + if (!path_data->init_frame_drop || + (path_data->init_frame_drop && !path_status)) { + CAM_DBG(CAM_ISP, "Start RDI:%d path", id); + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + } /* Enable the required RDI interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; if (csid_reg->rdi_reg[id]->ccif_violation_en) val |= CSID_PATH_ERROR_CCIF_VIOLATION; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (path_data->init_frame_drop && path_status)) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2355,9 +2457,16 @@ static int cam_ife_csid_get_time_stamp( CAM_IFE_CSID_QTIMER_MUL_FACTOR, CAM_IFE_CSID_QTIMER_DIV_FACTOR); - get_monotonic_boottime64(&ts); - time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); + if (!csid_hw->first_sof_ts) { + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = + (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + CAM_DBG(CAM_ISP, "timestamp:%lld", + time_stamp->boot_timestamp); + csid_hw->first_sof_ts = 1; + } else + time_stamp->boot_timestamp = 0; return 0; } @@ -2375,6 +2484,19 @@ static int cam_ife_csid_set_csid_debug(struct cam_ife_csid_hw *csid_hw, return 0; } +static int cam_ife_csid_set_init_frame_drop(struct cam_ife_csid_hw *csid_hw, + void *cmd_args) +{ + struct cam_isp_init_frame_drop_config *frame_drop_cfg; + + frame_drop_cfg = (struct cam_isp_init_frame_drop_config *) cmd_args; + csid_hw->init_frame_drop = frame_drop_cfg->init_frame_drop; + CAM_DBG(CAM_ISP, "CSID:%d set init frame drop:%d", + csid_hw->hw_intf->hw_idx, csid_hw->init_frame_drop); + + return 0; +} + static int cam_ife_csid_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -2551,6 +2673,7 @@ static int cam_ife_csid_release(void *hw_priv, break; case CAM_ISP_RESOURCE_PIX_PATH: res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + cam_ife_csid_reset_init_frame_drop(csid_hw); break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", @@ -3016,6 +3139,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SET_INIT_FRAME_DROP: + rc = cam_ife_csid_set_init_frame_drop(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); @@ -3033,6 +3159,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; uint32_t irq_status_rdi[4] = {0, 0, 0, 0}; uint32_t val, irq_status_ppp = 0; @@ -3264,6 +3393,53 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->init_frame_drop) && + (csid_hw->ipp_res.res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP]++; + CAM_DBG(CAM_ISP, + "CSID:%d IPP SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP], + csid_hw->init_frame_drop); + if (csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP] == + csid_hw->init_frame_drop) { + pxl_reg = csid_reg->ipp_reg; + path_data = csid_hw->ipp_res.res_priv; + if (path_data->sync_mode == + CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + val |= + CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + } else if (path_data->sync_mode == + CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb( + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } + } + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", @@ -3299,6 +3475,52 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->init_frame_drop) && + (csid_hw->ppp_res.res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP]++; + CAM_DBG(CAM_ISP, + "CSID:%d PPP SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP], + csid_hw->init_frame_drop); + if (csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP] == + csid_hw->init_frame_drop) { + path_data = csid_hw->ppp_res.res_priv; + pxl_reg = csid_reg->ppp_reg; + if (path_data->sync_mode == + CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + val |= + CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } else if (path_data->sync_mode == + CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb( + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } + } + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", @@ -3319,6 +3541,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_data = (struct cam_ife_csid_path_cfg *) + csid_hw->rdi_res[i].res_priv; + rdi_reg = csid_reg->rdi_reg[i]; if (irq_status_rdi[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { complete(&csid_hw->csid_rdin_complete[i]); @@ -3332,6 +3557,35 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + (path_data->init_frame_drop) && + (csid_hw->rdi_res[i].res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[i]++; + CAM_DBG(CAM_ISP, + "CSID:%d RDI:%d SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, i, + csid_hw->res_sof_cnt[i], + path_data->init_frame_drop); + if (csid_hw->res_sof_cnt[i] == + path_data->init_frame_drop) { + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_ctrl_addr); + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + } + } + } + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, @@ -3494,6 +3748,7 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->csid_debug = 0; ife_csid_hw->error_irq_count = 0; + ife_csid_hw->first_sof_ts = 0; return 0; err: diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 3a093d205f59f480be22e4ba2c96206e11bd616b..9b4d5c3d6add743285c14a5c031b67d8de71161f 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -419,6 +419,9 @@ struct cam_ife_csid_cid_data { * @master_idx: For Slave reservation, Give master IFE instance Index. * Slave will synchronize with master Start and stop operations * @clk_rate Clock rate + * @usage_type Usage type ie dual or single ife usecase + * @init_frame_drop init frame drop value. In dual ife case rdi need to drop one + * more frame than pix. * */ struct cam_ife_csid_path_cfg { @@ -437,6 +440,8 @@ struct cam_ife_csid_path_cfg { enum cam_isp_hw_sync_mode sync_mode; uint32_t master_idx; uint64_t clk_rate; + uint32_t usage_type; + uint32_t init_frame_drop; }; /** @@ -468,6 +473,14 @@ struct cam_ife_csid_path_cfg { * @irq_debug_cnt: Counter to track sof irq's when above flag is set. * @error_irq_count Error IRQ count, if continuous error irq comes * need to stop the CSID and mask interrupts. + * @device_enabled Device enabled will set once CSID powered on and + * initial configuration are done. + * @lock_state csid spin lock + * @dual_usage usage type, dual ife or single ife + * @init_frame_drop Initial frame drop number + * @res_sof_cnt path resource sof count value. it used for initial + * frame drop + * @first_sof_ts flag to mark the first sof has been registered * */ struct cam_ife_csid_hw { @@ -496,6 +509,10 @@ struct cam_ife_csid_hw { uint32_t error_irq_count; uint32_t device_enabled; spinlock_t lock_state; + uint32_t dual_usage; + uint32_t init_frame_drop; + uint32_t res_sof_cnt[CAM_IFE_PIX_PATH_RES_MAX]; + uint32_t first_sof_ts; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 58818fbecf67e8ae2559548c169006b0ccecc9ba..0c45bd1268b9acd43e4a805269069d7b015abf4d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -157,6 +157,7 @@ enum cam_ife_csid_cmd_type { CAM_IFE_CSID_CMD_GET_TIME_STAMP, CAM_IFE_CSID_SET_CSID_DEBUG, CAM_IFE_CSID_SOF_IRQ_DEBUG, + CAM_IFE_CSID_SET_INIT_FRAME_DROP, CAM_IFE_CSID_CMD_MAX, }; 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 9ea8e3f5b7d1c3907f12c64628cea4086fef8207..696566d6a37a32ff34840907550c32af6f2260f7 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 @@ -647,8 +647,13 @@ static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, for (i = 0; i < packet->num_io_configs; i++) { for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { - if (!io_cfg[i].mem_handle[j]) + if (!io_cfg[i].mem_handle[j]) { + CAM_ERR(CAM_JPEG, + "Mem Handle %d is NULL for %d io config", + j, i); break; + } + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == GET_FD_FROM_HANDLE(pf_buf_info)) { 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 52907cd6803e655e367ec22165a8f15bd91d9356..225f859674f1c6a7a522b0971805b6f04146073b 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 @@ -91,6 +91,9 @@ int cam_jpeg_enc_init_hw(void *device_priv, CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); goto soc_failed; } + spin_lock(&jpeg_enc_dev->hw_lock); + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_UP; + spin_unlock(&jpeg_enc_dev->hw_lock); mutex_unlock(&core_info->core_mutex); @@ -140,6 +143,9 @@ int cam_jpeg_enc_deinit_hw(void *device_priv, return -EFAULT; } + spin_lock(&jpeg_enc_dev->hw_lock); + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + spin_unlock(&jpeg_enc_dev->hw_lock); rc = cam_jpeg_enc_disable_soc_resources(soc_info); if (rc) CAM_ERR(CAM_JPEG, "soc disable failed %d", rc); @@ -173,12 +179,19 @@ irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data) hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; + spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + return -EINVAL; + } irq_status = cam_io_r_mb(mem_base + core_info->jpeg_enc_hw_info->reg_offset.int_status); cam_io_w_mb(irq_status, soc_info->reg_map[0].mem_base + core_info->jpeg_enc_hw_info->reg_offset.int_clr); + spin_unlock(&jpeg_enc_dev->hw_lock); CAM_DBG(CAM_JPEG, "irq_num %d irq_status = %x , core_state %d", irq_num, irq_status, core_info->core_state); @@ -268,6 +281,12 @@ int cam_jpeg_enc_reset_hw(void *data, mutex_lock(&core_info->core_mutex); spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { CAM_ERR(CAM_JPEG, "alrady resetting"); spin_unlock(&jpeg_enc_dev->hw_lock); @@ -319,10 +338,18 @@ int cam_jpeg_enc_start_hw(void *data, hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; + spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + return -EINVAL; + } if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) { CAM_ERR(CAM_JPEG, "Error not ready"); + spin_unlock(&jpeg_enc_dev->hw_lock); return -EINVAL; } + spin_unlock(&jpeg_enc_dev->hw_lock); cam_io_w_mb(hw_info->reg_val.hw_cmd_start, mem_base + hw_info->reg_offset.hw_cmd); @@ -352,6 +379,12 @@ int cam_jpeg_enc_stop_hw(void *data, mutex_lock(&core_info->core_mutex); spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { CAM_ERR(CAM_JPEG, "alrady stopping"); spin_unlock(&jpeg_enc_dev->hw_lock); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c index aa8ed7d7039874a711aa120430c1f3d21fb6b062..f86f63ef86c998e1ac98f26a8cc8cd765417a4ff 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c @@ -251,33 +251,50 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) return -EINVAL; - if (!tbl.bufq[idx].active) - return -EPERM; + mutex_lock(&tbl.bufq[idx].q_lock); + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_MEM, "idx: %d not active", idx); + rc = -EPERM; + goto end; + } - if (buf_handle != tbl.bufq[idx].buf_handle) - return -EINVAL; + if (buf_handle != tbl.bufq[idx].buf_handle) { + CAM_ERR(CAM_MEM, "idx: %d Invalid buf handle %d", + idx, buf_handle); + rc = -EINVAL; + goto end; + } - if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) - return -EINVAL; + if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) { + CAM_ERR(CAM_MEM, "idx: %d Invalid flag 0x%x", + idx, tbl.bufq[idx].flags); + rc = -EINVAL; + goto end; + } if (tbl.bufq[idx].kmdvaddr) { dmabuf = tbl.bufq[idx].dma_buf; if (!dmabuf) { CAM_ERR(CAM_MEM, "Invalid DMA buffer pointer"); - return -EINVAL; + rc = -EINVAL; + goto end; } rc = dma_buf_begin_cpu_access(dmabuf, DMA_BIDIRECTIONAL); if (rc) { CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); - return rc; + goto end; } } else { - return -EINVAL; + CAM_ERR(CAM_MEM, "Invalid kmdvaddr"); + rc = -EINVAL; + goto end; } *vaddr_ptr = tbl.bufq[idx].kmdvaddr; *len = tbl.bufq[idx].len; +end: + mutex_unlock(&tbl.bufq[idx].q_lock); return rc; } EXPORT_SYMBOL(cam_mem_get_cpu_buf); @@ -300,30 +317,38 @@ int cam_mem_put_cpu_buf(int32_t buf_handle) if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) return -EINVAL; - if (!tbl.bufq[idx].active) - return -EPERM; + mutex_lock(&tbl.bufq[idx].q_lock); + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_MEM, "idx: %d not active", idx); + rc = -EPERM; + goto end; + } - if (buf_handle != tbl.bufq[idx].buf_handle) - return -EINVAL; + if (buf_handle != tbl.bufq[idx].buf_handle) { + CAM_ERR(CAM_MEM, "idx: %d Invalid buf handle %d", + idx, buf_handle); + rc = -EINVAL; + goto end; + } dmabuf = tbl.bufq[idx].dma_buf; if (!dmabuf) { CAM_ERR(CAM_CRM, "Invalid DMA buffer pointer"); - return -EINVAL; + rc = -EINVAL; + goto end; } if ((tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) && (tbl.bufq[idx].kmdvaddr)) { rc = dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); - if (rc) { + if (rc) CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); - return rc; - } } else { CAM_ERR(CAM_MEM, "Invalid buf flag"); rc = -EINVAL; } - +end: + mutex_unlock(&tbl.bufq[idx].q_lock); return rc; } EXPORT_SYMBOL(cam_mem_put_cpu_buf); @@ -779,7 +804,8 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) dmabuf = dma_buf_get(cmd->fd); if (IS_ERR_OR_NULL((void *)(dmabuf))) { - CAM_ERR(CAM_MEM, "Failed to import dma_buf fd"); + CAM_ERR(CAM_MEM, "Failed to import dma_buf fd %d, rc %d", + cmd->fd, (IS_ERR(dmabuf) ? PTR_ERR(dmabuf) : 0)); return -EINVAL; } @@ -953,6 +979,7 @@ static int cam_mem_mgr_cleanup_table(void) tbl.bufq[i].num_hdl = 0; tbl.bufq[i].dma_buf = NULL; tbl.bufq[i].active = false; + tbl.bufq[i].kmdvaddr = 0; mutex_unlock(&tbl.bufq[i].q_lock); mutex_destroy(&tbl.bufq[i].q_lock); } @@ -1051,6 +1078,7 @@ static int cam_mem_util_unmap(int32_t idx, tbl.bufq[idx].len = 0; tbl.bufq[idx].num_hdl = 0; tbl.bufq[idx].active = false; + tbl.bufq[idx].kmdvaddr = 0; mutex_unlock(&tbl.bufq[idx].q_lock); mutex_destroy(&tbl.bufq[idx].q_lock); clear_bit(idx, tbl.bitmap); 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 b33bea5f8c9ac927aec2a82b37827b865030e14e..fa6e83efb69797528c400dcbe2c5da0daafb5509 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 @@ -48,6 +48,9 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->last_flush_id = 0; link->initial_sync_req = -1; link->in_msync_mode = false; + link->initial_skip = true; + link->sof_timestamp = 0; + link->prev_sof_timestamp = 0; } void cam_req_mgr_handle_core_shutdown(void) @@ -348,10 +351,12 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, struct cam_req_mgr_req_queue *in_q = link->req.in_q; slot = &in_q->slot[idx]; - CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); + CAM_DBG(CAM_CRM, "RESET: last applied idx %d: idx %d: slot->status %d", + in_q->last_applied_idx, idx, slot->status); /* Check if CSL has already pushed new request*/ - if (slot->status == CRM_SLOT_STATUS_REQ_ADDED) + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED || + in_q->last_applied_idx == idx) return; /* Reset input queue slot */ @@ -512,9 +517,11 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, } if (link->req.apply_data[pd].skip_idx || link->req.apply_data[pd].req_id < 0) { - CAM_DBG(CAM_CRM, "skip %d req_id %lld", + CAM_DBG(CAM_CRM, + "skip %d req_id %lld pd %d dev_name %s", link->req.apply_data[pd].skip_idx, - link->req.apply_data[pd].req_id); + link->req.apply_data[pd].req_id, + pd, dev->dev_info.name); continue; } if (!(dev->dev_info.trigger & trigger)) @@ -605,6 +612,19 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.validate_only = validate_only; traverse_data.open_req_cnt = link->open_req_cnt; + /* + * Some no-sync mode requests are processed after link config, + * then process the sync mode requests after no-sync mode requests + * are handled, the initial_skip should be false when processing + * the sync mode requests. + */ + if (link->initial_skip) { + CAM_DBG(CAM_CRM, + "Set initial_skip to false for link %x", + link->link_hdl); + link->initial_skip = false; + } + /* * Traverse through all pd tables, if result is success, * apply the settings @@ -890,9 +910,12 @@ static int __cam_req_mgr_check_sync_req_is_ready( struct cam_req_mgr_slot *slot) { struct cam_req_mgr_core_link *sync_link = NULL; - int64_t req_id = 0; + struct cam_req_mgr_slot *sync_rd_slot = NULL; + int64_t req_id = 0, sync_req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; + uint64_t sync_frame_duration = 0; + bool ready = true, sync_ready = true; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -902,11 +925,65 @@ static int __cam_req_mgr_check_sync_req_is_ready( sync_link = link->sync_link; req_id = slot->req_id; sync_num_slots = sync_link->req.in_q->num_slots; + sync_rd_idx = sync_link->req.in_q->rd_idx; + sync_rd_slot = &sync_link->req.in_q->slot[sync_rd_idx]; + sync_req_id = sync_rd_slot->req_id; CAM_DBG(CAM_REQ, "link_hdl %x req %lld frame_skip_flag %d ", link->link_hdl, req_id, link->sync_link_sof_skip); + if (sync_link->initial_skip) { + link->initial_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "sync link %x not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } + + if (sync_link->prev_sof_timestamp) + sync_frame_duration = sync_link->sof_timestamp + - sync_link->prev_sof_timestamp; + else + sync_frame_duration = DEFAULT_FRAME_DURATION; + + CAM_DBG(CAM_CRM, + "sync link %x last frame duration is %d ns", + sync_link->link_hdl, sync_frame_duration); + + if (link->initial_skip) { + link->initial_skip = false; + + if (link->sof_timestamp > sync_link->sof_timestamp && + sync_link->sof_timestamp > 0 && + link->sof_timestamp - sync_link->sof_timestamp < + sync_frame_duration / 2) { + /* + * If this frame sync with the previous frame of sync + * link, then we need to skip this frame, since the + * previous frame of sync link is also skipped. + */ + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "This frame sync with previous sync_link %x frame", + sync_link->link_hdl); + return -EAGAIN; + } else if (link->sof_timestamp <= sync_link->sof_timestamp) { + /* + * Sometimes, link receives the SOF event is eariler + * than sync link in IFE CSID side, but link's SOF + * event is processed later than sync link's, then + * we need to skip this SOF event since the sync + * link's SOF event is also skipped. + */ + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "The previous frame of sync link is skipped"); + return -EAGAIN; + } + } + if (sync_link->sync_link_sof_skip) { CAM_DBG(CAM_REQ, "No req applied on corresponding SOF on sync link: %x", @@ -921,17 +998,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( CAM_DBG(CAM_CRM, "Skip Process Req: %lld on link: %x", req_id, link->link_hdl); - link->sync_link_sof_skip = true; - return rc; - } - - rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); - if (rc) { - CAM_DBG(CAM_CRM, - "Req: %lld [My link] not ready on link: %x, rc=%d", - req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; - return rc; + ready = false; } sync_slot_idx = __cam_req_mgr_find_slot_for_req( @@ -939,16 +1006,14 @@ static int __cam_req_mgr_check_sync_req_is_ready( if (sync_slot_idx == -1) { CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", req_id, sync_link->link_hdl); - link->sync_link_sof_skip = true; - return -EINVAL; + sync_ready = false; } - sync_rd_idx = sync_link->req.in_q->rd_idx; if ((sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED) && (((sync_slot_idx - sync_rd_idx + sync_num_slots) % sync_num_slots) >= 1) && - (sync_link->req.in_q->slot[sync_rd_idx].status != + (sync_rd_slot->status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, "Req: %lld [other link] not next req to be applied on link: %x", @@ -956,14 +1021,101 @@ static int __cam_req_mgr_check_sync_req_is_ready( return -EAGAIN; } + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [My link] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + ready = false; + } + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, "Req: %lld not ready on [other link] link: %x, rc=%d", req_id, sync_link->link_hdl, rc); - link->sync_link_sof_skip = true; - return rc; + sync_ready = false; + } + + /* + * If both of them are ready or not ready, then just + * skip this sof and don't skip sync link next SOF. + */ + if (sync_ready != ready) { + CAM_DBG(CAM_CRM, + "Req: %lld ready %d sync_ready %d, ignore sync link next SOF", + req_id, ready, sync_ready); + + /* + * Only skip the frames if current frame sync with + * next frame of sync link. + */ + if (link->sof_timestamp - sync_link->sof_timestamp > + sync_frame_duration / 2) + link->sync_link_sof_skip = true; + + return -EINVAL; + } else if (ready == false) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on link: %x", + req_id, link->link_hdl); + return -EINVAL; + } + + /* + * Do the self-correction when the frames are sync, + * we consider that the frames are synced if the + * difference of two SOF timestamp less than + * (sync_frame_duration / 5). + */ + if ((link->sof_timestamp > sync_link->sof_timestamp) && + (sync_link->sof_timestamp > 0) && + (link->sof_timestamp - sync_link->sof_timestamp < + sync_frame_duration / 5) && + (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { + + /* + * This means current frame should sync with next + * frame of sync link, then the request id of in + * rd slot of two links should be same. + */ + CAM_DBG(CAM_CRM, + "link %x req_id %lld, sync_link %x req_id %lld", + link->link_hdl, req_id, + sync_link->link_hdl, sync_req_id); + + if (req_id > sync_req_id) { + CAM_DBG(CAM_CRM, + "link %x too quickly, skip this frame", + link->link_hdl); + return -EAGAIN; + } else if (req_id < sync_req_id) { + CAM_DBG(CAM_CRM, + "sync link %x too quickly, skip next frame of sync link", + sync_link->link_hdl); + link->sync_link_sof_skip = true; + } + } else if ((sync_link->sof_timestamp > 0) && + (link->sof_timestamp < sync_link->sof_timestamp) && + (sync_link->sof_timestamp - link->sof_timestamp < + sync_frame_duration / 5) && + (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { + + /* + * There is a timing issue once enter this condition, + * it means link receives the SOF event earlier than + * sync link in IFE CSID side, but the process in CRM + * is sync_link earlier than link, then previous SOF + * event of sync link is skipped, so we also need to + * skip this SOF event. + */ + if (req_id >= sync_req_id) { + CAM_DBG(CAM_CRM, + "Timing issue, the sof event of link %x is delayed", + link->link_hdl); + return -EAGAIN; + } } CAM_DBG(CAM_REQ, @@ -993,10 +1145,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( * */ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, - uint32_t trigger) + struct cam_req_mgr_trigger_notify *trigger_data) { - int rc = 0, idx; + int rc = 0, idx, last_app_idx; int reset_step = 0; + uint32_t trigger = trigger_data->trigger; struct cam_req_mgr_slot *slot = NULL; struct cam_req_mgr_req_queue *in_q; struct cam_req_mgr_core_session *session; @@ -1034,6 +1187,13 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, } if (trigger == CAM_TRIGGER_POINT_SOF) { + /* + * Update the timestamp in session lock protection + * to avoid timing issue. + */ + link->prev_sof_timestamp = link->sof_timestamp; + link->sof_timestamp = trigger_data->sof_timestamp_val; + if (link->trigger_mask) { CAM_ERR_RATE_LIMIT(CAM_CRM, "Applying for last EOF fails"); @@ -1129,6 +1289,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, slot->req_id, link->link_hdl); idx = in_q->rd_idx; + reset_step = link->max_delay; if (link->sync_link) { if ((link->in_msync_mode) && @@ -1136,6 +1297,25 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, reset_step = link->sync_link->max_delay; } + + /* This is to handle a rare scenario of scheduling + * issue. If ISP sends multiple sofs due to scheduling + * issue, it is required to retain last applied index + * to help recover. + * In this case, ISP goes into Bubble, asking to reapply + * the bubbled request which has already been reset by + * CRM. Below code retains the last applied request. + */ + + if (slot->req_id > 0) { + last_app_idx = in_q->last_applied_idx; + in_q->last_applied_idx = idx; + if (abs(last_app_idx - idx) >= + reset_step + 1) + __cam_req_mgr_reset_req_slot(link, + last_app_idx); + } + __cam_req_mgr_dec_idx( &idx, reset_step + 1, in_q->num_slots); @@ -2103,7 +2283,7 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); } - rc = __cam_req_mgr_process_req(link, trigger_data->trigger); + rc = __cam_req_mgr_process_req(link, trigger_data); release_lock: mutex_unlock(&link->req.lock); @@ -2334,6 +2514,7 @@ static int cam_req_mgr_cb_notify_trigger( notify_trigger->link_hdl = trigger_data->link_hdl; notify_trigger->dev_hdl = trigger_data->dev_hdl; notify_trigger->trigger = trigger_data->trigger; + notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val; task->process_cb = &cam_req_mgr_process_trigger; rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); @@ -2359,18 +2540,24 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { * */ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, - struct cam_req_mgr_link_info *link_info) + struct cam_req_mgr_ver_info *link_info) { - int rc = 0, i = 0; + int rc = 0, i = 0, num_devices = 0; struct cam_req_mgr_core_dev_link_setup link_data; struct cam_req_mgr_connected_device *dev; struct cam_req_mgr_req_tbl *pd_tbl; enum cam_pipeline_delay max_delay; uint32_t subscribe_event = 0; - - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) - return -EPERM; - + if (link_info->version == VERSION_1) { + if (link_info->u.link_info_v1.num_devices > + CAM_REQ_MGR_MAX_HANDLES) + return -EPERM; + } + else if (link_info->version == VERSION_2) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) + return -EPERM; + } mutex_init(&link->req.lock); CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); link->req.num_tbl = 0; @@ -2380,11 +2567,21 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, return rc; max_delay = CAM_PIPELINE_DELAY_0; - for (i = 0; i < link_info->num_devices; i++) { + if (link_info->version == VERSION_1) + num_devices = link_info->u.link_info_v1.num_devices; + else if (link_info->version == VERSION_2) + num_devices = link_info->u.link_info_v2.num_devices; + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; /* Using dev hdl, get ops ptr to communicate with device */ - dev->ops = (struct cam_req_mgr_kmd_ops *) - cam_get_device_ops(link_info->dev_hdls[i]); + if (link_info->version == VERSION_1) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v1.dev_hdls[i]); + else if (link_info->version == VERSION_2) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v2.dev_hdls[i]); if (!dev->ops || !dev->ops->get_dev_info || !dev->ops->link_setup) { @@ -2392,18 +2589,29 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, rc = -ENXIO; goto error; } - dev->dev_hdl = link_info->dev_hdls[i]; + if (link_info->version == VERSION_1) + dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; + else if (link_info->version == VERSION_2) + dev->dev_hdl = link_info->u.link_info_v2.dev_hdls[i]; dev->parent = (void *)link; dev->dev_info.dev_hdl = dev->dev_hdl; rc = dev->ops->get_dev_info(&dev->dev_info); trace_cam_req_mgr_connect_device(link, &dev->dev_info); - - CAM_DBG(CAM_CRM, - "%x: connected: %s, id %d, delay %d, trigger %x", - link_info->session_hdl, dev->dev_info.name, - dev->dev_info.dev_id, dev->dev_info.p_delay, - dev->dev_info.trigger); + if (link_info->version == VERSION_1) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + else if (link_info->version == VERSION_2) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); if (rc < 0 || dev->dev_info.p_delay >= CAM_PIPELINE_DELAY_MAX || @@ -2412,10 +2620,18 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, CAM_ERR(CAM_CRM, "get device info failed"); goto error; } else { - CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", - link_info->session_hdl, - dev->dev_info.name, - dev->dev_info.p_delay); + if (link_info->version == VERSION_1) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } + else if (link_info->version == VERSION_2) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } if (dev->dev_info.p_delay > max_delay) max_delay = dev->dev_info.p_delay; @@ -2430,7 +2646,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, link_data.max_delay = max_delay; link_data.subscribe_event = subscribe_event; - for (i = 0; i < link_info->num_devices; i++) { + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; link_data.dev_hdl = dev->dev_hdl; @@ -2473,7 +2689,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, if (link->max_delay < dev->dev_info.p_delay) link->max_delay = dev->dev_info.p_delay; } - link->num_devs = link_info->num_devices; + link->num_devs = num_devices; /* Assign id for pd tables */ __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); @@ -2631,7 +2847,7 @@ int cam_req_mgr_destroy_session( return rc; } -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) { int rc = 0; int wq_flag = 0; @@ -2644,9 +2860,9 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "NULL pointer"); return -EINVAL; } - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) { + if (link_info->u.link_info_v1.num_devices > CAM_REQ_MGR_MAX_HANDLES) { CAM_ERR(CAM_CRM, "Invalid num devices %d", - link_info->num_devices); + link_info->u.link_info_v1.num_devices); return -EINVAL; } @@ -2654,7 +2870,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) - cam_get_device_priv(link_info->session_hdl); + cam_get_device_priv(link_info->u.link_info_v1.session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); mutex_unlock(&g_crm_core_dev->crm_lock); @@ -2671,7 +2887,116 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); - root_dev.session_hdl = link_info->session_hdl; + root_dev.session_hdl = link_info->u.link_info_v1.session_hdl; + root_dev.priv = (void *)link; + root_dev.dev_id = CAM_CRM; + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->u.link_info_v1.link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->u.link_info_v1.num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->u.link_info_v1.session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->u.link_info_v1.link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->u.link_info_v2.num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->u.link_info_v2.session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->u.link_info_v2.session_hdl; root_dev.priv = (void *)link; mutex_lock(&link->lock); @@ -2683,12 +3008,12 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) rc = link->link_hdl; goto link_hdl_fail; } - link_info->link_hdl = link->link_hdl; + link_info->u.link_info_v2.link_hdl = link->link_hdl; link->last_flush_id = 0; /* Allocate memory to hold data of all linked devs */ rc = __cam_req_mgr_create_subdevs(&link->l_dev, - link_info->num_devices); + link_info->u.link_info_v2.num_devices); if (rc < 0) { CAM_ERR(CAM_CRM, "Insufficient memory to create new crm subdevs"); @@ -2706,7 +3031,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* Create worker for current link */ snprintf(buf, sizeof(buf), "%x-%x", - link_info->session_hdl, link->link_hdl); + link_info->u.link_info_v2.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); @@ -2731,7 +3056,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) __cam_req_mgr_destroy_subdev(link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); - link_info->link_hdl = -1; + link_info->u.link_info_v2.link_hdl = -1; link_hdl_fail: mutex_unlock(&link->lock); __cam_req_mgr_unreserve_link(cam_session, link); @@ -2739,6 +3064,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) return rc; } + int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) { int rc = 0; @@ -2942,8 +3268,6 @@ int cam_req_mgr_sync_config( link1->is_master = false; link2->is_master = false; - link1->initial_skip = false; - link2->initial_skip = false; link1->in_msync_mode = false; link2->in_msync_mode = false; @@ -2954,6 +3278,16 @@ int cam_req_mgr_sync_config( link1->sync_link = link2; link2->sync_link = link1; __cam_req_mgr_set_master_link(link1, link2); + } else { + /* + * Reset below info after the mode is configured + * to NO-SYNC mode since they may be overridden + * if the sync config is invoked after SOF comes. + */ + link1->initial_skip = true; + link2->initial_skip = true; + link1->sof_timestamp = 0; + link2->sof_timestamp = 0; } cam_session->sync_mode = sync_info->sync_mode; 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 26f5426b67b0ef25adc9e2c21ea898e21941d8c3..bcaf4da387b37c52faa3fc7a125be085f860c2bb 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 @@ -32,10 +32,16 @@ #define MAX_SYNC_COUNT 65535 +/* Default frame rate is 30 */ +#define DEFAULT_FRAME_DURATION 33333333 + #define SYNC_LINK_SOF_CNT_MAX_LMT 1 #define MAXIMUM_LINKS_PER_SESSION 4 +#define VERSION_1 1 +#define VERSION_2 2 + /** * enum crm_workq_task_type * @codes: to identify which type of task is present @@ -233,12 +239,14 @@ struct cam_req_mgr_slot { * @slot : request slot holding incoming request id and bubble info. * @rd_idx : indicates slot index currently in process. * @wr_idx : indicates slot index to hold new upcoming req. + * @last_applied_idx : indicates slot index last applied successfully. */ struct cam_req_mgr_req_queue { int32_t num_slots; struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; int32_t rd_idx; int32_t wr_idx; + int32_t last_applied_idx; }; /** @@ -316,7 +324,10 @@ struct cam_req_mgr_connected_device { * master-slave sync * @in_msync_mode : Flag to determine if a link is in master-slave mode * @initial_sync_req : The initial req which is required to sync with the - * other link + * other link, it means current hasn't receive any + * stream after streamon if it is true + * @sof_timestamp_value : SOF timestamp value + * @prev_sof_timestamp : Previous SOF timestamp value */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -343,6 +354,8 @@ struct cam_req_mgr_core_link { bool initial_skip; bool in_msync_mode; int64_t initial_sync_req; + uint64_t sof_timestamp; + uint64_t prev_sof_timestamp; }; /** @@ -410,7 +423,9 @@ int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); * a unique link handle for the link and is specific to a * session. Returns link handle */ -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info); +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info); +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info); + /** * cam_req_mgr_unlink() 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 5cf1d844f5e2a9314f119851092b61f3113ca2a4..31607ac6391fec2ceba76e20475ced2c20f0d2a2 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -268,27 +268,50 @@ static long cam_private_ioctl(struct file *file, void *fh, break; case CAM_REQ_MGR_LINK: { - struct cam_req_mgr_link_info link_info; + struct cam_req_mgr_ver_info ver_info; - if (k_ioctl->size != sizeof(link_info)) + if (k_ioctl->size != sizeof(ver_info.u.link_info_v1)) return -EINVAL; - if (copy_from_user(&link_info, + if (copy_from_user(&ver_info.u.link_info_v1, u64_to_user_ptr(k_ioctl->handle), sizeof(struct cam_req_mgr_link_info))) { return -EFAULT; } - - rc = cam_req_mgr_link(&link_info); + ver_info.version = VERSION_1; + rc = cam_req_mgr_link(&ver_info); if (!rc) if (copy_to_user( u64_to_user_ptr(k_ioctl->handle), - &link_info, + &ver_info.u.link_info_v1, sizeof(struct cam_req_mgr_link_info))) rc = -EFAULT; } break; + case CAM_REQ_MGR_LINK_V2: { + struct cam_req_mgr_ver_info ver_info; + + if (k_ioctl->size != sizeof(ver_info.u.link_info_v2)) + return -EINVAL; + + if (copy_from_user(&ver_info.u.link_info_v2, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info_v2))) { + return -EFAULT; + } + ver_info.version = VERSION_2; + rc = cam_req_mgr_link_v2(&ver_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ver_info.u.link_info_v2, + sizeof(struct + cam_req_mgr_link_info_v2))) + rc = -EFAULT; + } + break; + case CAM_REQ_MGR_UNLINK: { struct cam_req_mgr_unlink_info unlink_info; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h index 409e74961b45ba1e5b3fdfa97590219abff8ece6..934bc76014a5c4a3c733c636364bbefbdb4dfe48 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -201,12 +201,14 @@ enum cam_req_mgr_link_evt_type { * @frame_id : frame id for internal tracking * @trigger : trigger point of this notification, CRM will send apply * only to the devices which subscribe to this point. + * @sof_timestamp_val: Captured time stamp value at sof hw event */ struct cam_req_mgr_trigger_notify { int32_t link_hdl; int32_t dev_hdl; int64_t frame_id; uint32_t trigger; + uint64_t sof_timestamp_val; }; /** diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c index dda04f8e516417eb4bc8dafef6e13a4d597ce34f..d531fdcf388ba8b861d53351ca80aad1d921a3fc 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -128,6 +128,21 @@ static int32_t cam_get_free_handle_index(void) return idx; } +void cam_dump_tbl_info(void) +{ + int i; + + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) + CAM_INFO(CAM_CRM, "session_hdl=%x hdl_value=%x\n" + "type=%d state=%d dev_id=%lld", + hdl_tbl->hdl[i].session_hdl, + hdl_tbl->hdl[i].hdl_value, + hdl_tbl->hdl[i].type, + hdl_tbl->hdl[i].state, + hdl_tbl->hdl[i].dev_id); + +} + int32_t cam_create_session_hdl(void *priv) { int idx; @@ -144,6 +159,7 @@ int32_t cam_create_session_hdl(void *priv) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create session handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -177,6 +193,7 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create device handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -189,6 +206,7 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) hdl_tbl->hdl[idx].state = HDL_ACTIVE; hdl_tbl->hdl[idx].priv = hdl_data->priv; hdl_tbl->hdl[idx].ops = hdl_data->ops; + hdl_tbl->hdl[idx].dev_id = hdl_data->dev_id; spin_unlock_bh(&hdl_tbl_lock); pr_debug("%s: handle = %x", __func__, handle); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h index 7b8e3e601ed8ac6fd77e3425889e94c1e6e33264..50d6f309da15c7f775e1671e409b82e103d91d03 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -50,6 +50,7 @@ struct handle { uint32_t hdl_value; enum hdl_type type; enum hdl_state state; + uint64_t dev_id; void *ops; void *priv; }; @@ -80,6 +81,7 @@ struct cam_create_dev_hdl { int32_t v4l2_sub_dev_flag; int32_t media_entity_flag; int32_t reserved; + uint64_t dev_id; void *ops; void *priv; }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile index 65c23274e5ae171eb13743928453ece65fbd14b6..dac985dc4a27af559410a274a8091b99f0342196 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile +++ b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ir_led/ 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 f6f562c7909371312eca7b38e6d701709a71432f..3bdc0f5e0b9f4b6749c439220647b896943745e9 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -786,7 +786,7 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = a_ctrl; - + bridge_params.dev_id = CAM_ACTUATOR; actuator_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; 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 ed88282737c0942ae2c7d548141e87d0dc40b3f2..a06a4c6c6339ced623ed097ba212d2661df10531 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1094,7 +1094,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, * RD_DONE exclusively. */ rem_jiffies = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (!rem_jiffies) { rc = -ETIMEDOUT; @@ -1275,10 +1275,11 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, val = 1 << ((master * 2) + queue); cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); CAM_DBG(CAM_CCI, - "waiting_for_rd_done [exp_words: %d]", exp_words); + "waiting_for_rd_done [exp_words: %d]", + ((read_cfg->num_byte / 4) + 1)); rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (rc <= 0) { #ifdef DUMP_CCI_REGISTERS cam_cci_dump_registers(cci_dev, master, queue); @@ -1692,14 +1693,19 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, struct cam_cci_ctrl *cci_ctrl) { int32_t rc = 0; - + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + switch (cci_ctrl->cmd) { case MSM_CCI_INIT: + mutex_lock(&cci_dev->init_mutex); rc = cam_cci_init(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_RELEASE: + mutex_lock(&cci_dev->init_mutex); rc = cam_cci_release(sd); + mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: rc = cam_cci_read_bytes(sd, cci_ctrl); 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 6ac042c83604bc5a9493b7cb318feb32318620ed..69b5af0026100e20b4d2648e747597da4da9e7c7 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -71,20 +71,26 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR); + CAM_DBG(CAM_CCI, "BASE: %pK", base); CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1); if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + struct cam_cci_master_info *cci_master_info; if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; cci_dev->cci_master_info[MASTER_0].reset_pending = FALSE; - complete( - &cci_dev->cci_master_info[MASTER_0].reset_complete); + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; } if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; cci_dev->cci_master_info[MASTER_1].reset_pending = FALSE; - complete( - &cci_dev->cci_master_info[MASTER_1].reset_complete); + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; } } @@ -93,7 +99,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) cci_dev->cci_master_info[MASTER_0].status = 0; rd_done_th_assert = true; complete(&cci_dev->cci_master_info[MASTER_0].th_complete); - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); } if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && (!rd_done_th_assert)) { @@ -102,7 +108,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (cci_dev->is_burst_read) complete( &cci_dev->cci_master_info[MASTER_0].th_complete); - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); } if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && (!rd_done_th_assert)) { @@ -149,7 +155,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) cci_dev->cci_master_info[MASTER_1].status = 0; rd_done_th_assert = true; complete(&cci_dev->cci_master_info[MASTER_1].th_complete); - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); } if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && (!rd_done_th_assert)) { @@ -158,7 +164,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (cci_dev->is_burst_read) complete( &cci_dev->cci_master_info[MASTER_1].th_complete); - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); } if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && (!rd_done_th_assert)) { @@ -217,16 +223,33 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, - base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, - base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq_status0); - + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); } cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); @@ -402,7 +425,8 @@ static int cam_cci_platform_probe(struct platform_device *pdev) } g_cci_subdev[soc_info->index] = &new_cci_dev->v4l2_dev_str.sd; - CAM_ERR(CAM_CCI, "Device Type :%d", soc_info->index); + mutex_init(&(new_cci_dev->init_mutex)); + CAM_INFO(CAM_CCI, "Device Type :%d", soc_info->index); cam_register_subdev_fops(&cci_v4l2_subdev_fops); cci_v4l2_subdev_fops.unlocked_ioctl = cam_cci_subdev_fops_ioctl; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index 83c935b52885817f40907cda389f6540d7672dbf..2e4c032cb3227ca43fa079d49fa8d7ceb90abfc2 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -140,6 +140,7 @@ struct cam_cci_master_info { uint8_t reset_pending; struct mutex mutex; struct completion reset_complete; + struct completion rd_done; struct completion th_complete; struct mutex mutex_q[NUM_QUEUES]; struct completion report_q[NUM_QUEUES]; @@ -172,40 +173,41 @@ enum cam_cci_state_t { /** * struct cci_device - * @pdev: Platform device - * @subdev: V4L2 sub device - * @base: Base address of CCI device - * @hw_version: Hardware version - * @ref_count: Reference Count - * @cci_state: CCI state machine - * @num_clk: Number of CCI clock - * @cci_clk: CCI clock structure - * @cci_clk_info: CCI clock information - * @cam_cci_i2c_queue_info: CCI queue information - * @i2c_freq_mode: I2C frequency of operations - * @cci_clk_params: CCI hw clk params - * @cci_gpio_tbl: CCI GPIO table - * @cci_gpio_tbl_size: GPIO table size - * @cci_pinctrl: Pinctrl structure - * @cci_pinctrl_status: CCI pinctrl status - * @cci_clk_src: CCI clk src rate - * @cci_vreg: CCI regulator structure - * @cci_reg_ptr: CCI individual regulator structure - * @regulator_count: Regulator count - * @support_seq_write: - * Set this flag when sequential write is enabled - * @write_wq: Work queue structure - * @valid_sync: Is it a valid sync with CSID - * @v4l2_dev_str: V4L2 device structure - * @cci_wait_sync_cfg: CCI sync config - * @cycles_per_us: Cycles per micro sec - * @payload_size: CCI packet payload size - * @irq_status1: Store irq_status1 to be cleared after - * draining FIFO buffer for burst read - * @lock_status: to protect changes to irq_status1 - * @is_burst_read: Flag to determine if we are performing - * a burst read operation or not - * @irqs_disabled: Mask for IRQs that are disabled + * @pdev: Platform device + * @subdev: V4L2 sub device + * @base: Base address of CCI device + * @hw_version: Hardware version + * @ref_count: Reference Count + * @cci_state: CCI state machine + * @num_clk: Number of CCI clock + * @cci_clk: CCI clock structure + * @cci_clk_info: CCI clock information + * @cam_cci_i2c_queue_info: CCI queue information + * @i2c_freq_mode: I2C frequency of operations + * @cci_clk_params: CCI hw clk params + * @cci_gpio_tbl: CCI GPIO table + * @cci_gpio_tbl_size: GPIO table size + * @cci_pinctrl: Pinctrl structure + * @cci_pinctrl_status: CCI pinctrl status + * @cci_clk_src: CCI clk src rate + * @cci_vreg: CCI regulator structure + * @cci_reg_ptr: CCI individual regulator structure + * @regulator_count: Regulator count + * @support_seq_write: Set this flag when sequential write is enabled + * @write_wq: Work queue structure + * @valid_sync: Is it a valid sync with CSID + * @v4l2_dev_str: V4L2 device structure + * @cci_wait_sync_cfg: CCI sync config + * @cycles_per_us: Cycles per micro sec + * @payload_size: CCI packet payload size + * @irq_status1: Store irq_status1 to be cleared after + * draining FIFO buffer for burst read + * @lock_status: to protect changes to irq_status1 + * @is_burst_read: Flag to determine if we are performing + * a burst read operation or not + * @irqs_disabled: Mask for IRQs that are disabled + * @init_mutex: Mutex for maintaining refcount for attached + * devices to cci during init/deinit. */ struct cci_device { struct v4l2_subdev subdev; @@ -234,6 +236,7 @@ struct cci_device { spinlock_t lock_status; bool is_burst_read; uint32_t irqs_disabled; + struct mutex init_mutex; }; enum cam_cci_i2c_cmd_type { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h index 027a0501dcae57e5aa57c45b3f67c83de1a18925..ead18afc77ad854e2863f7ee913b0cb6a5003488 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -61,6 +61,12 @@ #define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 #define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 +#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK 0x6000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 #define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD 0x10000 #define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE 0x20000 diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c index fa290c0b982c64dbbfdf57b84276b4ed2003c568..f66d86ce091e43184c451f67800d7343e33d899c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -19,7 +19,7 @@ int cam_cci_init(struct v4l2_subdev *sd, uint8_t i = 0, j = 0; int32_t rc = 0; struct cci_device *cci_dev; - enum cci_i2c_master_t master = MASTER_0; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote; struct cam_hw_soc_info *soc_info = NULL; @@ -47,7 +47,6 @@ int cam_cci_init(struct v4l2_subdev *sd, if (cci_dev->ref_count++) { CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); - master = c_ctrl->cci_info->cci_i2c_master; CAM_DBG(CAM_CCI, "master %d", master); if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); @@ -55,6 +54,8 @@ int cam_cci_init(struct v4l2_subdev *sd, /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); + reinit_completion( + &cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); @@ -93,6 +94,7 @@ int cam_cci_init(struct v4l2_subdev *sd, /* Re-initialize the completion */ reinit_completion(&cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); @@ -128,12 +130,12 @@ int cam_cci_init(struct v4l2_subdev *sd, } } - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + cci_dev->cci_master_info[master].reset_pending = TRUE; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[MASTER_0].reset_complete, + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) { CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); @@ -205,6 +207,8 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) &new_cci_dev->cci_master_info[i].reset_complete); init_completion( &new_cci_dev->cci_master_info[i].th_complete); + init_completion( + &new_cci_dev->cci_master_info[i].rd_done); for (j = 0; j < NUM_QUEUES; j++) { mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]); @@ -406,7 +410,9 @@ int cam_cci_soc_release(struct cci_device *cci_dev) cci_dev->cci_state = CCI_STATE_DISABLED; cci_dev->cycles_per_us = 0; - cam_cpas_stop(cci_dev->cpas_handle); + rc = cam_cpas_stop(cci_dev->cpas_handle); + if (rc) + CAM_ERR(CAM_CCI, "cpas stop failed %d", rc); return rc; } 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 5304b463f7ab771044829558d6010898709034bb..2a5f0a5c7c0a8bb4c61627027e294512325d3ac8 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 @@ -551,7 +551,7 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) { struct cam_hw_soc_info *soc_info; - int32_t i = 0; + int32_t i = 0, rc = 0; if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) return; @@ -574,7 +574,10 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) cam_csiphy_reset(csiphy_dev); cam_soc_util_disable_platform_resource(soc_info, true, true); - cam_cpas_stop(csiphy_dev->cpas_handle); + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc) + CAM_ERR(CAM_CSIPHY, "cpas stop failed %d", rc); + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; } @@ -725,7 +728,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = csiphy_dev; - + bridge_params.dev_id = CAM_CSIPHY; if (csiphy_acq_params.combo_mode >= 2) { CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", csiphy_acq_params.combo_mode); @@ -934,7 +937,10 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (rc < 0) { csiphy_dev->csiphy_info.secure_mode[offset] = CAM_SECURE_MODE_NON_SECURE; - cam_cpas_stop(csiphy_dev->cpas_handle); + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, + "de-voting CPAS: %d", rc); goto release_mutex; } } @@ -942,7 +948,9 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, rc = cam_csiphy_enable_hw(csiphy_dev); if (rc != 0) { CAM_ERR(CAM_CSIPHY, "cam_csiphy_enable_hw failed"); - cam_cpas_stop(csiphy_dev->cpas_handle); + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc); goto release_mutex; } rc = cam_csiphy_config_dev(csiphy_dev); @@ -952,7 +960,9 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (rc < 0) { CAM_ERR(CAM_CSIPHY, "cam_csiphy_config_dev failed"); cam_csiphy_disable_hw(csiphy_dev); - cam_cpas_stop(csiphy_dev->cpas_handle); + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc); goto release_mutex; } csiphy_dev->start_dev_count++; 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 0bf5aac2f0900ae7cd25b54f4cfa99350f46a64f..416cb2a9fa96882d9b93919b43c6366d607cf81e 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 @@ -272,7 +272,7 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = - &data_rate_delta_table; + &data_rate_delta_table_1_2; } 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; @@ -288,7 +288,8 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->hw_version = CSIPHY_VERSION_V20; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->clk_lane = 0; - csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_2_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/include/cam_csiphy_1_2_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 67653e81fde123570822b17afb340ea1cb929c41..ac113d613fce8588e0d2e3acca2a8155dee90926 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -21,7 +21,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 21, + .csiphy_2ph_config_array_size = 22, .csiphy_3ph_config_array_size = 38, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -78,10 +78,11 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -105,6 +106,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -128,6 +130,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -151,6 +154,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -174,6 +178,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -197,10 +202,11 @@ struct csiphy_reg_t {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -224,6 +230,7 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -247,6 +254,7 @@ struct csiphy_reg_t {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -270,6 +278,7 @@ struct csiphy_reg_t {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -293,6 +302,7 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -420,7 +430,7 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }, }; -struct data_rate_settings_t data_rate_delta_table = { +struct data_rate_settings_t data_rate_delta_table_1_2 = { .num_data_rate_settings = 3, .data_rate_settings = { { 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 index b7345d4abeebcb45a9916f553f171421256eb572..e64a5da7426052ad57bebeec46cf8e6a559f2c33 100644 --- 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 @@ -297,4 +297,32 @@ struct csiphy_reg_t csiphy_3ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }, }; +struct data_rate_settings_t data_rate_delta_table_2_0 = { + .num_data_rate_settings = 2, + .data_rate_settings = { + { + // data rate <= 2 Gsps + // max bandwidth = 2 * 2.28 * (10**3) Mbps + .bandwidth = 4560000000, + .data_rate_reg_array_size = 3, + .csiphy_data_rate_regs = { + {0x0164, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS} + } + }, + { + // 2 Gsps <= data rate <= 2.5 Gsps + // max bandwidth = 2.5 * 2.28 * (10**3) Mbps + .bandwidth = 5700000000, + .data_rate_reg_array_size = 3, + .csiphy_data_rate_regs = { + {0x0164, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x40, 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_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 209daa2064d9adc813122d82ed911dad82b42224..c74be4cf4e45211755acacbec101981440a91ef1 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -356,7 +356,7 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = e_ctrl; - + bridge_params.dev_id = CAM_EEPROM; eeprom_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; @@ -439,7 +439,8 @@ static int32_t cam_eeprom_parse_memory_map( validate_size = sizeof(struct cam_cmd_unconditional_wait); if (remain_buf_len < validate_size || - *num_map >= MSM_EEPROM_MAX_MEM_MAP_CNT) { + *num_map >= (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { CAM_ERR(CAM_EEPROM, "not enough buffer"); return -EINVAL; } @@ -449,7 +450,9 @@ static int32_t cam_eeprom_parse_memory_map( if (i2c_random_wr->header.count == 0 || i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || - (size_t)*num_map > U16_MAX - i2c_random_wr->header.count) { + (size_t)*num_map >= ((MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE) - + i2c_random_wr->header.count)) { CAM_ERR(CAM_EEPROM, "OOB Error"); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h index 7ffafc377da674831576a7493e4079da6f537527..9c36134a1b8f0393b4e4043cb2c6ccfd49187c88 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -35,7 +35,7 @@ #define PROPERTY_MAXSIZE 32 #define MSM_EEPROM_MEMORY_MAP_MAX_SIZE 80 -#define MSM_EEPROM_MAX_MEM_MAP_CNT 8 +#define MSM_EEPROM_MAX_MEM_MAP_CNT 16 #define MSM_EEPROM_MEM_MAP_PROPERTIES_CNT 8 enum cam_eeprom_state { 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 1a0edb8d4d021b6a608c1a19258762725eb109f6..f4c9d254df7cd02ef72911d49084a01a51c08283 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 @@ -71,7 +71,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = fctrl; - + bridge_params.dev_id = CAM_FLASH; flash_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); fctrl->bridge_intf.device_hdl = diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2444a34c4dbaaf10a6c658f0ee3a8877b1b83401 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/Makefile @@ -0,0 +1,10 @@ +ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr +ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ir_led_dev.o cam_ir_led_soc.o cam_ir_led_core.o diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.c new file mode 100644 index 0000000000000000000000000000000000000000..590e689bf72a2a61f5926f27ab6e02d9ca055ae2 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "cam_ir_led_core.h" + +int cam_ir_led_stop_dev(struct cam_ir_led_ctrl *ictrl) +{ + return ictrl->func_tbl->camera_ir_led_off(ictrl); +} + +int cam_ir_led_release_dev(struct cam_ir_led_ctrl *ictrl) +{ + int rc = 0; + + if (ictrl->device_hdl != -1) { + rc = cam_destroy_device_hdl(ictrl->device_hdl); + if (rc) + CAM_ERR(CAM_IR_LED, + "Failed in destroying device handle rc = %d", + rc); + ictrl->device_hdl = -1; + } + + return rc; +} + +void cam_ir_led_shutdown(struct cam_ir_led_ctrl *ictrl) +{ + int rc; + + if (ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) + return; + + if (ictrl->ir_led_state == CAM_IR_LED_STATE_ON) { + rc = cam_ir_led_stop_dev(ictrl); + if (rc) + CAM_ERR(CAM_IR_LED, "Stop Failed rc: %d", rc); + } + + rc = cam_ir_led_release_dev(ictrl); + if (rc) + CAM_ERR(CAM_IR_LED, "Release failed rc: %d", rc); + else + ictrl->ir_led_state = CAM_IR_LED_STATE_INIT; +} diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.h new file mode 100644 index 0000000000000000000000000000000000000000..b05aab2f29958eb70876c5e2bb4f90eb35e279f6 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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_IR_LED_CORE_H_ +#define _CAM_IR_LED_CORE_H_ +#include "cam_ir_led_dev.h" + +void cam_ir_led_shutdown(struct cam_ir_led_ctrl *ir_led_ctrl); +int cam_ir_led_stop_dev(struct cam_ir_led_ctrl *ir_led_ctrl); +int cam_ir_led_release_dev(struct cam_ir_led_ctrl *fctrl); +#endif /*_CAM_IR_LED_CORE_H_*/ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..31dfb2c98fc8602cd85316417429428b13d2bd96 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c @@ -0,0 +1,583 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "cam_ir_led_dev.h" +#include "cam_ir_led_soc.h" +#include "cam_ir_led_core.h" + +static struct cam_ir_led_table cam_pmic_ir_led_table; + +static struct cam_ir_led_table *ir_led_table[] = { + &cam_pmic_ir_led_table, +}; + +static int32_t cam_pmic_ir_led_init( + struct cam_ir_led_ctrl *ictrl) +{ + return ictrl->func_tbl->camera_ir_led_off(ictrl); +} + +static int32_t cam_pmic_ir_led_release( + struct cam_ir_led_ctrl *ictrl) +{ + int32_t rc = 0; + + CAM_DBG(CAM_IR_LED, "Enter"); + rc = ictrl->func_tbl->camera_ir_led_off(ictrl); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "camera_ir_led_off failed (%d)", rc); + return rc; + } + return rc; +} + +static int32_t cam_pmic_ir_led_off(struct cam_ir_led_ctrl *ictrl) +{ + int32_t rc = 0; + + CAM_DBG(CAM_IR_LED, "Enter"); + if (ictrl->pwm_dev) { + pwm_disable(ictrl->pwm_dev); + } else { + CAM_ERR(CAM_IR_LED, "pwm device is null"); + return -EINVAL; + } + + rc = gpio_direction_input( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio); + if (rc) + CAM_ERR(CAM_IR_LED, "gpio operation failed(%d)", rc); + + return rc; +} + +static int32_t cam_pmic_ir_led_on( + struct cam_ir_led_ctrl *ictrl, + struct cam_ir_led_set_on_off *ir_led_data) +{ + int rc; + + if (ictrl->pwm_dev) { + rc = pwm_config(ictrl->pwm_dev, + ir_led_data->pwm_duty_on_ns, + ir_led_data->pwm_period_ns); + if (rc) { + CAM_ERR(CAM_IR_LED, "PWM config failed (%d)", rc); + return rc; + } + + rc = pwm_enable(ictrl->pwm_dev); + CAM_DBG(CAM_IR_LED, "enabled=%d, period=%llu, duty_cycle=%llu", + ictrl->pwm_dev->state.enabled, + ictrl->pwm_dev->state.period, + ictrl->pwm_dev->state.duty_cycle); + if (rc) { + CAM_ERR(CAM_IR_LED, "PWM enable failed(%d)", rc); + return rc; + } + rc = gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, + 1); + if (rc) { + CAM_ERR(CAM_IR_LED, "gpio operation failed(%d)", rc); + return rc; + } + rc = gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio, + 1); + if (rc) { + CAM_ERR(CAM_IR_LED, "gpio operation failed(%d)", rc); + return rc; + } + } else { + CAM_ERR(CAM_IR_LED, "pwm device is null"); + } + + return 0; +} + +static int32_t cam_ir_led_handle_init( + struct cam_ir_led_ctrl *ictrl) +{ + uint32_t i = 0; + int32_t rc = -EFAULT; + enum cam_ir_led_driver_type ir_led_driver_type = + ictrl->ir_led_driver_type; + + CAM_DBG(CAM_IR_LED, "IRLED HW type=%d", ir_led_driver_type); + for (i = 0; i < ARRAY_SIZE(ir_led_table); i++) { + if (ir_led_driver_type == ir_led_table[i]->ir_led_driver_type) { + ictrl->func_tbl = &ir_led_table[i]->func_tbl; + rc = 0; + break; + } + } + + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "failed invalid ir_led_driver_type %d", + ir_led_driver_type); + return -EINVAL; + } + + rc = ictrl->func_tbl->camera_ir_led_init(ictrl); + if (rc < 0) + CAM_ERR(CAM_IR_LED, "camera_ir_led_init failed (%d)", rc); + + return rc; +} +static int32_t cam_ir_led_config(struct cam_ir_led_ctrl *ictrl, + void *arg) +{ + int rc = 0; + uint32_t *cmd_buf = NULL; + uintptr_t generic_ptr; + uint32_t *offset = NULL; + size_t len_of_buffer; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_config_dev_cmd config; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_ir_led_set_on_off *cam_ir_led_info = NULL; + + if (!ictrl || !arg) { + CAM_ERR(CAM_IR_LED, "ictrl/arg is NULL"); + return -EINVAL; + } + /* getting CSL Packet */ + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user((&config), u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) { + CAM_ERR(CAM_IR_LED, "Copy cmd handle from user failed"); + rc = -EFAULT; + return rc; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + (uintptr_t *)&generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed in getting the buffer : %d", rc); + return rc; + } + + if (config.offset > len_of_buffer) { + CAM_ERR(CAM_IR_LED, + "offset is out of bounds: offset: %lld len: %zu", + config.offset, len_of_buffer); + return -EINVAL; + } + + /* Add offset to the ir_led csl header */ + csl_packet = (struct cam_packet *)(uintptr_t)(generic_ptr + + config.offset); + + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + (uintptr_t *)&generic_ptr, &len_of_buffer); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "Failed to get the command Buffer"); + return -EINVAL; + } + + cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + cmd_desc->offset); + cam_ir_led_info = (struct cam_ir_led_set_on_off *)cmd_buf; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_IR_LED_PACKET_OPCODE_ON: + rc = ictrl->func_tbl->camera_ir_led_on( + ictrl, cam_ir_led_info); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "Fail to turn irled ON rc=%d", rc); + return rc; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_ON; + break; + case CAM_IR_LED_PACKET_OPCODE_OFF: + if (ictrl->ir_led_state != CAM_IR_LED_STATE_ON) { + CAM_DBG(CAM_IR_LED, + "IRLED_OFF NA, Already OFF, state:%d", + ictrl->ir_led_state); + return 0; + } + rc = ictrl->func_tbl->camera_ir_led_off(ictrl); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "Fail to turn irled OFF rc=%d", rc); + return rc; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_OFF; + break; + case CAM_PKT_NOP_OPCODE: + CAM_DBG(CAM_IR_LED, "CAM_PKT_NOP_OPCODE"); + break; + default: + CAM_ERR(CAM_IR_LED, "Invalid Opcode : %d", + (csl_packet->header.op_code & 0xFFFFFF)); + return -EINVAL; + } + + return rc; +} + +static int32_t cam_ir_led_driver_cmd(struct cam_ir_led_ctrl *ictrl, + void *arg, struct cam_ir_led_private_soc *soc_private) +{ + int rc = 0; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_sensor_acquire_dev ir_led_acq_dev; + struct cam_create_dev_hdl dev_hdl; + struct cam_ir_led_query_cap_info ir_led_cap = {0}; + + if (!ictrl || !arg) { + CAM_ERR(CAM_IR_LED, "ictrl/arg is NULL with arg:%pK ictrl%pK", + ictrl, arg); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_IR_LED, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + mutex_lock(&(ictrl->ir_led_mutex)); + CAM_DBG(CAM_IR_LED, "cmd->op_code %d", cmd->op_code); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: + if (ictrl->ir_led_state != CAM_IR_LED_STATE_INIT) { + CAM_ERR(CAM_IR_LED, + "Cannot apply Acquire dev: Prev state: %d", + ictrl->ir_led_state); + rc = -EINVAL; + goto release_mutex; + } + + rc = copy_from_user(&ir_led_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(ir_led_acq_dev)); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed Copy from User rc=%d", rc); + goto release_mutex; + } + + dev_hdl.priv = ictrl; + + ir_led_acq_dev.device_handle = + cam_create_device_hdl(&dev_hdl); + ictrl->device_hdl = + ir_led_acq_dev.device_handle; + + rc = copy_to_user(u64_to_user_ptr(cmd->handle), &ir_led_acq_dev, + sizeof(struct cam_sensor_acquire_dev)); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed Copy to User rc=%d", rc); + rc = -EFAULT; + goto release_mutex; + } + rc = cam_ir_led_handle_init(ictrl); + ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE; + break; + case CAM_RELEASE_DEV: + if ((ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) || + (ictrl->ir_led_state == CAM_IR_LED_STATE_START)) { + CAM_WARN(CAM_IR_LED, + " Cannot apply Release dev: Prev state:%d", + ictrl->ir_led_state); + } + + if (ictrl->device_hdl == -1 && + ictrl->ir_led_state == CAM_IR_LED_STATE_ACQUIRE) { + CAM_ERR(CAM_IR_LED, + " Invalid Handle: device hdl: %d", + ictrl->device_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_ir_led_release_dev(ictrl); + if (rc) + CAM_ERR(CAM_IR_LED, + " Failed in destroying the device Handle rc= %d", + rc); + ictrl->ir_led_state = CAM_IR_LED_STATE_INIT; + break; + case CAM_QUERY_CAP: + ir_led_cap.slot_info = ictrl->soc_info.index; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), &ir_led_cap, + sizeof(struct cam_ir_led_query_cap_info))) { + CAM_ERR(CAM_IR_LED, " Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + break; + case CAM_START_DEV: + if (ictrl->ir_led_state != CAM_IR_LED_STATE_ACQUIRE) { + CAM_ERR(CAM_IR_LED, + "Cannot apply Start Dev: Prev state: %d", + ictrl->ir_led_state); + rc = -EINVAL; + goto release_mutex; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_START; + break; + case CAM_STOP_DEV: + rc = cam_ir_led_stop_dev(ictrl); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed STOP_DEV: rc=%d", rc); + goto release_mutex; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE; + break; + case CAM_CONFIG_DEV: + if ((ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) || + (ictrl->ir_led_state == CAM_IR_LED_STATE_ACQUIRE)) { + CAM_ERR(CAM_IR_LED, + "Cannot apply Config Dev: Prev state: %d", + ictrl->ir_led_state); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_ir_led_config(ictrl, arg); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed CONFIG_DEV: rc=%d", rc); + goto release_mutex; + } + break; + case CAM_FLUSH_REQ: + rc = cam_ir_led_stop_dev(ictrl); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed FLUSH_REQ: rc=%d", rc); + goto release_mutex; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE; + break; + default: + CAM_ERR(CAM_IR_LED, "Invalid Opcode:%d", cmd->op_code); + rc = -EINVAL; + } + +release_mutex: + mutex_unlock(&(ictrl->ir_led_mutex)); + return rc; +} + +static const struct of_device_id cam_ir_led_dt_match[] = { + {.compatible = "qcom,camera-ir-led", .data = NULL}, + {} +}; + +static long cam_ir_led_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_ir_led_ctrl *ictrl = NULL; + struct cam_ir_led_private_soc *soc_private = NULL; + + CAM_DBG(CAM_IR_LED, "Enter"); + + ictrl = v4l2_get_subdevdata(sd); + soc_private = ictrl->soc_info.soc_private; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ir_led_driver_cmd(ictrl, arg, + soc_private); + break; + default: + CAM_ERR(CAM_IR_LED, " Invalid ioctl cmd type"); + rc = -EINVAL; + break; + } + + CAM_DBG(CAM_IR_LED, "Exit"); + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_ir_led_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_IR_LED, + " Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ir_led_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) + CAM_ERR(CAM_IR_LED, "cam_ir_led_ioctl failed"); + break; + default: + CAM_ERR(CAM_IR_LED, " Invalid compat ioctl cmd_type:%d", + cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_IR_LED, + " Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static int cam_ir_led_platform_remove(struct platform_device *pdev) +{ + struct cam_ir_led_ctrl *ictrl; + + ictrl = platform_get_drvdata(pdev); + if (!ictrl) { + CAM_ERR(CAM_IR_LED, " Ir_led device is NULL"); + return 0; + } + + kfree(ictrl); + + return 0; +} + +static int cam_ir_led_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_ir_led_ctrl *ictrl = + v4l2_get_subdevdata(sd); + + if (!ictrl) { + CAM_ERR(CAM_IR_LED, " Ir_led ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&ictrl->ir_led_mutex); + cam_ir_led_shutdown(ictrl); + mutex_unlock(&ictrl->ir_led_mutex); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_ir_led_subdev_core_ops = { + .ioctl = cam_ir_led_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_ir_led_subdev_do_ioctl +#endif +}; + +static struct v4l2_subdev_ops cam_ir_led_subdev_ops = { + .core = &cam_ir_led_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_ir_led_internal_ops = { + .close = cam_ir_led_subdev_close, +}; + +static int32_t cam_ir_led_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_ir_led_ctrl *ictrl = NULL; + + CAM_DBG(CAM_IR_LED, "Enter"); + if (!pdev->dev.of_node) { + CAM_ERR(CAM_IR_LED, "of_node NULL"); + return -EINVAL; + } + + ictrl = kzalloc(sizeof(struct cam_ir_led_ctrl), GFP_KERNEL); + if (!ictrl) { + CAM_ERR(CAM_IR_LED, "kzalloc failed!!"); + return -ENOMEM; + } + + ictrl->pdev = pdev; + ictrl->soc_info.pdev = pdev; + ictrl->soc_info.dev = &pdev->dev; + ictrl->soc_info.dev_name = pdev->name; + + rc = cam_ir_led_get_dt_data(ictrl, &ictrl->soc_info); + if (rc) { + CAM_ERR(CAM_IR_LED, "cam_ir_led_get_dt_data failed rc=%d", rc); + if (ictrl->soc_info.soc_private != NULL) { + kfree(ictrl->soc_info.soc_private); + ictrl->soc_info.soc_private = NULL; + } + kfree(ictrl); + ictrl = NULL; + return -EINVAL; + } + + ictrl->v4l2_dev_str.internal_ops = + &cam_ir_led_internal_ops; + ictrl->v4l2_dev_str.ops = &cam_ir_led_subdev_ops; + ictrl->v4l2_dev_str.name = CAMX_IR_LED_DEV_NAME; + ictrl->v4l2_dev_str.sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + ictrl->v4l2_dev_str.ent_function = CAM_IRLED_DEVICE_TYPE; + ictrl->v4l2_dev_str.token = ictrl; + + rc = cam_register_subdev(&(ictrl->v4l2_dev_str)); + if (rc) { + CAM_ERR(CAM_IR_LED, "Fail to create subdev with %d", rc); + kfree(ictrl); + return rc; + } + + ictrl->device_hdl = -1; + platform_set_drvdata(pdev, ictrl); + v4l2_set_subdevdata(&ictrl->v4l2_dev_str.sd, ictrl); + mutex_init(&(ictrl->ir_led_mutex)); + ictrl->ir_led_state = CAM_IR_LED_STATE_INIT; + return rc; +} + +static struct cam_ir_led_table cam_pmic_ir_led_table = { + .ir_led_driver_type = IR_LED_DRIVER_PMIC, + .func_tbl = { + .camera_ir_led_init = &cam_pmic_ir_led_init, + .camera_ir_led_release = &cam_pmic_ir_led_release, + .camera_ir_led_off = &cam_pmic_ir_led_off, + .camera_ir_led_on = &cam_pmic_ir_led_on, + }, +}; + +MODULE_DEVICE_TABLE(of, cam_ir_led_dt_match); + +static struct platform_driver cam_ir_led_platform_driver = { + .probe = cam_ir_led_platform_probe, + .remove = cam_ir_led_platform_remove, + .driver = { + .name = "CAM-IR-LED-DRIVER", + .owner = THIS_MODULE, + .of_match_table = cam_ir_led_dt_match, + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(cam_ir_led_platform_driver); + +MODULE_DESCRIPTION("CAM IR_LED"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..7549435ae92b9381f7dd6d5271ef9296223429da --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h @@ -0,0 +1,164 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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_IR_LED_DEV_H_ +#define _CAM_IR_LED_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_interface.h" +#include "cam_subdev.h" +#include "cam_mem_mgr.h" +#include "cam_sensor_cmn_header.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define CAMX_IR_LED_DEV_NAME "cam-ir-led-dev" +#define CAM_IR_LED_PIPELINE_DELAY 1 +#define CAM_IR_LED_PACKET_OPCODE_OFF 0 +#define CAM_IR_LED_PACKET_OPCODE_ON 1 + +enum cam_ir_led_switch_trigger_ops { + LED_SWITCH_OFF = 0, + LED_SWITCH_ON, +}; + +enum cam_ir_led_driver_type { + IR_LED_DRIVER_GPIO, + IR_LED_DRIVER_PMIC, + IR_LED_DRIVER_DEFAULT, +}; + +enum cam_ir_led_state { + CAM_IR_LED_STATE_INIT = 0, + CAM_IR_LED_STATE_ACQUIRE, + CAM_IR_LED_STATE_START, + CAM_IR_LED_STATE_ON, + CAM_IR_LED_STATE_OFF, +}; + +/** + * struct cam_ir_led_intf_params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @link_hdl : Link Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_ir_led_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_ir_led_common_attr + * @is_settings_valid : Notify the valid settings + * @request_id : Request id provided by umd + * @count : Number of led count + * @cmd_type : Command buffer type + */ +struct cam_ir_led_common_attr { + bool is_settings_valid; + uint64_t request_id; + uint16_t count; + uint8_t cmd_type; +}; + +/** + * struct ir_led_init_packet + * @cmn_attr : Provides common attributes + * @ir_led_type : Ir_led type(PMIC/I2C/GPIO) + */ +struct cam_ir_led_init_packet { + struct cam_ir_led_common_attr cmn_attr; + uint8_t ir_led_type; +}; + +/** + * struct cam_ir_led_private_soc + * @switch_trigger_name : Switch trigger name + * @ir_led_trigger_name : Ir_led trigger name array + * @ir_led_op_current : Ir_led operational current + * @ir_led_max_current : Max supported current for LED in ir_led mode + * @ir_led_max_duration : Max turn on duration for LED in Ir_led mode + * @torch_trigger_name : Torch trigger name array + * @torch_op_current : Torch operational current + * @torch_max_current : Max supported current for LED in torch mode + */ + +struct cam_ir_led_private_soc { + const char *switch_trigger_name; + const char *ir_led_trigger_name; + uint32_t ir_led_op_current; + uint32_t ir_led_max_current; + uint32_t ir_led_max_duration; + const char *torch_trigger_name; + uint32_t torch_op_current; + uint32_t torch_max_current; +}; + +/** + * struct cam_ir_led_ctrl + * @soc_info : Soc related information + * @pdev : Platform device + * @pwm_dev : PWM device handle + * @func_tbl : structure of h/w specific function pointers + * @of_node : Of Node ptr + * @v4l2_dev_str : V4L2 device structure + * @ir_led_mutex : Mutex for ir_led operations + * @ir_led_state : Current ir_led state (INIT/ACQUIRE/START/ON/OFF) + * @device_hdl : Device Handle + * @ir_led_driver_type : ir_led driver type (GPIO/PWM) + */ +struct cam_ir_led_ctrl { + struct cam_hw_soc_info soc_info; + struct platform_device *pdev; + struct pwm_device *pwm_dev; + struct cam_ir_led_func *func_tbl; + struct device_node *of_node; + struct cam_subdev v4l2_dev_str; + struct mutex ir_led_mutex; + enum cam_ir_led_state ir_led_state; + int32_t device_hdl; + enum cam_ir_led_driver_type ir_led_driver_type; +}; + +struct cam_ir_led_func { + int32_t (*camera_ir_led_init)(struct cam_ir_led_ctrl *); + int32_t (*camera_ir_led_release)(struct cam_ir_led_ctrl *); + int32_t (*camera_ir_led_off)(struct cam_ir_led_ctrl *); + int32_t (*camera_ir_led_on)(struct cam_ir_led_ctrl *, + struct cam_ir_led_set_on_off *); +}; + +struct cam_ir_led_table { + enum cam_ir_led_driver_type ir_led_driver_type; + struct cam_ir_led_func func_tbl; +}; + +#endif /*_CAM_IR_LED_DEV_H_*/ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..cb0262fe2767256af7183a325ffe9d9116b544d3 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c @@ -0,0 +1,57 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "cam_ir_led_soc.h" +#include "cam_res_mgr_api.h" + +int cam_ir_led_get_dt_data(struct cam_ir_led_ctrl *ictrl, + struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0; + + if (!ictrl) { + CAM_ERR(CAM_IR_LED, "NULL ir_led control structure"); + return -EINVAL; + } + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "get_dt_properties failed rc %d", rc); + return rc; + } + + soc_info->soc_private = + kzalloc(sizeof(struct cam_ir_led_private_soc), GFP_KERNEL); + if (!soc_info->soc_private) { + CAM_ERR(CAM_IR_LED, "soc_info->soc_private is NULL"); + rc = -ENOMEM; + goto release_soc_res; + } + + if (of_property_read_bool(soc_info->dev->of_node, "pwms")) { + ictrl->pwm_dev = of_pwm_get(ictrl->pdev->dev.of_node, NULL); + if (ictrl->pwm_dev == NULL) + CAM_ERR(CAM_IR_LED, "Cannot get PWM device"); + ictrl->ir_led_driver_type = IR_LED_DRIVER_PMIC; + } else { + ictrl->ir_led_driver_type = IR_LED_DRIVER_GPIO; + } + + return rc; + +release_soc_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..3a9139ae2cc16312c929d0e26edbb6a02c26bd6e --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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_IR_LED_SOC_H_ +#define _CAM_IR_LED_SOC_H_ + +#include "cam_ir_led_dev.h" + +int cam_ir_led_get_dt_data(struct cam_ir_led_ctrl *fctrl, + struct cam_hw_soc_info *soc_info); + +#endif /*_CAM_IR_LED_SOC_H_*/ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index 8f8ddca8c66849eba3f0bdffa0a71f6ae8932416..937c46ab5033ef43b9003f22a629d54d7ff391f8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,7 +90,7 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = o_ctrl; - + bridge_params.dev_id = CAM_OIS; ois_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 7c44aaa4ccec5fb1ef82df1f4fcb715ea677b068..7d048b9829092d80199ec0958e3f3bf4eef75e5c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -556,6 +556,8 @@ void cam_sensor_query_cap(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensordata->subdev_id[SUB_MODULE_LED_FLASH]; query_cap->ois_slot_id = s_ctrl->sensordata->subdev_id[SUB_MODULE_OIS]; + query_cap->ir_led_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_IR_LED]; query_cap->slot_info = s_ctrl->soc_info.index; } @@ -776,7 +778,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = s_ctrl; - + bridge_params.dev_id = CAM_SENSOR; sensor_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; @@ -927,6 +929,16 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } break; case CAM_CONFIG_DEV: { + if (s_ctrl->sensor_state < CAM_SENSOR_ACQUIRE) { + rc = -EINVAL; + CAM_ERR(CAM_SENSOR, + "sensor_id:[0x%x] not acquired to configure [%d] ", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensor_state + ); + goto release_mutex; + } + rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c index 6d7d07cb4ff32f92150dc1539159ec71edec10dd..0e19f4b3aa660e647ebbae6dd1b472634d44e58a 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -98,6 +98,21 @@ int32_t cam_sensor_get_sub_module_index(struct device_node *of_node, else sensor_info->subdev_id[SUB_MODULE_CSIPHY] = val; + src_node = of_parse_phandle(of_node, "ir-led-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "ir led src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "ir led cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_IR_LED] = val; + of_node_put(src_node); + } + return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 5c5310987f62a653b2c64b5d30838dd7b4b26ddf..955dc0cf36cf8c5028943e10e6391d8588cdf4b0 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -132,6 +132,7 @@ enum sensor_sub_module { SUB_MODULE_CSID, SUB_MODULE_CSIPHY, SUB_MODULE_OIS, + SUB_MODULE_IR_LED, SUB_MODULE_EXT, SUB_MODULE_MAX, }; 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 19f410393f9b3299bbb8892033bc14ea09495448..ae0b531a916973e0e707acf9090a920980fc9ac1 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 @@ -189,7 +189,7 @@ static struct cam_iommu_cb_set iommu_cb_set; static struct dentry *smmu_dentry; -static bool smmu_fatal_flag; +static bool smmu_fatal_flag = true; static enum dma_data_direction cam_smmu_translate_dir( enum cam_smmu_map_dir dir); 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 84acb71707e2963effc08ded4707702936e388c1..b53eeebe7eb40890dbea9308bd4ccc72bd9825ee 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -288,6 +288,7 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) int rc; long idx = 0; bool bit; + int i = 0; if (!sync_obj || !merged_obj) { CAM_ERR(CAM_SYNC, "Invalid pointer(s)"); @@ -305,6 +306,14 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) return -EINVAL; } + for (i = 0; i < num_objs; i++) { + rc = cam_sync_check_valid(sync_obj[i]); + if (rc) { + CAM_ERR(CAM_SYNC, "Sync_obj[%d] %d valid check fail", + i, sync_obj[i]); + return rc; + } + } do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); if (idx >= CAM_SYNC_MAX_OBJS) @@ -376,6 +385,29 @@ int cam_sync_destroy(int32_t sync_obj) return cam_sync_deinit_object(sync_dev->sync_table, sync_obj); } +int cam_sync_check_valid(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + if (!test_bit(sync_obj, sync_dev->bitmap)) { + CAM_ERR(CAM_SYNC, "Error: Released sync obj received %d", + sync_obj); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + return 0; +} int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms) { unsigned long timeleft; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h index c735d51fe46250a54af7b169a5a6d919d8c4b92e..f2f67cb3eb7b4816fdf40c406b8dc38c5208afc5 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -147,5 +147,14 @@ int cam_sync_destroy(int32_t sync_obj); */ int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms); +/** + * @brief: Check if sync object is valid + * + * @param sync_obj: int referencing the sync object to be checked + * + * @return 0 upon success, -EINVAL if sync object is in bad state or arguments + * are invalid + */ +int cam_sync_check_valid(int32_t sync_obj); #endif /* __CAM_SYNC_API_H__ */ diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c index 4f326342e3a73695a0718d3c8a3e26cca2975e33..8ad9858987026c947997047a31539cece08b38f5 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundataion. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundataion. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -98,6 +98,9 @@ const char *cam_get_module_name(unsigned int module_id) case CAM_REQ: name = "CAM-REQ"; break; + case CAM_IR_LED: + name = "CAM-IR-LED"; + break; default: name = "CAM"; break; diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h index 3fa92df65a3a85fc923b7264098fc91815dcb697..52c334201478a446636c8b901ab0887bd73c48c3 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h @@ -47,6 +47,7 @@ #define CAM_PERF (1 << 25) #define CAM_HYP (1 << 26) +#define CAM_IR_LED (1 << 27) #define STR_BUFFER_MAX_LENGTH 1024 /* diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c index eae0dc00c03fba5299ba9e017c566b28fda83aa0..593bed9b137d41071c928c699bf9a836975ac741 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c @@ -182,11 +182,15 @@ int cam_packet_util_process_patches(struct cam_packet *packet, int i; int rc = 0; int32_t hdl; + uint64_t requestId; + uint32_t num_patches; /* process patch descriptor */ patch_desc = (struct cam_patch_desc *) ((uint32_t *) &packet->payload + packet->patch_offset/4); + requestId = packet->header.request_id; + num_patches = packet->num_patches; CAM_DBG(CAM_UTIL, "packet = %pK patch_desc = %pK size = %lu", (void *)packet, (void *)patch_desc, sizeof(struct cam_patch_desc)); @@ -197,7 +201,16 @@ int cam_packet_util_process_patches(struct cam_packet *packet, rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, hdl, &iova_addr, &src_buf_size); if (rc < 0) { - CAM_ERR(CAM_UTIL, "unable to get src buf address"); + CAM_ERR(CAM_UTIL, + "unable to get src buf address ReqId: %llu, num_patches = %d", + requestId, num_patches); + CAM_ERR(CAM_UTIL, + "i = %d patch info = %x %x %x %x src_bfsz:0x%x", + i, patch_desc[i].dst_buf_hdl, + patch_desc[i].dst_offset, + patch_desc[i].src_buf_hdl, + patch_desc[i].src_offset, + (uint32_t)src_buf_size); return rc; } src_buf_iova_addr = (uint32_t *)iova_addr; @@ -206,18 +219,37 @@ int cam_packet_util_process_patches(struct cam_packet *packet, rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, &cpu_addr, &dst_buf_len); if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { - CAM_ERR(CAM_UTIL, "unable to get dst buf address"); + CAM_ERR(CAM_UTIL, + "unable to get dst buf address ReqId: %llu, num_patches = %d", + requestId, num_patches); + CAM_ERR(CAM_UTIL, + "i = %d patch info = %x %x %x %x dst_bfsz:0x%x", + i, patch_desc[i].dst_buf_hdl, + patch_desc[i].dst_offset, + patch_desc[i].src_buf_hdl, + patch_desc[i].src_offset, + (uint32_t)dst_buf_len); return rc; } dst_cpu_addr = (uint32_t *)cpu_addr; - CAM_DBG(CAM_UTIL, "i = %d patch info = %x %x %x %x", i, - patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, + CAM_DBG(CAM_UTIL, + "ReqId: %llu, i = %d patch info = %x %x %x %x", + requestId, i, patch_desc[i].dst_buf_hdl, + patch_desc[i].dst_offset, patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); if ((size_t)patch_desc[i].src_offset >= src_buf_size) { CAM_ERR(CAM_UTIL, - "Invalid src buf patch offset"); + "Invalid src buf patch offset ReqId: %llu, num_patches = %d", + requestId, num_patches); + CAM_ERR(CAM_UTIL, + "i = %d patch info = %x %x %x %x src_bfsz:0x%x", + i, patch_desc[i].dst_buf_hdl, + patch_desc[i].dst_offset, + patch_desc[i].src_buf_hdl, + patch_desc[i].src_offset, + (uint32_t)src_buf_size); return -EINVAL; } @@ -225,7 +257,15 @@ int cam_packet_util_process_patches(struct cam_packet *packet, ((dst_buf_len - sizeof(void *)) < (size_t)patch_desc[i].dst_offset)) { CAM_ERR(CAM_UTIL, - "Invalid dst buf patch offset"); + "Invalid dst buf patch offset ReqId: %llu, num_patches = %d", + requestId, num_patches); + CAM_ERR(CAM_UTIL, + "i = %d patch info = %x %x %x %x dst_bfsz:0x%x", + i, patch_desc[i].dst_buf_hdl, + patch_desc[i].dst_offset, + patch_desc[i].src_buf_hdl, + patch_desc[i].src_offset, + (uint32_t)dst_buf_len); return -EINVAL; } @@ -353,3 +393,115 @@ int cam_packet_util_process_generic_cmd_buffer( return rc; } + +int32_t cam_packet_validate_plane_size( + struct cam_buf_io_cfg *io_cfg, + int plane_index, + size_t size) +{ + int rc = 0; + uint32_t kmd_plane_size = 0; + uint32_t plane_stride = 0; + uint32_t slice_height = 0; + uint32_t metadata_size = 0; + uint32_t format = io_cfg->format; + uint32_t plane_pixel_size = 0; + + if (plane_index < CAM_PACKET_MAX_PLANES) { + plane_stride = io_cfg->planes[plane_index].plane_stride; + slice_height = io_cfg->planes[plane_index].slice_height; + } + + if (!(plane_stride && slice_height)) { + CAM_ERR(CAM_ISP, + "Invalid values from UMD stride %d, slice height %d", + plane_stride, + slice_height); + return -EINVAL; + } + + switch (format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + kmd_plane_size = ((plane_stride * slice_height) + 16 - 1) + / 16 * 16; + break; + case CAM_FORMAT_MIPI_RAW_10: + if (plane_stride % 4 == 0) + kmd_plane_size = ((plane_stride * slice_height) + + 16 - 1) / 16 * 16; + break; + case CAM_FORMAT_MIPI_RAW_12: + if (plane_stride % 2 == 0) + kmd_plane_size = ((plane_stride * slice_height) + + 16 - 1) / 16 * 16; + break; + case CAM_FORMAT_MIPI_RAW_14: + if (plane_stride % 4 == 0) + kmd_plane_size = plane_stride * slice_height * 7 / 4; + break; + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN64: + kmd_plane_size = plane_stride * slice_height; + break; + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + if (plane_index < CAM_PACKET_MAX_PLANES) + kmd_plane_size = plane_stride * slice_height; + break; + case CAM_FORMAT_PD10: + if (plane_index < CAM_PACKET_MAX_PLANES) + kmd_plane_size = plane_stride * slice_height; + break; + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_UBWC_TP10: + metadata_size = io_cfg->planes[plane_index].meta_size; + plane_pixel_size = ((plane_stride * slice_height) + + (4096 - 1)) & ~((uint32_t) 4096 - 1); + kmd_plane_size = metadata_size + plane_pixel_size; + break; + case CAM_FORMAT_UBWC_P010: + case CAM_FORMAT_PLAIN32_20: + case CAM_FORMAT_TP10: + case CAM_FORMAT_YUV422: + case CAM_FORMAT_PD8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_ARGB: + case CAM_FORMAT_ARGB_10: + case CAM_FORMAT_ARGB_12: + case CAM_FORMAT_ARGB_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_QTI_RAW_8: + case CAM_FORMAT_QTI_RAW_10: + case CAM_FORMAT_QTI_RAW_12: + case CAM_FORMAT_QTI_RAW_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN8_SWAP: + case CAM_FORMAT_PLAIN8_10: + case CAM_FORMAT_PLAIN8_10_SWAP: + kmd_plane_size = plane_stride * slice_height; + break; + default: + kmd_plane_size = plane_stride * slice_height; + break; + } + if (!kmd_plane_size || + kmd_plane_size > (size - io_cfg->offsets[plane_index])) { + CAM_ERR(CAM_ISP, + "kmd size: %d umd size: %d width: %d height: %d stride: %d sliceheight: %d ", + kmd_plane_size, + size, + io_cfg->planes[plane_index].width, + io_cfg->planes[plane_index].height, + plane_stride, + slice_height); + return -EINVAL; + } + return rc; +} diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h index 33c07ad89f4edad143f8375d67af14c5fa5b3d7f..e49968e6a2914018c14ae222bbc2b55afec568d9 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h @@ -135,4 +135,20 @@ int cam_packet_util_process_generic_cmd_buffer( struct cam_cmd_buf_desc *cmd_buf, cam_packet_generic_blob_handler blob_handler_cb, void *user_data); +/** + * cam_packet_validate_plane_size() + * + * @brief: Utility function to calculate and validate size of buffer + * required for a format. + * @io_cfg: Contains IO config info + * @plane_index Plane index for which size is to be calculated + * + * @return: Size of buffer + * + */ +int32_t cam_packet_validate_plane_size( + struct cam_buf_io_cfg *io_cfg, + int plane_index, + size_t size); + #endif /* _CAM_PACKET_UTIL_H_ */ 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 8ba6deb54fbce99dfdacc446edde802572034eb4..7df30337e2ecf0d492ee4e681407ffcaace5b837 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 @@ -23,7 +23,7 @@ static char supported_clk_info[256]; static char debugfs_dir_name[64]; static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t src_clk_idx, int32_t clk_rate) + int32_t src_clk_idx, int64_t clk_rate) { int i; long clk_rate_round; @@ -38,7 +38,7 @@ static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, for (i = 0; i < CAM_MAX_VOTE; i++) { if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { CAM_DBG(CAM_UTIL, - "soc = %d round rate = %ld actual = %d", + "soc = %d round rate = %ld actual = %lld", soc_info->clk_rate[i][src_clk_idx], clk_rate_round, clk_rate); return i; @@ -387,7 +387,7 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, * @return: Success or failure */ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; long clk_rate_round; @@ -395,7 +395,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, if (!clk || !clk_name) return -EINVAL; - CAM_DBG(CAM_UTIL, "set %s, rate %d", clk_name, clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate); if (clk_rate > 0) { clk_rate_round = clk_round_rate(clk, clk_rate); CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); @@ -431,7 +431,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, } int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate) + int64_t clk_rate) { int32_t src_clk_idx; struct clk *clk = NULL; @@ -452,7 +452,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, clk_rate); - CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" + CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s\n" "apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h index 0ee8445c0129fb6be103af91d55b8fcfac99197c..d0bab027790e484a291886266ef86b943d43a4cd 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 @@ -390,7 +390,7 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, * @return: success or failure */ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate); + int64_t clk_rate); /** * cam_soc_util_get_option_clk_by_name() diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c index c690cf8e3a88342785c640db62bc8752ee215a12..2cca56255de0966562cc00a8abc8ea2685e2179f 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c @@ -1022,9 +1022,6 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, goto err_put; } - /* cache flush/invalidation is done by buffer provider */ - attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; - table = dma_buf_map_attachment(attach, dma_dir); if (IS_ERR_OR_NULL(table)) { rc = PTR_ERR(table); @@ -1107,9 +1104,6 @@ static int cam_smmu_unmap_buf_and_remove_from_list( return -EINVAL; } - /* skip cache operations */ - mapping_info->attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; - /* iommu buffer clean up */ dma_buf_unmap_attachment(mapping_info->attach, mapping_info->table, mapping_info->dir); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index 097046d30ff04131c66c7bfb4cd896a9496839f0..c159b144c42d3a8762d30166e505124baffa4895 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -357,26 +357,48 @@ static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg) file->f_flags & O_NONBLOCK); if (rc) return rc; - event_data = (struct msm_isp_event_data *) - isp_event.u.data; - isp_event_user = (struct v4l2_event *)arg; - memcpy(isp_event_user, &isp_event, + if (isp_event.type == ISP_EVENT_SOF_UPDATE_NANOSEC) { + struct msm_isp_event_data_nanosec *event_data_nanosec; + struct msm_isp_event_data_nanosec + *event_data_nanosec_user; + + event_data_nanosec = + (struct msm_isp_event_data_nanosec *) + isp_event.u.data; + isp_event_user = (struct v4l2_event *)arg; + memcpy(isp_event_user, &isp_event, sizeof(*isp_event_user)); - event_data32 = (struct msm_isp_event_data32 *) - isp_event_user->u.data; - memset(event_data32, 0, - sizeof(struct msm_isp_event_data32)); - event_data32->timestamp.tv_sec = - event_data->timestamp.tv_sec; - event_data32->timestamp.tv_usec = - event_data->timestamp.tv_usec; - event_data32->mono_timestamp.tv_sec = - event_data->mono_timestamp.tv_sec; - event_data32->mono_timestamp.tv_usec = - event_data->mono_timestamp.tv_usec; - event_data32->frame_id = event_data->frame_id; - memcpy(&(event_data32->u), &(event_data->u), - sizeof(event_data32->u)); + event_data_nanosec_user = + (struct msm_isp_event_data_nanosec *) + isp_event_user->u.data; + memset(event_data_nanosec_user, 0, + sizeof(struct msm_isp_event_data_nanosec)); + event_data_nanosec_user->nano_timestamp = + event_data_nanosec->nano_timestamp; + event_data_nanosec_user->frame_id = + event_data_nanosec->frame_id; + } else { + event_data = (struct msm_isp_event_data *) + isp_event.u.data; + isp_event_user = (struct v4l2_event *)arg; + memcpy(isp_event_user, &isp_event, + sizeof(*isp_event_user)); + event_data32 = (struct msm_isp_event_data32 *) + isp_event_user->u.data; + memset(event_data32, 0, + sizeof(struct msm_isp_event_data32)); + event_data32->timestamp.tv_sec = + event_data->timestamp.tv_sec; + event_data32->timestamp.tv_usec = + event_data->timestamp.tv_usec; + event_data32->mono_timestamp.tv_sec = + event_data->mono_timestamp.tv_sec; + event_data32->mono_timestamp.tv_usec = + event_data->mono_timestamp.tv_usec; + event_data32->frame_id = event_data->frame_id; + memcpy(&(event_data32->u), &(event_data->u), + sizeof(event_data32->u)); + } } else { rc = v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 233e61f45880cbbff89fde4a557638f3a7903def..bd54899f64541bacb0dc8c6a58642a7ead5d0fa6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -131,6 +131,8 @@ struct msm_isp_timestamp { struct timeval vt_time; /*Wall clock for userspace event*/ struct timeval event_time; + /* event time in nanosec*/ + uint64_t buf_time_ns; }; struct msm_vfe_irq_ops { @@ -874,6 +876,9 @@ struct vfe_device { /* irq info */ uint32_t dual_irq_mask; uint32_t irq_sof_id; + + /* nano sec timestamp */ + uint32_t nanosec_ts_enable; }; struct vfe_parent_device { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 61351734368f8edd8c62f1941af557ac3905904e..52086907fe78c7e4a539ccfe6a827a6789551f13 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -38,7 +38,7 @@ #define VFE47_STATS_BURST_LEN 3 #define VFE47_UB_SIZE_VFE0 2048 #define VFE47_UB_SIZE_VFE1 1536 -#define VFE47_UB_STATS_SIZE 144 +#define VFE47_UB_STATS_SIZE 288 #define MSM_ISP47_TOTAL_IMAGE_UB_VFE0 (VFE47_UB_SIZE_VFE0 - VFE47_UB_STATS_SIZE) #define MSM_ISP47_TOTAL_IMAGE_UB_VFE1 (VFE47_UB_SIZE_VFE1 - VFE47_UB_STATS_SIZE) #define VFE47_WM_BASE(idx) (0xA0 + 0x2C * idx) @@ -1895,30 +1895,37 @@ void msm_vfe47_cfg_axi_ub_equal_default( struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t total_image_size = 0; - uint8_t num_used_wms = 0; + uint8_t pix_num_used_wms = 0; + uint8_t rdi_num_used_wms = 0; uint32_t prop_size = 0; uint32_t wm_ub_size; + uint32_t min_ub; uint64_t delta; + uint32_t vfe_ub_size = 0; - if (frame_src == VFE_PIX_0) { - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i] && - SRC_TO_INTF( - HANDLE_TO_IDX(axi_data->free_wm[i])) == - VFE_PIX_0) { - num_used_wms++; - total_image_size += - axi_data->wm_image_size[i]; - } + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + /* separate wm for each interface as min_ub is different for + * both pix and rdi + */ + if (VFE_PIX_0 == SRC_TO_INTF( + HANDLE_TO_IDX(axi_data->free_wm[i]))) + pix_num_used_wms++; + else + rdi_num_used_wms++; + total_image_size += + axi_data->wm_image_size[i]; } - ub_offset = (axi_data->hw_info->num_rdi * 2) * - axi_data->hw_info->min_wm_ub; - prop_size = vfe_dev->hw_info->vfe_ops.axi_ops.get_ub_size( - vfe_dev) - - axi_data->hw_info->min_wm_ub * (num_used_wms + - axi_data->hw_info->num_rdi * 2); } - + /* get ub for each vfe */ + vfe_ub_size = vfe_dev->hw_info->vfe_ops.axi_ops.get_ub_size(vfe_dev); + /* calculate min_ub needed for both pix and rdi wm + * for pix min_ub 96 and rdi 192 as per hw + */ + min_ub = (axi_data->hw_info->min_wm_ub * pix_num_used_wms) + + (axi_data->hw_info->min_wm_ub * 2 * rdi_num_used_wms); + /* calculate propotional ub for all wm */ + prop_size = vfe_ub_size - min_ub; for (i = 0; i < axi_data->hw_info->num_wm; i++) { if (!axi_data->free_wm[i]) { msm_camera_io_w(0, @@ -1927,57 +1934,27 @@ void msm_vfe47_cfg_axi_ub_equal_default( vfe_dev, i)); continue; } - - if (frame_src != SRC_TO_INTF( + /* calcualte delta by considering + * wm_image_size + total imagesize + */ + delta = (uint64_t)axi_data->wm_image_size[i] * + (uint64_t)prop_size; + do_div(delta, total_image_size); + /* to meet hw constraint add min_ub of 192 + * for RDI and 96 for pix + */ + if (VFE_PIX_0 != SRC_TO_INTF( HANDLE_TO_IDX(axi_data->free_wm[i]))) - continue; - - if (frame_src == VFE_PIX_0) { - if (total_image_size) { - delta = (uint64_t)axi_data->wm_image_size[i] * - (uint64_t)prop_size; - do_div(delta, total_image_size); - wm_ub_size = axi_data->hw_info->min_wm_ub + + wm_ub_size = (axi_data->hw_info->min_wm_ub * 2) + (uint32_t)delta; - msm_camera_io_w(ub_offset << 16 | - (wm_ub_size - 1), - vfe_dev->vfe_base + - vfe_dev->hw_info->vfe_ops.axi_ops - .ub_reg_offset(vfe_dev, i)); - ub_offset += wm_ub_size; - } else { - pr_err("%s: image size is zero\n", __func__); - } - } else { - uint32_t rdi_ub_offset; - int plane; - int vfe_idx; - struct msm_vfe_axi_stream *stream_info; - - stream_info = msm_isp_get_stream_common_data(vfe_dev, - HANDLE_TO_IDX(axi_data->free_wm[i])); - if (!stream_info) { - pr_err("%s: stream_info is NULL!", __func__); - return; - } - vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - for (plane = 0; plane < stream_info->num_planes; - plane++) - if (stream_info->wm[vfe_idx][plane] == - axi_data->free_wm[i]) - break; - - rdi_ub_offset = (SRC_TO_INTF( - HANDLE_TO_IDX(axi_data->free_wm[i])) - - VFE_RAW_0) * - axi_data->hw_info->min_wm_ub * 2; - wm_ub_size = axi_data->hw_info->min_wm_ub * 2; - msm_camera_io_w(rdi_ub_offset << 16 | (wm_ub_size - 1), - vfe_dev->vfe_base + - vfe_dev->hw_info->vfe_ops.axi_ops.ub_reg_offset( - vfe_dev, i)); - } + else + wm_ub_size = axi_data->hw_info->min_wm_ub + + (uint32_t)delta; + msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), + vfe_dev->vfe_base + + vfe_dev->hw_info->vfe_ops.axi_ops.ub_reg_offset( + vfe_dev, i)); + ub_offset += wm_ub_size; } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c index d23c7caf004b1bc25ab98c841aed93f2b338357e..80f98182d624ac254ad5bcbd82740c63f4d19c63 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c @@ -30,7 +30,7 @@ #define MSM_VFE48_BUS_CLIENT_INIT 0xABAB #define VFE48_STATS_BURST_LEN 3 #define VFE48_UB_SIZE_VFE 2048 /* 2048 * 256 bits = 64KB */ -#define VFE48_UB_STATS_SIZE 144 +#define VFE48_UB_STATS_SIZE 288 #define MSM_ISP48_TOTAL_IMAGE_UB_VFE (VFE48_UB_SIZE_VFE - VFE48_UB_STATS_SIZE) @@ -321,15 +321,15 @@ void msm_vfe48_stats_cfg_ub(struct vfe_device *vfe_dev) int i; uint32_t ub_offset = 0, stats_burst_len; uint32_t ub_size[VFE47_NUM_STATS_TYPE] = { - 16, /* MSM_ISP_STATS_HDR_BE */ - 16, /* MSM_ISP_STATS_BG */ - 16, /* MSM_ISP_STATS_BF */ - 16, /* MSM_ISP_STATS_HDR_BHIST */ - 16, /* MSM_ISP_STATS_RS */ - 16, /* MSM_ISP_STATS_CS */ - 16, /* MSM_ISP_STATS_IHIST */ - 16, /* MSM_ISP_STATS_BHIST */ - 16, /* MSM_ISP_STATS_AEC_BG */ + 32, /* MSM_ISP_STATS_HDR_BE */ + 32, /* MSM_ISP_STATS_BG */ + 32, /* MSM_ISP_STATS_BF */ + 32, /* MSM_ISP_STATS_HDR_BHIST */ + 32, /* MSM_ISP_STATS_RS */ + 32, /* MSM_ISP_STATS_CS */ + 32, /* MSM_ISP_STATS_IHIST */ + 32, /* MSM_ISP_STATS_BHIST */ + 32, /* MSM_ISP_STATS_AEC_BG */ }; stats_burst_len = VFE48_STATS_BURST_LEN; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 7ceb09b8ec90193acf9e5e64932cdfef6d2bc5f9..a773f3770c540e796daf2ee20dd2d97eca815d4d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -628,12 +628,9 @@ static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info, MSM_VFE_STREAM_STOP_PERIOD; } - if (stream_info->undelivered_request_cnt > 0 && - drop_reconfig != 1) + if (stream_info->undelivered_request_cnt > 0) stream_info->current_framedrop_period = MSM_VFE_STREAM_STOP_PERIOD; - if (stream_info->controllable_output && drop_reconfig == 1) - stream_info->current_framedrop_period = 1; /* * re-configure the period pattern, only if it's not already * set to what we want @@ -695,7 +692,8 @@ void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, uint32_t drop_reconfig = vfe_dev->isp_page->drop_reconfig; if (stream_info->num_isp > 1 && - vfe_dev->pdev->id == ISP_VFE0) { + vfe_dev->pdev->id == ISP_VFE0 && + !vfe_dev->dual_vfe_sync_mode) { c_data = vfe_dev->common_data; temp = c_data->dual_vfe_res->vfe_dev[ ISP_VFE1]; @@ -1152,6 +1150,19 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, break; } + if ((vfe_dev->nanosec_ts_enable) && + (event_type == ISP_EVENT_SOF) && + (frame_src == VFE_PIX_0)) { + struct msm_isp_event_data_nanosec event_data_nanosec; + + event_data_nanosec.frame_id = + vfe_dev->axi_data.src_info[frame_src].frame_id; + event_data_nanosec.nano_timestamp = ts->buf_time_ns; + msm_isp_send_event_update_nanosec(vfe_dev, + ISP_EVENT_SOF_UPDATE_NANOSEC, + &event_data_nanosec); + } + event_data.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id; event_data.timestamp = ts->event_time; event_data.mono_timestamp = ts->buf_time; @@ -3700,8 +3711,14 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return -EINVAL; } - /* return early for dual vfe0 */ - if (stream_info->num_isp > 1 && vfe_dev->pdev->id == ISP_VFE0) + /* return early for dual vfe */ + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE1 && + vfe_dev->dual_vfe_sync_mode) + return 0; + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0 && + !vfe_dev->dual_vfe_sync_mode) return 0; if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { @@ -3736,9 +3753,10 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, (stream_info->undelivered_request_cnt <= MAX_BUFFERS_IN_HW) ) { - pr_debug("%s:%d invalid time to request frame %d\n", + pr_debug("%s:%d invalid time to request frame %d try drop_reconfig\n", __func__, __LINE__, frame_id); vfe_dev->isp_page->drop_reconfig = 1; + return 0; } else if ((vfe_dev->axi_data.src_info[frame_src].active) && ((frame_id == vfe_dev->axi_data.src_info[frame_src].frame_id) || @@ -3746,10 +3764,11 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, (stream_info->undelivered_request_cnt <= MAX_BUFFERS_IN_HW)) { vfe_dev->isp_page->drop_reconfig = 1; - pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d\n", + pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d try drop_reconfig\n", __func__, vfe_dev->pdev->id, frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].active); + return 0; } else if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id != vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev->axi_data.src_info[frame_src].sof_counter_step)) || @@ -3770,19 +3789,18 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if ((frame_src == VFE_PIX_0) && !stream_info->undelivered_request_cnt && MSM_VFE_STREAM_STOP_PERIOD != stream_info->activated_framedrop_period) { + /* wm is reloaded if undelivered_request_cnt is zero. + * As per the hw behavior wm should be disabled or skip writing + * before reload happens other wise wm could start writing from + * middle of the frame and could result in image corruption. + * instead of dropping frame in this error scenario use + * drop_reconfig flag to process the request in next sof. + */ pr_debug("%s:%d vfe %d frame_id %d prev_pattern %x stream_id %x\n", __func__, __LINE__, vfe_dev->pdev->id, frame_id, stream_info->activated_framedrop_period, stream_info->stream_id); - - rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, - user_stream_id, frame_id, buf_index, frame_src); - if (rc < 0) - pr_err("%s:%d failed: return_empty_buffer src %d\n", - __func__, __LINE__, frame_src); - stream_info->current_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; - msm_isp_cfg_framedrop_reg(stream_info); + vfe_dev->isp_page->drop_reconfig = 1; return 0; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c index 2eed3c077ff2e6c94646ce3361ff2769b4d59a27..6dec6f8cb15cf8897961af7f31b0b9115890665c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1214,7 +1214,7 @@ static void msm_isp_update_rdi_output_count( for (i = 0; i < stream_cfg_cmd->num_streams; i++) { if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) + >= MAX_NUM_STREAM) return; stream_info = &axi_data->stream_info[ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 5afb8b70eb335c8d0f483503b32c2838f7d6c741..c1bc1c2f017787dcc1911fd77ff773edab345e79 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -218,6 +218,8 @@ void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, get_monotonic_boottime(&ts); time_stamp->buf_time.tv_sec = ts.tv_sec; time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; + time_stamp->buf_time_ns = + ((uint64_t)ts.tv_sec * 1000000000) + ts.tv_nsec; } } @@ -265,6 +267,9 @@ static inline u32 msm_isp_evt_mask_to_isp_event(u32 evt_mask) case ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR: evt_id = ISP_EVENT_BUF_FATAL_ERROR; break; + case ISP_EVENT_MASK_INDEX_SOF_UPDATE_NANOSEC: + evt_id = ISP_EVENT_SOF_UPDATE_NANOSEC; + break; default: evt_id = ISP_EVENT_SUBS_MASK_NONE; break; @@ -294,6 +299,7 @@ static inline int msm_isp_subscribe_event_mask(struct v4l2_fh *fh, } } } else if (evt_mask_index == ISP_EVENT_MASK_INDEX_SOF || + evt_mask_index == ISP_EVENT_MASK_INDEX_SOF_UPDATE_NANOSEC || evt_mask_index == ISP_EVENT_MASK_INDEX_REG_UPDATE || evt_mask_index == ISP_EVENT_MASK_INDEX_STREAM_UPDATE_DONE) { for (interface = 0; interface < VFE_SRC_MAX; interface++) { @@ -339,7 +345,7 @@ static inline int msm_isp_process_event_subscription(struct v4l2_fh *fh, } for (evt_mask_index = ISP_EVENT_MASK_INDEX_STATS_NOTIFY; - evt_mask_index <= ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR; + evt_mask_index <= ISP_EVENT_MASK_INDEX_SOF_UPDATE_NANOSEC; evt_mask_index++) { if (evt_mask & (1<dual_vfe_sync_enable = mode->enable; return 0; } +static int msm_isp_nano_sec_timestamp( + struct vfe_device *vfe_dev, void *arg) +{ + struct msm_vfe_nano_sec_timestamp *mode = arg; + + vfe_dev->nanosec_ts_enable = mode->enable; + return 0; +} int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg) { int rc = 0; @@ -912,9 +926,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, case VIDIOC_MSM_ISP_CFG_STREAM: mutex_lock(&vfe_dev->core_mutex); MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); - mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_axi_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->buf_mgr->lock); MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; @@ -1031,9 +1043,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, case VIDIOC_MSM_ISP_CFG_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); - mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_stats_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->buf_mgr->lock); MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; @@ -1076,6 +1086,11 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, rc = msm_isp_set_dual_vfe_sync_mode(vfe_dev, arg); mutex_unlock(&vfe_dev->core_mutex); break; + case VIDIOC_MSM_ISP_NANOSEC_TIMESTAMP: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_nano_sec_timestamp(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; default: pr_err_ratelimited("%s: Invalid ISP command %x\n", __func__, cmd); @@ -1576,6 +1591,21 @@ int msm_isp_send_event(struct vfe_device *vfe_dev, return 0; } +int msm_isp_send_event_update_nanosec(struct vfe_device *vfe_dev, + uint32_t event_type, + struct msm_isp_event_data_nanosec *event_data) +{ + struct v4l2_event isp_event; + + memset(&isp_event, 0, sizeof(struct v4l2_event)); + isp_event.id = 0; + isp_event.type = event_type; + memcpy(&isp_event.u.data[0], event_data, + sizeof(struct msm_isp_event_data_nanosec)); + v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event); + return 0; +} + #define CAL_WORD(width, M, N) ((width * M + N - 1) / N) int msm_isp_cal_word_per_line(uint32_t output_format, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h index 638697b6d63594c9f3bf1bd3852108857dfec29a..032ede501bc7221e54238b021632bfef724c9409 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h @@ -54,6 +54,8 @@ int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg); int msm_isp_send_event(struct vfe_device *vfe_dev, uint32_t type, struct msm_isp_event_data *event_data); +int msm_isp_send_event_update_nanosec(struct vfe_device *vfe_dev, + uint32_t type, struct msm_isp_event_data_nanosec *event_data); int msm_isp_cal_word_per_line(uint32_t output_format, uint32_t pixel_per_line); int msm_isp_get_bit_per_pixel(uint32_t output_format); diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index ed011f236e7ddf7e83a498ac7f54f09168bab526..fe15782812d2291ff6e3b843c2af1a90c94ae2c8 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,7 +32,7 @@ #define CYCLES_PER_MICRO_SEC_DEFAULT 4915 #define CCI_MAX_DELAY 1000000 -#define CCI_TIMEOUT msecs_to_jiffies(100) +#define CCI_TIMEOUT msecs_to_jiffies(500) /* TODO move this somewhere else */ #define MSM_CCI_DRV_NAME "msm_cci" diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index e77c98efc11d9322811f3d73e493dd4e9cc74599..851bb261ca1ba3e4c7decca107100eeb2cab486f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -62,7 +62,14 @@ #define SOF_DEBUG_DISABLE 0 #define SCM_SVC_CAMERASS 0x18 -#define SECURE_SYSCALL_ID 0x6 +#define SECURE_SYSCALL_ID 0x7 +#define TOPOLOGY_SYSCALL_ID 0x8 +#define STREAM_NOTIF_SYSCALL_ID 0x9 + +#define CSIPHY_0_LANES_MASK 0x000f +#define CSIPHY_1_LANES_MASK 0x00f0 +#define CSIPHY_2_LANES_MASK 0x0f00 +#define CSIPHY_3_LANES_MASK 0xf000 #define TRUE 1 #define FALSE 0 @@ -73,6 +80,13 @@ #undef CDBG #define CDBG(fmt, args...) pr_debug(fmt, ##args) +static const uint32_t CSIPHY_LANES_MASKS[] = { + CSIPHY_0_LANES_MASK, + CSIPHY_1_LANES_MASK, + CSIPHY_2_LANES_MASK, + CSIPHY_3_LANES_MASK, +}; + static struct camera_vreg_t csid_vreg_info[] = { {"qcom,mipi-csi-vdd", 0, 0, 12000}, }; @@ -340,6 +354,63 @@ static bool msm_csid_find_max_clk_rate(struct csid_device *csid_dev) } return ret; } + +static int msm_csid_seccam_send_topology(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) +{ + void __iomem *csidbase; + struct scm_desc desc = {0}; + + csidbase = csid_dev->base; + if (!csidbase || !csid_params) { + pr_err("%s:%d csidbase %pK, csid params %pK\n", __func__, + __LINE__, csidbase, csid_params); + return -EINVAL; + } + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = csid_params->phy_sel; + desc.args[1] = csid_params->topology; + + CDBG("phy_sel %d, topology %d\n", + csid_params->phy_sel, csid_params->topology); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, + TOPOLOGY_SYSCALL_ID), &desc)) { + pr_err("%s:%d scm call to hypervisor failed\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +static int msm_csid_seccam_reset_pipeline(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) +{ + void __iomem *csidbase; + struct scm_desc desc = {0}; + + csidbase = csid_dev->base; + if (!csidbase || !csid_params) { + pr_err("%s:%d csidbase %pK, csid params %pK\n", __func__, + __LINE__, csidbase, csid_params); + return -EINVAL; + } + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = csid_params->phy_sel; + desc.args[1] = csid_params->is_streamon; + + CDBG("phy_sel %d, is_streamon %d\n", + csid_params->phy_sel, csid_params->is_streamon); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, + STREAM_NOTIF_SYSCALL_ID), &desc)) { + pr_err("%s:%d scm call to hypervisor failed\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + static int msm_csid_config(struct csid_device *csid_dev, struct msm_camera_csid_params *csid_params) { @@ -377,17 +448,19 @@ static int msm_csid_config(struct csid_device *csid_dev, desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); desc.args[0] = csid_params->is_secure; - desc.args[1] = csid_params->phy_sel; + desc.args[1] = CSIPHY_LANES_MASKS[csid_params->phy_sel]; CDBG("phy_sel : %d, secure : %d\n", csid_params->phy_sel, csid_params->is_secure); + + msm_camera_tz_clear_tzbsp_status(); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID), &desc)) { pr_err("%s:%d scm call to hypervisor failed\n", __func__, __LINE__); return -EINVAL; } - msm_camera_tz_clear_tzbsp_status(); } csid_dev->csid_lane_cnt = csid_params->lane_cnt; @@ -757,7 +830,8 @@ static int msm_csid_release(struct csid_device *csid_dev) desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); desc.args[0] = 0; - desc.args[1] = csid_dev->current_csid_params.phy_sel; + desc.args[1] = CSIPHY_LANES_MASKS[ + csid_dev->current_csid_params.phy_sel]; if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID), &desc)) { @@ -886,6 +960,32 @@ static int32_t msm_csid_cmd(struct csid_device *csid_dev, void *arg) kfree(csid_params.lut_params.vc_cfg[i]); break; } + case CSID_SECCAM_TOPOLOGY: { + struct msm_camera_csid_params csid_params; + + if (copy_from_user(&csid_params, + (void __user *)cdata->cfg.csid_params, + sizeof(struct msm_camera_csid_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_csid_seccam_send_topology(csid_dev, &csid_params); + break; + } + case CSID_SECCAM_RESET: { + struct msm_camera_csid_params csid_params; + + if (copy_from_user(&csid_params, + (void __user *)cdata->cfg.csid_params, + sizeof(struct msm_camera_csid_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_csid_seccam_reset_pipeline(csid_dev, &csid_params); + break; + } case CSID_RELEASE: rc = msm_csid_release(csid_dev); break; @@ -1058,6 +1158,41 @@ static int32_t msm_csid_cmd32(struct csid_device *csid_dev, void *arg) } break; } + case CSID_SECCAM_TOPOLOGY: { + struct msm_camera_csid_params csid_params; + struct msm_camera_csid_params32 csid_params32; + + if (copy_from_user(&csid_params32, + (void __user *)compat_ptr(arg32->cfg.csid_params), + sizeof(struct msm_camera_csid_params32))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + csid_params.topology = csid_params32.topology; + csid_params.phy_sel = csid_params32.phy_sel; + + rc = msm_csid_seccam_send_topology(csid_dev, &csid_params); + break; + } + case CSID_SECCAM_RESET: { + struct msm_camera_csid_params csid_params; + struct msm_camera_csid_params32 csid_params32; + + if (copy_from_user(&csid_params32, + (void __user *)compat_ptr(arg32->cfg.csid_params), + sizeof(struct msm_camera_csid_params32))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + csid_params.is_streamon = csid_params32.is_streamon; + csid_params.phy_sel = csid_params32.phy_sel; + rc = msm_csid_seccam_reset_pipeline(csid_dev, &csid_params); + break; + } case CSID_RELEASE: rc = msm_csid_release(csid_dev); break; diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 6e48329b01d04dad987cce31643bfb75b50ccba2..a9995e73ee1d9be080dc5ae117dc19ad300908b5 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -1483,6 +1483,11 @@ static int npu_exec_network(struct npu_client *client, return -EINVAL; } + if (!req.patching_required) { + pr_err("Only support patched network"); + return -EINVAL; + } + ret = npu_host_exec_network(client, &req); if (ret) { @@ -1513,7 +1518,8 @@ static int npu_exec_network_v2(struct npu_client *client, return -EFAULT; } - if (req.patch_buf_info_num > NPU_MAX_PATCH_NUM) { + if ((req.patch_buf_info_num > NPU_MAX_PATCH_NUM) || + (req.patch_buf_info_num == 0)) { pr_err("Invalid patch buf info num %d[max:%d]\n", req.patch_buf_info_num, NPU_MAX_PATCH_NUM); return -EINVAL; diff --git a/drivers/media/platform/msm/npu/npu_hw_access.c b/drivers/media/platform/msm/npu/npu_hw_access.c index 08423699803756f2f3f0110acc5beedbe87890b9..27b3a2e2db01572deb8fb09228e6b41de2c70c6a 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.c +++ b/drivers/media/platform/msm/npu/npu_hw_access.c @@ -298,8 +298,6 @@ int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size, goto map_end; } - dma_sync_sg_for_device(&(npu_dev->pdev->dev), ion_buf->table->sgl, - ion_buf->table->nents, DMA_BIDIRECTIONAL); ion_buf->iova = ion_buf->table->sgl->dma_address; ion_buf->size = ion_buf->dma_buf->size; *addr = ion_buf->iova; diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index 7e8a9c3f591b8987420dd74caa2efebe56ef6126..6669e29f532c6019a25748fd7bd26aed0f1f4eb0 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -579,6 +579,17 @@ static struct npu_network *alloc_network(struct npu_host_ctx *ctx, WARN_ON(!mutex_is_locked(&ctx->lock)); + for (i = 0; i < MAX_LOADED_NETWORK; i++) { + if ((network->id != 0) && + (network->client != client)) { + pr_err("NPU is used by other client now\n"); + return NULL; + } + + network++; + } + + network = ctx->networks; for (i = 0; i < MAX_LOADED_NETWORK; i++) { if (network->id == 0) break; @@ -1078,8 +1089,16 @@ int32_t npu_host_get_info(struct npu_device *npu_dev, int32_t npu_host_map_buf(struct npu_client *client, struct msm_npu_map_buf_ioctl *map_ioctl) { - return npu_mem_map(client, map_ioctl->buf_ion_hdl, map_ioctl->size, + struct npu_device *npu_dev = client->npu_dev; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + int ret; + + mutex_lock(&host_ctx->lock); + ret = npu_mem_map(client, map_ioctl->buf_ion_hdl, map_ioctl->size, &map_ioctl->npu_phys_addr); + mutex_unlock(&host_ctx->lock); + + return ret; } int32_t npu_host_unmap_buf(struct npu_client *client, @@ -1097,8 +1116,10 @@ int32_t npu_host_unmap_buf(struct npu_client *client, &host_ctx->fw_deinit_done, NW_CMD_TIMEOUT)) pr_warn("npu: wait for fw_deinit_done time out\n"); + mutex_lock(&host_ctx->lock); npu_mem_unmap(client, unmap_ioctl->buf_ion_hdl, unmap_ioctl->npu_phys_addr); + mutex_unlock(&host_ctx->lock); return 0; } diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index e191a4201b8c029a51f55fef96da8c6d5f274786..463f56f4a8ac1d6556f45039f4a3ef7059de2a2c 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -544,6 +544,7 @@ static int get_hfi_extradata_index(enum hal_extradata_id index) break; case HAL_EXTRADATA_ASPECT_RATIO: case HAL_EXTRADATA_OUTPUT_CROP: + case HAL_EXTRADATA_INPUT_CROP: ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA; break; case HAL_EXTRADATA_MPEG2_SEQDISP: @@ -604,6 +605,9 @@ static int get_hfi_extradata_id(enum hal_extradata_id index) case HAL_EXTRADATA_OUTPUT_CROP: ret = MSM_VIDC_EXTRADATA_OUTPUT_CROP; break; + case HAL_EXTRADATA_INPUT_CROP: + ret = MSM_VIDC_EXTRADATA_INPUT_CROP; + break; default: ret = get_hfi_extradata_index(index); break; diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index bb5661bd00ad008d263b3422e6fb205dc606d026..cb804b175024d30e7d67c411cfb67f051369d384 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -104,12 +104,22 @@ static int get_hal_pixel_depth(u32 hfi_bit_depth) return MSM_VIDC_BIT_DEPTH_UNSUPPORTED; } +static inline int validate_pkt_size(u32 rem_size, u32 msg_size) +{ + if (rem_size < msg_size) { + dprintk(VIDC_ERR, "%s: bad_packet_size: %d\n", + __func__, rem_size); + return false; + } + return true; +} + static int hfi_process_sess_evt_seq_changed(u32 device_id, struct hfi_msg_event_notify_packet *pkt, struct msm_vidc_cb_info *info) { struct msm_vidc_cb_event event_notify = {0}; - int num_properties_changed; + u32 num_properties_changed; struct hfi_frame_size *frame_sz; struct hfi_profile_level *profile_level; struct hfi_bit_depth *pixel_depth; @@ -117,17 +127,15 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, struct hfi_buffer_requirements *buf_req; struct hfi_index_extradata_input_crop_payload *crop_info; struct hfi_dpb_counts *dpb_counts; - u32 entropy_mode = 0; + u32 rem_size, entropy_mode = 0; u8 *data_ptr; int prop_id; int luma_bit_depth, chroma_bit_depth; struct hfi_colour_space *colour_info; - if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) { - dprintk(VIDC_ERR, - "hal_process_session_init_done: bad_pkt_size\n"); + if (!validate_pkt_size(pkt->size, + sizeof(struct hfi_msg_event_notify_packet))) return -E2BIG; - } event_notify.device_id = device_id; event_notify.session_id = (void *)(uintptr_t)pkt->session_id; @@ -148,10 +156,18 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, if (num_properties_changed) { data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; + rem_size = pkt->size - sizeof(struct + hfi_msg_event_notify_packet) + sizeof(u32); do { + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = (int) *((u32 *)data_ptr); + rem_size -= sizeof(u32); switch (prop_id) { case HFI_PROPERTY_PARAM_FRAME_SIZE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_frame_size))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); frame_sz = (struct hfi_frame_size *) data_ptr; @@ -161,8 +177,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, frame_sz->height, frame_sz->width); data_ptr += sizeof(struct hfi_frame_size); + rem_size -= sizeof(struct hfi_frame_size); break; case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_profile_level))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); profile_level = (struct hfi_profile_level *) data_ptr; @@ -173,8 +193,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, profile_level->level); data_ptr += sizeof(struct hfi_profile_level); + rem_size -= sizeof(struct hfi_profile_level); break; case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_bit_depth))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pixel_depth = (struct hfi_bit_depth *) data_ptr; /* @@ -205,8 +229,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, event_notify.bit_depth, luma_bit_depth, chroma_bit_depth); data_ptr += sizeof(struct hfi_bit_depth); + rem_size -= sizeof(struct hfi_bit_depth); break; case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_pic_struct))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pic_struct = (struct hfi_pic_struct *) data_ptr; event_notify.pic_struct = @@ -216,8 +244,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, pic_struct->progressive_only); data_ptr += sizeof(struct hfi_pic_struct); + rem_size -= sizeof(struct hfi_pic_struct); break; case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_dpb_counts))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); dpb_counts = (struct hfi_dpb_counts *) data_ptr; event_notify.max_dpb_count = @@ -232,9 +264,13 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, dpb_counts->max_ref_count, dpb_counts->max_dec_buffering); data_ptr += - sizeof(struct hfi_pic_struct); + sizeof(struct hfi_dpb_counts); + rem_size -= sizeof(struct hfi_dpb_counts); break; case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_colour_space))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); colour_info = (struct hfi_colour_space *) data_ptr; @@ -245,8 +281,11 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, colour_info->colour_space); data_ptr += sizeof(struct hfi_colour_space); + rem_size -= sizeof(struct hfi_colour_space); break; case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); entropy_mode = *(u32 *)data_ptr; event_notify.entropy_mode = entropy_mode; @@ -254,8 +293,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, "Entropy Mode: 0x%x\n", entropy_mode); data_ptr += sizeof(u32); + rem_size -= sizeof(u32); break; case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_buffer_requirements))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); buf_req = (struct hfi_buffer_requirements *) @@ -267,8 +310,13 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, event_notify.capture_buf_count); data_ptr += sizeof(struct hfi_buffer_requirements); + rem_size -= + sizeof(struct hfi_buffer_requirements); break; case HFI_INDEX_EXTRADATA_INPUT_CROP: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_index_extradata_input_crop_payload))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); crop_info = (struct hfi_index_extradata_input_crop_payload *) @@ -289,6 +337,8 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, data_ptr += sizeof(struct hfi_index_extradata_input_crop_payload); + rem_size -= sizeof(struct + hfi_index_extradata_input_crop_payload); break; default: dprintk(VIDC_ERR, @@ -321,6 +371,12 @@ static int hfi_process_evt_release_buffer_ref(u32 device_id, "hal_process_session_init_done: bad_pkt_size\n"); return -E2BIG; } + if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32) + + sizeof(struct hfi_msg_release_buffer_ref_event_packet)) { + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, pkt->size); + return -E2BIG; + } data = (struct hfi_msg_release_buffer_ref_event_packet *) pkt->rg_ext_event_data; @@ -754,7 +810,7 @@ static inline void copy_cap_prop( } static int hfi_fill_codec_info(u8 *data_ptr, - struct vidc_hal_sys_init_done *sys_init_done) + struct vidc_hal_sys_init_done *sys_init_done, u32 rem_size) { u32 i; u32 codecs = 0, codec_count = 0, size = 0; @@ -765,6 +821,9 @@ static int hfi_fill_codec_info(u8 *data_ptr, if (prop_id == HFI_PROPERTY_PARAM_CODEC_SUPPORTED) { struct hfi_codec_supported *prop; + if (!validate_pkt_size(rem_size - sizeof(u32), + sizeof(struct hfi_codec_supported))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); prop = (struct hfi_codec_supported *) data_ptr; sys_init_done->dec_codec_supported = @@ -772,6 +831,8 @@ static int hfi_fill_codec_info(u8 *data_ptr, sys_init_done->enc_codec_supported = prop->encoder_codec_supported; size = sizeof(struct hfi_codec_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_codec_supported) + sizeof(u32); } else { dprintk(VIDC_WARN, "%s: prop_id %#x, expected codec_supported property\n", @@ -812,14 +873,22 @@ static int hfi_fill_codec_info(u8 *data_ptr, } sys_init_done->codec_count = codec_count; + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = *((u32 *)(orig_data_ptr + size)); if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) { - struct hfi_max_sessions_supported *prop = - (struct hfi_max_sessions_supported *) + struct hfi_max_sessions_supported *prop; + + if (!validate_pkt_size(rem_size - sizeof(u32), sizeof(struct + hfi_max_sessions_supported))) + return -E2BIG; + prop = (struct hfi_max_sessions_supported *) (orig_data_ptr + size + sizeof(u32)); sys_init_done->max_sessions_supported = prop->max_sessions; size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_max_sessions_supported) + sizeof(u32); dprintk(VIDC_DBG, "max_sessions_supported %d\n", prop->max_sessions); } @@ -942,6 +1011,21 @@ static enum vidc_status hfi_parse_init_done_properties( u32 prop_id, next_offset; u32 codecs = 0, domain = 0; +#define VALIDATE_PROPERTY_STRUCTURE_SIZE(pkt_size, property_size) ({\ + if (pkt_size < property_size) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + +#define VALIDATE_PROPERTY_PAYLOAD_SIZE(pkt_size, payload_size, \ + property_count) ({\ + if (pkt_size/payload_size < property_count) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + while (status == VIDC_ERR_NONE && num_properties && rem_bytes >= sizeof(u32)) { @@ -955,6 +1039,10 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_codec_mask_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + codecs = prop->codecs; domain = prop->video_domains; next_offset += sizeof(struct hfi_codec_mask_supported); @@ -967,11 +1055,14 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_capability_supported_info *) (data_ptr + next_offset); - if ((rem_bytes - next_offset) < prop->num_capabilities * - sizeof(struct hfi_capability_supported)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(u32), + sizeof(struct hfi_capability_supported), + prop->num_capabilities); + next_offset += sizeof(u32) + prop->num_capabilities * sizeof(struct hfi_capability_supported); @@ -992,10 +1083,10 @@ static enum vidc_status hfi_parse_init_done_properties( char *fmt_ptr; struct hfi_uncompressed_plane_info *plane_info; - if ((rem_bytes - next_offset) < sizeof(*prop)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + num_format_entries = prop->format_entries; next_offset = sizeof(*prop); fmt_ptr = (char *)&prop->rg_format_info[0]; @@ -1006,11 +1097,10 @@ static enum vidc_status hfi_parse_init_done_properties( plane_info = (struct hfi_uncompressed_plane_info *) fmt_ptr; - if ((rem_bytes - next_offset) < - sizeof(*plane_info)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*plane_info)); + bytes_to_skip = sizeof(*plane_info) - sizeof(struct hfi_uncompressed_plane_constraints) + @@ -1018,6 +1108,10 @@ static enum vidc_status hfi_parse_init_done_properties( sizeof(struct hfi_uncompressed_plane_constraints); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + bytes_to_skip); + fmt_ptr += bytes_to_skip; next_offset += bytes_to_skip; num_format_entries--; @@ -1030,6 +1124,15 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_properties_supported *prop = (struct hfi_properties_supported *) (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(*prop) + + sizeof(u32), sizeof(u32), + prop->num_properties); + next_offset += sizeof(*prop) - sizeof(u32) + prop->num_properties * sizeof(u32); num_properties--; @@ -1041,6 +1144,15 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_profile_level_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - + sizeof(u32), + sizeof(struct hfi_profile_level), + prop->profile_count); + next_offset += sizeof(u32) + prop->profile_count * sizeof(struct hfi_profile_level); @@ -1065,6 +1177,10 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_nal_stream_format_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + copy_nal_stream_format_caps_to_sessions( prop->nal_stream_format_supported, capabilities, num_sessions, @@ -1077,12 +1193,18 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); next_offset += sizeof(u32); num_properties--; break; } case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_intra_refresh)); next_offset += sizeof(struct hfi_intra_refresh); num_properties--; @@ -1090,6 +1212,9 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_TME_VERSION_SUPPORTED: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); capabilities->tme_version = *((u32 *)(data_ptr + next_offset)); next_offset += @@ -1103,8 +1228,13 @@ static enum vidc_status hfi_parse_init_done_properties( __func__, data_ptr, prop_id); break; } - rem_bytes -= next_offset; - data_ptr += next_offset; + + if (rem_bytes > next_offset) { + rem_bytes -= next_offset; + data_ptr += next_offset; + } else { + rem_bytes = 0; + } } return status; @@ -1115,7 +1245,8 @@ enum vidc_status hfi_process_sys_init_done_prop_read( struct vidc_hal_sys_init_done *sys_init_done) { enum vidc_status status = VIDC_ERR_NONE; - u32 rem_bytes, bytes_read, num_properties; + int bytes_read; + u32 rem_bytes, num_properties; u8 *data_ptr; if (!pkt || !sys_init_done) { @@ -1123,6 +1254,11 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "hfi_msg_sys_init_done: Invalid input\n"); return VIDC_ERR_FAIL; } + if (pkt->size < sizeof(struct hfi_msg_sys_init_done_packet)) { + dprintk(VIDC_ERR, "%s: bad_packet_size: %d\n", + __func__, pkt->size); + return VIDC_ERR_FAIL; + } rem_bytes = pkt->size - sizeof(struct hfi_msg_sys_init_done_packet) + sizeof(u32); @@ -1150,7 +1286,9 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "Venus didn't set any properties in SYS_INIT_DONE"); return status; } - bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done); + bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done, rem_bytes); + if (bytes_read < 0) + return VIDC_ERR_FAIL; data_ptr += bytes_read; rem_bytes -= bytes_read; num_properties--; @@ -1435,15 +1573,13 @@ static int hfi_process_session_etb_done(u32 device_id, struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; struct msm_vidc_cb_data_done data_done = {0}; struct hfi_picture_type *hfi_picture_type = NULL; + u32 is_sync_frame; dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id); if (!pkt || pkt->size < - sizeof(struct hfi_msg_session_empty_buffer_done_packet)) { - dprintk(VIDC_ERR, - "hal_process_session_etb_done: bad_pkt_size\n"); - return -E2BIG; - } + sizeof(struct hfi_msg_session_empty_buffer_done_packet)) + goto bad_packet_size; data_done.device_id = device_id; data_done.session_id = (void *)(uintptr_t)pkt->session_id; @@ -1463,8 +1599,13 @@ static int hfi_process_session_etb_done(u32 device_id, data_done.input_done.extra_data_buffer = pkt->extra_data_buffer; data_done.input_done.status = hfi_map_err_status(pkt->error_type); - hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0]; - if (hfi_picture_type->is_sync_frame) { + is_sync_frame = pkt->rgData[0]; + if (is_sync_frame) { + if (pkt->size < + sizeof(struct hfi_msg_session_empty_buffer_done_packet) + + sizeof(struct hfi_picture_type)) + goto bad_packet_size; + hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1]; if (hfi_picture_type->picture_type) data_done.input_done.flags = hfi_picture_type->picture_type; @@ -1481,6 +1622,10 @@ static int hfi_process_session_etb_done(u32 device_id, info->response.data = data_done; return 0; +bad_packet_size: + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; } static int hfi_process_session_ftb_done( @@ -1715,8 +1860,7 @@ static int hfi_process_session_rel_buf_done(u32 device_id, cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; cmd_done.status = hfi_map_err_status(pkt->error_type); - cmd_done.data.buffer_info = - *(struct hal_buffer_info *)pkt->rg_buffer_info; + cmd_done.data.buffer_info.buffer_addr = *pkt->rg_buffer_info; cmd_done.size = sizeof(struct hal_buffer_info); info->response_type = HAL_SESSION_RELEASE_BUFFER_DONE; diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 6ccbccf70c9fd78a989ff46c0bdf4f6d8c3d5f0c..0791613ead213dc330d162999c463a14af3eaf23 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -781,12 +781,92 @@ static int msm_vidc_pm_suspend(struct device *dev) static int msm_vidc_pm_resume(struct device *dev) { + place_marker("vidc resumed"); dprintk(VIDC_INFO, "%s\n", __func__); return 0; } +int msm_vidc_freeze_core(struct msm_vidc_core *core) +{ + int rc = 0; + int max_retry = 300; + struct hfi_device *hdev; + + hdev = core->device; + + mutex_lock(&core->lock); + + dprintk(VIDC_WARN, "%s: fatal SSR intended to dismantle vidc\n", + __func__); + + core->ssr_type = SSR_ERR_FATAL; + + if (core->state == VIDC_CORE_INIT_DONE) { + dprintk(VIDC_INFO, "%s: ssr type %d\n", __func__, + core->ssr_type); + /* + * In current implementation user-initiated SSR triggers + * a fatal error from hardware. However, there is no way + * to know if fatal error is due to SSR or not. Handle + * user SSR as non-fatal. + */ + + core->trigger_ssr = true; + rc = call_hfi_op(hdev, core_trigger_ssr, + hdev->hfi_device_data, core->ssr_type); + + if (rc) { + dprintk(VIDC_ERR, "%s: trigger_ssr failed\n", __func__); + core->trigger_ssr = false; + } + + } else { + dprintk(VIDC_WARN, "%s: video core %pK not initialized\n", + __func__, core); + } + mutex_unlock(&core->lock); + + while ((core->state != VIDC_CORE_UNINIT) && (max_retry > 0)) { + msleep(20); + max_retry--; + } + + mutex_lock(&core->lock); + core->trigger_ssr = false; + mutex_unlock(&core->lock); + + return rc; +} + +static int msm_vidc_pm_freeze(struct device *dev) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!dev || !dev->driver) + return 0; + + core = dev_get_drvdata(dev); + if (!core) + return 0; + + if (of_device_is_compatible(dev->of_node, "qcom,msm-vidc")) { + place_marker("vidc hibernation start"); + + rc = msm_vidc_freeze_core(core); + + place_marker("vidc hibernation end"); + } + + dprintk(VIDC_INFO, "%s: done\n", __func__); + + return rc; +} + static const struct dev_pm_ops msm_vidc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume) + .suspend = msm_vidc_pm_suspend, + .resume = msm_vidc_pm_resume, + .freeze = msm_vidc_pm_freeze, }; MODULE_DEVICE_TABLE(of, msm_vidc_dt_match); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 3282b57ed8478a8b76ee4f12cfa3825852ed6c65..9e0b4dfe3b4c1f44eb708e1db1f000032b8c6f1c 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -699,6 +699,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { (1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) | (1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP) | (1 << V4L2_MPEG_VIDC_EXTRADATA_HDR10PLUS_METADATA) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) | (1ULL << V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP) ), .qmenu = mpeg_video_vidc_extradata, @@ -1827,6 +1828,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO: case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP: case V4L2_MPEG_VIDC_EXTRADATA_HDR10PLUS_METADATA: + case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP: inst->bufq[OUTPUT_PORT].num_planes = 2; break; case V4L2_MPEG_VIDC_EXTRADATA_LTR: diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 8a198efb8a4ec9c2904b6cce2238c560d3de4743..9c708bc7e1e3d9f9ccc6ee15e93b7dc80fe38d01 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1613,6 +1613,12 @@ int msm_vidc_private(void *vidc_inst, unsigned int cmd, int rc = 0; struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst; + if (cmd != VIDIOC_VIDEO_CMD) { + dprintk(VIDC_ERR, + "%s: invalid private cmd %#x\n", __func__, cmd); + return -ENOIOCTLCMD; + } + if (!inst || !arg) { dprintk(VIDC_ERR, "%s: invalid args\n", __func__); return -EINVAL; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 1f226a099dd9335f1ca349154b8541dcac0ebabf..7178fdfbe5e19200d0ec9905571c3b7843686304 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -633,6 +633,7 @@ static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, u32 filled_len) { unsigned long freq = 0; + unsigned long sw_overhead = 0; unsigned long vpp_cycles = 0, vsp_cycles = 0; unsigned long fw_cycles = 0, fw_vpp_cycles = 0; u32 vpp_cycles_per_mb; @@ -668,9 +669,6 @@ static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, vpp_cycles = mbs_per_second * vpp_cycles_per_mb / inst->clk_data.work_route; - /* 21 / 20 is minimum overhead factor */ - vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); - vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles; /* bitrate is based on fps, scale it using operating rate */ @@ -682,21 +680,36 @@ static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, vsp_cycles += ((u64)inst->clk_data.bitrate * vsp_factor_num) / vsp_factor_den; - } else if (inst->session_type == MSM_VIDC_DECODER) { - vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles / - inst->clk_data.work_route; + /* sw overhead factor */ + sw_overhead = ((u64)vsp_cycles * fw_vpp_cycles) / vpp_cycles; + vsp_cycles += max(vsp_cycles/20, sw_overhead); + /* 21 / 20 is minimum overhead factor */ vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); - /* 1.059 pipeline overhead factor */ if (inst->clk_data.work_route > 1) - vpp_cycles += vpp_cycles/17; + vpp_cycles += (vpp_cycles * 14 / 1000); + + } else if (inst->session_type == MSM_VIDC_DECODER) { + vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles / + inst->clk_data.work_route; vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles; /* vsp perf is about 0.5 bits/cycle */ vsp_cycles += ((fps * filled_len * 8) * 10) / 5; + /* sw overhead factor */ + sw_overhead = ((u64)vsp_cycles * fw_vpp_cycles) / vpp_cycles; + vsp_cycles += max(vsp_cycles/20, sw_overhead); + + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + /* 1.059 pipeline overhead factor */ + if (inst->clk_data.work_route > 1) + vpp_cycles += vpp_cycles/17; + } else { dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__); return msm_vidc_max_freq(inst->core); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 405d62fedc8f91de1862de327b898bdfe6cb7a3b..faacbd1ff444418e31bc103c344a226ef8414a5b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2247,10 +2247,6 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) /* handle the hw error before core released to get full debug info */ msm_vidc_handle_hw_error(core); - if (response->status == VIDC_ERR_NOC_ERROR) { - dprintk(VIDC_WARN, "Got NOC error"); - MSM_VIDC_ERROR(true); - } dprintk(VIDC_DBG, "Calling core_release\n"); rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data); @@ -5461,6 +5457,9 @@ enum hal_extradata_id msm_comm_get_hal_extradata_index( case V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS: ret = HAL_EXTRADATA_ENC_DTS_METADATA; break; + case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP: + ret = HAL_EXTRADATA_INPUT_CROP; + break; default: dprintk(VIDC_WARN, "Extradata not found: %d\n", index); break; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index b1be0124cf73203440a2a87483b28a06df605aa2..cc681d81656c9bf86eed86e8b6070c8b99b41737 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -513,6 +513,7 @@ struct msm_vidc_ctrl { void handle_cmd_response(enum hal_command_response cmd, void *data); int msm_vidc_trigger_ssr(struct msm_vidc_core *core, enum hal_ssr_trigger_type type); +int msm_vidc_freeze_core(struct msm_vidc_core *core); int msm_vidc_noc_error_info(struct msm_vidc_core *core); bool heic_encode_session_supported(struct msm_vidc_inst *inst); int msm_vidc_check_session_supported(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 e4ab7e6a1e93b4c07f1da7648774e08381ceaa85..ab65a72e784f8ebce3ff22ecad66593f742597d5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -63,6 +63,19 @@ static struct msm_vidc_codec_data default_codec_data[] = { CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 125, 675, 320), }; +/* Update with atoll data */ +static struct msm_vidc_codec_data atoll_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200), +}; + /* Update with SM6150 data */ static struct msm_vidc_codec_data sm6150_codec_data[] = { CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), @@ -165,6 +178,65 @@ static struct msm_vidc_common_data default_common_data[] = { }, }; +static struct msm_vidc_common_data atoll_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 1944000, + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,max-b-frame-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 225975, + }, +}; + static struct msm_vidc_common_data sm6150_common_data[] = { { .key = "qcom,never-unload-fw", @@ -690,6 +762,22 @@ static struct msm_vidc_platform_data default_data = { .vpu_ver = VPU_VERSION_5, }; +static struct msm_vidc_platform_data atoll_data = { + .codec_data = atoll_codec_data, + .codec_data_length = ARRAY_SIZE(atoll_codec_data), + .common_data = atoll_common_data, + .common_data_length = ARRAY_SIZE(atoll_common_data), + .ubwc_config = NULL, + .ubwc_config_length = 0, + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_4, +}; + static struct msm_vidc_platform_data sm6150_data = { .codec_data = sm6150_codec_data, .codec_data_length = ARRAY_SIZE(sm6150_codec_data), @@ -787,6 +875,10 @@ static struct msm_vidc_platform_data sdm670_data = { }; static const struct of_device_id msm_vidc_dt_match[] = { + { + .compatible = "qcom,atoll-vidc", + .data = &atoll_data, + }, { .compatible = "qcom,sm6150-vidc", .data = &sm6150_data, diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 3125794ea183b6da3b6824d6d6cbd90c9cbced75..b22f228e20171c2d99c45c9109d9f209f7ce0cb5 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -45,6 +45,9 @@ #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF #define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 + +#define VERSION_HANA (0x5 << 28 | 0x10 << 16) static struct hal_device_data hal_ctxt; @@ -3441,22 +3444,50 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) log_level = VIDC_ERR; } +#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \ + if (pkt_size < pkt_hdr_size || \ + payload_size < MIN_PAYLOAD_SIZE || \ + payload_size > \ + (pkt_size - pkt_hdr_size + sizeof(u8))) { \ + dprintk(VIDC_ERR, \ + "%s: invalid msg size - %d\n", \ + __func__, pkt->msg_size); \ + continue; \ + } \ + }) + while (!__iface_dbgq_read(device, packet)) { - struct hfi_msg_sys_coverage_packet *pkt = - (struct hfi_msg_sys_coverage_packet *) packet; + struct hfi_packet_header *pkt = + (struct hfi_packet_header *) packet; + + if (pkt->size < sizeof(struct hfi_packet_header)) { + dprintk(VIDC_ERR, "Invalid pkt size - %s\n", + __func__); + continue; + } if (pkt->packet_type == HFI_MSG_SYS_COV) { + struct hfi_msg_sys_coverage_packet *pkt = + (struct hfi_msg_sys_coverage_packet *) packet; int stm_size = 0; + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + stm_size = stm_log_inv_ts(0, 0, pkt->rg_msg_data, pkt->msg_size); if (stm_size == 0) dprintk(VIDC_ERR, "In %s, stm_log returned size of 0\n", __func__); - } else { + + } else if (pkt->packet_type == HFI_MSG_SYS_DEBUG) { struct hfi_msg_sys_debug_packet *pkt = (struct hfi_msg_sys_debug_packet *) packet; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + /* * All fw messages starts with new line character. This * causes dprintk to print this message in two lines @@ -3464,9 +3495,11 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) * from the message fixes this to print it in a single * line. */ + pkt->rg_msg_data[pkt->msg_size-1] = '\0'; dprintk(log_level, "%s", &pkt->rg_msg_data[1]); } } +#undef SKIP_INVALID_PKT if (local_packet) kfree(packet); @@ -3976,6 +4009,42 @@ static inline int __prepare_ahb2axi_bridge(struct venus_hfi_device *device) return 0; } +static inline int __unprepare_ahb2axi_bridge(struct venus_hfi_device *device, + u32 version) +{ + int rc; + + if (!device) { + dprintk(VIDC_ERR, "NULL device\n"); + return -EINVAL; + } + + /* reset axi0 and axi1 as needed only for specific video hardware */ + version &= ~GENMASK(15, 0); + if (version != VERSION_HANA) + return -EINVAL; + + dprintk(VIDC_ERR, + "reset axi cbcr to recover\n"); + + rc = __handle_reset_clk(device->res, ASSERT); + if (rc) { + dprintk(VIDC_ERR, "failed to assert reset clocks\n"); + return rc; + } + + /* wait for deassert */ + usleep_range(150, 250); + + rc = __handle_reset_clk(device->res, DEASSERT); + if (rc) { + dprintk(VIDC_ERR, "failed to deassert reset clocks\n"); + return rc; + } + + return 0; +} + static inline int __prepare_enable_clks(struct venus_hfi_device *device) { struct clock_info *cl = NULL, *cl_fail = NULL; @@ -4715,8 +4784,10 @@ static int __venus_power_on(struct venus_hfi_device *device) return rc; } -static void __venus_power_off(struct venus_hfi_device *device) +static void __venus_power_off(struct venus_hfi_device *device, bool axi_reset) { + u32 version; + if (!device->power_enabled) return; @@ -4724,7 +4795,14 @@ static void __venus_power_off(struct venus_hfi_device *device) disable_irq_nosync(device->hal_data->irq); device->intr_status = 0; + if (axi_reset) + version = __read_register(device, VIDC_WRAPPER_HW_VERSION); + __disable_unprepare_clks(device); + + if (axi_reset) + __unprepare_ahb2axi_bridge(device, version); + if (__disable_regulators(device)) dprintk(VIDC_WARN, "Failed to disable regulators\n"); @@ -4759,7 +4837,7 @@ static inline int __suspend(struct venus_hfi_device *device) __disable_subcaches(device); - __venus_power_off(device); + __venus_power_off(device, false); dprintk(VIDC_PROF, "Venus power off\n"); return rc; @@ -4834,7 +4912,7 @@ static inline int __resume(struct venus_hfi_device *device) err_reset_core: __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); err_set_video_state: - __venus_power_off(device); + __venus_power_off(device, false); err_venus_power_on: dprintk(VIDC_ERR, "Failed to resume from power collapse\n"); return rc; @@ -4893,7 +4971,7 @@ static int __load_fw(struct venus_hfi_device *device) subsystem_put(device->resources.fw.cookie); device->resources.fw.cookie = NULL; fail_load_fw: - __venus_power_off(device); + __venus_power_off(device, true); fail_venus_power_on: fail_init_pkt: __deinit_resources(device); @@ -4914,7 +4992,7 @@ static void __unload_fw(struct venus_hfi_device *device) __vote_buses(device, NULL, 0); subsystem_put(device->resources.fw.cookie); __interface_queues_release(device); - __venus_power_off(device); + __venus_power_off(device, true); device->resources.fw.cookie = NULL; __deinit_resources(device); diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index aa0cd4ae77795a1c291d5aba18c575cd447581a9..8a1a7cec757be32b594a7fda9883740f4e87a972 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -613,7 +613,7 @@ struct hfi_msg_session_empty_buffer_done_packet { u32 extra_data_buffer; u32 flags; struct hfi_frame_cr_stats_type ubwc_cr_stats; - u32 rgData[0]; + u32 rgData[1]; }; struct hfi_msg_session_fill_buffer_done_compressed_packet { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 9e4bdaa4bbd6308ec07d645bf011d2db707cbf73..206be4be9a02cefafaa778f1f49512448d9ba8c8 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -120,6 +120,7 @@ enum hal_extradata_id { HAL_EXTRADATA_UBWC_CR_STATS_INFO, HAL_EXTRADATA_HDR10PLUS_METADATA, HAL_EXTRADATA_ENC_DTS_METADATA, + HAL_EXTRADATA_INPUT_CROP, }; enum hal_property { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 424c663e8a5d9ab35e2f53d618442b92682ddcb8..b9c2e90313d07c318fc7d07ae7889b31895bdbe6 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -670,7 +670,6 @@ struct hfi_bit_depth { }; struct hfi_picture_type { - u32 is_sync_frame; u32 picture_type; }; @@ -917,6 +916,11 @@ struct vidc_hal_session_cmd_pkt { u32 session_id; }; +struct hfi_packet_header { + u32 size; + u32 packet_type; +}; + struct hfi_cmd_sys_init_packet { u32 size; u32 packet_type; diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index cd363a2100d453c6b5be15b35430907acd44cdde..257ae0d8cfe27250d52a6d6ee3523c40d0028320 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -629,7 +629,6 @@ static int au0828_usb_probe(struct usb_interface *interface, pr_err("%s() au0282_dev_register failed to register on V4L2\n", __func__); mutex_unlock(&dev->lock); - kfree(dev); goto done; } diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index 687a0dbbe19986560359948221001f5140531061..614612325332e3415ea6d64c558da31fa86fe6b4 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -45,7 +45,9 @@ void lkdtm_EXEC_KMALLOC(void); void lkdtm_EXEC_VMALLOC(void); void lkdtm_EXEC_RODATA(void); void lkdtm_EXEC_USERSPACE(void); +void lkdtm_EXEC_NULL(void); void lkdtm_ACCESS_USERSPACE(void); +void lkdtm_ACCESS_NULL(void); /* lkdtm_refcount.c */ void lkdtm_REFCOUNT_INC_OVERFLOW(void); diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 981b3ef71e477ab976e67e20280271e8f133655a..199271708aedb57988118b91443c2289d6320523 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -220,7 +220,9 @@ struct crashtype crashtypes[] = { CRASHTYPE(EXEC_VMALLOC), CRASHTYPE(EXEC_RODATA), CRASHTYPE(EXEC_USERSPACE), + CRASHTYPE(EXEC_NULL), CRASHTYPE(ACCESS_USERSPACE), + CRASHTYPE(ACCESS_NULL), CRASHTYPE(WRITE_RO), CRASHTYPE(WRITE_RO_AFTER_INIT), CRASHTYPE(WRITE_KERN), diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c index 53b85c9d16b89247d0fa66d0dce5192d71f9c63e..62f76d506f0405443eeb1804b220e803339d9378 100644 --- a/drivers/misc/lkdtm_perms.c +++ b/drivers/misc/lkdtm_perms.c @@ -47,7 +47,7 @@ static noinline void execute_location(void *dst, bool write) { void (*func)(void) = dst; - pr_info("attempting ok execution at %p\n", do_nothing); + pr_info("attempting ok execution at %px\n", do_nothing); do_nothing(); if (write == CODE_WRITE) { @@ -55,7 +55,7 @@ static noinline void execute_location(void *dst, bool write) flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); } - pr_info("attempting bad execution at %p\n", func); + pr_info("attempting bad execution at %px\n", func); func(); } @@ -66,14 +66,14 @@ static void execute_user_location(void *dst) /* Intentionally crossing kernel/user memory boundary. */ void (*func)(void) = dst; - pr_info("attempting ok execution at %p\n", do_nothing); + pr_info("attempting ok execution at %px\n", do_nothing); do_nothing(); copied = access_process_vm(current, (unsigned long)dst, do_nothing, EXEC_SIZE, FOLL_WRITE); if (copied < EXEC_SIZE) return; - pr_info("attempting bad execution at %p\n", func); + pr_info("attempting bad execution at %px\n", func); func(); } @@ -82,7 +82,7 @@ void lkdtm_WRITE_RO(void) /* Explicitly cast away "const" for the test. */ unsigned long *ptr = (unsigned long *)&rodata; - pr_info("attempting bad rodata write at %p\n", ptr); + pr_info("attempting bad rodata write at %px\n", ptr); *ptr ^= 0xabcd1234; } @@ -100,7 +100,7 @@ void lkdtm_WRITE_RO_AFTER_INIT(void) return; } - pr_info("attempting bad ro_after_init write at %p\n", ptr); + pr_info("attempting bad ro_after_init write at %px\n", ptr); *ptr ^= 0xabcd1234; } @@ -112,7 +112,7 @@ void lkdtm_WRITE_KERN(void) size = (unsigned long)do_overwritten - (unsigned long)do_nothing; ptr = (unsigned char *)do_overwritten; - pr_info("attempting bad %zu byte write at %p\n", size, ptr); + pr_info("attempting bad %zu byte write at %px\n", size, ptr); memcpy(ptr, (unsigned char *)do_nothing, size); flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); @@ -164,6 +164,11 @@ void lkdtm_EXEC_USERSPACE(void) vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_EXEC_NULL(void) +{ + execute_location(NULL, CODE_AS_IS); +} + void lkdtm_ACCESS_USERSPACE(void) { unsigned long user_addr, tmp = 0; @@ -185,16 +190,29 @@ void lkdtm_ACCESS_USERSPACE(void) ptr = (unsigned long *)user_addr; - pr_info("attempting bad read at %p\n", ptr); + pr_info("attempting bad read at %px\n", ptr); tmp = *ptr; tmp += 0xc0dec0de; - pr_info("attempting bad write at %p\n", ptr); + pr_info("attempting bad write at %px\n", ptr); *ptr = tmp; vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_ACCESS_NULL(void) +{ + unsigned long tmp; + unsigned long *ptr = (unsigned long *)NULL; + + pr_info("attempting bad read at %px\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %px\n", ptr); + *ptr = tmp; +} + void __init lkdtm_perms_init(void) { /* Make sure we can write to __ro_after_init values during __init */ diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 02422cdbb5a8a1bcb62b87309c857ba9b05ab183..8f3ccf8f63f4c330c81338d398b6684fe7ceaaa5 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -547,7 +547,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, smc_id = TZ_OS_APP_SHUTDOWN_ID; desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID; desc.args[0] = req->app_id; - ret = __qseecom_scm_call2_locked(smc_id, &desc); + ret = scm_call2(smc_id, &desc); break; } case QSEOS_APP_LOOKUP_COMMAND: { @@ -3579,6 +3579,33 @@ int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req, return 0; } +static int __boundary_checks_offset_64(struct qseecom_send_modfd_cmd_req *req, + struct qseecom_send_modfd_listener_resp *lstnr_resp, + struct qseecom_dev_handle *data, int i) +{ + + if ((data->type != QSEECOM_LISTENER_SERVICE) && + (req->ifd_data[i].fd > 0)) { + if ((req->cmd_req_len < sizeof(uint64_t)) || + (req->ifd_data[i].cmd_buf_offset > + req->cmd_req_len - sizeof(uint64_t))) { + pr_err("Invalid offset (req len) 0x%x\n", + req->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } else if ((data->type == QSEECOM_LISTENER_SERVICE) && + (lstnr_resp->ifd_data[i].fd > 0)) { + if ((lstnr_resp->resp_len < sizeof(uint64_t)) || + (lstnr_resp->ifd_data[i].cmd_buf_offset > + lstnr_resp->resp_len - sizeof(uint64_t))) { + pr_err("Invalid offset (lstnr resp len) 0x%x\n", + lstnr_resp->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } + return 0; +} + static int __qseecom_update_cmd_buf(void *msg, bool cleanup, struct qseecom_dev_handle *data) { @@ -3922,7 +3949,8 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, if (sg_ptr->nents == 1) { uint64_t *update_64bit; - if (__boundary_checks_offset(req, lstnr_resp, data, i)) + if (__boundary_checks_offset_64(req, lstnr_resp, + data, i)) goto err; /* 64bit app uses 64bit address */ update_64bit = (uint64_t *) field; @@ -6734,9 +6762,11 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req, for (i = 0; i < MAX_ION_FD; i++) { if (req->ifd_data[i].fd > 0) { ion_fd = req->ifd_data[i].fd; - if ((req->req_len < sizeof(uint32_t)) || + if ((req->req_len < + sizeof(struct qseecom_param_memref)) || (req->ifd_data[i].cmd_buf_offset > - req->req_len - sizeof(uint32_t))) { + req->req_len - + sizeof(struct qseecom_param_memref))) { pr_err("Invalid offset/req len 0x%x/0x%x\n", req->req_len, req->ifd_data[i].cmd_buf_offset); diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index b0986b6aa31bea2e39a78a2296c7b21a197854ab..aca68f0d011ed493d96602ba1cf205d2cf04d6c6 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -282,7 +282,7 @@ static void mmc_release_card(struct device *dev) kfree(card->info); kfree(card); - if (host) + if (host && card == host->card) host->card = NULL; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 05e448186c16153ac394c21e921b0053948c0ec4..ac5182881d9f81c05e5491a5673139a6698c661e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3245,26 +3245,29 @@ int mmc_resume_bus(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); mmc_bus_get(host); - if (host->ops->get_cd) + if (host->ops->get_cd) { card_present = host->ops->get_cd(host); + if (!card_present) { + pr_err("%s: Card removed - card_present:%d\n", + mmc_hostname(host), card_present); + mmc_card_set_removed(host->card); + } + } if (host->bus_ops && !host->bus_dead && host->card && card_present) { mmc_power_up(host, host->card->ocr); BUG_ON(!host->bus_ops->resume); err = host->bus_ops->resume(host); - if (err) { - pr_err("%s: %s: resume failed: %d\n", - mmc_hostname(host), __func__, err); - /* - * If we have cd-gpio based detection mechanism and - * deferred resume is supported, we will not detect - * card removal event when system is suspended. So if - * resume fails after a system suspend/resume, - * schedule the work to detect card presence. - */ - if (mmc_card_is_removable(host) && - !(host->caps & MMC_CAP_NEEDS_POLL)) { - mmc_detect_change(host, 0); + if (err && (err != -ENOMEDIUM)) { + pr_err("%s: bus resume: failed: %d\n", + mmc_hostname(host), err); + err = mmc_hw_reset(host); + if (err) { + pr_err("%s: reset: failed: %d\n", + mmc_hostname(host), err); + goto err_reset; + } else { + mmc_card_clr_suspended(host->card); } } if (mmc_card_cmdq(host->card)) { @@ -3272,14 +3275,13 @@ int mmc_resume_bus(struct mmc_host *host) if (err) pr_err("%s: %s: unhalt failed: %d\n", mmc_hostname(host), __func__, err); - else - mmc_card_clr_suspended(host->card); } } +err_reset: mmc_bus_put(host); pr_debug("%s: Deferred resume completed\n", mmc_hostname(host)); - return 0; + return err; } EXPORT_SYMBOL(mmc_resume_bus); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index baddf6a44d32cdd89cc22dffb66cc56e0dba9e60..3fb8c152167a7b70eea9664aa0c82eae6b0c3e3e 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1322,8 +1322,6 @@ static int _mmc_sd_resume(struct mmc_host *host) mmc_hostname(host), __func__, err); mmc_card_set_removed(host->card); mmc_detect_change(host, msecs_to_jiffies(200)); - } else if (err) { - goto out; } mmc_card_clr_suspended(host->card); @@ -1348,11 +1346,21 @@ static int mmc_sd_resume(struct mmc_host *host) MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_sd_resume(host); - pm_runtime_set_active(&host->card->dev); - pm_runtime_mark_last_busy(&host->card->dev); - pm_runtime_enable(&host->card->dev); - MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); + if (err) { + pr_err("%s: sd resume err: %d\n", mmc_hostname(host), err); + if (host->ops->get_cd && !host->ops->get_cd(host)) { + err = -ENOMEDIUM; + mmc_card_set_removed(host->card); + } + } + if (err != -ENOMEDIUM) { + pm_runtime_set_active(&host->card->dev); + pm_runtime_mark_last_busy(&host->card->dev); + pm_runtime_enable(&host->card->dev); + } + + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 351330dfb954545a41bb1b58790db29ccdd708d4..1bd1819cca7ded630566d021a873d07eed8ad42d 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1118,7 +1118,7 @@ static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) { } #endif -static void __init init_mmcsd_host(struct mmc_davinci_host *host) +static void init_mmcsd_host(struct mmc_davinci_host *host) { mmc_davinci_reset_ctrl(host, 1); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index ff5c4ad37a3a7ef6cdf9300775265cd9591a36e0..8c0b80a54e4debe3cd28de7fbfc9d9837a00f067 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -425,7 +425,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) val = readl(host->ioaddr + ESDHC_MIX_CTRL); else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) /* the std tuning bits is in ACMD12_ERR for imx6sl */ - val = readl(host->ioaddr + SDHCI_ACMD12_ERR); + val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); } if (val & ESDHC_MIX_CTRL_EXE_TUNE) @@ -490,7 +490,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) } writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { - u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); + u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); if (val & SDHCI_CTRL_TUNED_CLK) { v |= ESDHC_MIX_CTRL_SMPCLK_SEL; @@ -508,7 +508,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) v &= ~ESDHC_MIX_CTRL_EXE_TUNE; } - writel(v, host->ioaddr + SDHCI_ACMD12_ERR); + writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS); writel(m, host->ioaddr + ESDHC_MIX_CTRL); } return; @@ -937,9 +937,9 @@ static void esdhc_reset_tuning(struct sdhci_host *host) writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { - ctrl = readl(host->ioaddr + SDHCI_ACMD12_ERR); + ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - writel(ctrl, host->ioaddr + SDHCI_ACMD12_ERR); + writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); } } } @@ -1303,7 +1303,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) /* clear tuning bits in case ROM has set it already */ writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); - writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR); + writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); } diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 959ca0a25305f2873a7089a918bd9b27004d2985..44ee02bf57c7c8630f0e036097ff251db8837d4e 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -3121,7 +3121,7 @@ static void sdhci_msm_registers_save(struct sdhci_host *host) msm_host->regs_restore.hc_2c_2e = sdhci_readl(host, SDHCI_CLOCK_CONTROL); msm_host->regs_restore.hc_3c_3e = - sdhci_readl(host, SDHCI_ACMD12_ERR); + sdhci_readl(host, SDHCI_AUTO_CMD_STATUS); msm_host->regs_restore.vendor_pwrctl_ctl = readl_relaxed(host->ioaddr + msm_host_offset->CORE_PWRCTL_CTL); @@ -3184,7 +3184,7 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host) sdhci_writel(host, msm_host->regs_restore.hc_2c_2e, SDHCI_CLOCK_CONTROL); sdhci_writel(host, msm_host->regs_restore.hc_3c_3e, - SDHCI_ACMD12_ERR); + SDHCI_AUTO_CMD_STATUS); sdhci_writel(host, msm_host->regs_restore.hc_38_3a, SDHCI_SIGNAL_ENABLE); sdhci_writel(host, msm_host->regs_restore.hc_34_36, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a986da5bc04408a3c99e934dea17dce0d921934c..899d14d0ef8b045c4b319f80667e305c6f85e102 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -120,9 +120,9 @@ void sdhci_dumpregs(struct sdhci_host *host) SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n", sdhci_readl(host, SDHCI_INT_ENABLE), sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - SDHCI_DUMP("AC12 err: 0x%08x | Slot int: 0x%08x\n", - sdhci_readw(host, SDHCI_ACMD12_ERR), - sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); + SDHCI_DUMP("ACmd stat: 0x%08x | Slot int: 0x%08x\n", + sdhci_readw(host, SDHCI_AUTO_CMD_STATUS), + sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES), sdhci_readl(host, SDHCI_CAPABILITIES_1)); @@ -325,7 +325,7 @@ static void sdhci_set_default_irqs(struct sdhci_host *host) SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | - SDHCI_INT_RESPONSE | SDHCI_INT_ACMD12ERR; + SDHCI_INT_RESPONSE | SDHCI_INT_AUTO_CMD_ERR; if (host->tuning_mode == SDHCI_TUNING_MODE_2 || host->tuning_mode == SDHCI_TUNING_MODE_3) @@ -894,6 +894,11 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) else host->ier = (host->ier & ~dma_irqs) | pio_irqs; + if (host->flags & (SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12)) + host->ier |= SDHCI_INT_AUTO_CMD_ERR; + else + host->ier &= ~SDHCI_INT_AUTO_CMD_ERR; + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } @@ -1139,8 +1144,7 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) return (!(host->flags & SDHCI_DEVICE_DEAD) && ((mrq->cmd && mrq->cmd->error) || (mrq->sbc && mrq->sbc->error) || - (mrq->data && ((mrq->data->error && !mrq->data->stop) || - (mrq->data->stop && mrq->data->stop->error))) || + (mrq->data && mrq->data->stop && mrq->data->stop->error) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))); } @@ -1192,6 +1196,16 @@ static void sdhci_finish_data(struct sdhci_host *host) host->data = NULL; host->data_cmd = NULL; + /* + * The controller needs a reset of internal state machines upon error + * conditions. + */ + if (data->error) { + if (!host->cmd || host->cmd == data_cmd) + sdhci_do_reset(host, SDHCI_RESET_CMD); + sdhci_do_reset(host, SDHCI_RESET_DATA); + } + if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) == (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) sdhci_adma_table_post(host, data); @@ -1216,17 +1230,6 @@ static void sdhci_finish_data(struct sdhci_host *host) if (data->stop && (data->error || !data->mrq->sbc)) { - - /* - * The controller needs a reset of internal state machines - * upon error conditions. - */ - if (data->error) { - if (!host->cmd || host->cmd == data_cmd) - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); - } - /* * 'cap_cmd_during_tfr' request must not use the command line * after mmc_command_done() has been called. It is upper layer's @@ -3088,9 +3091,24 @@ static void sdhci_timeout_data_timer(unsigned long data) * * \*****************************************************************************/ -static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) +static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) { u16 auto_cmd_status; + /* Handle auto-CMD12 error */ + if (intmask & SDHCI_INT_AUTO_CMD_ERR && host->data_cmd) { + struct mmc_request *mrq = host->data_cmd->mrq; + u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS); + int data_err_bit = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ? + SDHCI_INT_DATA_TIMEOUT : + SDHCI_INT_DATA_CRC; + + /* Treat auto-CMD12 error the same as data error */ + if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) { + *intmask_p |= data_err_bit; + return; + } + } + if (!host->cmd) { /* * SDHCI recovers from errors by resetting the cmd and data @@ -3113,7 +3131,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | - SDHCI_INT_ACMD12ERR)) { + SDHCI_INT_AUTO_CMD_ERR)) { if (intmask & SDHCI_INT_TIMEOUT) { host->cmd->error = -ETIMEDOUT; host->mmc->err_stats[MMC_ERR_CMD_TIMEOUT]++; @@ -3122,31 +3140,23 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) host->mmc->err_stats[MMC_ERR_CMD_CRC]++; } - if (intmask & SDHCI_INT_ACMD12ERR) { + if (intmask & SDHCI_INT_AUTO_CMD_ERR) { auto_cmd_status = host->auto_cmd_err_sts; host->mmc->err_stats[MMC_ERR_AUTO_CMD]++; pr_err_ratelimited("%s: %s: AUTO CMD err sts 0x%08x\n", mmc_hostname(host->mmc), __func__, auto_cmd_status); if (auto_cmd_status & (SDHCI_AUTO_CMD12_NOT_EXEC | - SDHCI_AUTO_CMD_INDEX_ERR | - SDHCI_AUTO_CMD_ENDBIT_ERR)) + SDHCI_AUTO_CMD_INDEX | + SDHCI_AUTO_CMD_END_BIT)) host->cmd->error = -EIO; - else if (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT_ERR) + else if (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) host->cmd->error = -ETIMEDOUT; - else if (auto_cmd_status & SDHCI_AUTO_CMD_CRC_ERR) + else if (auto_cmd_status & SDHCI_AUTO_CMD_CRC) host->cmd->error = -EILSEQ; } - /* - * If this command initiates a data phase and a response - * CRC error is signalled, the card can start transferring - * data - the card may have received the command without - * error. We must not terminate the mmc_request early. - * - * If the card did not receive the command or returned an - * error which prevented it sending data, the data phase - * will time out. + /* Treat data command CRC error the same as data CRC error * * Even in case of cmd INDEX OR ENDBIT error we * handle it the same way. @@ -3155,6 +3165,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) (((intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) == SDHCI_INT_CRC) || (host->cmd->error == -EILSEQ))) { host->cmd = NULL; + *intmask_p |= SDHCI_INT_DATA_CRC; return; } @@ -3162,6 +3173,21 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) return; } + /* Handle auto-CMD23 error */ + if (intmask & SDHCI_INT_AUTO_CMD_ERR) { + struct mmc_request *mrq = host->cmd->mrq; + u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS); + int err = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ? + -ETIMEDOUT : + -EILSEQ; + + if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + mrq->sbc->error = err; + sdhci_finish_mrq(host, mrq); + return; + } + } + if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); } @@ -3496,9 +3522,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) MMC_TRACE(host->mmc, "%s: intmask: 0x%x\n", __func__, intmask); - if (intmask & SDHCI_INT_ACMD12ERR) + if (intmask & SDHCI_INT_AUTO_CMD_ERR) host->auto_cmd_err_sts = sdhci_readw(host, - SDHCI_ACMD12_ERR); + SDHCI_AUTO_CMD_STATUS); /* Clear selected interrupts. */ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | @@ -3539,7 +3565,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) && (host->clock <= 400000)) udelay(40); - sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); + sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask); } if (intmask & SDHCI_INT_DATA_MASK) { @@ -3999,7 +4025,7 @@ static void sdhci_cmdq_clear_set_irqs(struct mmc_host *mmc, bool clear) SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | - SDHCI_INT_ACMD12ERR; + SDHCI_INT_AUTO_CMD_ERR; sdhci_writel(host, ier, SDHCI_INT_ENABLE); sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 85b59bd93e8c3be2c9408a0504c0bbc7cf6f4094..f2cf328764d913d8f095d51ff54de65e1fdf3df4 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -144,7 +144,7 @@ #define SDHCI_INT_DATA_CRC 0x00200000 #define SDHCI_INT_DATA_END_BIT 0x00400000 #define SDHCI_INT_BUS_POWER 0x00800000 -#define SDHCI_INT_ACMD12ERR 0x01000000 +#define SDHCI_INT_AUTO_CMD_ERR 0x01000000 #define SDHCI_INT_ADMA_ERROR 0x02000000 #define SDHCI_INT_NORMAL_MASK 0x00007FFF @@ -152,7 +152,7 @@ #define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \ - SDHCI_INT_ACMD12ERR) + SDHCI_INT_AUTO_CMD_ERR) #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ @@ -170,12 +170,12 @@ #define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE) -#define SDHCI_ACMD12_ERR 0x3C +#define SDHCI_AUTO_CMD_STATUS 0x3C #define SDHCI_AUTO_CMD12_NOT_EXEC 0x0001 -#define SDHCI_AUTO_CMD_TIMEOUT_ERR 0x0002 -#define SDHCI_AUTO_CMD_CRC_ERR 0x0004 -#define SDHCI_AUTO_CMD_ENDBIT_ERR 0x0008 -#define SDHCI_AUTO_CMD_INDEX_ERR 0x0010 +#define SDHCI_AUTO_CMD_TIMEOUT 0x00000002 +#define SDHCI_AUTO_CMD_CRC 0x00000004 +#define SDHCI_AUTO_CMD_END_BIT 0x00000008 +#define SDHCI_AUTO_CMD_INDEX 0x00000010 #define SDHCI_AUTO_CMD12_NOT_ISSUED 0x0080 #define SDHCI_HOST_CONTROL2 0x3E diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index 982a668c618ccace9d508150a933ea5f2dae8eac..1de9ab22dca2b2b099318f3bdeebfd0241ceb7ba 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -27,6 +27,183 @@ #define SMEM_AARM_PARTITION_TABLE 9 #define SMEM_APPS 0 static bool enable_euclean; +static bool enable_perfstats; + +static ssize_t msm_nand_attr_perf_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t msm_nand_attr_perf_stats_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static struct device_attribute dev_msm_nand_perf_stats = + __ATTR(perf_stats, 0644, + msm_nand_attr_perf_stats_show, msm_nand_attr_perf_stats_store); + +#define print_sysfs(fmt, ...) \ +{ \ + count += scnprintf(buf + count, PAGE_SIZE - count, \ + fmt, ##__VA_ARGS__); \ +} + +static ssize_t msm_nand_attr_perf_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t count = 0; + struct msm_nand_info *info = dev_get_drvdata(dev); + + if (!enable_perfstats) { + print_sysfs("Performance stats is disabled\n"); + return count; + } + + spin_lock(&info->perf.lock); + print_sysfs("total_read_size = %llu\n", info->perf.total_read_size); + print_sysfs("total_write_size = %llu\n", info->perf.total_write_size); + print_sysfs("total_erase_blks = %llu\n\n", info->perf.total_erase_blks); + + print_sysfs("total_read_time_us = %lld\n", + ktime_to_us(info->perf.total_read_time)); + print_sysfs("total_write_time_us = %lld\n", + ktime_to_us(info->perf.total_write_time)); + print_sysfs("total_erase_time_us = %lld\n\n", + ktime_to_us(info->perf.total_erase_time)); + + print_sysfs("min_read_time_us = %lld\n", + ktime_to_us(info->perf.min_read_time)); + print_sysfs("min_write_time_us = %lld\n", + ktime_to_us(info->perf.min_write_time)); + print_sysfs("min_erase_time_us = %lld\n\n", + ktime_to_us(info->perf.min_erase_time)); + + print_sysfs("max_read_time_us = %lld\n", + ktime_to_us(info->perf.max_read_time)); + print_sysfs("max_write_time_us = %lld\n", + ktime_to_us(info->perf.max_write_time)); + print_sysfs("max_erase_time_us = %lld\n\n", + ktime_to_us(info->perf.max_erase_time)); + + spin_unlock(&info->perf.lock); + return count; +} + +static ssize_t msm_nand_attr_perf_stats_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct msm_nand_info *info = dev_get_drvdata(dev); + + if (!enable_perfstats) { + pr_err("couldn't write as perf stats is disabled\n"); + return -EPERM; + } + + if (count > 1 || (count == 1 && *buf != '\n')) { + pr_err("write not permitted\n"); + return -EPERM; + } + + spin_lock(&info->perf.lock); + info->perf.min_read_time = ktime_set(KTIME_MAX, 0); + info->perf.min_write_time = ktime_set(KTIME_MAX, 0); + info->perf.min_erase_time = ktime_set(KTIME_MAX, 0); + + info->perf.max_read_time = ktime_set(0, 0); + info->perf.max_write_time = ktime_set(0, 0); + info->perf.max_erase_time = ktime_set(0, 0); + + info->perf.total_read_time = ktime_set(0, 0); + info->perf.total_write_time = ktime_set(0, 0); + info->perf.total_erase_time = ktime_set(0, 0); + + info->perf.total_read_size = 0; + info->perf.total_write_size = 0; + info->perf.total_erase_blks = 0; + spin_unlock(&info->perf.lock); + + return count; +} + +static void msm_nand_init_perf_stats(struct msm_nand_info *info) +{ + spin_lock_init(&info->perf.lock); + info->perf.min_read_time = ktime_set(KTIME_MAX, 0); + info->perf.min_write_time = ktime_set(KTIME_MAX, 0); + info->perf.min_erase_time = ktime_set(KTIME_MAX, 0); +} + +static void msm_nand_init_sysfs(struct device *dev) +{ + sysfs_attr_init(&dev_msm_nand_perf_stats); + if (device_create_file(dev, &dev_msm_nand_perf_stats)) + pr_err("Sysfs entry create failed"); +} + +static void msm_nand_cleanup_sysfs(struct device *dev) +{ + device_remove_file(dev, &dev_msm_nand_perf_stats); +} + +static void msm_nand_update_read_perf_stats(struct msm_nand_info *info, + ktime_t start, u32 size) +{ + ktime_t time_delta; + + time_delta = ktime_sub(ktime_get(), start); + + spin_lock(&info->perf.lock); + info->perf.total_read_size += size; + info->perf.total_read_time = ktime_add(info->perf.total_read_time, + time_delta); + if (ktime_after(time_delta, info->perf.max_read_time)) + info->perf.max_read_time = time_delta; + + if (ktime_before(time_delta, info->perf.min_read_time)) + info->perf.min_read_time = time_delta; + + spin_unlock(&info->perf.lock); +} + +static void msm_nand_update_write_perf_stats(struct msm_nand_info *info, + ktime_t start, u32 size) +{ + ktime_t time_delta; + + time_delta = ktime_sub(ktime_get(), start); + + spin_lock(&info->perf.lock); + info->perf.total_write_size += size; + info->perf.total_write_time = ktime_add(info->perf.total_write_time, + time_delta); + if (ktime_after(time_delta, info->perf.max_write_time)) + info->perf.max_write_time = time_delta; + + if (ktime_before(time_delta, info->perf.min_write_time)) + info->perf.min_write_time = time_delta; + + spin_unlock(&info->perf.lock); +} + +static void msm_nand_update_erase_perf_stats(struct msm_nand_info *info, + ktime_t start, u32 count) +{ + ktime_t time_delta; + + time_delta = ktime_sub(ktime_get(), start); + + spin_lock(&info->perf.lock); + info->perf.total_erase_blks += count; + info->perf.total_erase_time = ktime_add(info->perf.total_erase_time, + time_delta); + if (ktime_after(time_delta, info->perf.max_erase_time)) + info->perf.max_erase_time = time_delta; + + if (ktime_before(time_delta, info->perf.min_erase_time)) + info->perf.min_erase_time = time_delta; + + spin_unlock(&info->perf.lock); +} /* * Get the DMA memory for requested amount of size. It returns the pointer @@ -1650,6 +1827,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct sps_iovec iovec_temp; bool erased_page; uint64_t fix_data_in_pages = 0; + ktime_t start; /* * The following 6 commands will be sent only once for the first @@ -1674,6 +1852,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } *dma_buffer; struct msm_nand_rw_cmd_desc *cmd_list = NULL; + if (unlikely(enable_perfstats)) + start = ktime_get(); + memset(&rw_params, 0, sizeof(struct msm_nand_rw_params)); err = msm_nand_validate_mtd_params(mtd, true, from, ops, &rw_params); if (err) @@ -1981,6 +2162,8 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, err, ops->retlen, ops->oobretlen); pr_debug("========================================================\n"); + if (unlikely(enable_perfstats) && likely(!err)) + msm_nand_update_read_perf_stats(info, start, ops->retlen); return err; } @@ -2201,6 +2384,8 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, struct msm_nand_rw_reg_data data; struct sps_iovec *iovec; struct sps_iovec iovec_temp; + ktime_t start; + /* * The following 7 commands will be sent only once : * For first codeword (CW) - addr0, addr1, dev0_cfg0, dev0_cfg1, @@ -2224,6 +2409,9 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, } *dma_buffer; struct msm_nand_rw_cmd_desc *cmd_list = NULL; + if (unlikely(enable_perfstats)) + start = ktime_get(); + memset(&rw_params, 0, sizeof(struct msm_nand_rw_params)); err = msm_nand_validate_mtd_params(mtd, false, to, ops, &rw_params); if (err) @@ -2399,6 +2587,8 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, err, ops->retlen, ops->oobretlen); pr_debug("================================================\n"); + if (unlikely(enable_perfstats) && likely(!err)) + msm_nand_update_write_perf_stats(info, start, ops->retlen); return err; } @@ -2496,6 +2686,8 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) struct msm_nand_erase_reg_data data; struct sps_iovec *iovec; struct sps_iovec iovec_temp; + ktime_t start; + /* * The following 9 commands are required to erase a page - * flash, addr0, addr1, cfg0, cfg1, exec, flash_status(read), @@ -2508,6 +2700,9 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) uint32_t flash_status; } *dma_buffer; + if (unlikely(enable_perfstats)) + start = ktime_get(); + if (mtd->writesize == PAGE_SIZE_2K) page = instr->addr >> 11; @@ -2622,6 +2817,8 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) mutex_unlock(&info->lock); msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer)); out: + if (unlikely(enable_perfstats) && likely(!err)) + msm_nand_update_erase_perf_stats(info, start, 1); return err; } @@ -3613,6 +3810,8 @@ static int msm_nand_probe(struct platform_device *pdev) info->nand_phys, info->bam_phys, info->bam_irq); pr_info("Allocated DMA buffer at virt_addr 0x%pK, phys_addr 0x%x\n", info->nand_chip.dma_virt_addr, info->nand_chip.dma_phys_addr); + msm_nand_init_sysfs(dev); + msm_nand_init_perf_stats(info); goto out; free_bam: msm_nand_bam_free(info); @@ -3634,6 +3833,7 @@ static int msm_nand_remove(struct platform_device *pdev) { struct msm_nand_info *info = dev_get_drvdata(&pdev->dev); + msm_nand_cleanup_sysfs(&pdev->dev); if (pm_runtime_suspended(&(pdev)->dev)) pm_runtime_resume(&(pdev)->dev); @@ -3678,6 +3878,9 @@ static struct platform_driver msm_nand_driver = { module_param(enable_euclean, bool, 0644); MODULE_PARM_DESC(enable_euclean, "Set this parameter to enable reporting EUCLEAN to upper layer when the correctable bitflips are equal to the max correctable limit."); +module_param(enable_perfstats, bool, 0644); +MODULE_PARM_DESC(enable_perfstats, "Set this parameter to enable collection and reporting of performance data."); + module_platform_driver(msm_nand_driver); MODULE_ALIAS(DRIVER_NAME); diff --git a/drivers/mtd/devices/msm_qpic_nand.h b/drivers/mtd/devices/msm_qpic_nand.h index bb45a400d5319c8f6b577897bc2b83b186a2be93..ee0a0f28bdf8e61a226af460d3027c0f8d525919 100644 --- a/drivers/mtd/devices/msm_qpic_nand.h +++ b/drivers/mtd/devices/msm_qpic_nand.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,9 @@ #include #include #include +#include +#include + #define PAGE_SIZE_2K 2048 #define PAGE_SIZE_4K 4096 @@ -302,6 +305,23 @@ struct msm_nand_clk_data { bool rpmh_clk; }; +struct msm_nand_perf_stats { + u64 total_read_size; + u64 total_write_size; + u64 total_erase_blks; + ktime_t total_read_time; + ktime_t total_write_time; + ktime_t total_erase_time; + ktime_t min_read_time; + ktime_t min_write_time; + ktime_t min_erase_time; + ktime_t max_read_time; + ktime_t max_write_time; + ktime_t max_erase_time; + spinlock_t lock; +}; + + /* Structure that defines NANDc private data. */ struct msm_nand_info { struct mtd_info mtd; @@ -326,6 +346,7 @@ struct msm_nand_info { struct mutex lock; struct flash_identification flash_dev; struct msm_nand_clk_data clk_data; + struct msm_nand_perf_stats perf; u64 dma_mask; }; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 99e60bb5fe07292216f5bd944e35b42d03653705..1edd4ff5382c4eefed4e703a03ab4ceda14c1a80 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3169,8 +3169,12 @@ static int bond_netdev_event(struct notifier_block *this, return NOTIFY_DONE; if (event_dev->flags & IFF_MASTER) { + int ret; + netdev_dbg(event_dev, "IFF_MASTER\n"); - return bond_master_netdev_event(event, event_dev); + ret = bond_master_netdev_event(event, event_dev); + if (ret != NOTIFY_DONE) + return ret; } if (event_dev->flags & IFF_SLAVE) { diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c index 7d16c51e69131186ebe1dc5b656efb25c96e3096..641a532b67cbc1b7e8101c171b195830c0501ded 100644 --- a/drivers/net/bonding/bond_sysfs_slave.c +++ b/drivers/net/bonding/bond_sysfs_slave.c @@ -55,7 +55,9 @@ static SLAVE_ATTR_RO(link_failure_count); static ssize_t perm_hwaddr_show(struct slave *slave, char *buf) { - return sprintf(buf, "%pM\n", slave->perm_hwaddr); + return sprintf(buf, "%*phC\n", + slave->dev->addr_len, + slave->perm_hwaddr); } static SLAVE_ATTR_RO(perm_hwaddr); diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index c38f047d73a4fdc8895b8d649aaf2416e9237d67..b4ffa2031369df54d7e30ea8157f9fe84d1a1cca 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define DEBUG_QTI_CAN 0 @@ -125,6 +126,8 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_END_BOOT_ROM_UPGRADE 0x9B #define CMD_END_FW_UPDATE_FILE 0x9C #define CMD_UPDATE_TIME_INFO 0x9D +#define CMD_SUSPEND_EVENT 0x9E +#define CMD_RESUME_EVENT 0x9F #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -171,8 +174,8 @@ struct can_add_filter_resp { struct can_receive_frame { u8 can_if; - u64 ts; - u32 mid; + __le64 ts; + __le32 mid; u8 dlc; u8 data[8]; } __packed; @@ -187,7 +190,7 @@ struct can_config_bit_timing { } __packed; struct can_time_info { - u64 time; + __le64 time; } __packed; static struct can_bittiming_const rh850_bittiming_const = { @@ -230,7 +233,7 @@ static struct can_bittiming_const qti_can_data_bittiming_const = { struct vehicle_property { int id; - u64 ts; + __le64 ts; int zone; int val_type; u32 data_len; @@ -332,7 +335,8 @@ static void qti_can_receive_frame(struct qti_can *priv_data, for (i = 0; i < cf->can_dlc; i++) cf->data[i] = frame->data[i]; - nsec = ms_to_ktime(le64_to_cpu(frame->ts) + priv_data->time_diff); + nsec = ms_to_ktime(le64_to_cpu(frame->ts) + + priv_data->time_diff); skt = skb_hwtstamps(skb); skt->hwtstamp = nsec; skb->tstamp = nsec; @@ -449,7 +453,7 @@ static int qti_can_process_response(struct qti_can *priv_data, (struct can_time_info *)resp->data; if (priv_data->use_qtimer) - mstime = (((s64)qtimer_time()) / NSEC_PER_MSEC); + mstime = div_u64(qtimer_time(), NSEC_PER_MSEC); else mstime = ktime_to_ms(ktime_get_boottime()); @@ -619,6 +623,30 @@ static int qti_can_query_firmware_version(struct qti_can *priv_data) return ret; } +static int qti_can_notify_power_events(struct qti_can *priv_data, u8 event_type) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = event_type; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + ret = qti_can_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + static int qti_can_set_bitrate(struct net_device *netdev) { char *tx_buf, *rx_buf; @@ -1045,6 +1073,40 @@ static int qti_can_convert_ioctl_cmd_to_spi_cmd(int ioctl_cmd) return -EINVAL; } +static int qti_can_end_fwupgrade_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + int spi_cmd, ret; + + struct qti_can *priv_data; + struct qti_can_netdev_privdata *netdev_priv_data; + struct spi_device *spi; + int len = 0; + u8 *data = NULL; + + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->qti_can; + spi = priv_data->spidev; + spi_cmd = qti_can_convert_ioctl_cmd_to_spi_cmd(cmd); + LOGDI("%s spi_cmd %x\n", __func__, spi_cmd); + if (spi_cmd < 0) { + LOGDE("%s wrong command %d\n", __func__, cmd); + return spi_cmd; + } + + if (!ifr) + return -EINVAL; + + mutex_lock(&priv_data->spi_lock); + LOGDI("%s len %d\n", __func__, len); + + ret = qti_can_send_spi_locked(priv_data, spi_cmd, len, data); + + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + static int qti_can_do_blocking_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { @@ -1087,6 +1149,11 @@ static int qti_can_do_blocking_ioctl(struct net_device *netdev, return -EFAULT; } + if (ioctl_data->len < 0) { + LOGDE("ioctl_data->len is: %d\n", ioctl_data->len); + return -EINVAL; + } + /* Regular NULL check will fail here as ioctl_data is at * some offset */ @@ -1097,6 +1164,11 @@ static int qti_can_do_blocking_ioctl(struct net_device *netdev, } LOGDI("%s len %d\n", __func__, len); + if (len > 64 || len < 0) { + LOGDE("len value[%d] is not correct!!\n", len); + return -EINVAL; + } + priv_data->wait_cmd = spi_cmd; priv_data->cmd_result = -1; reinit_completion(&priv_data->response_completion); @@ -1170,10 +1242,12 @@ static int qti_can_netdev_do_ioctl(struct net_device *netdev, qti_can_frame_filter(netdev, ifr, cmd); ret = 0; break; + case IOCTL_END_FIRMWARE_UPGRADE: + ret = qti_can_end_fwupgrade_ioctl(netdev, ifr, cmd); + break; case IOCTL_GET_FW_BR_VERSION: case IOCTL_BEGIN_FIRMWARE_UPGRADE: case IOCTL_FIRMWARE_UPGRADE_DATA: - case IOCTL_END_FIRMWARE_UPGRADE: case IOCTL_BEGIN_BOOT_ROM_UPGRADE: case IOCTL_BOOT_ROM_UPGRADE_DATA: case IOCTL_END_BOOT_ROM_UPGRADE: @@ -1379,6 +1453,8 @@ static int qti_can_probe(struct spi_device *spi) gpio_direction_output(priv_data->reset, 1); /* wait for controller to come up after reset */ msleep(priv_data->reset_delay_msec); + } else { + msleep(priv_data->reset_delay_msec); } priv_data->support_can_fd = of_property_read_bool(spi->dev.of_node, @@ -1485,19 +1561,47 @@ static int qti_can_remove(struct spi_device *spi) static int qti_can_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); + struct qti_can *priv_data = NULL; + u8 power_event = CMD_SUSPEND_EVENT; + int ret = 0; - enable_irq_wake(spi->irq); - return 0; + if (spi) { + priv_data = spi_get_drvdata(spi); + enable_irq_wake(spi->irq); + } else { + ret = -1; + } + + if (priv_data && !(ret < 0)) + ret = qti_can_notify_power_events(priv_data, power_event); + + return ret; } static int qti_can_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); - struct qti_can *priv_data = spi_get_drvdata(spi); + struct qti_can *priv_data = NULL; + int ret = 0; + u8 power_event = CMD_RESUME_EVENT; - disable_irq_wake(spi->irq); - qti_can_rx_message(priv_data); - return 0; + if (spi) { + priv_data = spi_get_drvdata(spi); + disable_irq_wake(spi->irq); + + if (priv_data) + qti_can_rx_message(priv_data); + else + ret = -1; + + } else { + ret = -1; + } + + if (priv_data && !(ret < 0)) + ret = qti_can_notify_power_events(priv_data, power_event); + + return ret; } static const struct dev_pm_ops qti_can_dev_pm_ops = { @@ -1514,6 +1618,7 @@ static struct spi_driver qti_can_driver = { #ifdef CONFIG_PM .pm = &qti_can_dev_pm_ops, #endif + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = qti_can_probe, .remove = qti_can_remove, diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 8a1da7e677070d33571748c2b511d4e38169324f..7f8d269dd75ad347fd616c0230c1adb452d9bac5 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -130,6 +130,9 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port, (fs->m_ext.vlan_etype || fs->m_ext.data[1])) return -EINVAL; + if (fs->location != RX_CLS_LOC_ANY && fs->location >= CFP_NUM_RULES) + return -EINVAL; + if (fs->location != RX_CLS_LOC_ANY && test_bit(fs->location, priv->cfp.used)) return -EBUSY; @@ -330,6 +333,9 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, int ret; u32 reg; + if (loc >= CFP_NUM_RULES) + return -EINVAL; + /* Refuse deletion of unused rules, and the default reserved rule */ if (!test_bit(loc, priv->cfp.used) || loc == 0) return -EINVAL; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h index cddbeccc245976789c74372ba49ed035ad5a2c90..a3dfebf9c00c7ce89e3a5186cf7d66fe560ebbcb 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h @@ -384,6 +384,11 @@ int atl_update_eth_stats(struct atl_nic *nic); void atl_adjust_eth_stats(struct atl_ether_stats *stats, struct atl_ether_stats *base, bool add); void atl_fwd_release_rings(struct atl_nic *nic); +#ifdef CONFIG_ATLFWD_FWD +int atl_fwd_resume_rings(struct atl_nic *nic); +#else +static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } +#endif int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay); int atl_mdio_hwsem_get(struct atl_hw *hw); void atl_mdio_hwsem_put(struct atl_hw *hw); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c index 019bec332d2271474a94ac39cf82e62a2df43b0f..bf04d22de15f6ace0c82787fb8009838f451d9e8 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c @@ -593,12 +593,47 @@ void atl_fwd_release_event(struct atl_fwd_event *evt) } EXPORT_SYMBOL(atl_fwd_release_event); -int atl_fwd_request_event(struct atl_fwd_event *evt) +static int atl_fwd_init_event(struct atl_fwd_event *evt) { struct atl_fwd_ring *ring = evt->ring; int dir_tx = atl_fwd_ring_tx(ring); struct atl_nic *nic = ring->nic; struct atl_hw *hw = &nic->hw; + bool tx_wb = !!(evt->flags & ATL_FWD_EVT_TXWB); + int idx; + int ret; + + if (tx_wb) { + struct atl_hw_ring *hwring = &ring->hw; + + atl_write(hw, ATL_TX_RING_HEAD_WB_LSW(hwring), + evt->tx_head_wrb); + atl_write(hw, ATL_TX_RING_HEAD_WB_MSW(hwring), + upper_32_bits(evt->tx_head_wrb)); + return 0; + } + + idx = evt->idx; + + ret = atl_fwd_set_msix_vec(nic, evt); + if (ret) + return ret; + + atl_set_intr_bits(&nic->hw, ring->idx, + dir_tx ? -1 : idx, + dir_tx ? idx : -1); + + atl_write_bit(hw, ATL_INTR_AUTO_CLEAR, idx, 1); + atl_write_bit(hw, ATL_INTR_AUTO_MASK, idx, + !!(evt->flags & ATL_FWD_EVT_AUTOMASK)); + + return 0; +} + +int atl_fwd_request_event(struct atl_fwd_event *evt) +{ + struct atl_fwd_ring *ring = evt->ring; + struct atl_nic *nic = ring->nic; unsigned long *map = &nic->fwd.msi_map; bool tx_wb = !!(evt->flags & ATL_FWD_EVT_TXWB); int idx; @@ -631,13 +666,9 @@ int atl_fwd_request_event(struct atl_fwd_event *evt) ring->evt = evt; if (tx_wb) { - struct atl_hw_ring *hwring = &ring->hw; - - atl_write(hw, ATL_TX_RING_HEAD_WB_LSW(hwring), - evt->tx_head_wrb); - atl_write(hw, ATL_TX_RING_HEAD_WB_MSW(hwring), - upper_32_bits(evt->tx_head_wrb)); - return 0; + ret = atl_fwd_init_event(evt); + if (ret) + goto fail; } idx = find_next_zero_bit(map, ATL_NUM_MSI_VECS, ATL_FWD_MSI_BASE); @@ -649,20 +680,12 @@ int atl_fwd_request_event(struct atl_fwd_event *evt) evt->idx = idx; - ret = atl_fwd_set_msix_vec(nic, evt); + ret = atl_fwd_init_event(evt); if (ret) goto fail; __set_bit(idx, map); - atl_set_intr_bits(&nic->hw, ring->idx, - dir_tx ? -1 : idx, - dir_tx ? idx : -1); - - atl_write_bit(hw, ATL_INTR_AUTO_CLEAR, idx, 1); - atl_write_bit(hw, ATL_INTR_AUTO_MASK, idx, - !!(evt->flags & ATL_FWD_EVT_AUTOMASK)); - return 0; fail: @@ -681,10 +704,12 @@ int atl_fwd_enable_event(struct atl_fwd_event *evt) return -EINVAL; atl_write_bit(hw, ATL_TX_RING_CTL(&ring->hw), 28, 1); + ring->state |= ATL_FWR_ST_EVT_ENABLED; return 0; } atl_intr_enable(hw, BIT(evt->idx)); + ring->state |= ATL_FWR_ST_EVT_ENABLED; return 0; } EXPORT_SYMBOL(atl_fwd_enable_event); @@ -699,10 +724,12 @@ int atl_fwd_disable_event(struct atl_fwd_event *evt) return -EINVAL; atl_write_bit(hw, ATL_TX_RING_CTL(&ring->hw), 28, 0); + ring->state &= ~ATL_FWR_ST_EVT_ENABLED; return 0; } atl_intr_disable(hw, BIT(evt->idx)); + ring->state &= ~ATL_FWR_ST_EVT_ENABLED; return 0; } EXPORT_SYMBOL(atl_fwd_disable_event); @@ -721,3 +748,39 @@ int atl_fwd_transmit_skb(struct net_device *ndev, struct sk_buff *skb) } EXPORT_SYMBOL(atl_fwd_transmit_skb); +int atl_fwd_resume_rings(struct atl_nic *nic) +{ + struct atl_fwd_ring **rings = nic->fwd.rings[0]; + int i; + int ret; + + for (i = 0; i < ATL_NUM_FWD_RINGS * 2; i++) { + struct atl_fwd_ring *ring = rings[i]; + + if (!ring) + continue; + + atl_fwd_init_ring(ring); + + if (ring->evt) { + ret = atl_fwd_init_event(ring->evt); + if (ret) + return ret; + + if (ring->state & ATL_FWR_ST_EVT_ENABLED) { + ret = atl_fwd_enable_event(ring->evt); + if (ret) + return ret; + } + } + + if (ring->state & ATL_FWR_ST_ENABLED) { + ret = atl_fwd_enable_ring(ring); + if (ret) + return ret; + } + } + + return 0; +} + diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h index d348fc03b082b85b749a9ae83058951d23b7819c..05c3e21e0592c5ae79f0b91dfcc902e1b41f4fed 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h @@ -364,6 +364,7 @@ int atl_fwd_transmit_skb(struct net_device *ndev, struct sk_buff *skb); enum atl_fwd_ring_state { ATL_FWR_ST_ENABLED = BIT(0), + ATL_FWR_ST_EVT_ENABLED = BIT(1), }; #endif diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c index 30ade8c2e6bd6d35acd71885525b82650ef5e3d9..531aa9d9b4fef1066b545c13b9f000a09842be98 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c @@ -490,7 +490,10 @@ static int atl_suspend_common(struct device *dev, bool deep) atl_dev_err("Enable WoL failed: %d\n", -ret); } + pci_save_state(pdev); pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + __clear_bit(ATL_ST_ENABLED, &nic->state); rtnl_unlock(); @@ -516,6 +519,9 @@ static int atl_resume_common(struct device *dev, bool deep) rtnl_lock(); + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device_mem(pdev); if (ret) goto exit; @@ -540,6 +546,10 @@ static int atl_resume_common(struct device *dev, bool deep) if (ret) goto exit; + ret = atl_fwd_resume_rings(nic); + if (ret) + goto exit; + netif_device_attach(nic->ndev); exit: diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom_ipa.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom_ipa.c index 230c2bbbd15a1578d3d4cee91e3f3870a4d95963..586d7c2335d03ccca1f4fa0fad2cd1f0933bd4c4 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom_ipa.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_qcom_ipa.c @@ -14,28 +14,99 @@ #include #include + +#define IPA_ETH_NET_DRIVER #include #include "atl_fwd.h" #include "atl_qcom_ipa.h" -#define ATL_IPA_DEFAULT_RING_SZ 128 -#define ATL_IPA_DEFAULT_BUFF_SZ 2048 - static inline struct atl_fwd_ring *CH_RING(struct ipa_eth_channel *ch) { return (struct atl_fwd_ring *)(ch->nd_priv); } +static void *atl_ipa_dma_alloc(struct device *dev, size_t size, + dma_addr_t *daddr, gfp_t gfp, + struct ipa_eth_dma_allocator *dma_allocator) +{ + struct atl_nic *nic = (struct atl_nic *)dev_get_drvdata(dev); + struct ipa_eth_device *eth_dev = nic->fwd.private; + struct ipa_eth_resource mem; + + if (dma_allocator->alloc(eth_dev, size, gfp, &mem)) + return NULL; + + if (daddr) + *daddr = mem.daddr; + + return mem.vaddr; +} + +static void atl_ipa_dma_free(void *buf, struct device *dev, size_t size, + dma_addr_t daddr, + struct ipa_eth_dma_allocator *dma_allocator) +{ + struct atl_nic *nic = (struct atl_nic *)dev_get_drvdata(dev); + struct ipa_eth_device *eth_dev = nic->fwd.private; + struct ipa_eth_resource mem = { + .size = size, + .vaddr = buf, + .daddr = daddr, + }; + + return dma_allocator->free(eth_dev, &mem); +} + +static void *atl_ipa_alloc_descs(struct device *dev, size_t size, + dma_addr_t *daddr, gfp_t gfp, + struct atl_fwd_mem_ops *ops) +{ + struct ipa_eth_channel *ch = ops->private; + + return atl_ipa_dma_alloc(dev, size, daddr, gfp, + ch->mem_params.desc.allocator); +} + +static void *atl_ipa_alloc_buf(struct device *dev, size_t size, + dma_addr_t *daddr, gfp_t gfp, + struct atl_fwd_mem_ops *ops) +{ + struct ipa_eth_channel *ch = ops->private; + + return atl_ipa_dma_alloc(dev, size, daddr, gfp, + ch->mem_params.buff.allocator); +} + +static void atl_ipa_free_descs(void *buf, struct device *dev, size_t size, + dma_addr_t daddr, struct atl_fwd_mem_ops *ops) +{ + struct ipa_eth_channel *ch = ops->private; + + return atl_ipa_dma_free(buf, dev, size, daddr, + ch->mem_params.desc.allocator); +} + +static void atl_ipa_free_buf(void *buf, struct device *dev, size_t size, + dma_addr_t daddr, struct atl_fwd_mem_ops *ops) +{ + struct ipa_eth_channel *ch = ops->private; + + return atl_ipa_dma_free(buf, dev, size, daddr, + ch->mem_params.desc.allocator); +} + static int atl_ipa_open_device(struct ipa_eth_device *eth_dev) { struct atl_nic *nic = (struct atl_nic *)dev_get_drvdata(eth_dev->dev); if (!nic || !nic->ndev) { - dev_err(eth_dev->dev, "Invalid atl_nic"); + dev_err(eth_dev->dev, "Invalid atl_nic\n"); return -ENODEV; } + nic->fwd.private = eth_dev; + /* atl specific init, ref counting go here */ eth_dev->nd_priv = nic; @@ -46,17 +117,48 @@ static int atl_ipa_open_device(struct ipa_eth_device *eth_dev) static void atl_ipa_close_device(struct ipa_eth_device *eth_dev) { + struct atl_nic *nic = eth_dev->nd_priv; + + nic->fwd.private = NULL; + eth_dev->nd_priv = NULL; eth_dev->net_dev = NULL; } static struct ipa_eth_channel *atl_ipa_request_channel( struct ipa_eth_device *eth_dev, enum ipa_eth_channel_dir dir, - unsigned long features, unsigned long events) + unsigned long events, unsigned long features, + const struct ipa_eth_channel_mem_params *mem_params) { struct atl_fwd_ring *ring = NULL; enum atl_fwd_ring_flags ring_flags = 0; struct ipa_eth_channel *channel = NULL; + struct atl_fwd_mem_ops *mem_ops = NULL; + struct ipa_eth_channel_mem *desc_mem = NULL; + struct ipa_eth_channel_mem *buff_mem = NULL; + size_t desc_count; + size_t buff_size; + + channel = + ipa_eth_net_alloc_channel(eth_dev, dir, + events, features, mem_params); + if (!channel) { + dev_err(eth_dev->dev, "Failed to alloc ipa eth channel\n"); + goto err_channel; + } + + desc_count = channel->mem_params.desc.count; + buff_size = channel->mem_params.buff.size; + + mem_ops = kzalloc(sizeof(*mem_ops), GFP_KERNEL); + if (!mem_ops) + goto err_mem_ops; + + mem_ops->alloc_descs = atl_ipa_alloc_descs; + mem_ops->alloc_buf = atl_ipa_alloc_buf; + mem_ops->free_descs = atl_ipa_free_descs; + mem_ops->free_buf = atl_ipa_free_buf; + mem_ops->private = channel; switch (dir) { case IPA_ETH_DIR_RX: @@ -65,67 +167,92 @@ static struct ipa_eth_channel *atl_ipa_request_channel( ring_flags |= ATL_FWR_TX; break; default: - dev_err(eth_dev->dev, "Unsupported direction %d", dir); - return NULL; + dev_err(eth_dev->dev, "Unsupported direction %d\n", dir); + goto err_dir; } ring_flags |= ATL_FWR_ALLOC_BUFS; ring_flags |= ATL_FWR_CONTIG_BUFS; ring = atl_fwd_request_ring(eth_dev->net_dev, ring_flags, - ATL_IPA_DEFAULT_RING_SZ, - ATL_IPA_DEFAULT_BUFF_SZ, 1, NULL); + desc_count, buff_size, 1, mem_ops); if (IS_ERR_OR_NULL(ring)) { - dev_err(eth_dev->dev, "Request ring failed"); - goto err_exit; + dev_err(eth_dev->dev, "Request ring failed\n"); + goto err_ring; } - channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (!channel) - goto err_exit; - - channel->events = 0; - channel->features = 0; - channel->direction = dir; + channel->nd_priv = ring; channel->queue = ring->idx; - channel->desc_size = 16; - channel->desc_count = ring->hw.size; - channel->desc_mem.size = channel->desc_size * channel->desc_count; + desc_mem = kzalloc(sizeof(*desc_mem), GFP_KERNEL); + if (!desc_mem) + goto err_desc_mem; - channel->desc_mem.vaddr = ring->hw.descs; - channel->desc_mem.daddr = ring->hw.daddr; - channel->desc_mem.paddr = - page_to_phys(vmalloc_to_page(channel->desc_mem.vaddr)); + channel->mem_params.desc.size = 16; + channel->mem_params.desc.count = ring->hw.size; - channel->buff_size = ATL_IPA_DEFAULT_BUFF_SZ; - channel->buff_count = channel->desc_count; - channel->buff_mem.size = channel->buff_size * channel->buff_count; + desc_mem->mem.size = + channel->mem_params.desc.size * channel->mem_params.desc.count; + desc_mem->mem.vaddr = ring->hw.descs; + desc_mem->mem.daddr = ring->hw.daddr; + desc_mem->mem.paddr = channel->mem_params.desc.allocator->paddr( + eth_dev, desc_mem->mem.vaddr); - channel->buff_mem.vaddr = (void *)ring->bufs->vaddr_vec; - channel->buff_mem.daddr = ring->bufs->daddr_vec_base; - channel->buff_mem.paddr = virt_to_phys((void *)ring->bufs->vaddr_vec); + buff_mem = kzalloc(sizeof(*buff_mem), GFP_KERNEL); + if (!buff_mem) + goto err_buff_mem; - channel->eth_dev = eth_dev; - channel->nd_priv = ring; + channel->mem_params.buff.size = buff_size; + channel->mem_params.buff.count = channel->mem_params.desc.count; - return channel; + buff_mem->mem.size = + channel->mem_params.buff.size * channel->mem_params.buff.count; + buff_mem->mem.vaddr = (void *)ring->bufs->vaddr_vec; + buff_mem->mem.daddr = ring->bufs->daddr_vec_base; + buff_mem->mem.paddr = channel->mem_params.buff.allocator->paddr( + eth_dev, buff_mem->mem.vaddr); -err_exit: - kzfree(channel); + list_add(&desc_mem->mem_list_entry, &channel->desc_mem); + list_add(&buff_mem->mem_list_entry, &channel->buff_mem); - if (!IS_ERR_OR_NULL(ring)) { - atl_fwd_release_ring(ring); - ring = NULL; - } + return channel; +err_buff_mem: + kzfree(desc_mem); +err_desc_mem: + atl_fwd_release_ring(ring); +err_ring: +err_dir: + if (mem_ops) + kzfree(mem_ops); +err_mem_ops: + ipa_eth_net_free_channel(channel); +err_channel: return NULL; } static void atl_ipa_release_channel(struct ipa_eth_channel *ch) { - atl_fwd_release_ring(CH_RING(ch)); - kzfree(ch); + struct ipa_eth_channel_mem *mem, *tmp; + struct atl_fwd_ring *ring = CH_RING(ch); + struct atl_fwd_mem_ops *mem_ops = ring->mem_ops; + + atl_fwd_release_ring(ring); + + if (mem_ops) + kzfree(mem_ops); + + list_for_each_entry_safe(mem, tmp, &ch->desc_mem, mem_list_entry) { + list_del(&mem->mem_list_entry); + kzfree(mem); + } + + list_for_each_entry_safe(mem, tmp, &ch->buff_mem, mem_list_entry) { + list_del(&mem->mem_list_entry); + kzfree(mem); + } + + ipa_eth_net_free_channel(ch); } static int atl_ipa_enable_channel(struct ipa_eth_channel *ch) @@ -153,7 +280,7 @@ static int atl_ipa_request_event(struct ipa_eth_channel *ch, case IPA_ETH_DEV_EV_RX_INT: if (ch->direction != IPA_ETH_DIR_RX) { dev_err(eth_dev->dev, - "Rx interrupt requested on incorrect channel"); + "Rx interrupt requested on tx channel\n"); return -EFAULT; } @@ -166,7 +293,7 @@ static int atl_ipa_request_event(struct ipa_eth_channel *ch, case IPA_ETH_DEV_EV_TX_INT: if (ch->direction != IPA_ETH_DIR_TX) { dev_err(eth_dev->dev, - "Tx interrupt requested on incorrect channel"); + "Tx interrupt requested on rx channel\n"); return -EFAULT; } @@ -179,7 +306,7 @@ static int atl_ipa_request_event(struct ipa_eth_channel *ch, case IPA_ETH_DEV_EV_TX_PTR: if (ch->direction != IPA_ETH_DIR_TX) { dev_err(eth_dev->dev, - "Tx ptr wrb requested on incorrect channel"); + "Tx ptr wrb requested on rx channel\n"); return -EFAULT; } @@ -190,7 +317,7 @@ static int atl_ipa_request_event(struct ipa_eth_channel *ch, break; default: - dev_err(eth_dev->dev, "Unsupported event requested"); + dev_err(eth_dev->dev, "Unsupported event requested\n"); return -ENODEV; } @@ -226,7 +353,7 @@ static void atl_ipa_release_event(struct ipa_eth_channel *ch, break; default: - dev_err(eth_dev->dev, "Unsupported event for release"); + dev_err(eth_dev->dev, "Unsupported event for release\n"); return; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 15ad247955f7892383ac14c769c9f20341933a3c..687b01bf1ea950b2d67204f5e05d2f97be839433 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1076,6 +1076,8 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, tpa_info = &rxr->rx_tpa[agg_id]; if (unlikely(cons != rxr->rx_next_cons)) { + netdev_warn(bp->dev, "TPA cons %x != expected cons %x\n", + cons, rxr->rx_next_cons); bnxt_sched_reset(bp, rxr); return; } @@ -1528,15 +1530,17 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, } cons = rxcmp->rx_cmp_opaque; - rx_buf = &rxr->rx_buf_ring[cons]; - data = rx_buf->data; - data_ptr = rx_buf->data_ptr; if (unlikely(cons != rxr->rx_next_cons)) { int rc1 = bnxt_discard_rx(bp, bnapi, raw_cons, rxcmp); + netdev_warn(bp->dev, "RX cons %x != expected cons %x\n", + cons, rxr->rx_next_cons); bnxt_sched_reset(bp, rxr); return rc1; } + rx_buf = &rxr->rx_buf_ring[cons]; + data = rx_buf->data; + data_ptr = rx_buf->data_ptr; prefetch(data_ptr); misc = le32_to_cpu(rxcmp->rx_cmp_misc_v1); @@ -1553,11 +1557,17 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, rx_buf->data = NULL; if (rxcmp1->rx_cmp_cfa_code_errors_v2 & RX_CMP_L2_ERRORS) { + u32 rx_err = le32_to_cpu(rxcmp1->rx_cmp_cfa_code_errors_v2); + bnxt_reuse_rx_data(rxr, cons, data); if (agg_bufs) bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs); rc = -EIO; + if (rx_err & RX_CMPL_ERRORS_BUFFER_ERROR_MASK) { + netdev_warn(bp->dev, "RX buffer error %x\n", rx_err); + bnxt_sched_reset(bp, rxr); + } goto next_rx; } @@ -6758,8 +6768,15 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp) skip_uc: rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0); + if (rc && vnic->mc_list_count) { + netdev_info(bp->dev, "Failed setting MC filters rc: %d, turning on ALL_MCAST mode\n", + rc); + vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST; + vnic->mc_list_count = 0; + rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0); + } if (rc) - netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", + netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %d\n", rc); return rc; @@ -8224,6 +8241,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_clear_int_mode(bp); init_err_pci_clean: + bnxt_free_hwrm_short_cmd_req(bp); bnxt_free_hwrm_resources(bp); bnxt_cleanup_pci(bp); diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 9046993947cc1e2d4ec5461b43c6f85910397cd7..2287749de087a28a0cca6b0062bb0eddbbd6811b 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2817,14 +2817,20 @@ static int macb_clk_init(struct platform_device *pdev, struct clk **pclk, *hclk = devm_clk_get(&pdev->dev, "hclk"); } - if (IS_ERR(*pclk)) { + if (IS_ERR_OR_NULL(*pclk)) { err = PTR_ERR(*pclk); + if (!err) + err = -ENODEV; + dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); return err; } - if (IS_ERR(*hclk)) { + if (IS_ERR_OR_NULL(*hclk)) { err = PTR_ERR(*hclk); + if (!err) + err = -ENODEV; + dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); return err; } diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 59b62b49ad48d673e5d0b72e581a1eb0b67c94a9..98734a37b6f64f7c062828ab56bcecac6c79ca8b 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -29,6 +29,13 @@ #define DRV_NAME "thunder-nicvf" #define DRV_VERSION "1.0" +/* NOTE: Packets bigger than 1530 are split across multiple pages and XDP needs + * the buffer to be contiguous. Allow XDP to be set up only if we don't exceed + * this value, keeping headroom for the 14 byte Ethernet header and two + * VLAN tags (for QinQ) + */ +#define MAX_XDP_MTU (1530 - ETH_HLEN - VLAN_HLEN * 2) + /* Supported devices */ static const struct pci_device_id nicvf_id_table[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, @@ -1454,6 +1461,15 @@ static int nicvf_change_mtu(struct net_device *netdev, int new_mtu) struct nicvf *nic = netdev_priv(netdev); int orig_mtu = netdev->mtu; + /* For now just support only the usual MTU sized frames, + * plus some headroom for VLAN, QinQ. + */ + if (nic->xdp_prog && new_mtu > MAX_XDP_MTU) { + netdev_warn(netdev, "Jumbo frames not yet supported with XDP, current MTU %d.\n", + netdev->mtu); + return -EINVAL; + } + netdev->mtu = new_mtu; if (!netif_running(netdev)) @@ -1702,8 +1718,10 @@ static int nicvf_xdp_setup(struct nicvf *nic, struct bpf_prog *prog) bool bpf_attached = false; int ret = 0; - /* For now just support only the usual MTU sized frames */ - if (prog && (dev->mtu > 1500)) { + /* For now just support only the usual MTU sized frames, + * plus some headroom for VLAN, QinQ. + */ + if (prog && dev->mtu > MAX_XDP_MTU) { netdev_warn(dev, "Jumbo frames not yet supported with XDP, current MTU %d.\n", dev->mtu); return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c index 79d03f8ee7b180d2cab9a2a647254461c0a0cb08..c7fa97a7e1f4d4b07dd6b00f7c5c7bffca4a0356 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.c +++ b/drivers/net/ethernet/hisilicon/hns/hnae.c @@ -150,7 +150,6 @@ static int hnae_alloc_buffers(struct hnae_ring *ring) /* free desc along with its attached buffer */ static void hnae_free_desc(struct hnae_ring *ring) { - hnae_free_buffers(ring); dma_unmap_single(ring_to_dev(ring), ring->desc_dma_addr, ring->desc_num * sizeof(ring->desc[0]), ring_to_dma_dir(ring)); @@ -183,6 +182,9 @@ static int hnae_alloc_desc(struct hnae_ring *ring) /* fini ring, also free the buffer for the ring */ static void hnae_fini_ring(struct hnae_ring *ring) { + if (is_rx_ring(ring)) + hnae_free_buffers(ring); + hnae_free_desc(ring); kfree(ring->desc_cb); ring->desc_cb = NULL; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 7e82dfbb43403f5e8f6be55e84239f2fe431a913..7d0f3cd8a002babbca711d24115a8373b06429f1 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -2743,6 +2743,17 @@ int hns_dsaf_get_regs_count(void) return DSAF_DUMP_REGS_NUM; } +static int hns_dsaf_get_port_id(u8 port) +{ + if (port < DSAF_SERVICE_NW_NUM) + return port; + + if (port >= DSAF_BASE_INNER_PORT_NUM) + return port - DSAF_BASE_INNER_PORT_NUM + DSAF_SERVICE_NW_NUM; + + return -EINVAL; +} + static void set_promisc_tcam_enable(struct dsaf_device *dsaf_dev, u32 port) { struct dsaf_tbl_tcam_ucast_cfg tbl_tcam_ucast = {0, 1, 0, 0, 0x80}; @@ -2808,23 +2819,33 @@ static void set_promisc_tcam_enable(struct dsaf_device *dsaf_dev, u32 port) memset(&temp_key, 0x0, sizeof(temp_key)); mask_entry.addr[0] = 0x01; hns_dsaf_set_mac_key(dsaf_dev, &mask_key, mask_entry.in_vlan_id, - port, mask_entry.addr); + 0xf, mask_entry.addr); tbl_tcam_mcast.tbl_mcast_item_vld = 1; tbl_tcam_mcast.tbl_mcast_old_en = 0; - if (port < DSAF_SERVICE_NW_NUM) { - mskid = port; - } else if (port >= DSAF_BASE_INNER_PORT_NUM) { - mskid = port - DSAF_BASE_INNER_PORT_NUM + DSAF_SERVICE_NW_NUM; - } else { + /* set MAC port to handle multicast */ + mskid = hns_dsaf_get_port_id(port); + if (mskid == -EINVAL) { dev_err(dsaf_dev->dev, "%s,pnum(%d)error,key(%#x:%#x)\n", dsaf_dev->ae_dev.name, port, mask_key.high.val, mask_key.low.val); return; } + dsaf_set_bit(tbl_tcam_mcast.tbl_mcast_port_msk[mskid / 32], + mskid % 32, 1); + /* set pool bit map to handle multicast */ + mskid = hns_dsaf_get_port_id(port_num); + if (mskid == -EINVAL) { + dev_err(dsaf_dev->dev, + "%s, pool bit map pnum(%d)error,key(%#x:%#x)\n", + dsaf_dev->ae_dev.name, port_num, + mask_key.high.val, mask_key.low.val); + return; + } dsaf_set_bit(tbl_tcam_mcast.tbl_mcast_port_msk[mskid / 32], mskid % 32, 1); + memcpy(&temp_key, &mask_key, sizeof(mask_key)); hns_dsaf_tcam_mc_cfg_vague(dsaf_dev, entry_index, &tbl_tcam_data_mc, (struct dsaf_tbl_tcam_data *)(&mask_key), diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c index 51e7e9f5af4992b3a21f3cbfd4d27bed06d092e0..70de7b5d28af7f5b80fba9c9060ba66ca9b31e9e 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c @@ -129,7 +129,7 @@ static void hns_xgmac_lf_rf_control_init(struct mac_driver *mac_drv) dsaf_set_bit(val, XGMAC_UNIDIR_EN_B, 0); dsaf_set_bit(val, XGMAC_RF_TX_EN_B, 1); dsaf_set_field(val, XGMAC_LF_RF_INSERT_M, XGMAC_LF_RF_INSERT_S, 0); - dsaf_write_reg(mac_drv, XGMAC_MAC_TX_LF_RF_CONTROL_REG, val); + dsaf_write_dev(mac_drv, XGMAC_MAC_TX_LF_RF_CONTROL_REG, val); } /** diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index d30c28fba249925c7f46d5fb104727e897dc799b..8fd04081780484bc896ff081cfdffca4943778f9 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -29,9 +29,6 @@ #define SERVICE_TIMER_HZ (1 * HZ) -#define NIC_TX_CLEAN_MAX_NUM 256 -#define NIC_RX_CLEAN_MAX_NUM 64 - #define RCB_IRQ_NOT_INITED 0 #define RCB_IRQ_INITED 1 #define HNS_BUFFER_SIZE_2048 2048 @@ -376,8 +373,6 @@ netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev, wmb(); /* commit all data before submit */ assert(skb->queue_mapping < priv->ae_handle->q_num); hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num); - ring->stats.tx_pkts++; - ring->stats.tx_bytes += skb->len; return NETDEV_TX_OK; @@ -1099,6 +1094,9 @@ static int hns_nic_tx_poll_one(struct hns_nic_ring_data *ring_data, /* issue prefetch for next Tx descriptor */ prefetch(&ring->desc_cb[ring->next_to_clean]); } + /* update tx ring statistics. */ + ring->stats.tx_pkts += pkts; + ring->stats.tx_bytes += bytes; NETIF_TX_UNLOCK(ring); @@ -2269,7 +2267,7 @@ static int hns_nic_init_ring_data(struct hns_nic_priv *priv) hns_nic_tx_fini_pro_v2; netif_napi_add(priv->netdev, &rd->napi, - hns_nic_common_poll, NIC_TX_CLEAN_MAX_NUM); + hns_nic_common_poll, NAPI_POLL_WEIGHT); rd->ring->irq_init_flag = RCB_IRQ_NOT_INITED; } for (i = h->q_num; i < h->q_num * 2; i++) { @@ -2282,7 +2280,7 @@ static int hns_nic_init_ring_data(struct hns_nic_priv *priv) hns_nic_rx_fini_pro_v2; netif_napi_add(priv->netdev, &rd->napi, - hns_nic_common_poll, NIC_RX_CLEAN_MAX_NUM); + hns_nic_common_poll, NAPI_POLL_WEIGHT); rd->ring->irq_init_flag = RCB_IRQ_NOT_INITED; } diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 4878b7169e0f5835a72107a57eb9f8c4aecedf2e..30cbdf0fed595460e181aea473f5320dc872f37b 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -3176,6 +3176,7 @@ static ssize_t ehea_probe_port(struct device *dev, if (ehea_add_adapter_mr(adapter)) { pr_err("creating MR failed\n"); + of_node_put(eth_dn); return -EIO; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 103c0a742d039dd385d472e172e09ddff8225d4d..fef0bff4a54bfab7dc37eff3b5715c9518073047 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -58,6 +58,8 @@ static int __init fm10k_init_module(void) /* create driver workqueue */ fm10k_workqueue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, fm10k_driver_name); + if (!fm10k_workqueue) + return -ENOMEM; fm10k_dbg_init(); diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 1de82f2473129601542631f409b7942692d692b5..d258a75c934b09fe5a0a3735957fce9c4f0c69dc 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -214,6 +214,8 @@ /* enable link status from external LINK_0 and LINK_1 pins */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */ +#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 /* PHY PM enable */ #define E1000_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */ #define E1000_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */ #define E1000_CTRL_RST 0x04000000 /* Global reset */ diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 8892ea5cbb01adcfd6807ee277c69237db818f8d..71b235f935d9403a50f7da3ec2e9b52cb19650a9 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -7934,9 +7934,7 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake, struct e1000_hw *hw = &adapter->hw; u32 ctrl, rctl, status; u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol; -#ifdef CONFIG_PM - int retval = 0; -#endif + bool wake; rtnl_lock(); netif_device_detach(netdev); @@ -7949,14 +7947,6 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake, igb_clear_interrupt_scheme(adapter); rtnl_unlock(); -#ifdef CONFIG_PM - if (!runtime) { - retval = pci_save_state(pdev); - if (retval) - return retval; - } -#endif - status = rd32(E1000_STATUS); if (status & E1000_STATUS_LU) wufc &= ~E1000_WUFC_LNKC; @@ -7973,10 +7963,6 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake, } ctrl = rd32(E1000_CTRL); - /* advertise wake from D3Cold */ - #define E1000_CTRL_ADVD3WUC 0x00100000 - /* phy power management enable */ - #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 ctrl |= E1000_CTRL_ADVD3WUC; wr32(E1000_CTRL, ctrl); @@ -7990,12 +7976,15 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake, wr32(E1000_WUFC, 0); } - *enable_wake = wufc || adapter->en_mng_pt; - if (!*enable_wake) + wake = wufc || adapter->en_mng_pt; + if (!wake) igb_power_down_link(adapter); else igb_power_up_link(adapter); + if (enable_wake) + *enable_wake = wake; + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ @@ -8038,22 +8027,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev) static int __maybe_unused igb_suspend(struct device *dev) { - int retval; - bool wake; - struct pci_dev *pdev = to_pci_dev(dev); - - retval = __igb_shutdown(pdev, &wake, 0); - if (retval) - return retval; - - if (wake) { - pci_prepare_to_sleep(pdev); - } else { - pci_wake_from_d3(pdev, false); - pci_set_power_state(pdev, PCI_D3hot); - } - - return 0; + return __igb_shutdown(to_pci_dev(dev), NULL, 0); } static int __maybe_unused igb_resume(struct device *dev) @@ -8124,22 +8098,7 @@ static int __maybe_unused igb_runtime_idle(struct device *dev) static int __maybe_unused igb_runtime_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - int retval; - bool wake; - - retval = __igb_shutdown(pdev, &wake, 1); - if (retval) - return retval; - - if (wake) { - pci_prepare_to_sleep(pdev); - } else { - pci_wake_from_d3(pdev, false); - pci_set_power_state(pdev, PCI_D3hot); - } - - return 0; + return __igb_shutdown(to_pci_dev(dev), NULL, 1); } static int __maybe_unused igb_runtime_resume(struct device *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index ece3fb147e3eee0707d67d0e4c336352edd1e066..36ae0b2519d2a005e0e31f6dacfc6cd6e6512ca5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -45,7 +45,9 @@ int mlx5e_create_tir(struct mlx5_core_dev *mdev, if (err) return err; + mutex_lock(&mdev->mlx5e_res.td.list_lock); list_add(&tir->list, &mdev->mlx5e_res.td.tirs_list); + mutex_unlock(&mdev->mlx5e_res.td.list_lock); return 0; } @@ -53,8 +55,10 @@ int mlx5e_create_tir(struct mlx5_core_dev *mdev, void mlx5e_destroy_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir) { + mutex_lock(&mdev->mlx5e_res.td.list_lock); mlx5_core_destroy_tir(mdev, tir->tirn); list_del(&tir->list); + mutex_unlock(&mdev->mlx5e_res.td.list_lock); } static int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, @@ -114,6 +118,7 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev) } INIT_LIST_HEAD(&mdev->mlx5e_res.td.tirs_list); + mutex_init(&mdev->mlx5e_res.td.list_lock); return 0; @@ -140,15 +145,17 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) { struct mlx5_core_dev *mdev = priv->mdev; struct mlx5e_tir *tir; - int err = -ENOMEM; + int err = 0; u32 tirn = 0; int inlen; void *in; inlen = MLX5_ST_SZ_BYTES(modify_tir_in); in = kvzalloc(inlen, GFP_KERNEL); - if (!in) + if (!in) { + err = -ENOMEM; goto out; + } if (enable_uc_lb) MLX5_SET(modify_tir_in, in, ctx.self_lb_block, @@ -156,6 +163,7 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1); + mutex_lock(&mdev->mlx5e_res.td.list_lock); list_for_each_entry(tir, &mdev->mlx5e_res.td.tirs_list, list) { tirn = tir->tirn; err = mlx5_core_modify_tir(mdev, tirn, in, inlen); @@ -167,6 +175,7 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) kvfree(in); if (err) netdev_err(priv->netdev, "refresh tir(0x%x) failed, %d\n", tirn, err); + mutex_unlock(&mdev->mlx5e_res.td.list_lock); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index d9db3ad3d765572ced3bde877f06d7dd11869828..26ad27b3f687397bece97abbf80f54e4fbbbcaf1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1622,7 +1622,7 @@ static int mlx5e_get_module_info(struct net_device *netdev, break; case MLX5_MODULE_ID_SFP: modinfo->type = ETH_MODULE_SFF_8472; - modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + modinfo->eeprom_len = MLX5_EEPROM_PAGE_LENGTH; break; default: netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index d2914116af8e253a25e29b070091b3db9e55c4ec..090d54275a7dd4369c04cc874c09619774c6bfcc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -79,8 +79,7 @@ static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport, opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1); MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport); - if (vport) - MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1); + MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1); nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in, in, nic_vport_context); @@ -108,8 +107,7 @@ static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport, MLX5_SET(modify_esw_vport_context_in, in, opcode, MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT); MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport); - if (vport) - MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); + MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 558fc6a05e2ac242b9fa7a03c6aa747061e2e225..826d1a4600f3163e3f02ee9ec32b48efe1aac184 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -155,26 +155,6 @@ static struct mlx5_profile profile[] = { .size = 8, .limit = 4 }, - .mr_cache[16] = { - .size = 8, - .limit = 4 - }, - .mr_cache[17] = { - .size = 8, - .limit = 4 - }, - .mr_cache[18] = { - .size = 8, - .limit = 4 - }, - .mr_cache[19] = { - .size = 4, - .limit = 2 - }, - .mr_cache[20] = { - .size = 4, - .limit = 2 - }, }, }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index ccb6287aeeb74445db238f11d91cdde970ee771a..1d2bb7fa68b17618fcbf675388dd33521cb3dff7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -392,10 +392,6 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, size -= offset + size - MLX5_EEPROM_PAGE_LENGTH; i2c_addr = MLX5_I2C_ADDR_LOW; - if (offset >= MLX5_EEPROM_PAGE_LENGTH) { - i2c_addr = MLX5_I2C_ADDR_HIGH; - offset -= MLX5_EEPROM_PAGE_LENGTH; - } MLX5_SET(mcia_reg, in, l, 0); MLX5_SET(mcia_reg, in, module, module_num); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 29d37355d8c682ecd89efedd9f1dced0b7341bbb..ab09f9e43c79ad8ade6cf1f6d67b6a984c7432f3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2521,11 +2521,11 @@ mlxsw_sp_port_set_link_ksettings(struct net_device *dev, if (err) return err; + mlxsw_sp_port->link.autoneg = autoneg; + if (!netif_running(dev)) return 0; - mlxsw_sp_port->link.autoneg = autoneg; - mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true); diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index 2fe96f1f3fe5cae8438cf23dada52c0a616a7a37..7ddaa7d88f1da28ff3037ca6964d0656d5708653 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -526,9 +526,8 @@ static void ks8851_rx_pkts(struct ks8851_net *ks) /* set dma read address */ ks8851_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI | 0x00); - /* start the packet dma process, and set auto-dequeue rx */ - ks8851_wrreg16(ks, KS_RXQCR, - ks->rc_rxqcr | RXQCR_SDA | RXQCR_ADRFE); + /* start DMA access */ + ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA); if (rxlen > 4) { unsigned int rxalign; @@ -559,7 +558,8 @@ static void ks8851_rx_pkts(struct ks8851_net *ks) } } - ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); + /* end DMA access and dequeue packet */ + ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_RRXEF); } } @@ -776,6 +776,15 @@ static void ks8851_tx_work(struct work_struct *work) static int ks8851_net_open(struct net_device *dev) { struct ks8851_net *ks = netdev_priv(dev); + int ret; + + ret = request_threaded_irq(dev->irq, NULL, ks8851_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + dev->name, ks); + if (ret < 0) { + netdev_err(dev, "failed to get irq\n"); + return ret; + } /* lock the card, even if we may not actually be doing anything * else at the moment */ @@ -840,6 +849,7 @@ static int ks8851_net_open(struct net_device *dev) netif_dbg(ks, ifup, ks->netdev, "network device up\n"); mutex_unlock(&ks->lock); + mii_check_link(&ks->mii); return 0; } @@ -890,6 +900,8 @@ static int ks8851_net_stop(struct net_device *dev) dev_kfree_skb(txb); } + free_irq(dev->irq, ks); + return 0; } @@ -1499,6 +1511,7 @@ static int ks8851_probe(struct spi_device *spi) spi_set_drvdata(spi, ks); + netif_carrier_off(ks->netdev); ndev->if_port = IF_PORT_100BASET; ndev->netdev_ops = &ks8851_netdev_ops; ndev->irq = spi->irq; @@ -1520,14 +1533,6 @@ static int ks8851_probe(struct spi_device *spi) ks8851_read_selftest(ks); ks8851_init_mac(ks); - ret = request_threaded_irq(spi->irq, NULL, ks8851_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - ndev->name, ks); - if (ret < 0) { - dev_err(&spi->dev, "failed to get irq\n"); - goto err_irq; - } - ret = register_netdev(ndev); if (ret) { dev_err(&spi->dev, "failed to register network device\n"); @@ -1540,14 +1545,10 @@ static int ks8851_probe(struct spi_device *spi) return 0; - err_netdev: - free_irq(ndev->irq, ks); - -err_irq: +err_id: if (gpio_is_valid(gpio)) gpio_set_value(gpio, 0); -err_id: regulator_disable(ks->vdd_reg); err_reg: regulator_disable(ks->vdd_io); @@ -1565,7 +1566,6 @@ static int ks8851_remove(struct spi_device *spi) dev_info(&spi->dev, "remove\n"); unregister_netdev(priv->netdev); - free_irq(spi->irq, priv); if (gpio_is_valid(priv->gpio)) gpio_set_value(priv->gpio, 0); regulator_disable(priv->vdd_reg); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index 5b783a91b115e332dbae8447f32e84c1957b8f7d..8793fa57f8445495c4c022b2342cf7c01aad6eb3 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -76,9 +76,9 @@ nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, static int nfp_bpf_check_exit(struct nfp_prog *nfp_prog, - const struct bpf_verifier_env *env) + struct bpf_verifier_env *env) { - const struct bpf_reg_state *reg0 = &env->cur_state.regs[0]; + const struct bpf_reg_state *reg0 = cur_regs(env) + BPF_REG_0; u64 imm; if (nfp_prog->act == NN_ACT_XDP) @@ -113,9 +113,10 @@ nfp_bpf_check_exit(struct nfp_prog *nfp_prog, static int nfp_bpf_check_ctx_ptr(struct nfp_prog *nfp_prog, - const struct bpf_verifier_env *env, u8 reg) + struct bpf_verifier_env *env, u8 reg_no) { - if (env->cur_state.regs[reg].type != PTR_TO_CTX) + const struct bpf_reg_state *reg = cur_regs(env) + reg_no; + if (reg->type != PTR_TO_CTX) return -EINVAL; return 0; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 9a7655560629ea7d3552ddaea9c47bf0a1c64e2a..1910ca21a1bc46e7477c0c5fab022087e5384fb0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -200,7 +200,7 @@ static netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev) ret = dev_queue_xmit(skb); nfp_repr_inc_tx_stats(netdev, len, ret); - return ret; + return NETDEV_TX_OK; } static int nfp_repr_stop(struct net_device *netdev) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 7f7deeaf1cf07913454a13b4f7801c7b3b07545f..da042bc520d46388d5cb915802905deaac4c15ad 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1047,6 +1047,8 @@ int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode) for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) { skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE); + if (!skb) + break; qlcnic_create_loopback_buff(skb->data, adapter->mac_addr); skb_put(skb, QLCNIC_ILB_PKT_SIZE); adapter->ahw->diag_cnt = 0; diff --git a/drivers/net/ethernet/qualcomm/rmnet/Makefile b/drivers/net/ethernet/qualcomm/rmnet/Makefile index 01bddf207cac5aab1a18342a19900fe73ed84418..b175fbb7f5760cdb640e3af7da10ecb2678f069c 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/Makefile +++ b/drivers/net/ethernet/qualcomm/rmnet/Makefile @@ -7,4 +7,5 @@ rmnet-y += rmnet_vnd.o rmnet-y += rmnet_handlers.o rmnet-y += rmnet_map_data.o rmnet-y += rmnet_map_command.o +rmnet-y += rmnet_descriptor.o obj-$(CONFIG_RMNET) += rmnet.o diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index cec68efac4f0eef4739a87074066bb614c262706..e85c37348485b0e78826585bc14a8d8625fe70ec 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -22,6 +22,7 @@ #include "rmnet_vnd.h" #include "rmnet_private.h" #include "rmnet_map.h" +#include "rmnet_descriptor.h" #include #include @@ -89,6 +90,8 @@ static int rmnet_unregister_real_device(struct net_device *real_dev, rmnet_map_cmd_exit(port); rmnet_map_tx_aggregate_exit(port); + rmnet_descriptor_deinit(port); + kfree(port); netdev_rx_handler_unregister(real_dev); @@ -126,6 +129,12 @@ static int rmnet_register_real_device(struct net_device *real_dev) for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++) INIT_HLIST_HEAD(&port->muxed_ep[entry]); + rc = rmnet_descriptor_init(port); + if (rc) { + rmnet_descriptor_deinit(port); + return rc; + } + rmnet_map_tx_aggregate_init(port); rmnet_map_cmd_init(port); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index 9d89ece3a8bc3bbbf2495342cc29b9d8e49dc759..ebfc2081e3d38276f04d06164e9fadb8fc6db41d 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -29,6 +29,9 @@ struct rmnet_endpoint { }; struct rmnet_port_priv_stats { + u64 dl_hdr_last_qmap_vers; + u64 dl_hdr_last_ep_id; + u64 dl_hdr_last_trans_id; u64 dl_hdr_last_seq; u64 dl_hdr_last_bytes; u64 dl_hdr_last_pkts; @@ -77,6 +80,10 @@ struct rmnet_port { struct list_head dl_list; struct rmnet_port_priv_stats stats; int dl_marker_flush; + + /* Descriptor pool */ + spinlock_t desc_pool_lock; + struct rmnet_frag_descriptor_pool *frag_desc_pool; }; extern struct rtnl_link_ops rmnet_link_ops; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c new file mode 100644 index 0000000000000000000000000000000000000000..acf5abdb7f12d04704ab1febb2a1517b062f66f1 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c @@ -0,0 +1,1221 @@ +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * + * This 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. + * + * RMNET Packet Descriptor Framework + * + */ + +#include +#include +#include +#include +#include "rmnet_config.h" +#include "rmnet_descriptor.h" +#include "rmnet_handlers.h" +#include "rmnet_private.h" +#include "rmnet_vnd.h" +#include +#include + +#define RMNET_FRAG_DESCRIPTOR_POOL_SIZE 64 +#define RMNET_DL_IND_HDR_SIZE (sizeof(struct rmnet_map_dl_ind_hdr) + \ + sizeof(struct rmnet_map_header) + \ + sizeof(struct rmnet_map_control_command_header)) +#define RMNET_DL_IND_TRL_SIZE (sizeof(struct rmnet_map_dl_ind_trl) + \ + sizeof(struct rmnet_map_header) + \ + sizeof(struct rmnet_map_control_command_header)) + +typedef void (*rmnet_perf_desc_hook_t)(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port); +typedef void (*rmnet_perf_chain_hook_t)(void); + +struct rmnet_frag_descriptor * +rmnet_get_frag_descriptor(struct rmnet_port *port) +{ + struct rmnet_frag_descriptor_pool *pool = port->frag_desc_pool; + struct rmnet_frag_descriptor *frag_desc; + + spin_lock(&port->desc_pool_lock); + if (!list_empty(&pool->free_list)) { + frag_desc = list_first_entry(&pool->free_list, + struct rmnet_frag_descriptor, + list); + list_del_init(&frag_desc->list); + } else { + frag_desc = kzalloc(sizeof(*frag_desc), GFP_ATOMIC); + if (!frag_desc) + goto out; + + INIT_LIST_HEAD(&frag_desc->list); + INIT_LIST_HEAD(&frag_desc->sub_frags); + pool->pool_size++; + } + +out: + spin_unlock(&port->desc_pool_lock); + return frag_desc; +} +EXPORT_SYMBOL(rmnet_get_frag_descriptor); + +void rmnet_recycle_frag_descriptor(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port) +{ + struct rmnet_frag_descriptor_pool *pool = port->frag_desc_pool; + struct page *page = skb_frag_page(&frag_desc->frag); + + list_del(&frag_desc->list); + if (page) + put_page(page); + + memset(frag_desc, 0, sizeof(*frag_desc)); + INIT_LIST_HEAD(&frag_desc->list); + INIT_LIST_HEAD(&frag_desc->sub_frags); + spin_lock(&port->desc_pool_lock); + list_add_tail(&frag_desc->list, &pool->free_list); + spin_unlock(&port->desc_pool_lock); +} +EXPORT_SYMBOL(rmnet_recycle_frag_descriptor); + +void rmnet_descriptor_add_frag(struct rmnet_port *port, struct list_head *list, + struct page *p, u32 page_offset, u32 len) +{ + struct rmnet_frag_descriptor *frag_desc; + + frag_desc = rmnet_get_frag_descriptor(port); + if (!frag_desc) + return; + + rmnet_frag_fill(frag_desc, p, page_offset, len); + list_add_tail(&frag_desc->list, list); +} +EXPORT_SYMBOL(rmnet_descriptor_add_frag); + +int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc, + int start, u8 *nexthdrp, __be16 *fragp) +{ + u8 nexthdr = *nexthdrp; + + *fragp = 0; + + while (ipv6_ext_hdr(nexthdr)) { + struct ipv6_opt_hdr *hp; + int hdrlen; + + if (nexthdr == NEXTHDR_NONE) + return -EINVAL; + + hp = rmnet_frag_data_ptr(frag_desc) + start; + + if (nexthdr == NEXTHDR_FRAGMENT) { + __be16 *fp; + + fp = rmnet_frag_data_ptr(frag_desc) + start + + offsetof(struct frag_hdr, frag_off); + *fragp = *fp; + if (ntohs(*fragp) & ~0x7) + break; + hdrlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) { + hdrlen = (hp->hdrlen + 2) << 2; + } else { + hdrlen = ipv6_optlen(hp); + } + + nexthdr = hp->nexthdr; + start += hdrlen; + } + + *nexthdrp = nexthdr; + return start; +} +EXPORT_SYMBOL(rmnet_frag_ipv6_skip_exthdr); + +static u8 rmnet_frag_do_flow_control(struct rmnet_map_header *qmap, + struct rmnet_port *port, + int enable) +{ + struct rmnet_map_control_command *cmd; + struct rmnet_endpoint *ep; + struct net_device *vnd; + u16 ip_family; + u16 fc_seq; + u32 qos_id; + u8 mux_id; + int r; + + mux_id = qmap->mux_id; + cmd = (struct rmnet_map_control_command *) + ((char *)qmap + sizeof(*qmap)); + + if (mux_id >= RMNET_MAX_LOGICAL_EP) + return RX_HANDLER_CONSUMED; + + ep = rmnet_get_endpoint(port, mux_id); + if (!ep) + return RX_HANDLER_CONSUMED; + + vnd = ep->egress_dev; + + ip_family = cmd->flow_control.ip_family; + fc_seq = ntohs(cmd->flow_control.flow_control_seq_num); + qos_id = ntohl(cmd->flow_control.qos_id); + + /* Ignore the ip family and pass the sequence number for both v4 and v6 + * sequence. User space does not support creating dedicated flows for + * the 2 protocols + */ + r = rmnet_vnd_do_flow_control(vnd, enable); + if (r) + return RMNET_MAP_COMMAND_UNSUPPORTED; + else + return RMNET_MAP_COMMAND_ACK; +} + +static void rmnet_frag_send_ack(struct rmnet_map_header *qmap, + unsigned char type, + struct rmnet_port *port) +{ + struct rmnet_map_control_command *cmd; + struct net_device *dev = port->dev; + struct sk_buff *skb; + u16 alloc_len = ntohs(qmap->pkt_len) + sizeof(*qmap); + + skb = alloc_skb(alloc_len, GFP_ATOMIC); + if (!skb) + return; + + skb->protocol = htons(ETH_P_MAP); + skb->dev = dev; + + cmd = rmnet_map_get_cmd_start(skb); + cmd->cmd_type = type & 0x03; + + netif_tx_lock(dev); + dev->netdev_ops->ndo_start_xmit(skb, dev); + netif_tx_unlock(dev); +} + +static void +rmnet_frag_process_flow_start(struct rmnet_map_control_command_header *cmd, + struct rmnet_port *port, + u16 cmd_len) +{ + struct rmnet_map_dl_ind_hdr *dlhdr; + u32 data_format; + bool is_dl_mark_v2; + + if (cmd_len + sizeof(struct rmnet_map_header) < RMNET_DL_IND_HDR_SIZE) + return; + + data_format = port->data_format; + is_dl_mark_v2 = data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2; + dlhdr = (struct rmnet_map_dl_ind_hdr *)((char *)cmd + sizeof(*cmd)); + + port->stats.dl_hdr_last_ep_id = cmd->source_id; + port->stats.dl_hdr_last_qmap_vers = cmd->reserved; + port->stats.dl_hdr_last_trans_id = cmd->transaction_id; + port->stats.dl_hdr_last_seq = dlhdr->le.seq; + port->stats.dl_hdr_last_bytes = dlhdr->le.bytes; + port->stats.dl_hdr_last_pkts = dlhdr->le.pkts; + port->stats.dl_hdr_last_flows = dlhdr->le.flows; + port->stats.dl_hdr_total_bytes += port->stats.dl_hdr_last_bytes; + port->stats.dl_hdr_total_pkts += port->stats.dl_hdr_last_pkts; + port->stats.dl_hdr_count++; + + /* If a target is taking frag path, we can assume DL marker v2 is in + * play + */ + if (is_dl_mark_v2) + rmnet_map_dl_hdr_notify_v2(port, dlhdr, cmd); + else + rmnet_map_dl_hdr_notify(port, dlhdr); +} + +static void +rmnet_frag_process_flow_end(struct rmnet_map_control_command_header *cmd, + struct rmnet_port *port, u16 cmd_len) +{ + struct rmnet_map_dl_ind_trl *dltrl; + u32 data_format; + bool is_dl_mark_v2; + + + if (cmd_len + sizeof(struct rmnet_map_header) < RMNET_DL_IND_TRL_SIZE) + return; + + data_format = port->data_format; + is_dl_mark_v2 = data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2; + dltrl = (struct rmnet_map_dl_ind_trl *)((char *)cmd + sizeof(*cmd)); + + port->stats.dl_trl_last_seq = dltrl->seq_le; + port->stats.dl_trl_count++; + + /* If a target is taking frag path, we can assume DL marker v2 is in + * play + */ + if (is_dl_mark_v2) + rmnet_map_dl_trl_notify_v2(port, dltrl, cmd); + else + rmnet_map_dl_trl_notify(port, dltrl); +} + +/* Process MAP command frame and send N/ACK message as appropriate. Message cmd + * name is decoded here and appropriate handler is called. + */ +void rmnet_frag_command(struct rmnet_map_header *qmap, struct rmnet_port *port) +{ + struct rmnet_map_control_command *cmd; + unsigned char command_name; + unsigned char rc = 0; + + cmd = (struct rmnet_map_control_command *) + ((char *)qmap + sizeof(*qmap)); + command_name = cmd->command_name; + + switch (command_name) { + case RMNET_MAP_COMMAND_FLOW_ENABLE: + rc = rmnet_frag_do_flow_control(qmap, port, 1); + break; + + case RMNET_MAP_COMMAND_FLOW_DISABLE: + rc = rmnet_frag_do_flow_control(qmap, port, 0); + break; + + default: + rc = RMNET_MAP_COMMAND_UNSUPPORTED; + break; + } + if (rc == RMNET_MAP_COMMAND_ACK) + rmnet_frag_send_ack(qmap, rc, port); +} + +int rmnet_frag_flow_command(struct rmnet_map_header *qmap, + struct rmnet_port *port, u16 pkt_len) +{ + struct rmnet_map_control_command_header *cmd; + unsigned char command_name; + + cmd = (struct rmnet_map_control_command_header *) + ((char *)qmap + sizeof(*qmap)); + command_name = cmd->command_name; + + switch (command_name) { + case RMNET_MAP_COMMAND_FLOW_START: + rmnet_frag_process_flow_start(cmd, port, pkt_len); + break; + + case RMNET_MAP_COMMAND_FLOW_END: + rmnet_frag_process_flow_end(cmd, port, pkt_len); + break; + + default: + return 1; + } + + return 0; +} +EXPORT_SYMBOL(rmnet_frag_flow_command); + +void rmnet_frag_deaggregate(skb_frag_t *frag, struct rmnet_port *port, + struct list_head *list) +{ + struct rmnet_map_header *maph; + u8 *data = skb_frag_address(frag); + u32 offset = 0; + u32 packet_len; + + while (offset < skb_frag_size(frag)) { + maph = (struct rmnet_map_header *)data; + packet_len = ntohs(maph->pkt_len); + + /* Some hardware can send us empty frames. Catch them */ + if (packet_len == 0) + return; + + packet_len += sizeof(*maph); + + if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) { + packet_len += sizeof(struct rmnet_map_dl_csum_trailer); + } else if (port->data_format & + (RMNET_FLAGS_INGRESS_MAP_CKSUMV5 | + RMNET_FLAGS_INGRESS_COALESCE) && !maph->cd_bit) { + u32 hsize = 0; + u8 type; + + type = ((struct rmnet_map_v5_coal_header *) + (data + sizeof(*maph)))->header_type; + switch (type) { + case RMNET_MAP_HEADER_TYPE_COALESCING: + hsize = sizeof(struct rmnet_map_v5_coal_header); + break; + case RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD: + hsize = sizeof(struct rmnet_map_v5_csum_header); + break; + } + + packet_len += hsize; + } + + if ((int)skb_frag_size(frag) - (int)packet_len < 0) + return; + + rmnet_descriptor_add_frag(port, list, skb_frag_page(frag), + frag->page_offset + offset, + packet_len); + + offset += packet_len; + data += packet_len; + } +} + +/* Fill in GSO metadata to allow the SKB to be segmented by the NW stack + * if needed (i.e. forwarding, UDP GRO) + */ +static void rmnet_frag_gso_stamp(struct sk_buff *skb, + struct rmnet_frag_descriptor *frag_desc) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct iphdr *iph = (struct iphdr *)skb->data; + __sum16 pseudo; + u16 pkt_len = skb->len - frag_desc->ip_len; + bool ipv4 = frag_desc->ip_proto == 4; + + if (ipv4) { + iph->check = 0; + iph->check = ip_fast_csum(iph, iph->ihl); + pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + pkt_len, frag_desc->trans_proto, + 0); + } else { + struct ipv6hdr *ip6h = (struct ipv6hdr *)iph; + + pseudo = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + pkt_len, frag_desc->trans_proto, 0); + } + + if (frag_desc->trans_proto == IPPROTO_TCP) { + struct tcphdr *tp = (struct tcphdr *) + ((u8 *)iph + frag_desc->ip_len); + + tp->check = pseudo; + shinfo->gso_type = (ipv4) ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6; + skb->csum_offset = offsetof(struct tcphdr, check); + } else { + struct udphdr *up = (struct udphdr *) + ((u8 *)iph + frag_desc->ip_len); + + up->check = pseudo; + shinfo->gso_type = SKB_GSO_UDP_L4; + skb->csum_offset = offsetof(struct udphdr, check); + } + + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = (u8 *)iph + frag_desc->ip_len - skb->head; + shinfo->gso_size = frag_desc->gso_size; + shinfo->gso_segs = frag_desc->gso_segs; +} + +/* Allocate and populate an skb to contain the packet represented by the + * frag descriptor. + */ +static struct sk_buff *rmnet_alloc_skb(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port) +{ + struct sk_buff *head_skb, *current_skb, *skb; + struct skb_shared_info *shinfo; + struct rmnet_frag_descriptor *sub_frag, *tmp; + + /* Use the exact sizes if we know them (i.e. RSB/RSC, rmnet_perf) */ + if (frag_desc->hdrs_valid) { + u16 hdr_len = frag_desc->ip_len + frag_desc->trans_len; + u16 data_len = frag_desc->gso_size * frag_desc->gso_segs; + + head_skb = alloc_skb(hdr_len + RMNET_MAP_DEAGGR_HEADROOM, + GFP_ATOMIC); + if (!head_skb) + return NULL; + + skb_reserve(head_skb, RMNET_MAP_DEAGGR_HEADROOM); + skb_put_data(head_skb, frag_desc->hdr_ptr, hdr_len); + skb_reset_network_header(head_skb); + + /* Update header lengths after RSB/RSC/perf */ + if (frag_desc->ip_proto == 4) { + struct iphdr *iph = ip_hdr(head_skb); + __be16 tot_len = htons(hdr_len + data_len); + + csum_replace2(&iph->check, iph->tot_len, tot_len); + iph->tot_len = tot_len; + } else { + struct ipv6hdr *ip6h = ipv6_hdr(head_skb); + + ip6h->payload_len = htons(hdr_len + data_len - + sizeof(*ip6h)); + } + + if (frag_desc->trans_len) { + skb_set_transport_header(head_skb, frag_desc->ip_len); + + if (frag_desc->trans_proto == IPPROTO_UDP) { + struct udphdr *uh = udp_hdr(head_skb); + + uh->len = htons(data_len + sizeof(*uh)); + } + } + + /* Packets that have no data portion don't need any frags */ + if (hdr_len == skb_frag_size(&frag_desc->frag)) + goto skip_frags; + + /* If the headers we added are the start of the page, + * we don't want to add them twice + */ + if (frag_desc->hdr_ptr == rmnet_frag_data_ptr(frag_desc)) { + if (!rmnet_frag_pull(frag_desc, port, hdr_len)) { + kfree_skb(head_skb); + return NULL; + } + } + } else { + /* Allocate enough space to avoid penalties in the stack + * from __pskb_pull_tail() + */ + head_skb = alloc_skb(256 + RMNET_MAP_DEAGGR_HEADROOM, + GFP_ATOMIC); + if (!head_skb) + return NULL; + + skb_reserve(head_skb, RMNET_MAP_DEAGGR_HEADROOM); + } + + /* Add main fragment */ + get_page(skb_frag_page(&frag_desc->frag)); + skb_add_rx_frag(head_skb, 0, skb_frag_page(&frag_desc->frag), + frag_desc->frag.page_offset, + skb_frag_size(&frag_desc->frag), + skb_frag_size(&frag_desc->frag)); + + shinfo = skb_shinfo(head_skb); + current_skb = head_skb; + + /* Add in any frags from rmnet_perf */ + list_for_each_entry_safe(sub_frag, tmp, &frag_desc->sub_frags, list) { + skb_frag_t *frag; + u32 frag_size; + + frag = &sub_frag->frag; + frag_size = skb_frag_size(frag); + +add_frag: + if (shinfo->nr_frags < MAX_SKB_FRAGS) { + get_page(skb_frag_page(frag)); + skb_add_rx_frag(current_skb, shinfo->nr_frags, + skb_frag_page(frag), frag->page_offset, + frag_size, frag_size); + if (current_skb != head_skb) { + head_skb->len += frag_size; + head_skb->data_len += frag_size; + } + } else { + /* Alloc a new skb and try again */ + skb = alloc_skb(0, GFP_ATOMIC); + if (!skb) + break; + + if (current_skb == head_skb) + shinfo->frag_list = skb; + else + current_skb->next = skb; + + current_skb = skb; + shinfo = skb_shinfo(current_skb); + goto add_frag; + } + + rmnet_recycle_frag_descriptor(sub_frag, port); + } + +skip_frags: + head_skb->dev = frag_desc->dev; + rmnet_set_skb_proto(head_skb); + + /* Handle any header metadata that needs to be updated after RSB/RSC + * segmentation + */ + if (frag_desc->ip_id_set) { + struct iphdr *iph; + + iph = (struct iphdr *)rmnet_map_data_ptr(head_skb); + csum_replace2(&iph->check, iph->id, frag_desc->ip_id); + iph->id = frag_desc->ip_id; + } + + if (frag_desc->tcp_seq_set) { + struct tcphdr *th; + + th = (struct tcphdr *) + (rmnet_map_data_ptr(head_skb) + frag_desc->ip_len); + th->seq = frag_desc->tcp_seq; + } + + /* Handle csum offloading */ + if (frag_desc->csum_valid) { + head_skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if (frag_desc->hdrs_valid && + (frag_desc->trans_proto == IPPROTO_TCP || + frag_desc->trans_proto == IPPROTO_UDP)) { + /* Unfortunately, we have to fake a bad checksum here, since + * the original bad value is lost by the hardware. The only + * reliable way to do it is to calculate the actual checksum + * and corrupt it. + */ + __sum16 *check; + __wsum csum; + unsigned int offset = skb_transport_offset(head_skb); + __sum16 pseudo; + + /* Calculate pseudo header */ + if (frag_desc->ip_proto == 4) { + struct iphdr *iph = ip_hdr(head_skb); + + pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + head_skb->len - + frag_desc->ip_len, + frag_desc->trans_proto, 0); + } else { + struct ipv6hdr *ip6h = ipv6_hdr(head_skb); + + pseudo = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + head_skb->len - + frag_desc->ip_len, + frag_desc->trans_proto, 0); + } + + if (frag_desc->trans_proto == IPPROTO_TCP) + check = &tcp_hdr(head_skb)->check; + else + check = &udp_hdr(head_skb)->check; + + *check = pseudo; + csum = skb_checksum(head_skb, offset, head_skb->len - offset, + 0); + /* Add 1 to corrupt. This cannot produce a final value of 0 + * since csum_fold() can't return a value of 0xFFFF + */ + *check = csum16_add(csum_fold(csum), htons(1)); + head_skb->ip_summed = CHECKSUM_NONE; + } + + /* Handle any rmnet_perf metadata */ + if (frag_desc->hash) { + head_skb->hash = frag_desc->hash; + head_skb->sw_hash = 1; + } + + if (frag_desc->flush_shs) + head_skb->cb[0] = 1; + + /* Handle coalesced packets */ + if (frag_desc->gso_segs > 1) + rmnet_frag_gso_stamp(head_skb, frag_desc); + + return head_skb; +} + +/* Deliver the packets contained within a frag descriptor */ +void rmnet_frag_deliver(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port) +{ + struct sk_buff *skb; + + skb = rmnet_alloc_skb(frag_desc, port); + if (skb) + rmnet_deliver_skb(skb, port); + rmnet_recycle_frag_descriptor(frag_desc, port); +} +EXPORT_SYMBOL(rmnet_frag_deliver); + +static void __rmnet_frag_segment_data(struct rmnet_frag_descriptor *coal_desc, + struct rmnet_port *port, + struct list_head *list, u8 pkt_id, + bool csum_valid) +{ + struct rmnet_priv *priv = netdev_priv(coal_desc->dev); + struct rmnet_frag_descriptor *new_frag; + u8 *hdr_start = rmnet_frag_data_ptr(coal_desc); + u32 offset; + + new_frag = rmnet_get_frag_descriptor(port); + if (!new_frag) + return; + + /* Account for header lengths to access the data start */ + offset = coal_desc->frag.page_offset + coal_desc->ip_len + + coal_desc->trans_len + coal_desc->data_offset; + + /* Header information and most metadata is the same as the original */ + memcpy(new_frag, coal_desc, sizeof(*coal_desc)); + INIT_LIST_HEAD(&new_frag->list); + INIT_LIST_HEAD(&new_frag->sub_frags); + rmnet_frag_fill(new_frag, skb_frag_page(&coal_desc->frag), offset, + coal_desc->gso_size * coal_desc->gso_segs); + + if (coal_desc->trans_proto == IPPROTO_TCP) { + struct tcphdr *th; + + th = (struct tcphdr *)(hdr_start + coal_desc->ip_len); + new_frag->tcp_seq_set = 1; + new_frag->tcp_seq = htonl(ntohl(th->seq) + + coal_desc->data_offset); + } + + if (coal_desc->ip_proto == 4) { + struct iphdr *iph; + + iph = (struct iphdr *)hdr_start; + new_frag->ip_id_set = 1; + new_frag->ip_id = htons(ntohs(iph->id) + coal_desc->pkt_id); + } + + new_frag->hdr_ptr = hdr_start; + new_frag->csum_valid = csum_valid; + priv->stats.coal.coal_reconstruct++; + + /* Update meta information to move past the data we just segmented */ + coal_desc->data_offset += coal_desc->gso_size * coal_desc->gso_segs; + coal_desc->pkt_id = pkt_id + 1; + coal_desc->gso_segs = 0; + + list_add_tail(&new_frag->list, list); +} + +static bool rmnet_frag_validate_csum(struct rmnet_frag_descriptor *frag_desc) +{ + u8 *data = rmnet_frag_data_ptr(frag_desc); + unsigned int datagram_len; + __wsum csum; + __sum16 pseudo; + + datagram_len = skb_frag_size(&frag_desc->frag) - frag_desc->ip_len; + if (frag_desc->ip_proto == 4) { + struct iphdr *iph = (struct iphdr *)data; + + pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + datagram_len, + frag_desc->trans_proto, 0); + } else { + struct ipv6hdr *ip6h = (struct ipv6hdr *)data; + + pseudo = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + datagram_len, frag_desc->trans_proto, + 0); + } + + csum = csum_partial(data + frag_desc->ip_len, datagram_len, + csum_unfold(pseudo)); + return !csum_fold(csum); +} + +/* Converts the coalesced frame into a list of descriptors. + * NLOs containing csum erros will not be included. + */ +static void +rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc, + u64 nlo_err_mask, struct rmnet_port *port, + struct list_head *list) +{ + struct iphdr *iph; + struct rmnet_priv *priv = netdev_priv(coal_desc->dev); + struct rmnet_map_v5_coal_header *coal_hdr; + u16 pkt_len; + u8 pkt, total_pkt = 0; + u8 nlo; + bool gro = coal_desc->dev->features & NETIF_F_GRO_HW; + + /* Pull off the headers we no longer need */ + if (!rmnet_frag_pull(coal_desc, port, sizeof(struct rmnet_map_header))) + return; + + coal_hdr = (struct rmnet_map_v5_coal_header *) + rmnet_frag_data_ptr(coal_desc); + if (!rmnet_frag_pull(coal_desc, port, sizeof(*coal_hdr))) + return; + + iph = (struct iphdr *)rmnet_frag_data_ptr(coal_desc); + + if (iph->version == 4) { + coal_desc->ip_proto = 4; + coal_desc->ip_len = iph->ihl * 4; + coal_desc->trans_proto = iph->protocol; + + /* Don't allow coalescing of any packets with IP options */ + if (iph->ihl != 5) + gro = false; + } else if (iph->version == 6) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)iph; + __be16 frag_off; + u8 protocol = ip6h->nexthdr; + + coal_desc->ip_proto = 6; + coal_desc->ip_len = rmnet_frag_ipv6_skip_exthdr(coal_desc, + sizeof(*ip6h), + &protocol, + &frag_off); + coal_desc->trans_proto = protocol; + + /* If we run into a problem, or this has a fragment header + * (which should technically not be possible, if the HW + * works as intended...), bail. + */ + if (coal_desc->ip_len < 0 || frag_off) { + priv->stats.coal.coal_ip_invalid++; + return; + } else if (coal_desc->ip_len > sizeof(*ip6h)) { + /* Don't allow coalescing of any packets with IPv6 + * extension headers. + */ + gro = false; + } + } else { + priv->stats.coal.coal_ip_invalid++; + return; + } + + if (coal_desc->trans_proto == IPPROTO_TCP) { + struct tcphdr *th; + + th = (struct tcphdr *)((u8 *)iph + coal_desc->ip_len); + coal_desc->trans_len = th->doff * 4; + } else if (coal_desc->trans_proto == IPPROTO_UDP) { + coal_desc->trans_len = sizeof(struct udphdr); + } else { + priv->stats.coal.coal_trans_invalid++; + return; + } + + coal_desc->hdrs_valid = 1; + + if (rmnet_map_v5_csum_buggy(coal_hdr)) { + /* Mark the checksum as valid if it checks out */ + if (rmnet_frag_validate_csum(coal_desc)) + coal_desc->csum_valid = true; + + coal_desc->hdr_ptr = rmnet_frag_data_ptr(coal_desc); + coal_desc->gso_size = ntohs(coal_hdr->nl_pairs[0].pkt_len); + coal_desc->gso_size -= coal_desc->ip_len + coal_desc->trans_len; + coal_desc->gso_segs = coal_hdr->nl_pairs[0].num_packets; + list_add_tail(&coal_desc->list, list); + return; + } + + /* Fast-forward the case where we have 1 NLO (i.e. 1 packet length), + * no checksum errors, and are allowing GRO. We can just reuse this + * descriptor unchanged. + */ + if (gro && coal_hdr->num_nlos == 1 && coal_hdr->csum_valid) { + coal_desc->csum_valid = true; + coal_desc->hdr_ptr = rmnet_frag_data_ptr(coal_desc); + coal_desc->gso_size = ntohs(coal_hdr->nl_pairs[0].pkt_len); + coal_desc->gso_size -= coal_desc->ip_len + coal_desc->trans_len; + coal_desc->gso_segs = coal_hdr->nl_pairs[0].num_packets; + list_add_tail(&coal_desc->list, list); + return; + } + + /* Segment the coalesced descriptor into new packets */ + for (nlo = 0; nlo < coal_hdr->num_nlos; nlo++) { + pkt_len = ntohs(coal_hdr->nl_pairs[nlo].pkt_len); + pkt_len -= coal_desc->ip_len + coal_desc->trans_len; + coal_desc->gso_size = pkt_len; + for (pkt = 0; pkt < coal_hdr->nl_pairs[nlo].num_packets; + pkt++, total_pkt++, nlo_err_mask >>= 1) { + bool csum_err = nlo_err_mask & 1; + + /* Segment the packet if we're not sending the larger + * packet up the stack. + */ + if (!gro) { + coal_desc->gso_segs = 1; + if (csum_err) + priv->stats.coal.coal_csum_err++; + + __rmnet_frag_segment_data(coal_desc, port, + list, total_pkt, + !csum_err); + continue; + } + + if (csum_err) { + priv->stats.coal.coal_csum_err++; + + /* Segment out the good data */ + if (coal_desc->gso_segs) + __rmnet_frag_segment_data(coal_desc, + port, + list, + total_pkt, + true); + + /* Segment out the bad checksum */ + coal_desc->gso_segs = 1; + __rmnet_frag_segment_data(coal_desc, port, + list, total_pkt, + false); + } else { + coal_desc->gso_segs++; + + } + } + + /* If we're switching NLOs, we need to send out everything from + * the previous one, if we haven't done so. NLOs only switch + * when the packet length changes. + */ + if (coal_desc->gso_segs) + __rmnet_frag_segment_data(coal_desc, port, list, + total_pkt, true); + } +} + +/* Record reason for coalescing pipe closure */ +static void rmnet_frag_data_log_close_stats(struct rmnet_priv *priv, u8 type, + u8 code) +{ + struct rmnet_coal_close_stats *stats = &priv->stats.coal.close; + + switch (type) { + case RMNET_MAP_COAL_CLOSE_NON_COAL: + stats->non_coal++; + break; + case RMNET_MAP_COAL_CLOSE_IP_MISS: + stats->ip_miss++; + break; + case RMNET_MAP_COAL_CLOSE_TRANS_MISS: + stats->trans_miss++; + break; + case RMNET_MAP_COAL_CLOSE_HW: + switch (code) { + case RMNET_MAP_COAL_CLOSE_HW_NL: + stats->hw_nl++; + break; + case RMNET_MAP_COAL_CLOSE_HW_PKT: + stats->hw_pkt++; + break; + case RMNET_MAP_COAL_CLOSE_HW_BYTE: + stats->hw_byte++; + break; + case RMNET_MAP_COAL_CLOSE_HW_TIME: + stats->hw_time++; + break; + case RMNET_MAP_COAL_CLOSE_HW_EVICT: + stats->hw_evict++; + break; + default: + break; + } + break; + case RMNET_MAP_COAL_CLOSE_COAL: + stats->coal++; + break; + default: + break; + } +} + +/* Check if the coalesced header has any incorrect values, in which case, the + * entire coalesced frame must be dropped. Then check if there are any + * checksum issues + */ +static int +rmnet_frag_data_check_coal_header(struct rmnet_frag_descriptor *frag_desc, + u64 *nlo_err_mask) +{ + struct rmnet_map_v5_coal_header *coal_hdr; + unsigned char *data = rmnet_frag_data_ptr(frag_desc); + struct rmnet_priv *priv = netdev_priv(frag_desc->dev); + u64 mask = 0; + int i; + u8 veid, pkts = 0; + + coal_hdr = (struct rmnet_map_v5_coal_header *) + (data + sizeof(struct rmnet_map_header)); + veid = coal_hdr->virtual_channel_id; + + if (coal_hdr->num_nlos == 0 || + coal_hdr->num_nlos > RMNET_MAP_V5_MAX_NLOS) { + priv->stats.coal.coal_hdr_nlo_err++; + return -EINVAL; + } + + for (i = 0; i < RMNET_MAP_V5_MAX_NLOS; i++) { + /* If there is a checksum issue, we need to split + * up the skb. Rebuild the full csum error field + */ + u8 err = coal_hdr->nl_pairs[i].csum_error_bitmap; + u8 pkt = coal_hdr->nl_pairs[i].num_packets; + + mask |= ((u64)err) << (8 * i); + + /* Track total packets in frame */ + pkts += pkt; + if (pkts > RMNET_MAP_V5_MAX_PACKETS) { + priv->stats.coal.coal_hdr_pkt_err++; + return -EINVAL; + } + } + + /* Track number of packets we get inside of coalesced frames */ + priv->stats.coal.coal_pkts += pkts; + + /* Update ethtool stats */ + rmnet_frag_data_log_close_stats(priv, + coal_hdr->close_type, + coal_hdr->close_value); + if (veid < RMNET_MAX_VEID) + priv->stats.coal.coal_veid[veid]++; + + *nlo_err_mask = mask; + + return 0; +} + +/* Process a QMAPv5 packet header */ +int rmnet_frag_process_next_hdr_packet(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port, + struct list_head *list, + u16 len) +{ + struct rmnet_priv *priv = netdev_priv(frag_desc->dev); + u64 nlo_err_mask; + int rc = 0; + + switch (rmnet_frag_get_next_hdr_type(frag_desc)) { + case RMNET_MAP_HEADER_TYPE_COALESCING: + priv->stats.coal.coal_rx++; + rc = rmnet_frag_data_check_coal_header(frag_desc, + &nlo_err_mask); + if (rc) + return rc; + + rmnet_frag_segment_coal_data(frag_desc, nlo_err_mask, port, + list); + if (list_first_entry(list, struct rmnet_frag_descriptor, + list) != frag_desc) + rmnet_recycle_frag_descriptor(frag_desc, port); + break; + case RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD: + if (rmnet_frag_get_csum_valid(frag_desc)) { + priv->stats.csum_ok++; + frag_desc->csum_valid = true; + } else { + priv->stats.csum_valid_unset++; + } + + if (!rmnet_frag_pull(frag_desc, port, + sizeof(struct rmnet_map_header) + + sizeof(struct rmnet_map_v5_csum_header))) { + rc = -EINVAL; + break; + } + + frag_desc->hdr_ptr = rmnet_frag_data_ptr(frag_desc); + + /* Remove padding only for csum offload packets. + * Coalesced packets should never have padding. + */ + if (!rmnet_frag_trim(frag_desc, port, len)) { + rc = -EINVAL; + break; + } + + list_del_init(&frag_desc->list); + list_add_tail(&frag_desc->list, list); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +/* Perf hook handler */ +rmnet_perf_desc_hook_t rmnet_perf_desc_entry __rcu __read_mostly; +EXPORT_SYMBOL(rmnet_perf_desc_entry); + +static void +__rmnet_frag_ingress_handler(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port) +{ + rmnet_perf_desc_hook_t rmnet_perf_ingress; + struct rmnet_map_header *qmap; + struct rmnet_endpoint *ep; + struct rmnet_frag_descriptor *frag, *tmp; + LIST_HEAD(segs); + u16 len, pad; + u8 mux_id; + + qmap = (struct rmnet_map_header *)skb_frag_address(&frag_desc->frag); + mux_id = qmap->mux_id; + pad = qmap->pad_len; + len = ntohs(qmap->pkt_len) - pad; + + if (qmap->cd_bit) { + qmi_rmnet_set_dl_msg_active(port); + if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) { + rmnet_frag_flow_command(qmap, port, len); + goto recycle; + } + + if (port->data_format & RMNET_FLAGS_INGRESS_MAP_COMMANDS) + rmnet_frag_command(qmap, port); + + goto recycle; + } + + if (mux_id >= RMNET_MAX_LOGICAL_EP) + goto recycle; + + ep = rmnet_get_endpoint(port, mux_id); + if (!ep) + goto recycle; + + frag_desc->dev = ep->egress_dev; + + /* Handle QMAPv5 packet */ + if (qmap->next_hdr && + (port->data_format & (RMNET_FLAGS_INGRESS_COALESCE | + RMNET_FLAGS_INGRESS_MAP_CKSUMV5))) { + if (rmnet_frag_process_next_hdr_packet(frag_desc, port, &segs, + len)) + goto recycle; + } else { + /* We only have the main QMAP header to worry about */ + if (!rmnet_frag_pull(frag_desc, port, sizeof(*qmap))) + return; + + frag_desc->hdr_ptr = rmnet_frag_data_ptr(frag_desc); + + if (!rmnet_frag_trim(frag_desc, port, len)) + return; + + list_add_tail(&frag_desc->list, &segs); + } + + if (port->data_format & RMNET_INGRESS_FORMAT_PS) + qmi_rmnet_work_maybe_restart(port); + + rcu_read_lock(); + rmnet_perf_ingress = rcu_dereference(rmnet_perf_desc_entry); + if (rmnet_perf_ingress) { + list_for_each_entry_safe(frag, tmp, &segs, list) { + list_del_init(&frag->list); + rmnet_perf_ingress(frag, port); + } + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + + list_for_each_entry_safe(frag, tmp, &segs, list) { + list_del_init(&frag->list); + rmnet_frag_deliver(frag, port); + } + return; + +recycle: + rmnet_recycle_frag_descriptor(frag_desc, port); +} + +/* Notify perf at the end of SKB chain */ +rmnet_perf_chain_hook_t rmnet_perf_chain_end __rcu __read_mostly; +EXPORT_SYMBOL(rmnet_perf_chain_end); + +void rmnet_frag_ingress_handler(struct sk_buff *skb, + struct rmnet_port *port) +{ + rmnet_perf_chain_hook_t rmnet_perf_opt_chain_end; + LIST_HEAD(desc_list); + + /* Deaggregation and freeing of HW originating + * buffers is done within here + */ + while (skb) { + struct sk_buff *skb_frag; + + rmnet_frag_deaggregate(skb_shinfo(skb)->frags, port, + &desc_list); + if (!list_empty(&desc_list)) { + struct rmnet_frag_descriptor *frag_desc, *tmp; + + list_for_each_entry_safe(frag_desc, tmp, &desc_list, + list) { + list_del_init(&frag_desc->list); + __rmnet_frag_ingress_handler(frag_desc, port); + } + } + + skb_frag = skb_shinfo(skb)->frag_list; + skb_shinfo(skb)->frag_list = NULL; + consume_skb(skb); + skb = skb_frag; + } + + rcu_read_lock(); + rmnet_perf_opt_chain_end = rcu_dereference(rmnet_perf_chain_end); + if (rmnet_perf_opt_chain_end) + rmnet_perf_opt_chain_end(); + rcu_read_unlock(); +} + +void rmnet_descriptor_deinit(struct rmnet_port *port) +{ + struct rmnet_frag_descriptor_pool *pool; + struct rmnet_frag_descriptor *frag_desc, *tmp; + + pool = port->frag_desc_pool; + + list_for_each_entry_safe(frag_desc, tmp, &pool->free_list, list) { + kfree(frag_desc); + pool->pool_size--; + } + + kfree(pool); +} + +int rmnet_descriptor_init(struct rmnet_port *port) +{ + struct rmnet_frag_descriptor_pool *pool; + int i; + + spin_lock_init(&port->desc_pool_lock); + pool = kzalloc(sizeof(*pool), GFP_ATOMIC); + if (!pool) + return -ENOMEM; + + INIT_LIST_HEAD(&pool->free_list); + port->frag_desc_pool = pool; + + for (i = 0; i < RMNET_FRAG_DESCRIPTOR_POOL_SIZE; i++) { + struct rmnet_frag_descriptor *frag_desc; + + frag_desc = kzalloc(sizeof(*frag_desc), GFP_ATOMIC); + if (!frag_desc) + return -ENOMEM; + + INIT_LIST_HEAD(&frag_desc->list); + INIT_LIST_HEAD(&frag_desc->sub_frags); + list_add_tail(&frag_desc->list, &pool->free_list); + pool->pool_size++; + } + + return 0; +} diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.h new file mode 100644 index 0000000000000000000000000000000000000000..795f6f27d773ce2f0ecb35c20c47551287f14b02 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.h @@ -0,0 +1,151 @@ +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * + * This 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. + * + * RMNET Packet Descriptor Framework + * + */ + +#ifndef _RMNET_DESCRIPTOR_H_ +#define _RMNET_DESCRIPTOR_H_ + +#include +#include +#include +#include "rmnet_config.h" +#include "rmnet_map.h" + +struct rmnet_frag_descriptor_pool { + struct list_head free_list; + u32 pool_size; +}; + +struct rmnet_frag_descriptor { + struct list_head list; + struct list_head sub_frags; + skb_frag_t frag; + u8 *hdr_ptr; + struct net_device *dev; + u32 hash; + __be32 tcp_seq; + __be16 ip_id; + u16 data_offset; + u16 gso_size; + u16 gso_segs; + u16 ip_len; + u16 trans_len; + u8 ip_proto; + u8 trans_proto; + u8 pkt_id; + u8 csum_valid:1, + hdrs_valid:1, + ip_id_set:1, + tcp_seq_set:1, + flush_shs:1, + reserved:3; +}; + +/* Descriptor management */ +struct rmnet_frag_descriptor * +rmnet_get_frag_descriptor(struct rmnet_port *port); +void rmnet_recycle_frag_descriptor(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port); +void rmnet_descriptor_add_frag(struct rmnet_port *port, struct list_head *list, + struct page *p, u32 page_offset, u32 len); +int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc, + int start, u8 *nexthdrp, __be16 *fragp); + +/* QMAP command packets */ +void rmnet_frag_command(struct rmnet_map_header *qmap, struct rmnet_port *port); +int rmnet_frag_flow_command(struct rmnet_map_header *qmap, + struct rmnet_port *port, u16 pkt_len); + +/* Ingress data handlers */ +void rmnet_frag_deaggregate(skb_frag_t *frag, struct rmnet_port *port, + struct list_head *list); +void rmnet_frag_deliver(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port); +int rmnet_frag_process_next_hdr_packet(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port, + struct list_head *list, + u16 len); +void rmnet_frag_ingress_handler(struct sk_buff *skb, + struct rmnet_port *port); + +int rmnet_descriptor_init(struct rmnet_port *port); +void rmnet_descriptor_deinit(struct rmnet_port *port); + +static inline void *rmnet_frag_data_ptr(struct rmnet_frag_descriptor *frag_desc) +{ + return skb_frag_address(&frag_desc->frag); +} + +static inline void *rmnet_frag_pull(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port, + unsigned int size) +{ + if (size >= skb_frag_size(&frag_desc->frag)) { + pr_info("%s(): Pulling %u bytes from %u byte pkt. Dropping\n", + __func__, size, skb_frag_size(&frag_desc->frag)); + rmnet_recycle_frag_descriptor(frag_desc, port); + return NULL; + } + + frag_desc->frag.page_offset += size; + skb_frag_size_sub(&frag_desc->frag, size); + + return rmnet_frag_data_ptr(frag_desc); +} + +static inline void *rmnet_frag_trim(struct rmnet_frag_descriptor *frag_desc, + struct rmnet_port *port, + unsigned int size) +{ + if (!size) { + pr_info("%s(): Trimming %u byte pkt to 0. Dropping\n", + __func__, skb_frag_size(&frag_desc->frag)); + rmnet_recycle_frag_descriptor(frag_desc, port); + return NULL; + } + + if (size < skb_frag_size(&frag_desc->frag)) + skb_frag_size_set(&frag_desc->frag, size); + + return rmnet_frag_data_ptr(frag_desc); +} + +static inline void rmnet_frag_fill(struct rmnet_frag_descriptor *frag_desc, + struct page *p, u32 page_offset, u32 len) +{ + get_page(p); + __skb_frag_set_page(&frag_desc->frag, p); + skb_frag_size_set(&frag_desc->frag, len); + frag_desc->frag.page_offset = page_offset; +} + +static inline u8 +rmnet_frag_get_next_hdr_type(struct rmnet_frag_descriptor *frag_desc) +{ + unsigned char *data = rmnet_frag_data_ptr(frag_desc); + + data += sizeof(struct rmnet_map_header); + return ((struct rmnet_map_v5_coal_header *)data)->header_type; +} + +static inline bool +rmnet_frag_get_csum_valid(struct rmnet_frag_descriptor *frag_desc) +{ + unsigned char *data = rmnet_frag_data_ptr(frag_desc); + + data += sizeof(struct rmnet_map_header); + return ((struct rmnet_map_v5_csum_header *)data)->csum_valid_required; +} + +#endif /* _RMNET_DESCRIPTOR_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index a21b9360bb9e9464eb6ac387c4431aaedac8772e..b833ad1d13752d27b8817d388d725223353de1cc 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -25,6 +25,7 @@ #include "rmnet_vnd.h" #include "rmnet_map.h" #include "rmnet_handlers.h" +#include "rmnet_descriptor.h" #include #include @@ -86,11 +87,6 @@ void rmnet_set_skb_proto(struct sk_buff *skb) } EXPORT_SYMBOL(rmnet_set_skb_proto); -/* Perf hook handler */ -void (*rmnet_perf_skb_entry)(struct sk_buff *skb, - struct rmnet_port *port) __rcu __read_mostly; -EXPORT_SYMBOL(rmnet_perf_skb_entry); - /* Shs hook handler */ int (*rmnet_shs_skb_entry)(struct sk_buff *skb, struct rmnet_port *port) __rcu __read_mostly; @@ -106,8 +102,6 @@ EXPORT_SYMBOL(rmnet_shs_skb_entry_wq); void rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) { - void (*rmnet_perf_ingress)(struct sk_buff *skb, - struct rmnet_port *port); int (*rmnet_shs_stamp)(struct sk_buff *skb, struct rmnet_port *port); struct rmnet_priv *priv = netdev_priv(skb->dev); @@ -121,13 +115,6 @@ rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) skb_set_mac_header(skb, 0); rcu_read_lock(); - rmnet_perf_ingress = rcu_dereference(rmnet_perf_skb_entry); - if (rmnet_perf_ingress) { - rmnet_perf_ingress(skb, port); - rcu_read_unlock(); - return; - } - rmnet_shs_stamp = rcu_dereference(rmnet_shs_skb_entry); if (rmnet_shs_stamp) { rmnet_shs_stamp(skb, port); @@ -302,10 +289,6 @@ int (*rmnet_perf_deag_entry)(struct sk_buff *skb, struct rmnet_port *port) __rcu __read_mostly; EXPORT_SYMBOL(rmnet_perf_deag_entry); -/* Notify perf at the end of SKB chain */ -void (*rmnet_perf_chain_end)(void) __rcu __read_mostly; -EXPORT_SYMBOL(rmnet_perf_chain_end); - static void rmnet_map_ingress_handler(struct sk_buff *skb, struct rmnet_port *port) @@ -313,7 +296,6 @@ rmnet_map_ingress_handler(struct sk_buff *skb, struct sk_buff *skbn; int (*rmnet_perf_core_deaggregate)(struct sk_buff *skb, struct rmnet_port *port); - void (*rmnet_perf_opt_chain_end)(void); if (skb->dev->type == ARPHRD_ETHER) { if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_KERNEL)) { @@ -324,6 +306,14 @@ rmnet_map_ingress_handler(struct sk_buff *skb, skb_push(skb, ETH_HLEN); } + if (port->data_format & (RMNET_FLAGS_INGRESS_COALESCE | + RMNET_FLAGS_INGRESS_MAP_CKSUMV5)) { + if (skb_is_nonlinear(skb)) { + rmnet_frag_ingress_handler(skb, port); + return; + } + } + /* No aggregation. Pass the frame on as is */ if (!(port->data_format & RMNET_FLAGS_INGRESS_DEAGGREGATION)) { __rmnet_map_ingress_handler(skb, port); @@ -358,12 +348,6 @@ rmnet_map_ingress_handler(struct sk_buff *skb, next_skb: skb = skb_frag; } - - rcu_read_lock(); - rmnet_perf_opt_chain_end = rcu_dereference(rmnet_perf_chain_end); - if (rmnet_perf_opt_chain_end) - rmnet_perf_opt_chain_end(); - rcu_read_unlock(); } static int rmnet_map_egress_handler(struct sk_buff *skb, @@ -403,19 +387,9 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, map_header->mux_id = mux_id; if (port->data_format & RMNET_EGRESS_FORMAT_AGGREGATION) { - int non_linear_skb; - if (rmnet_map_tx_agg_skip(skb, required_headroom)) goto done; - non_linear_skb = (orig_dev->features & NETIF_F_GSO) && - skb_is_nonlinear(skb); - - if (non_linear_skb) { - if (unlikely(__skb_linearize(skb))) - goto done; - } - rmnet_map_tx_aggregate(skb, port); return -EINPROGRESS; } diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h index b5b1cfaf913560073e999b8b65b4d7563853bffc..354b2097b85b62fe1257188ce78b89509a278119 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -122,15 +122,17 @@ struct rmnet_map_dl_csum_trailer { struct rmnet_map_ul_csum_header { __be16 csum_start_offset; u16 csum_insert_offset:14; - u16 udp_ip4_ind:1; + u16 udp_ind:1; u16 csum_enabled:1; } __aligned(1); struct rmnet_map_control_command_header { - u8 command_name; - u8 cmd_type:2; - u8 reserved:6; - u16 reserved2; + u8 command_name; + u8 cmd_type:2; + u8 reserved:5; + u8 e:1; + u16 source_id:15; + u16 ext:1; u32 transaction_id; } __aligned(1); @@ -176,8 +178,18 @@ struct rmnet_map_dl_ind_trl { struct rmnet_map_dl_ind { u8 priority; - void (*dl_hdr_handler)(struct rmnet_map_dl_ind_hdr *); - void (*dl_trl_handler)(struct rmnet_map_dl_ind_trl *); + union { + void (*dl_hdr_handler)(struct rmnet_map_dl_ind_hdr *); + void (*dl_hdr_handler_v2)(struct rmnet_map_dl_ind_hdr *, + struct + rmnet_map_control_command_header *); + } __aligned(1); + union { + void (*dl_trl_handler)(struct rmnet_map_dl_ind_trl *); + void (*dl_trl_handler_v2)(struct rmnet_map_dl_ind_trl *, + struct + rmnet_map_control_command_header *); + } __aligned(1); struct list_head list; }; @@ -248,6 +260,7 @@ int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len); void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, struct net_device *orig_dev, int csum_type); +bool rmnet_map_v5_csum_buggy(struct rmnet_map_v5_coal_header *coal_hdr); int rmnet_map_process_next_hdr_packet(struct sk_buff *skb, struct sk_buff_head *list, u16 len); @@ -255,6 +268,16 @@ int rmnet_map_tx_agg_skip(struct sk_buff *skb, int offset); void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port); void rmnet_map_tx_aggregate_init(struct rmnet_port *port); void rmnet_map_tx_aggregate_exit(struct rmnet_port *port); +void rmnet_map_dl_hdr_notify(struct rmnet_port *port, + struct rmnet_map_dl_ind_hdr *dl_hdr); +void rmnet_map_dl_hdr_notify_v2(struct rmnet_port *port, + struct rmnet_map_dl_ind_hdr *dl_hdr, + struct rmnet_map_control_command_header *qcmd); +void rmnet_map_dl_trl_notify(struct rmnet_port *port, + struct rmnet_map_dl_ind_trl *dltrl); +void rmnet_map_dl_trl_notify_v2(struct rmnet_port *port, + struct rmnet_map_dl_ind_trl *dltrl, + struct rmnet_map_control_command_header *qcmd); int rmnet_map_flow_command(struct sk_buff *skb, struct rmnet_port *port, bool rmnet_perf); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c index 67a4e1ca508c6237d4ae3726b45be0bfb0b11f0c..158f6918e4d753cf8b0b9f702c56eef2c688cbc4 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -96,8 +96,22 @@ static void rmnet_map_send_ack(struct sk_buff *skb, netif_tx_unlock(dev); } -static void rmnet_map_dl_hdr_notify(struct rmnet_port *port, - struct rmnet_map_dl_ind_hdr *dlhdr) +void +rmnet_map_dl_hdr_notify_v2(struct rmnet_port *port, + struct rmnet_map_dl_ind_hdr *dlhdr, + struct rmnet_map_control_command_header *qcmd) +{ + struct rmnet_map_dl_ind *tmp; + + port->dl_marker_flush = 0; + + list_for_each_entry(tmp, &port->dl_list, list) + tmp->dl_hdr_handler_v2(dlhdr, qcmd); +} + +void +rmnet_map_dl_hdr_notify(struct rmnet_port *port, + struct rmnet_map_dl_ind_hdr *dlhdr) { struct rmnet_map_dl_ind *tmp; @@ -107,8 +121,28 @@ static void rmnet_map_dl_hdr_notify(struct rmnet_port *port, tmp->dl_hdr_handler(dlhdr); } -static void rmnet_map_dl_trl_notify(struct rmnet_port *port, - struct rmnet_map_dl_ind_trl *dltrl) +void +rmnet_map_dl_trl_notify_v2(struct rmnet_port *port, + struct rmnet_map_dl_ind_trl *dltrl, + struct rmnet_map_control_command_header *qcmd) +{ + struct rmnet_map_dl_ind *tmp; + struct napi_struct *napi; + + list_for_each_entry(tmp, &port->dl_list, list) + tmp->dl_trl_handler_v2(dltrl, qcmd); + + if (port->dl_marker_flush) { + napi = get_current_napi_context(); + napi_gro_flush(napi, false); + } + + port->dl_marker_flush = -1; +} + +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; @@ -129,11 +163,26 @@ static void rmnet_map_process_flow_start(struct sk_buff *skb, bool rmnet_perf) { struct rmnet_map_dl_ind_hdr *dlhdr; + struct rmnet_map_control_command_header *qcmd; + u32 data_format; + bool is_dl_mark_v2; if (skb->len < RMNET_DL_IND_HDR_SIZE) return; - pskb_pull(skb, RMNET_MAP_CMD_SIZE); + data_format = port->data_format; + is_dl_mark_v2 = data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2; + if (is_dl_mark_v2) { + pskb_pull(skb, sizeof(struct rmnet_map_header)); + qcmd = (struct rmnet_map_control_command_header *) + rmnet_map_data_ptr(skb); + port->stats.dl_hdr_last_ep_id = qcmd->source_id; + port->stats.dl_hdr_last_qmap_vers = qcmd->reserved; + port->stats.dl_hdr_last_trans_id = qcmd->transaction_id; + pskb_pull(skb, sizeof(struct rmnet_map_control_command_header)); + } else { + pskb_pull(skb, RMNET_MAP_CMD_SIZE); + } dlhdr = (struct rmnet_map_dl_ind_hdr *)rmnet_map_data_ptr(skb); @@ -145,44 +194,62 @@ static void rmnet_map_process_flow_start(struct sk_buff *skb, port->stats.dl_hdr_total_pkts += port->stats.dl_hdr_last_pkts; port->stats.dl_hdr_count++; - rmnet_map_dl_hdr_notify(port, dlhdr); + if (is_dl_mark_v2) + rmnet_map_dl_hdr_notify_v2(port, dlhdr, qcmd); + else + rmnet_map_dl_hdr_notify(port, dlhdr); + if (rmnet_perf) { unsigned int pull_size; pull_size = sizeof(struct rmnet_map_dl_ind_hdr); - if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) + if (data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) pull_size += sizeof(struct rmnet_map_dl_csum_trailer); pskb_pull(skb, pull_size); } - } static void rmnet_map_process_flow_end(struct sk_buff *skb, struct rmnet_port *port, - bool rmnet_perf) + bool rmnet_perf) { struct rmnet_map_dl_ind_trl *dltrl; + struct rmnet_map_control_command_header *qcmd; + u32 data_format; + bool is_dl_mark_v2; if (skb->len < RMNET_DL_IND_TRL_SIZE) return; - pskb_pull(skb, RMNET_MAP_CMD_SIZE); + data_format = port->data_format; + is_dl_mark_v2 = data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2; + if (is_dl_mark_v2) { + pskb_pull(skb, sizeof(struct rmnet_map_header)); + qcmd = (struct rmnet_map_control_command_header *) + rmnet_map_data_ptr(skb); + pskb_pull(skb, sizeof(struct rmnet_map_control_command_header)); + } else { + pskb_pull(skb, RMNET_MAP_CMD_SIZE); + } dltrl = (struct rmnet_map_dl_ind_trl *)rmnet_map_data_ptr(skb); port->stats.dl_trl_last_seq = dltrl->seq_le; port->stats.dl_trl_count++; - rmnet_map_dl_trl_notify(port, dltrl); + if (is_dl_mark_v2) + rmnet_map_dl_trl_notify_v2(port, dltrl, qcmd); + else + rmnet_map_dl_trl_notify(port, dltrl); + if (rmnet_perf) { unsigned int pull_size; pull_size = sizeof(struct rmnet_map_dl_ind_trl); - if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) + if (data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) pull_size += sizeof(struct rmnet_map_dl_csum_trailer); pskb_pull(skb, pull_size); } - } /* Process MAP command frame and send N/ACK message as appropriate. Message cmd diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index 3e1ed8c2549bb34a0c888d51b8af3102c3320ba4..daa33935a93613d6431c9cef3f7fa0c5f567ee0e 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -230,9 +230,9 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr, ul_header->csum_insert_offset = skb->csum_offset; ul_header->csum_enabled = 1; if (ip4h->protocol == IPPROTO_UDP) - ul_header->udp_ip4_ind = 1; + ul_header->udp_ind = 1; else - ul_header->udp_ip4_ind = 0; + ul_header->udp_ind = 0; /* Changing remaining fields to network order */ hdr++; @@ -263,6 +263,7 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr, struct rmnet_map_ul_csum_header *ul_header, struct sk_buff *skb) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr; __be16 *hdr = (__be16 *)ul_header, offset; offset = htons((__force u16)(skb_transport_header(skb) - @@ -270,7 +271,11 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr, ul_header->csum_start_offset = offset; ul_header->csum_insert_offset = skb->csum_offset; ul_header->csum_enabled = 1; - ul_header->udp_ip4_ind = 0; + + if (ip6h->nexthdr == IPPROTO_UDP) + ul_header->udp_ind = 1; + else + ul_header->udp_ind = 0; /* Changing remaining fields to network order */ hdr++; @@ -479,7 +484,7 @@ void rmnet_map_v4_checksum_uplink_packet(struct sk_buff *skb, ul_header->csum_start_offset = 0; ul_header->csum_insert_offset = 0; ul_header->csum_enabled = 0; - ul_header->udp_ip4_ind = 0; + ul_header->udp_ind = 0; priv->stats.csum_sw++; } @@ -550,6 +555,29 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, } } +bool rmnet_map_v5_csum_buggy(struct rmnet_map_v5_coal_header *coal_hdr) +{ + /* Only applies to frames with a single packet */ + if (coal_hdr->num_nlos != 1 || coal_hdr->nl_pairs[0].num_packets != 1) + return false; + + /* TCP header has FIN or PUSH set */ + if (coal_hdr->close_type == RMNET_MAP_COAL_CLOSE_COAL) + return true; + + /* Hit packet limit, byte limit, or time limit/EOF on DMA */ + if (coal_hdr->close_type == RMNET_MAP_COAL_CLOSE_HW) { + switch (coal_hdr->close_value) { + case RMNET_MAP_COAL_CLOSE_HW_PKT: + case RMNET_MAP_COAL_CLOSE_HW_BYTE: + case RMNET_MAP_COAL_CLOSE_HW_TIME: + return true; + } + } + + return false; +} + static void rmnet_map_move_headers(struct sk_buff *skb) { struct iphdr *iph; @@ -636,30 +664,32 @@ static void rmnet_map_gso_stamp(struct sk_buff *skb, struct rmnet_map_coal_metadata *coal_meta) { struct skb_shared_info *shinfo = skb_shinfo(skb); - struct iphdr *iph = ip_hdr(skb); + unsigned char *data = skb->data; __sum16 pseudo; u16 pkt_len = skb->len - coal_meta->ip_len; bool ipv4 = coal_meta->ip_proto == 4; if (ipv4) { + struct iphdr *iph = (struct iphdr *)data; + pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr, pkt_len, coal_meta->trans_proto, 0); } else { - struct ipv6hdr *ip6h = ipv6_hdr(skb); + struct ipv6hdr *ip6h = (struct ipv6hdr *)data; pseudo = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, pkt_len, coal_meta->trans_proto, 0); } if (coal_meta->trans_proto == IPPROTO_TCP) { - struct tcphdr *tp = tcp_hdr(skb); + struct tcphdr *tp = (struct tcphdr *)(data + coal_meta->ip_len); tp->check = pseudo; shinfo->gso_type = (ipv4) ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6; skb->csum_offset = offsetof(struct tcphdr, check); } else { - struct udphdr *up = udp_hdr(skb); + struct udphdr *up = (struct udphdr *)(data + coal_meta->ip_len); up->check = pseudo; shinfo->gso_type = SKB_GSO_UDP_L4; @@ -667,7 +697,7 @@ static void rmnet_map_gso_stamp(struct sk_buff *skb, } skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_start = skb->data + coal_meta->ip_len - skb->head; shinfo->gso_size = coal_meta->data_len; shinfo->gso_segs = coal_meta->pkt_count; } @@ -675,10 +705,12 @@ static void rmnet_map_gso_stamp(struct sk_buff *skb, static void __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb, struct rmnet_map_coal_metadata *coal_meta, - struct sk_buff_head *list, u8 pkt_id) + struct sk_buff_head *list, u8 pkt_id, + bool csum_valid) { struct sk_buff *skbn; struct rmnet_priv *priv = netdev_priv(coal_skb->dev); + __sum16 *check = NULL; u32 alloc_len; /* We can avoid copying the data if the SKB we got from the lower-level @@ -705,8 +737,12 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb, struct tcphdr *th = tcp_hdr(skbn); th->seq = htonl(ntohl(th->seq) + coal_meta->data_offset); + check = &th->check; } else if (coal_meta->trans_proto == IPPROTO_UDP) { - udp_hdr(skbn)->len = htons(skbn->len); + struct udphdr *uh = udp_hdr(skbn); + + uh->len = htons(skbn->len); + check = &uh->check; } /* Push IP header and update necessary fields */ @@ -726,7 +762,44 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb, sizeof(struct ipv6hdr)); } - skbn->ip_summed = CHECKSUM_UNNECESSARY; + /* Handle checksum status */ + if (likely(csum_valid)) { + skbn->ip_summed = CHECKSUM_UNNECESSARY; + } else if (check) { + /* Unfortunately, we have to fake a bad checksum here, since + * the original bad value is lost by the hardware. The only + * reliable way to do it is to calculate the actual checksum + * and corrupt it. + */ + __wsum csum; + unsigned int offset = skb_transport_offset(skbn); + __sum16 pseudo; + + /* Calculate pseudo header */ + if (coal_meta->ip_proto == 4) { + struct iphdr *iph = ip_hdr(skbn); + + pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + skbn->len - + coal_meta->ip_len, + coal_meta->trans_proto, 0); + } else { + struct ipv6hdr *ip6h = ipv6_hdr(skbn); + + pseudo = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + skbn->len - coal_meta->ip_len, + coal_meta->trans_proto, 0); + } + + *check = pseudo; + csum = skb_checksum(skbn, offset, skbn->len - offset, 0); + /* Add 1 to corrupt. This cannot produce a final value of 0 + * since csum_fold() can't return a value of 0xFFFF. + */ + *check = csum16_add(csum_fold(csum), htons(1)); + skbn->ip_summed = CHECKSUM_NONE; + } + skbn->dev = coal_skb->dev; priv->stats.coal.coal_reconstruct++; @@ -742,6 +815,34 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb, coal_meta->pkt_count = 0; } +static bool rmnet_map_validate_csum(struct sk_buff *skb, + struct rmnet_map_coal_metadata *meta) +{ + u8 *data = rmnet_map_data_ptr(skb); + unsigned int datagram_len; + __wsum csum; + __sum16 pseudo; + + datagram_len = skb->len - meta->ip_len; + if (meta->ip_proto == 4) { + struct iphdr *iph = (struct iphdr *)data; + + pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + datagram_len, + meta->trans_proto, 0); + } else { + struct ipv6hdr *ip6h = (struct ipv6hdr *)data; + + pseudo = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + datagram_len, meta->trans_proto, + 0); + } + + csum = skb_checksum(skb, meta->ip_len, datagram_len, + csum_unfold(pseudo)); + return !csum_fold(csum); +} + /* Converts the coalesced SKB into a list of SKBs. * NLOs containing csum erros will not be included. * The original coalesced SKB should be treated as invalid and @@ -825,38 +926,75 @@ static void rmnet_map_segment_coal_skb(struct sk_buff *coal_skb, return; } + if (rmnet_map_v5_csum_buggy(coal_hdr)) { + rmnet_map_move_headers(coal_skb); + /* Mark as valid if it checks out */ + if (rmnet_map_validate_csum(coal_skb, &coal_meta)) + coal_skb->ip_summed = CHECKSUM_UNNECESSARY; + + __skb_queue_tail(list, coal_skb); + return; + } + + /* Fast-forward the case where we have 1 NLO (i.e. 1 packet length), + * no checksum errors, and are allowing GRO. We can just reuse this + * SKB unchanged. + */ + if (gro && coal_hdr->num_nlos == 1 && coal_hdr->csum_valid) { + rmnet_map_move_headers(coal_skb); + coal_skb->ip_summed = CHECKSUM_UNNECESSARY; + coal_meta.data_len = ntohs(coal_hdr->nl_pairs[0].pkt_len); + coal_meta.data_len -= coal_meta.ip_len + coal_meta.trans_len; + coal_meta.pkt_count = coal_hdr->nl_pairs[0].num_packets; + if (coal_meta.pkt_count > 1) + rmnet_map_gso_stamp(coal_skb, &coal_meta); + + __skb_queue_tail(list, coal_skb); + return; + } + + /* Segment the coalesced SKB into new packets */ for (nlo = 0; nlo < coal_hdr->num_nlos; nlo++) { pkt_len = ntohs(coal_hdr->nl_pairs[nlo].pkt_len); pkt_len -= coal_meta.ip_len + coal_meta.trans_len; coal_meta.data_len = pkt_len; for (pkt = 0; pkt < coal_hdr->nl_pairs[nlo].num_packets; - pkt++, total_pkt++) { - nlo_err_mask <<= 1; - if (nlo_err_mask & (1ULL << 63)) { + pkt++, total_pkt++, nlo_err_mask >>= 1) { + bool csum_err = nlo_err_mask & 1; + + /* Segment the packet if we're not sending the larger + * packet up the stack. + */ + if (!gro) { + coal_meta.pkt_count = 1; + if (csum_err) + priv->stats.coal.coal_csum_err++; + + __rmnet_map_segment_coal_skb(coal_skb, + &coal_meta, list, + total_pkt, + !csum_err); + continue; + } + + if (csum_err) { priv->stats.coal.coal_csum_err++; /* Segment out the good data */ - if (gro && coal_meta.pkt_count) { + if (gro && coal_meta.pkt_count) __rmnet_map_segment_coal_skb(coal_skb, &coal_meta, list, - total_pkt); - } - - /* skip over bad packet */ - coal_meta.data_offset += pkt_len; - coal_meta.pkt_id = total_pkt + 1; + total_pkt, + true); + + /* Segment out the bad checksum */ + coal_meta.pkt_count = 1; + __rmnet_map_segment_coal_skb(coal_skb, + &coal_meta, list, + total_pkt, false); } else { coal_meta.pkt_count++; - - /* Segment the packet if we aren't sending the - * larger packet up the stack. - */ - if (!gro) - __rmnet_map_segment_coal_skb(coal_skb, - &coal_meta, - list, - total_pkt); } } @@ -864,27 +1002,9 @@ static void rmnet_map_segment_coal_skb(struct sk_buff *coal_skb, * the previous one, if we haven't done so. NLOs only switch * when the packet length changes. */ - if (gro && coal_meta.pkt_count) { - /* Fast forward the (hopefully) common case. - * Frames with only one NLO (i.e. one packet length) and - * no checksum errors don't need to be segmented here. - * We can just pass off the original skb. - */ - if (pkt_len * coal_meta.pkt_count == - coal_skb->len - coal_meta.ip_len - - coal_meta.trans_len) { - rmnet_map_move_headers(coal_skb); - coal_skb->ip_summed = CHECKSUM_UNNECESSARY; - if (coal_meta.pkt_count > 1) - rmnet_map_gso_stamp(coal_skb, - &coal_meta); - __skb_queue_tail(list, coal_skb); - return; - } - + if (coal_meta.pkt_count) __rmnet_map_segment_coal_skb(coal_skb, &coal_meta, list, - total_pkt); - } + total_pkt, true); } } @@ -964,7 +1084,7 @@ static int rmnet_map_data_check_coal_header(struct sk_buff *skb, u8 err = coal_hdr->nl_pairs[i].csum_error_bitmap; u8 pkt = coal_hdr->nl_pairs[i].num_packets; - mask |= ((u64)err) << (7 - i) * 8; + mask |= ((u64)err) << (8 * i); /* Track total packets in frame */ pkts += pkt; @@ -1105,13 +1225,45 @@ enum hrtimer_restart rmnet_map_flush_tx_packet_queue(struct hrtimer *t) return HRTIMER_NORESTART; } +static void rmnet_map_linearize_copy(struct sk_buff *dst, struct sk_buff *src) +{ + unsigned int linear = src->len - src->data_len, target = src->len; + unsigned char *src_buf; + struct sk_buff *skb; + + src_buf = src->data; + skb_put_data(dst, src_buf, linear); + target -= linear; + + skb = src; + + while (target) { + unsigned int i = 0, non_linear = 0; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + non_linear = skb_frag_size(&skb_shinfo(skb)->frags[i]); + src_buf = skb_frag_address(&skb_shinfo(skb)->frags[i]); + + skb_put_data(dst, src_buf, non_linear); + target -= non_linear; + } + + if (skb_shinfo(skb)->frag_list) { + skb = skb_shinfo(skb)->frag_list; + continue; + } + + if (skb->next) + skb = skb->next; + } +} + void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) { struct timespec diff, last; int size, agg_count = 0; struct sk_buff *agg_skb; unsigned long flags; - u8 *dest_buff; new_packet: spin_lock_irqsave(&port->agg_lock, flags); @@ -1133,7 +1285,8 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) return; } - port->agg_skb = skb_copy_expand(skb, 0, size, GFP_ATOMIC); + port->agg_skb = alloc_skb(port->egress_agg_params.agg_size, + GFP_ATOMIC); if (!port->agg_skb) { port->agg_skb = 0; port->agg_count = 0; @@ -1143,6 +1296,8 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) dev_queue_xmit(skb); return; } + rmnet_map_linearize_copy(port->agg_skb, skb); + port->agg_skb->dev = skb->dev; port->agg_skb->protocol = htons(ETH_P_MAP); port->agg_count = 1; getnstimeofday(&port->agg_time); @@ -1167,8 +1322,7 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) goto new_packet; } - dest_buff = skb_put(port->agg_skb, skb->len); - memcpy(dest_buff, skb->data, skb->len); + rmnet_map_linearize_copy(port->agg_skb, skb); port->agg_count++; dev_kfree_skb_any(skb); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h index 009954a74f88f7f654dff64049910e8410547643..70ab2137bc192e6bc2183ae96a3269e6ed893762 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,8 +20,11 @@ /* Constants */ #define RMNET_EGRESS_FORMAT_AGGREGATION BIT(31) -#define RMNET_INGRESS_FORMAT_DL_MARKER BIT(30) -#define RMNET_INGRESS_FORMAT_RPS_STAMP BIG(29) +#define RMNET_INGRESS_FORMAT_DL_MARKER_V1 BIT(30) +#define RMNET_INGRESS_FORMAT_DL_MARKER_V2 BIT(29) + +#define RMNET_INGRESS_FORMAT_DL_MARKER (RMNET_INGRESS_FORMAT_DL_MARKER_V1 |\ +RMNET_INGRESS_FORMAT_DL_MARKER_V2) /* Power save feature*/ #define RMNET_INGRESS_FORMAT_PS BIT(27) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index ed4152927545452eb71afda9cbc7a4d06bf3972b..cd857726e19324b263578413db95d29b1116892f 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -224,6 +224,9 @@ static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = { }; static const char rmnet_port_gstrings_stats[][ETH_GSTRING_LEN] = { + "MAP Cmd last version", + "MAP Cmd last ep id", + "MAP Cmd last transaction id", "DL header last seen sequence", "DL header last seen bytes", "DL header last seen packets", diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index acd65a4f94d4fa6a01db4f29d61a837be257b361..f2150efddc88752a3ea705892b58254d8aa8acca 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -201,6 +201,11 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x, if (unlikely(rdes0 & RDES0_OWN)) return dma_own; + if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { + stats->rx_length_errors++; + return discard_frame; + } + if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) { if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) { x->rx_desc++; @@ -231,9 +236,10 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x, * It doesn't match with the information reported into the databook. * At any rate, we need to understand if the CSUM hw computation is ok * and report this info to the upper layers. */ - ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR), - !!(rdes0 & RDES0_FRAME_TYPE), - !!(rdes0 & ERDES0_RX_MAC_ADDR)); + if (likely(ret == good_frame)) + ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR), + !!(rdes0 & RDES0_FRAME_TYPE), + !!(rdes0 & ERDES0_RX_MAC_ADDR)); if (unlikely(rdes0 & RDES0_DRIBBLING)) x->dribbling_bit++; diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c index db4cee57bb2465eb98fe38cb947624e779da4673..66c17bab5997dd2086243d214c16ab1517805598 100644 --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c @@ -91,8 +91,6 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, return dma_own; if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { - pr_warn("%s: Oversized frame spanned multiple buffers\n", - __func__); stats->rx_length_errors++; return discard_frame; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 4a9dbee6f0546e884a9b50c5af67656f42a29ea3..0f85e540001fff41a2d9990215a2917254ef9d85 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2536,9 +2536,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) netdev_warn(priv->dev, "%s: failed debugFS registration\n", __func__); #endif - /* Start the ball rolling... */ - stmmac_start_all_dma(priv); - priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) { @@ -2558,6 +2555,9 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) priv->hw->dma->enable_tso(priv->ioaddr, 1, chan); } + /* Start the ball rolling... */ + stmmac_start_all_dma(priv); + return 0; } @@ -2582,8 +2582,6 @@ static int stmmac_open(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); int ret; - stmmac_check_ether_addr(priv); - if (priv->hw->pcs != STMMAC_PCS_RGMII && priv->hw->pcs != STMMAC_PCS_TBI && priv->hw->pcs != STMMAC_PCS_RTBI) { @@ -3415,9 +3413,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) * ignored */ if (frame_len > priv->dma_buf_sz) { - netdev_err(priv->dev, - "len %d larger than size (%d)\n", - frame_len, priv->dma_buf_sz); + if (net_ratelimit()) + netdev_err(priv->dev, + "len %d larger than size (%d)\n", + frame_len, priv->dma_buf_sz); priv->dev->stats.rx_length_errors++; break; } @@ -3475,9 +3474,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) } else { skb = rx_q->rx_skbuff[entry]; if (unlikely(!skb)) { - netdev_err(priv->dev, - "%s: Inconsistent Rx chain\n", - priv->dev->name); + if (net_ratelimit()) + netdev_err(priv->dev, + "%s: Inconsistent Rx chain\n", + priv->dev->name); priv->dev->stats.rx_dropped++; break; } @@ -4213,6 +4213,8 @@ int stmmac_dvr_probe(struct device *device, if (ret) goto error_hw_init; + stmmac_check_ether_addr(priv); + /* Configure real RX and TX queues */ netif_set_real_num_rx_queues(ndev, priv->plat->rx_queues_to_use); netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index d819e8eaba1225dc5e9b188e42636721cc66a4c0..cc1e887e47b50f31bba7a53e8f146d9ac7fb4fa7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -159,6 +159,12 @@ static const struct dmi_system_id quark_pci_dmi[] = { }, .driver_data = (void *)&galileo_stmmac_dmi_data, }, + /* + * There are 2 types of SIMATIC IOT2000: IOT20202 and IOT2040. + * The asset tag "6ES7647-0AA00-0YA2" is only for IOT2020 which + * has only one pci network device while other asset tags are + * for IOT2040 which has two. + */ { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), @@ -170,8 +176,6 @@ static const struct dmi_system_id quark_pci_dmi[] = { { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), - DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, - "6ES7647-0AA00-1YA2"), }, .driver_data = (void *)&iot2040_stmmac_dmi_data, }, diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 28cb38af1a348799687149e07084cd55cf4aa1a9..ff7a71ca0b134a1f51b7175879966750509147bd 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -3538,12 +3538,16 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device, gbe_dev->dma_chan_name, gbe_dev->tx_queue_id); - if (ret) + if (ret) { + of_node_put(interfaces); return ret; + } ret = netcp_txpipe_open(&gbe_dev->tx_pipe); - if (ret) + if (ret) { + of_node_put(interfaces); return ret; + } /* Create network interfaces */ INIT_LIST_HEAD(&gbe_dev->gbe_intf_head); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index e74e1e897864181dbaca5ed8cd57c162d1baf89e..d46dc8cd167047ad0d7d32f0d01a1451ebd75b17 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1575,12 +1575,14 @@ static int axienet_probe(struct platform_device *pdev) ret = of_address_to_resource(np, 0, &dmares); if (ret) { dev_err(&pdev->dev, "unable to get DMA resource\n"); + of_node_put(np); goto free_netdev; } lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares); if (IS_ERR(lp->dma_regs)) { dev_err(&pdev->dev, "could not map DMA regs\n"); ret = PTR_ERR(lp->dma_regs); + of_node_put(np); goto free_netdev; } lp->rx_irq = irq_of_parse_and_map(np, 1); diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index e33a6c672a0a4357e565fa5e1f1b5d12e28d0088..0f07b5978fa1afd99348de486caaf985ce6ae1dc 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -779,6 +779,7 @@ struct netvsc_device { wait_queue_head_t wait_drain; bool destroy; + bool tx_disable; /* if true, do not wake up queue again */ /* Receive buffer allocated by us but manages by NetVSP */ void *recv_buf; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 806239b89990d31820d54faa98d8e6e892e53437..a3bb4d5c64f5ac555533cfceefcf8b3cf3bd366d 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -107,6 +107,7 @@ static struct netvsc_device *alloc_net_device(void) init_waitqueue_head(&net_device->wait_drain); net_device->destroy = false; + net_device->tx_disable = false; atomic_set(&net_device->open_cnt, 0); net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT; net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT; @@ -712,7 +713,7 @@ static void netvsc_send_tx_complete(struct netvsc_device *net_device, } else { struct netdev_queue *txq = netdev_get_tx_queue(ndev, q_idx); - if (netif_tx_queue_stopped(txq) && + if (netif_tx_queue_stopped(txq) && !net_device->tx_disable && (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER || queue_sends < 1)) { netif_tx_wake_queue(txq); @@ -865,7 +866,8 @@ static inline int netvsc_send_pkt( netif_tx_stop_queue(txq); } else if (ret == -EAGAIN) { netif_tx_stop_queue(txq); - if (atomic_read(&nvchan->queue_sends) < 1) { + if (atomic_read(&nvchan->queue_sends) < 1 && + !net_device->tx_disable) { netif_tx_wake_queue(txq); ret = -ENOSPC; } diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 74b9e51b2b47059f405645a74a141f3487c5a98a..eb92720dd1c4acfd3b7deb7a2855567e8c883e61 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -108,6 +108,15 @@ static void netvsc_set_rx_mode(struct net_device *net) rcu_read_unlock(); } +static void netvsc_tx_enable(struct netvsc_device *nvscdev, + struct net_device *ndev) +{ + nvscdev->tx_disable = false; + virt_wmb(); /* ensure queue wake up mechanism is on */ + + netif_tx_wake_all_queues(ndev); +} + static int netvsc_open(struct net_device *net) { struct net_device_context *ndev_ctx = netdev_priv(net); @@ -128,7 +137,7 @@ static int netvsc_open(struct net_device *net) rdev = nvdev->extension; if (!rdev->link_state) { netif_carrier_on(net); - netif_tx_wake_all_queues(net); + netvsc_tx_enable(nvdev, net); } if (vf_netdev) { @@ -183,6 +192,17 @@ static int netvsc_wait_until_empty(struct netvsc_device *nvdev) } } +static void netvsc_tx_disable(struct netvsc_device *nvscdev, + struct net_device *ndev) +{ + if (nvscdev) { + nvscdev->tx_disable = true; + virt_wmb(); /* ensure txq will not wake up after stop */ + } + + netif_tx_disable(ndev); +} + static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); @@ -191,7 +211,7 @@ static int netvsc_close(struct net_device *net) struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); int ret; - netif_tx_disable(net); + netvsc_tx_disable(nvdev, net); /* No need to close rndis filter if it is removed already */ if (!nvdev) @@ -893,7 +913,7 @@ static int netvsc_detach(struct net_device *ndev, /* If device was up (receiving) then shutdown */ if (netif_running(ndev)) { - netif_tx_disable(ndev); + netvsc_tx_disable(nvdev, ndev); ret = rndis_filter_close(nvdev); if (ret) { @@ -1720,7 +1740,7 @@ static void netvsc_link_change(struct work_struct *w) if (rdev->link_state) { rdev->link_state = false; netif_carrier_on(net); - netif_tx_wake_all_queues(net); + netvsc_tx_enable(net_device, net); } else { notify = true; } @@ -1730,7 +1750,7 @@ static void netvsc_link_change(struct work_struct *w) if (!rdev->link_state) { rdev->link_state = true; netif_carrier_off(net); - netif_tx_stop_all_queues(net); + netvsc_tx_disable(net_device, net); } kfree(event); break; @@ -1739,7 +1759,7 @@ static void netvsc_link_change(struct work_struct *w) if (!rdev->link_state) { rdev->link_state = true; netif_carrier_off(net); - netif_tx_stop_all_queues(net); + netvsc_tx_disable(net_device, net); event->event = RNDIS_STATUS_MEDIA_CONNECT; spin_lock_irqsave(&ndev_ctx->lock, flags); list_add(&event->list, &ndev_ctx->reconfig_events); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e9e67c22c8bb41f250f01d55e97b99a52bd19c25..727b991312a4e435accc4cbc59f542ee4189e9c0 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1497,9 +1497,10 @@ static int marvell_get_sset_count(struct phy_device *phydev) static void marvell_get_strings(struct phy_device *phydev, u8 *data) { + int count = marvell_get_sset_count(phydev); int i; - for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { + for (i = 0; i < count; i++) { memcpy(data + i * ETH_GSTRING_LEN, marvell_hw_stats[i].string, ETH_GSTRING_LEN); } @@ -1536,9 +1537,10 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) static void marvell_get_stats(struct phy_device *phydev, struct ethtool_stats *stats, u64 *data) { + int count = marvell_get_sset_count(phydev); int i; - for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) + for (i = 0; i < count; i++) data[i] = marvell_get_stat(phydev, i); } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2fa2bd56edfa247b3294fa66b3db454d738d07e1..a44b004086b78a4e1d331b43484161486359061e 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -926,8 +926,6 @@ static int ksz9031_suspend(struct phy_device *phydev) int wol_enabled; u32 reg_value; - mutex_lock(&phydev->lock); - reg_value = ksz9031_extended_read( phydev, OP_DATA, 0x2, MII_KSZPHY_OMSO_REG); wol_enabled = reg_value & MII_KSZPHY_OMSO_PME_N2; @@ -939,7 +937,6 @@ static int ksz9031_suspend(struct phy_device *phydev) value |= BMCR_PDOWN; phy_write(phydev, MII_BMCR, value); - mutex_unlock(&phydev->lock); return 0; } @@ -948,14 +945,10 @@ static int ksz9031_resume(struct phy_device *phydev) { int value; - mutex_lock(&phydev->lock); - value = phy_read(phydev, MII_BMCR); value &= ~(BMCR_PDOWN | BMCR_ISOLATE); phy_write(phydev, MII_BMCR, value); - mutex_unlock(&phydev->lock); - return 0; } diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index a1b68b19d9124e17dd7e1d9cf427fa009903ace3..5ab725a571a848727204a5e01e74e44da3462fd0 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -878,6 +878,10 @@ static int sfp_probe(struct platform_device *pdev) if (poll) mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); + sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); + if (!sfp->sfp_bus) + return -ENOMEM; + return 0; } @@ -887,10 +891,6 @@ static int sfp_remove(struct platform_device *pdev) sfp_unregister_socket(sfp->sfp_bus); - sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); - if (!sfp->sfp_bus) - return -ENOMEM; - return 0; } diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index f4e93f5fc2043ebb29c5b36e94afe49ec0c7d7ba..ea90db3c77058b6a799245bd5a3ff9f672b5da5e 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -153,7 +153,7 @@ slhc_init(int rslots, int tslots) void slhc_free(struct slcompress *comp) { - if ( comp == NULLSLCOMPR ) + if ( IS_ERR_OR_NULL(comp) ) return; if ( comp->tstate != NULLSLSTATE ) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index bb96153f496e0e161fb9aaff49310f8735b673f5..e9a92ed5a30819a6572dfe28fc914e2b1e1cb502 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1157,6 +1157,12 @@ static int team_port_add(struct team *team, struct net_device *port_dev) return -EINVAL; } + if (netdev_has_upper_dev(dev, port_dev)) { + netdev_err(dev, "Device %s is already an upper device of the team interface\n", + portname); + return -EBUSY; + } + if (port_dev->features & NETIF_F_VLAN_CHALLENGED && vlan_uses_dev(dev)) { netdev_err(dev, "Device %s is VLAN challenged and team device has VLAN set up\n", @@ -1245,6 +1251,23 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_option_port_add; } + /* set promiscuity level to new slave */ + if (dev->flags & IFF_PROMISC) { + err = dev_set_promiscuity(port_dev, 1); + if (err) + goto err_set_slave_promisc; + } + + /* set allmulti level to new slave */ + if (dev->flags & IFF_ALLMULTI) { + err = dev_set_allmulti(port_dev, 1); + if (err) { + if (dev->flags & IFF_PROMISC) + dev_set_promiscuity(port_dev, -1); + goto err_set_slave_promisc; + } + } + netif_addr_lock_bh(dev); dev_uc_sync_multiple(port_dev, dev); dev_mc_sync_multiple(port_dev, dev); @@ -1261,6 +1284,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev) return 0; +err_set_slave_promisc: + __team_option_inst_del_port(team, port); + err_option_port_add: team_upper_dev_unlink(team, port); @@ -1306,6 +1332,12 @@ static int team_port_del(struct team *team, struct net_device *port_dev) team_port_disable(team, port); list_del_rcu(&port->list); + + if (dev->flags & IFF_PROMISC) + dev_set_promiscuity(port_dev, -1); + if (dev->flags & IFF_ALLMULTI) + dev_set_allmulti(port_dev, -1); + team_upper_dev_unlink(team, port); netdev_rx_handler_unregister(port_dev); team_port_disable_netpoll(port); diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index aabbcfb6e6da93afe36861ff96c782f533252aa0..3d8a70d3ea9bd67c91f85c6cab38d1afbf5f25f3 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -148,6 +148,7 @@ struct ipheth_device { u8 bulk_in; u8 bulk_out; struct delayed_work carrier_work; + bool confirmed_pairing; }; static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); @@ -259,7 +260,7 @@ static void ipheth_rcvbulk_callback(struct urb *urb) dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += len; - + dev->confirmed_pairing = true; netif_rx(skb); ipheth_rx_submit(dev, GFP_ATOMIC); } @@ -280,14 +281,24 @@ static void ipheth_sndbulk_callback(struct urb *urb) dev_err(&dev->intf->dev, "%s: urb status: %d\n", __func__, status); - netif_wake_queue(dev->net); + if (status == 0) + netif_wake_queue(dev->net); + else + // on URB error, trigger immediate poll + schedule_delayed_work(&dev->carrier_work, 0); } static int ipheth_carrier_set(struct ipheth_device *dev) { - struct usb_device *udev = dev->udev; + struct usb_device *udev; int retval; + if (!dev) + return 0; + if (!dev->confirmed_pairing) + return 0; + + udev = dev->udev; retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), IPHETH_CMD_CARRIER_CHECK, /* request */ @@ -302,11 +313,14 @@ static int ipheth_carrier_set(struct ipheth_device *dev) return retval; } - if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) + if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) { netif_carrier_on(dev->net); - else + if (dev->tx_urb->status != -EINPROGRESS) + netif_wake_queue(dev->net); + } else { netif_carrier_off(dev->net); - + netif_stop_queue(dev->net); + } return 0; } @@ -386,7 +400,6 @@ static int ipheth_open(struct net_device *net) return retval; schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); - netif_start_queue(net); return retval; } @@ -489,7 +502,7 @@ static int ipheth_probe(struct usb_interface *intf, dev->udev = udev; dev->net = netdev; dev->intf = intf; - + dev->confirmed_pairing = false; /* Set up endpoints */ hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); if (hintf == NULL) { @@ -540,7 +553,9 @@ static int ipheth_probe(struct usb_interface *intf, retval = -EIO; goto err_register_netdev; } - + // carrier down and transmit queues stopped until packet from device + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n"); return 0; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 65e47cc52d14b6f45de21d92e69f43dc6af0c969..01abe8eea7538931790778152863c835d1c9b66a 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1188,6 +1188,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ {QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */ + {QMI_FIXED_INTF(0x2020, 0x2031, 4)}, /* Olicard 600 */ {QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 36144d4eefa021e06f1073e4997d019ff66f0370..a368a44232be444394813a4aa282ab702deabc34 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -136,6 +136,7 @@ config CLD_LL_CORE support. source "drivers/net/wireless/cnss2/Kconfig" +source "drivers/net/wireless/cnss/Kconfig" source "drivers/net/wireless/cnss_utils/Kconfig" source "drivers/net/wireless/cnss_genl/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 5386709a8b6347a22be553a4a34610458422b3e4..a199c9e037f6b552f2f2de1c6f9f5434fac1c398 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o obj-$(CONFIG_CNSS2) += cnss2/ +obj-$(CONFIG_CNSS) += cnss/ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ obj-$(CONFIG_CNSS_UTILS) += cnss_utils/ obj-$(CONFIG_CNSS_GENL) += cnss_genl/ diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..c18cea7be4910542e5d3693d086fe5143095f21f --- /dev/null +++ b/drivers/net/wireless/cnss/Kconfig @@ -0,0 +1,129 @@ +config CNSS + tristate "CNSS driver for wifi module" + select CNSS_UTILS + select CRYPTO + select CRYPTO_HASH + select CRYPTO_BLKCIPHER + ---help--- + This module adds support for the CNSS connectivity subsystem used + for wifi devices based on the QCA AR6320 chipset. + This driver also adds support to integrate WLAN module to subsystem + restart framework. + +config CNSS_SDIO + bool "Enable/disable cnss sdio platform driver for wifi module" + depends on CNSS + depends on MMC + ---help--- + This module adds support for the CNSS wlan module interfaced + with SDIO bus. + This driver also adds support to integrate WLAN module to subsystem + restart framework, power on WLAN chip and registered the WLAN module + as a SDIO client device. + +config CNSS_PCI + bool "Enable/disable cnss pci platform driver for wifi module" + depends on CNSS + depends on PCI + ---help--- + This module adds support for the CNSS wlan module interfaced + with PCIe bus. + This driver also adds support to integrate WLAN module to subsystem + restart framework, power on WLAN chip and registered the WLAN module + as a PCIe client device. + +config CNSS_ASYNC + bool "Enable/disable cnss pci platform driver asynchronous probe" + depends on CNSS_PCI + ---help--- + If enabled, CNSS PCI platform driver would do asynchronous probe. + Using asynchronous probe will allow CNSS PCI platform driver to + probe in parallel with other device drivers and will help to + reduce kernel boot time. + +config CNSS_MAC_BUG + bool "Enable/disable 0-4K memory initialization for QCA6174" + depends on CNSS + ---help--- + If enabled, 0-4K memory is reserved for QCA6174 to address + a MAC HW bug. MAC would do an invalid pointer fetch based on + the data, that was read from 0 to 4K. So fill it with zero's; + to an address for which PCIe root complex would honor the read + without any errors. + +config CLD_DEBUG + bool "Enable/disable CLD debug features" + help + WLAN CLD driver uses this config to enable certain debug features. + Some of the debug features may affect performance or may compromise + on security. + + Say N, if you are building a release kernel for production use. + Only say Y, if you are building a kernel with debug support. + +config CLD_USB_CORE + tristate "Qualcomm Technologies Inc. Core wlan driver for QCA USB interface" + select WIRELESS_EXT + select WEXT_PRIV + select WEXT_CORE + select WEXT_SPY + select NL80211_TESTMODE + ---help--- + This section contains the necessary modules needed to enable the + core WLAN driver for Qualcomm Technologies Inc USB wlan chipset. + Select Y to compile the driver in order to have WLAN functionality + support. + +config CLD_HL_SDIO_CORE + tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface" + select WIRELESS_EXT + select WEXT_PRIV + select WEXT_CORE + select WEXT_SPY + select NL80211_TESTMODE + depends on ARCH_QCOM + depends on MMC + +config CLD_LL_CORE + tristate "Qualcomm Technologies Inc. Core wlan driver" + select NL80211_TESTMODE + select WEXT_CORE + select WEXT_PRIV + select WEXT_SPY + select WIRELESS_EXT + ---help--- + This section contains the necessary modules needed to enable the + core WLAN driver for Qualcomm Technologies Inc QCA6174 chipset. + Select Y to compile the driver in order to have WLAN functionality + support. + +config CNSS_SECURE_FW + bool "Enable/Disable Memory Allocation for Secure Firmware Feature" + depends on CNSS + ---help--- + CLD Driver can use this for holding local copy of firmware + binaries which is used for sha crypto computation. + The Memory Allocation is done only if this Config Parameter is + enabled + +config BUS_AUTO_SUSPEND + bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers" + depends on CNSS + depends on PCI + ---help--- + Runtime Power Management is supported for PCIe based WLAN Drivers. + The features enable cld wlan driver to suspend pcie bus when APPS + is awake based on the driver inactivity with the Firmware. + The Feature uses runtime power management framework from kernel to + track bus access clients and to synchronize the driver activity + during system pm. + This config flag controls the feature per target based. The feature + requires CNSS driver support. + +source "drivers/net/wireless/cnss/logger/Kconfig" + +config WLAN_FEATURE_RX_WAKELOCK + bool "Enable RX wake lock feature" + help + Enable WLAN_FEATURE_HOLD_RX_WAKELOCK which is required to take rx + wakelock when driver receives packets from fw. diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..38ad5625ea006bf0178ce70bffa46f73b16acddd --- /dev/null +++ b/drivers/net/wireless/cnss/Makefile @@ -0,0 +1,6 @@ +# Makefile for CNSS platform driver + +obj-$(CONFIG_CNSS_PCI) += cnss_pci.o +obj-$(CONFIG_CNSS_SDIO) += cnss_sdio.o +obj-$(CONFIG_CNSS) += cnss_common.o +obj-$(CONFIG_CNSS_LOGGER) += logger/ diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c new file mode 100644 index 0000000000000000000000000000000000000000..c69597ba839c014b42e6b8e86b9321dbee5ff06e --- /dev/null +++ b/drivers/net/wireless/cnss/cnss_common.c @@ -0,0 +1,450 @@ +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * + * This 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 +#include +#include +#include "cnss_common.h" +#include + +#define AR6320_REV1_VERSION 0x5000000 +#define AR6320_REV1_1_VERSION 0x5000001 +#define AR6320_REV1_3_VERSION 0x5000003 +#define AR6320_REV2_1_VERSION 0x5010000 +#define AR6320_REV3_VERSION 0x5020000 +#define AR6320_REV3_2_VERSION 0x5030000 +#define AR900B_DEV_VERSION 0x1000000 +#define QCA9377_REV1_1_VERSION 0x5020001 + +static struct cnss_fw_files FW_FILES_QCA6174_FW_1_1 = { + "qwlan11.bin", "bdwlan11.bin", "otp11.bin", "utf11.bin", + "utfbd11.bin", "epping11.bin", "evicted11.bin"}; +static struct cnss_fw_files FW_FILES_QCA6174_FW_2_0 = { + "qwlan20.bin", "bdwlan20.bin", "otp20.bin", "utf20.bin", + "utfbd20.bin", "epping20.bin", "evicted20.bin"}; +static struct cnss_fw_files FW_FILES_QCA6174_FW_1_3 = { + "qwlan13.bin", "bdwlan13.bin", "otp13.bin", "utf13.bin", + "utfbd13.bin", "epping13.bin", "evicted13.bin"}; +static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = { + "qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin", + "utfbd30.bin", "epping30.bin", "evicted30.bin"}; +static struct cnss_fw_files FW_FILES_DEFAULT = { + "qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin", + "utfbd.bin", "epping.bin", "evicted.bin"}; + +enum cnss_dev_bus_type { + CNSS_BUS_NONE = -1, + CNSS_BUS_PCI, + CNSS_BUS_SDIO +}; + +static DEFINE_MUTEX(unsafe_channel_list_lock); +static DEFINE_MUTEX(dfs_nol_info_lock); + +static struct cnss_unsafe_channel_list { + u16 unsafe_ch_count; + u16 unsafe_ch_list[CNSS_MAX_CH_NUM]; +} unsafe_channel_list; + +static struct cnss_dfs_nol_info { + void *dfs_nol_info; + u16 dfs_nol_info_len; +} dfs_nol_info; + +static enum cnss_cc_src cnss_cc_source = CNSS_SOURCE_CORE; + +int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count) +{ + mutex_lock(&unsafe_channel_list_lock); + if (!unsafe_ch_list || ch_count > CNSS_MAX_CH_NUM) { + mutex_unlock(&unsafe_channel_list_lock); + return -EINVAL; + } + + unsafe_channel_list.unsafe_ch_count = ch_count; + + if (ch_count != 0) { + memcpy( + (char *)unsafe_channel_list.unsafe_ch_list, + (char *)unsafe_ch_list, ch_count * sizeof(u16)); + } + mutex_unlock(&unsafe_channel_list_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel); + +int cnss_get_wlan_unsafe_channel( + u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + mutex_lock(&unsafe_channel_list_lock); + if (!unsafe_ch_list || !ch_count) { + mutex_unlock(&unsafe_channel_list_lock); + return -EINVAL; + } + + if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) { + mutex_unlock(&unsafe_channel_list_lock); + return -ENOMEM; + } + + *ch_count = unsafe_channel_list.unsafe_ch_count; + memcpy( + (char *)unsafe_ch_list, + (char *)unsafe_channel_list.unsafe_ch_list, + unsafe_channel_list.unsafe_ch_count * sizeof(u16)); + mutex_unlock(&unsafe_channel_list_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel); + +int cnss_wlan_set_dfs_nol(const void *info, u16 info_len) +{ + void *temp; + struct cnss_dfs_nol_info *dfs_info; + + mutex_lock(&dfs_nol_info_lock); + if (!info || !info_len) { + mutex_unlock(&dfs_nol_info_lock); + return -EINVAL; + } + + temp = kmalloc(info_len, GFP_KERNEL); + if (!temp) { + mutex_unlock(&dfs_nol_info_lock); + return -ENOMEM; + } + + memcpy(temp, info, info_len); + dfs_info = &dfs_nol_info; + kfree(dfs_info->dfs_nol_info); + + dfs_info->dfs_nol_info = temp; + dfs_info->dfs_nol_info_len = info_len; + mutex_unlock(&dfs_nol_info_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_wlan_set_dfs_nol); + +int cnss_wlan_get_dfs_nol(void *info, u16 info_len) +{ + int len; + struct cnss_dfs_nol_info *dfs_info; + + mutex_lock(&dfs_nol_info_lock); + if (!info || !info_len) { + mutex_unlock(&dfs_nol_info_lock); + return -EINVAL; + } + + dfs_info = &dfs_nol_info; + + if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) { + mutex_unlock(&dfs_nol_info_lock); + return -ENOENT; + } + + len = min(info_len, dfs_info->dfs_nol_info_len); + + memcpy(info, dfs_info->dfs_nol_info, len); + mutex_unlock(&dfs_nol_info_lock); + + return len; +} +EXPORT_SYMBOL(cnss_wlan_get_dfs_nol); + +void cnss_init_work(struct work_struct *work, work_func_t func) +{ + INIT_WORK(work, func); +} +EXPORT_SYMBOL(cnss_init_work); + +void cnss_flush_work(void *work) +{ + struct work_struct *cnss_work = work; + + cancel_work_sync(cnss_work); +} +EXPORT_SYMBOL(cnss_flush_work); + +void cnss_flush_delayed_work(void *dwork) +{ + struct delayed_work *cnss_dwork = dwork; + + cancel_delayed_work_sync(cnss_dwork); +} +EXPORT_SYMBOL(cnss_flush_delayed_work); + +void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name) +{ + wakeup_source_init(ws, name); +} +EXPORT_SYMBOL(cnss_pm_wake_lock_init); + +void cnss_pm_wake_lock(struct wakeup_source *ws) +{ + __pm_stay_awake(ws); +} +EXPORT_SYMBOL(cnss_pm_wake_lock); + +void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec) +{ + __pm_wakeup_event(ws, msec); +} +EXPORT_SYMBOL(cnss_pm_wake_lock_timeout); + +void cnss_pm_wake_lock_release(struct wakeup_source *ws) +{ + __pm_relax(ws); +} +EXPORT_SYMBOL(cnss_pm_wake_lock_release); + +void cnss_pm_wake_lock_destroy(struct wakeup_source *ws) +{ + wakeup_source_trash(ws); +} +EXPORT_SYMBOL(cnss_pm_wake_lock_destroy); + +void cnss_get_monotonic_boottime(struct timespec *ts) +{ + get_monotonic_boottime(ts); +} +EXPORT_SYMBOL(cnss_get_monotonic_boottime); + +void cnss_get_boottime(struct timespec *ts) +{ + ktime_get_ts(ts); +} +EXPORT_SYMBOL(cnss_get_boottime); + +void cnss_init_delayed_work(struct delayed_work *work, work_func_t func) +{ + INIT_DELAYED_WORK(work, func); +} +EXPORT_SYMBOL(cnss_init_delayed_work); + +int cnss_vendor_cmd_reply(struct sk_buff *skb) +{ + return cfg80211_vendor_cmd_reply(skb); +} +EXPORT_SYMBOL(cnss_vendor_cmd_reply); + +int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu) +{ + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +} +EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr); + +/* wlan prop driver cannot invoke show_stack + * function directly, so to invoke this function it + * call wcnss_dump_stack function + */ +void cnss_dump_stack(struct task_struct *task) +{ + show_stack(task, NULL); +} +EXPORT_SYMBOL(cnss_dump_stack); + +struct cnss_dev_platform_ops *cnss_get_platform_ops(struct device *dev) +{ + if (!dev) + return NULL; + else + return dev->platform_data; +} + +int cnss_common_request_bus_bandwidth(struct device *dev, int bandwidth) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->request_bus_bandwidth) + return pf_ops->request_bus_bandwidth(bandwidth); + else + return -EINVAL; +} +EXPORT_SYMBOL(cnss_common_request_bus_bandwidth); + +void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long *size) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->get_virt_ramdump_mem) + return pf_ops->get_virt_ramdump_mem(size); + else + return NULL; +} +EXPORT_SYMBOL(cnss_common_get_virt_ramdump_mem); + +void cnss_common_device_self_recovery(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->device_self_recovery) + pf_ops->device_self_recovery(); +} +EXPORT_SYMBOL(cnss_common_device_self_recovery); + +void cnss_common_schedule_recovery_work(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->schedule_recovery_work) + pf_ops->schedule_recovery_work(); +} +EXPORT_SYMBOL(cnss_common_schedule_recovery_work); + +void cnss_common_device_crashed(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->device_crashed) + pf_ops->device_crashed(); +} +EXPORT_SYMBOL(cnss_common_device_crashed); + +u8 *cnss_common_get_wlan_mac_address(struct device *dev, u32 *num) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->get_wlan_mac_address) + return pf_ops->get_wlan_mac_address(num); + else + return NULL; +} +EXPORT_SYMBOL(cnss_common_get_wlan_mac_address); + +int cnss_common_set_wlan_mac_address( + struct device *dev, const u8 *in, u32 len) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->set_wlan_mac_address) + return pf_ops->set_wlan_mac_address(in, len); + else + return -EINVAL; +} +EXPORT_SYMBOL(cnss_common_set_wlan_mac_address); + +int cnss_power_up(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->power_up) + return pf_ops->power_up(dev); + else + return -EINVAL; +} +EXPORT_SYMBOL(cnss_power_up); + +int cnss_power_down(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->power_down) + return pf_ops->power_down(dev); + else + return -EINVAL; +} +EXPORT_SYMBOL(cnss_power_down); + +void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files, + u32 size, u32 tufello_dual_fw) +{ + if (tufello_dual_fw) + memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files)); + else + memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files)); +} +EXPORT_SYMBOL(cnss_get_qca9377_fw_files); + +int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + if (!pfw_files) + return -ENODEV; + + switch (target_version) { + case AR6320_REV1_VERSION: + case AR6320_REV1_1_VERSION: + memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_1, sizeof(*pfw_files)); + break; + case AR6320_REV1_3_VERSION: + memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_3, sizeof(*pfw_files)); + break; + case AR6320_REV2_1_VERSION: + memcpy(pfw_files, &FW_FILES_QCA6174_FW_2_0, sizeof(*pfw_files)); + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files)); + break; + default: + memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files)); + pr_err("%s default version 0x%X 0x%X", __func__, + target_type, target_version); + break; + } + return 0; +} +EXPORT_SYMBOL(cnss_get_fw_files_for_target); + +void cnss_set_cc_source(enum cnss_cc_src cc_source) +{ + cnss_cc_source = cc_source; +} +EXPORT_SYMBOL(cnss_set_cc_source); + +enum cnss_cc_src cnss_get_cc_source(void) +{ + return cnss_cc_source; +} +EXPORT_SYMBOL(cnss_get_cc_source); + +const char *cnss_wlan_get_evicted_data_file(void) +{ + return FW_FILES_QCA6174_FW_3_0.evicted_data; +} + +int cnss_common_register_tsf_captured_handler(struct device *dev, + irq_handler_t handler, void *ctx) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->register_tsf_captured_handler) + return pf_ops->register_tsf_captured_handler(handler, ctx); + else + return -EINVAL; +} +EXPORT_SYMBOL(cnss_common_register_tsf_captured_handler); + +int cnss_common_unregister_tsf_captured_handler(struct device *dev, + void *ctx) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->unregister_tsf_captured_handler) + return pf_ops->unregister_tsf_captured_handler(ctx); + else + return -EINVAL; +} +EXPORT_SYMBOL(cnss_common_unregister_tsf_captured_handler); diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h new file mode 100644 index 0000000000000000000000000000000000000000..73c6c19ac00024f94de996db5af416a950943657 --- /dev/null +++ b/drivers/net/wireless/cnss/cnss_common.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * + * This 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 _NET_CNSS_COMMON_H_ +#define _NET_CNSS_COMMON_H_ + +/* max 20mhz channel count */ +#define CNSS_MAX_CH_NUM 45 + +struct cnss_cap_tsf_info { + int irq_num; + void *context; + irq_handler_t irq_handler; +}; + +struct cnss_dev_platform_ops { + int (*request_bus_bandwidth)(int bandwidth); + void* (*get_virt_ramdump_mem)(unsigned long *size); + void (*device_self_recovery)(void); + void (*schedule_recovery_work)(void); + void (*device_crashed)(void); + u8 * (*get_wlan_mac_address)(u32 *num); + int (*set_wlan_mac_address)(const u8 *in, u32 len); + int (*power_up)(struct device *dev); + int (*power_down)(struct device *dev); + int (*register_tsf_captured_handler)(irq_handler_t handler, + void *adapter); + int (*unregister_tsf_captured_handler)(void *adapter); +}; + +int cnss_pci_request_bus_bandwidth(int bandwidth); +int cnss_sdio_request_bus_bandwidth(int bandwidth); + +void cnss_sdio_device_crashed(void); +void cnss_pci_device_crashed(void); + +void cnss_pci_device_self_recovery(void); +void cnss_sdio_device_self_recovery(void); + +void *cnss_pci_get_virt_ramdump_mem(unsigned long *size); +void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size); + +void cnss_sdio_schedule_recovery_work(void); +void cnss_pci_schedule_recovery_work(void); + +int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len); +int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len); + +u8 *cnss_pci_get_wlan_mac_address(u32 *num); +u8 *cnss_sdio_get_wlan_mac_address(u32 *num); +int cnss_sdio_power_up(struct device *dev); +int cnss_sdio_power_down(struct device *dev); +int cnss_pcie_power_up(struct device *dev); +int cnss_pcie_power_down(struct device *dev); +const char *cnss_wlan_get_evicted_data_file(void); +#endif /* _NET_CNSS_COMMON_H_ */ diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c new file mode 100644 index 0000000000000000000000000000000000000000..05259dd3204a6ea0a5762af34c1f7f0d5a1bf035 --- /dev/null +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -0,0 +1,3925 @@ +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cnss_common.h" + +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC +#include +#endif + +#define subsys_to_drv(d) container_of(d, struct cnss_data, subsys_desc) + +#define VREG_ON 1 +#define VREG_OFF 0 +#define WLAN_EN_HIGH 1 +#define WLAN_EN_LOW 0 +#define PCIE_LINK_UP 1 +#define PCIE_LINK_DOWN 0 +#define WLAN_BOOTSTRAP_HIGH 1 +#define WLAN_BOOTSTRAP_LOW 0 +#define CNSS_DUMP_FORMAT_VER 0x11 +#define CNSS_DUMP_MAGIC_VER_V2 0x42445953 +#define CNSS_DUMP_NAME "CNSS_WLAN" + +#define QCA6174_VENDOR_ID (0x168C) +#define QCA6174_DEVICE_ID (0x003E) +#define BEELINER_DEVICE_ID (0x0040) +#define QCA6174_REV_ID_OFFSET (0x08) +#define QCA6174_FW_1_1 (0x11) +#define QCA6174_FW_1_3 (0x13) +#define QCA6174_FW_2_0 (0x20) +#define QCA6174_FW_3_0 (0x30) +#define QCA6174_FW_3_2 (0x32) +#define BEELINER_FW (0x00) + +#define QCA6180_VENDOR_ID (0x168C) +#define QCA6180_DEVICE_ID (0x0041) +#define QCA6180_REV_ID_OFFSET (0x08) + +#define WLAN_EN_VREG_NAME "vdd-wlan-en" +#define WLAN_VREG_NAME "vdd-wlan" +#define WLAN_VREG_IO_NAME "vdd-wlan-io" +#define WLAN_VREG_XTAL_NAME "vdd-wlan-xtal" +#define WLAN_VREG_XTAL_AON_NAME "vdd-wlan-xtal-aon" +#define WLAN_VREG_CORE_NAME "vdd-wlan-core" +#define WLAN_VREG_SP2T_NAME "vdd-wlan-sp2t" +#define WLAN_SWREG_NAME "wlan-soc-swreg" +#define WLAN_ANT_SWITCH_NAME "wlan-ant-switch" +#define WLAN_EN_GPIO_NAME "wlan-en-gpio" +#define WLAN_BOOTSTRAP_GPIO_NAME "wlan-bootstrap-gpio" +#define PM_OPTIONS 0 +#define PM_OPTIONS_SUSPEND_LINK_DOWN \ + (MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN) +#define PM_OPTIONS_RESUME_LINK_DOWN \ + (MSM_PCIE_CONFIG_NO_CFG_RESTORE) + +#define SOC_SWREG_VOLT_MAX 1200000 +#define SOC_SWREG_VOLT_MIN 1200000 +#define WLAN_ANT_SWITCH_VOLT_MAX 2700000 +#define WLAN_ANT_SWITCH_VOLT_MIN 2700000 +#define WLAN_ANT_SWITCH_CURR 20000 +#define WLAN_VREG_IO_MAX 1800000 +#define WLAN_VREG_IO_MIN 1800000 +#define WLAN_VREG_XTAL_MAX 1800000 +#define WLAN_VREG_XTAL_MIN 1800000 +#define WLAN_VREG_CORE_MAX 1300000 +#define WLAN_VREG_CORE_MIN 1300000 +#define WLAN_VREG_SP2T_MAX 2700000 +#define WLAN_VREG_SP2T_MIN 2700000 + +#define POWER_ON_DELAY 2 +#define WLAN_VREG_IO_DELAY_MIN 100 +#define WLAN_VREG_IO_DELAY_MAX 1000 +#define WLAN_ENABLE_DELAY 10 +#define PCIE_SWITCH_DELAY 20 +#define WLAN_RECOVERY_DELAY 1 +#define PCIE_ENABLE_DELAY 100 +#define WLAN_BOOTSTRAP_DELAY 10 +#define EVICT_BIN_MAX_SIZE (512 * 1024) + +static DEFINE_SPINLOCK(pci_link_down_lock); + +#define FW_NAME_FIXED_LEN (6) +#define MAX_NUM_OF_SEGMENTS (16) +#define MAX_INDEX_FILE_SIZE (512) +#define FW_FILENAME_LENGTH (13) +#define TYPE_LENGTH (4) +#define PER_FILE_DATA (21) +#define MAX_IMAGE_SIZE (2 * 1024 * 1024) +#define FW_IMAGE_FTM (0x01) +#define FW_IMAGE_MISSION (0x02) +#define FW_IMAGE_BDATA (0x03) +#define FW_IMAGE_PRINT (0x04) + +#define SEG_METADATA (0x01) +#define SEG_NON_PAGED (0x02) +#define SEG_LOCKED_PAGE (0x03) +#define SEG_UNLOCKED_PAGE (0x04) +#define SEG_NON_SECURE_DATA (0x05) + +#define BMI_TEST_SETUP (0x09) + +struct cnss_wlan_gpio_info { + char *name; + u32 num; + bool state; + bool init; + bool prop; +}; + +struct cnss_wlan_vreg_info { + struct regulator *wlan_en_reg; + struct regulator *wlan_reg; + struct regulator *soc_swreg; + struct regulator *ant_switch; + struct regulator *wlan_reg_io; + struct regulator *wlan_reg_xtal; + struct regulator *wlan_reg_xtal_aon; + struct regulator *wlan_reg_core; + struct regulator *wlan_reg_sp2t; + bool state; +}; + +struct segment_memory { + dma_addr_t dma_region; + void *cpu_region; + u32 size; +}; + +/* FW image descriptor lists */ +struct image_desc_hdr { + u8 image_id; + u8 reserved[3]; + u32 segments_cnt; +}; + +struct segment_desc { + u8 segment_id; + u8 segment_idx; + u8 flags[2]; + u32 addr_count; + u32 addr_low; + u32 addr_high; +}; + +struct region_desc { + u32 addr_low; + u32 addr_high; + u32 size; + u32 reserved; +}; + +struct index_file { + u32 type; + u32 segment_idx; + u8 file_name[13]; +}; + +struct cnss_dual_wifi { + bool is_dual_wifi_enabled; +}; + +/** + * struct wlan_mac_addr - Structure to hold WLAN MAC Address + * @mac_addr: MAC address + */ +#define MAX_NO_OF_MAC_ADDR 4 +struct cnss_wlan_mac_addr { + u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN]; + u32 no_of_mac_addr_set; +}; + +/* device_info is expected to be fully populated after cnss_config is invoked. + * The function pointer callbacks are expected to be non null as well. + */ +static struct cnss_data { + struct platform_device *pldev; + struct subsys_device *subsys; + struct subsys_desc subsysdesc; + struct cnss_wlan_mac_addr wlan_mac_addr; + bool is_wlan_mac_set; + bool ramdump_dynamic; + struct ramdump_device *ramdump_dev; + unsigned long ramdump_size; + void *ramdump_addr; + phys_addr_t ramdump_phys; + struct msm_dump_data dump_data; + struct cnss_wlan_driver *driver; + struct pci_dev *pdev; + const struct pci_device_id *id; + struct dma_iommu_mapping *smmu_mapping; + bool smmu_s1_bypass; + dma_addr_t smmu_iova_start; + size_t smmu_iova_len; + dma_addr_t smmu_iova_ipa_start; + size_t smmu_iova_ipa_len; + struct cnss_wlan_vreg_info vreg_info; + bool wlan_en_vreg_support; + struct cnss_wlan_gpio_info gpio_info; + bool pcie_link_state; + bool pcie_link_down_ind; + bool pci_register_again; + bool notify_modem_status; + struct pci_saved_state *saved_state; + u16 revision_id; + bool recovery_in_progress; + atomic_t fw_available; + struct codeswap_codeseg_info *cnss_seg_info; + /* Virtual Address of the DMA page */ + void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS]; + struct cnss_fw_files fw_files; + struct pm_qos_request qos_request; + void *modem_notify_handler; + int modem_current_status; + struct msm_bus_scale_pdata *bus_scale_table; + u32 bus_client; + int current_bandwidth_vote; + void *subsys_handle; + struct esoc_desc *esoc_desc; + struct cnss_platform_cap cap; + struct msm_pcie_register_event event_reg; + struct wakeup_source ws; + u32 recovery_count; + enum cnss_driver_status driver_status; +#ifdef CONFIG_CNSS_SECURE_FW + void *fw_mem; +#endif + u32 device_id; + int fw_image_setup; + u32 bmi_test; + void *fw_cpu; + dma_addr_t fw_dma; + u32 fw_dma_size; + u32 fw_seg_count; + struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS]; + /* Firmware setup complete lock */ + struct mutex fw_setup_stat_lock; + void *bdata_cpu; + dma_addr_t bdata_dma; + u32 bdata_dma_size; + u32 bdata_seg_count; + struct segment_memory bdata_seg_mem[MAX_NUM_OF_SEGMENTS]; + int wlan_bootstrap_gpio; + atomic_t auto_suspended; + bool monitor_wake_intr; + struct cnss_dual_wifi dual_wifi_info; + struct cnss_dev_platform_ops platform_ops; +} *penv; + +static unsigned int pcie_link_down_panic; +module_param(pcie_link_down_panic, uint, 0600); +MODULE_PARM_DESC(pcie_link_down_panic, + "Trigger kernel panic when PCIe link down is detected"); + +static void cnss_put_wlan_enable_gpio(void) +{ + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + + if (penv->wlan_en_vreg_support) + regulator_put(vreg_info->wlan_en_reg); + else + gpio_free(gpio_info->num); +} + +static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info) +{ + int ret; + + if (vreg_info->wlan_reg_core) { + ret = regulator_enable(vreg_info->wlan_reg_core); + if (ret) { + pr_err("%s: regulator enable failed for wlan_reg_core\n", + __func__); + goto error_enable_reg_core; + } + } + + if (vreg_info->wlan_reg_io) { + ret = regulator_enable(vreg_info->wlan_reg_io); + if (ret) { + pr_err("%s: regulator enable failed for wlan_reg_io\n", + __func__); + goto error_enable_reg_io; + } + + usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX); + } + + if (vreg_info->wlan_reg_xtal_aon) { + ret = regulator_enable(vreg_info->wlan_reg_xtal_aon); + if (ret) { + pr_err("%s: wlan_reg_xtal_aon enable failed\n", + __func__); + goto error_enable_reg_xtal_aon; + } + } + + if (vreg_info->wlan_reg_xtal) { + ret = regulator_enable(vreg_info->wlan_reg_xtal); + if (ret) { + pr_err("%s: regulator enable failed for wlan_reg_xtal\n", + __func__); + goto error_enable_reg_xtal; + } + } + + ret = regulator_enable(vreg_info->wlan_reg); + if (ret) { + pr_err("%s: regulator enable failed for WLAN power\n", + __func__); + goto error_enable; + } + + if (vreg_info->wlan_reg_sp2t) { + ret = regulator_enable(vreg_info->wlan_reg_sp2t); + if (ret) { + pr_err("%s: regulator enable failed for wlan_reg_sp2t\n", + __func__); + goto error_enable_reg_sp2t; + } + } + + if (vreg_info->ant_switch) { + ret = regulator_enable(vreg_info->ant_switch); + if (ret) { + pr_err("%s: regulator enable failed for ant_switch\n", + __func__); + goto error_enable_ant_switch; + } + } + + if (vreg_info->soc_swreg) { + ret = regulator_enable(vreg_info->soc_swreg); + if (ret) { + pr_err("%s: regulator enable failed for external soc-swreg\n", + __func__); + goto error_enable_soc_swreg; + } + } + + return ret; + +error_enable_soc_swreg: + if (vreg_info->ant_switch) + regulator_disable(vreg_info->ant_switch); +error_enable_ant_switch: + if (vreg_info->wlan_reg_sp2t) + regulator_disable(vreg_info->wlan_reg_sp2t); +error_enable_reg_sp2t: + regulator_disable(vreg_info->wlan_reg); +error_enable: + if (vreg_info->wlan_reg_xtal) + regulator_disable(vreg_info->wlan_reg_xtal); +error_enable_reg_xtal: + if (vreg_info->wlan_reg_xtal_aon) + regulator_disable(vreg_info->wlan_reg_xtal_aon); +error_enable_reg_xtal_aon: + if (vreg_info->wlan_reg_io) + regulator_disable(vreg_info->wlan_reg_io); +error_enable_reg_io: + if (vreg_info->wlan_reg_core) + regulator_disable(vreg_info->wlan_reg_core); +error_enable_reg_core: + return ret; +} + +static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info) +{ + int ret; + + if (vreg_info->soc_swreg) { + ret = regulator_disable(vreg_info->soc_swreg); + if (ret) { + pr_err("%s: regulator disable failed for external soc-swreg\n", + __func__); + goto error_disable; + } + } + + if (vreg_info->ant_switch) { + ret = regulator_disable(vreg_info->ant_switch); + if (ret) { + pr_err("%s: regulator disable failed for ant_switch\n", + __func__); + goto error_disable; + } + } + + if (vreg_info->wlan_reg_sp2t) { + ret = regulator_disable(vreg_info->wlan_reg_sp2t); + if (ret) { + pr_err("%s: regulator disable failed for wlan_reg_sp2t\n", + __func__); + goto error_disable; + } + } + + ret = regulator_disable(vreg_info->wlan_reg); + if (ret) { + pr_err("%s: regulator disable failed for WLAN power\n", + __func__); + goto error_disable; + } + + if (vreg_info->wlan_reg_xtal) { + ret = regulator_disable(vreg_info->wlan_reg_xtal); + if (ret) { + pr_err("%s: regulator disable failed for wlan_reg_xtal\n", + __func__); + goto error_disable; + } + } + + if (vreg_info->wlan_reg_xtal_aon) { + ret = regulator_disable(vreg_info->wlan_reg_xtal_aon); + if (ret) { + pr_err("%s: wlan_reg_xtal_aon disable failed\n", + __func__); + goto error_disable; + } + } + + if (vreg_info->wlan_reg_io) { + ret = regulator_disable(vreg_info->wlan_reg_io); + if (ret) { + pr_err("%s: regulator disable failed for wlan_reg_io\n", + __func__); + goto error_disable; + } + } + + if (vreg_info->wlan_reg_core) { + ret = regulator_disable(vreg_info->wlan_reg_core); + if (ret) { + pr_err("%s: regulator disable failed for wlan_reg_core\n", + __func__); + goto error_disable; + } + } + +error_disable: + return ret; +} + +static int cnss_wlan_vreg_set(struct cnss_wlan_vreg_info *vreg_info, bool state) +{ + int ret = 0; + + if (vreg_info->state == state) { + pr_debug("Already wlan vreg state is %s\n", + state ? "enabled" : "disabled"); + goto out; + } + + if (state) + ret = cnss_wlan_vreg_on(vreg_info); + else + ret = cnss_wlan_vreg_off(vreg_info); + + if (ret) + goto out; + + pr_debug("%s: wlan vreg is now %s\n", __func__, + state ? "enabled" : "disabled"); + vreg_info->state = state; + +out: + return ret; +} + +static int cnss_wlan_gpio_init(struct cnss_wlan_gpio_info *info) +{ + int ret = 0; + + ret = gpio_request(info->num, info->name); + + if (ret) { + pr_err("can't get gpio %s ret %d\n", info->name, ret); + goto err_gpio_req; + } + + ret = gpio_direction_output(info->num, info->init); + + if (ret) { + pr_err("can't set gpio direction %s ret %d\n", info->name, ret); + goto err_gpio_dir; + } + info->state = info->init; + + return ret; + +err_gpio_dir: + gpio_free(info->num); + +err_gpio_req: + + return ret; +} + +static int cnss_wlan_bootstrap_gpio_init(void) +{ + int ret = 0; + + ret = gpio_request(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_GPIO_NAME); + if (ret) { + pr_err("%s: Can't get GPIO %s, ret = %d\n", + __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret); + goto out; + } + + ret = gpio_direction_output(penv->wlan_bootstrap_gpio, + WLAN_BOOTSTRAP_HIGH); + if (ret) { + pr_err("%s: Can't set GPIO %s direction, ret = %d\n", + __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret); + gpio_free(penv->wlan_bootstrap_gpio); + goto out; + } + + msleep(WLAN_BOOTSTRAP_DELAY); +out: + return ret; +} + +static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state) +{ + if (!info->prop) + return; + + if (info->state == state) { + pr_debug("Already %s gpio is %s\n", + info->name, state ? "high" : "low"); + return; + } + + gpio_set_value(info->num, state); + info->state = state; + + pr_debug("%s: %s gpio is now %s\n", __func__, + info->name, info->state ? "enabled" : "disabled"); +} + +static int cnss_configure_wlan_en_gpio(bool state) +{ + int ret = 0; + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + + if (penv->wlan_en_vreg_support) { + if (state) + ret = regulator_enable(vreg_info->wlan_en_reg); + else + ret = regulator_disable(vreg_info->wlan_en_reg); + } else { + cnss_wlan_gpio_set(gpio_info, state); + } + + msleep(WLAN_ENABLE_DELAY); + return ret; +} + +static void cnss_disable_xtal_ldo(struct platform_device *pdev) +{ + struct cnss_wlan_vreg_info *info = &penv->vreg_info; + + if (info->wlan_reg_xtal) { + regulator_disable(info->wlan_reg_xtal); + regulator_put(info->wlan_reg_xtal); + } + + if (info->wlan_reg_xtal_aon) { + regulator_disable(info->wlan_reg_xtal_aon); + regulator_put(info->wlan_reg_xtal_aon); + } +} + +static int cnss_enable_xtal_ldo(struct platform_device *pdev) +{ + int ret = 0; + struct cnss_wlan_vreg_info *info = &penv->vreg_info; + + if (!of_get_property(pdev->dev.of_node, + WLAN_VREG_XTAL_AON_NAME "-supply", NULL)) + goto enable_xtal; + + info->wlan_reg_xtal_aon = regulator_get(&pdev->dev, + WLAN_VREG_XTAL_AON_NAME); + if (IS_ERR(info->wlan_reg_xtal_aon)) { + ret = PTR_ERR(info->wlan_reg_xtal_aon); + pr_err("%s: XTAL AON Regulator get failed err:%d\n", __func__, + ret); + return ret; + } + + ret = regulator_enable(info->wlan_reg_xtal_aon); + if (ret) { + pr_err("%s: VREG_XTAL_ON enable failed\n", __func__); + goto end; + } + +enable_xtal: + + if (!of_get_property(pdev->dev.of_node, + WLAN_VREG_XTAL_NAME "-supply", NULL)) + goto out_disable_xtal_aon; + + info->wlan_reg_xtal = regulator_get(&pdev->dev, WLAN_VREG_XTAL_NAME); + + if (IS_ERR(info->wlan_reg_xtal)) { + ret = PTR_ERR(info->wlan_reg_xtal); + pr_err("%s XTAL Regulator get failed err:%d\n", __func__, ret); + goto out_disable_xtal_aon; + } + + ret = regulator_set_voltage(info->wlan_reg_xtal, WLAN_VREG_XTAL_MIN, + WLAN_VREG_XTAL_MAX); + if (ret) { + pr_err("%s: Set wlan_vreg_xtal failed\n", __func__); + goto out_put_xtal; + } + + ret = regulator_enable(info->wlan_reg_xtal); + if (ret) { + pr_err("%s: Enable wlan_vreg_xtal failed\n", __func__); + goto out_put_xtal; + } + + return 0; + +out_put_xtal: + if (info->wlan_reg_xtal) + regulator_put(info->wlan_reg_xtal); + +out_disable_xtal_aon: + if (info->wlan_reg_xtal_aon) + regulator_disable(info->wlan_reg_xtal_aon); + +end: + if (info->wlan_reg_xtal_aon) + regulator_put(info->wlan_reg_xtal_aon); + + return ret; +} + +static int cnss_get_wlan_enable_gpio( + struct cnss_wlan_gpio_info *gpio_info, + struct platform_device *pdev) +{ + int ret = 0; + struct device *dev = &pdev->dev; + + if (!of_find_property(dev->of_node, gpio_info->name, NULL)) { + gpio_info->prop = false; + return -ENODEV; + } + + gpio_info->prop = true; + ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0); + if (ret >= 0) { + gpio_info->num = ret; + } else { + if (ret == -EPROBE_DEFER) + pr_debug("get WLAN_EN GPIO probe defer\n"); + else + pr_err( + "can't get gpio %s ret %d", gpio_info->name, ret); + } + + ret = cnss_wlan_gpio_init(gpio_info); + if (ret) + pr_err("gpio init failed\n"); + + return ret; +} + +static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev) +{ + int ret = 0; + struct device_node *node = (&pdev->dev)->of_node; + + if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL)) + return ret; + + penv->wlan_bootstrap_gpio = + of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0); + if (penv->wlan_bootstrap_gpio > 0) { + ret = cnss_wlan_bootstrap_gpio_init(); + } else { + ret = penv->wlan_bootstrap_gpio; + pr_err( + "%s: Can't get GPIO %s, ret = %d", + __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret); + } + + return ret; +} + +static int cnss_wlan_get_resources(struct platform_device *pdev) +{ + int ret = 0; + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + struct device_node *node = pdev->dev.of_node; + + if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) { + vreg_info->wlan_reg_core = regulator_get(&pdev->dev, + WLAN_VREG_CORE_NAME); + if (IS_ERR(vreg_info->wlan_reg_core)) { + ret = PTR_ERR(vreg_info->wlan_reg_core); + + if (ret == -EPROBE_DEFER) { + pr_err("%s: wlan_reg_core probe deferred\n", + __func__); + } else { + pr_err("%s: Get wlan_reg_core failed\n", + __func__); + } + goto err_reg_core_get; + } + + ret = regulator_set_voltage(vreg_info->wlan_reg_core, + WLAN_VREG_CORE_MIN, + WLAN_VREG_CORE_MAX); + if (ret) { + pr_err("%s: Set wlan_reg_core failed\n", __func__); + goto err_reg_core_set; + } + + ret = regulator_enable(vreg_info->wlan_reg_core); + if (ret) { + pr_err("%s: Enable wlan_reg_core failed\n", __func__); + goto err_reg_core_enable; + } + } + + if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) { + vreg_info->wlan_reg_io = regulator_get(&pdev->dev, + WLAN_VREG_IO_NAME); + if (!IS_ERR(vreg_info->wlan_reg_io)) { + ret = regulator_set_voltage(vreg_info->wlan_reg_io, + WLAN_VREG_IO_MIN, + WLAN_VREG_IO_MAX); + if (ret) { + pr_err("%s: Set wlan_vreg_io failed\n", + __func__); + goto err_reg_io_set; + } + + ret = regulator_enable(vreg_info->wlan_reg_io); + if (ret) { + pr_err("%s: Enable wlan_vreg_io failed\n", + __func__); + goto err_reg_io_enable; + } + + usleep_range(WLAN_VREG_IO_DELAY_MIN, + WLAN_VREG_IO_DELAY_MAX); + } + } + + if (cnss_enable_xtal_ldo(pdev)) + goto err_reg_xtal_enable; + + vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME); + + if (IS_ERR(vreg_info->wlan_reg)) { + if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER) + pr_err("%s: vreg probe defer\n", __func__); + else + pr_err("%s: vreg regulator get failed\n", __func__); + ret = PTR_ERR(vreg_info->wlan_reg); + goto err_reg_get; + } + + ret = regulator_enable(vreg_info->wlan_reg); + + if (ret) { + pr_err("%s: vreg initial vote failed\n", __func__); + goto err_reg_enable; + } + + if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) { + vreg_info->wlan_reg_sp2t = + regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME); + if (!IS_ERR(vreg_info->wlan_reg_sp2t)) { + ret = regulator_set_voltage(vreg_info->wlan_reg_sp2t, + WLAN_VREG_SP2T_MIN, + WLAN_VREG_SP2T_MAX); + if (ret) { + pr_err("%s: Set wlan_vreg_sp2t failed\n", + __func__); + goto err_reg_sp2t_set; + } + + ret = regulator_enable(vreg_info->wlan_reg_sp2t); + if (ret) { + pr_err("%s: Enable wlan_vreg_sp2t failed\n", + __func__); + goto err_reg_sp2t_enable; + } + } + } + + if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) { + vreg_info->ant_switch = + regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME); + if (!IS_ERR(vreg_info->ant_switch)) { + ret = regulator_set_voltage(vreg_info->ant_switch, + WLAN_ANT_SWITCH_VOLT_MIN, + WLAN_ANT_SWITCH_VOLT_MAX); + if (ret < 0) { + pr_err("%s: Set ant_switch voltage failed\n", + __func__); + goto err_ant_switch_set; + } + + ret = regulator_set_load(vreg_info->ant_switch, + WLAN_ANT_SWITCH_CURR); + if (ret < 0) { + pr_err("%s: Set ant_switch current failed\n", + __func__); + goto err_ant_switch_set; + } + + ret = regulator_enable(vreg_info->ant_switch); + if (ret < 0) { + pr_err("%s: Enable ant_switch failed\n", + __func__); + goto err_ant_switch_enable; + } + } + } + + if (of_find_property(node, "qcom,wlan-uart-access", NULL)) + penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS; + + if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) { + vreg_info->soc_swreg = regulator_get(&pdev->dev, + WLAN_SWREG_NAME); + if (IS_ERR(vreg_info->soc_swreg)) { + pr_err("%s: soc-swreg node not found\n", + __func__); + goto err_reg_get2; + } + ret = regulator_set_voltage(vreg_info->soc_swreg, + SOC_SWREG_VOLT_MIN, + SOC_SWREG_VOLT_MAX); + if (ret) { + pr_err("%s: vreg initial voltage set failed on soc-swreg\n", + __func__); + goto err_reg_set; + } + ret = regulator_enable(vreg_info->soc_swreg); + if (ret) { + pr_err("%s: vreg initial vote failed\n", __func__); + goto err_reg_enable2; + } + penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG; + } + + penv->wlan_en_vreg_support = + of_property_read_bool(node, "qcom,wlan-en-vreg-support"); + if (penv->wlan_en_vreg_support) { + vreg_info->wlan_en_reg = + regulator_get(&pdev->dev, WLAN_EN_VREG_NAME); + if (IS_ERR(vreg_info->wlan_en_reg)) { + pr_err("%s:wlan_en vreg get failed\n", __func__); + ret = PTR_ERR(vreg_info->wlan_en_reg); + goto err_wlan_en_reg_get; + } + } + + if (!penv->wlan_en_vreg_support) { + ret = cnss_get_wlan_enable_gpio(gpio_info, pdev); + if (ret) { + pr_err( + "%s:Failed to config the WLAN_EN gpio\n", __func__); + goto err_gpio_wlan_en; + } + } + vreg_info->state = VREG_ON; + + ret = cnss_get_wlan_bootstrap_gpio(pdev); + if (ret) { + pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__); + goto err_gpio_wlan_bootstrap; + } + + return ret; + +err_gpio_wlan_bootstrap: + cnss_put_wlan_enable_gpio(); +err_gpio_wlan_en: +err_wlan_en_reg_get: + vreg_info->wlan_en_reg = NULL; + if (vreg_info->soc_swreg) + regulator_disable(vreg_info->soc_swreg); + vreg_info->state = VREG_OFF; + +err_reg_enable2: +err_reg_set: + if (vreg_info->soc_swreg) + regulator_put(vreg_info->soc_swreg); + +err_reg_get2: + if (vreg_info->ant_switch) + regulator_disable(vreg_info->ant_switch); + +err_ant_switch_enable: +err_ant_switch_set: + if (vreg_info->ant_switch) + regulator_put(vreg_info->ant_switch); + if (vreg_info->wlan_reg_sp2t) + regulator_disable(vreg_info->wlan_reg_sp2t); + +err_reg_sp2t_enable: +err_reg_sp2t_set: + if (vreg_info->wlan_reg_sp2t) + regulator_put(vreg_info->wlan_reg_sp2t); + regulator_disable(vreg_info->wlan_reg); + +err_reg_enable: + regulator_put(vreg_info->wlan_reg); +err_reg_get: + cnss_disable_xtal_ldo(pdev); + +err_reg_xtal_enable: + if (vreg_info->wlan_reg_io) + regulator_disable(vreg_info->wlan_reg_io); + +err_reg_io_enable: +err_reg_io_set: + if (vreg_info->wlan_reg_io) + regulator_put(vreg_info->wlan_reg_io); + if (vreg_info->wlan_reg_core) + regulator_disable(vreg_info->wlan_reg_core); + +err_reg_core_enable: +err_reg_core_set: + if (vreg_info->wlan_reg_core) + regulator_put(vreg_info->wlan_reg_core); + +err_reg_core_get: + return ret; +} + +static void cnss_wlan_release_resources(void) +{ + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + + if (penv->wlan_bootstrap_gpio > 0) + gpio_free(penv->wlan_bootstrap_gpio); + cnss_put_wlan_enable_gpio(); + gpio_info->state = WLAN_EN_LOW; + gpio_info->prop = false; + cnss_wlan_vreg_set(vreg_info, VREG_OFF); + if (vreg_info->soc_swreg) + regulator_put(vreg_info->soc_swreg); + if (vreg_info->ant_switch) + regulator_put(vreg_info->ant_switch); + if (vreg_info->wlan_reg_sp2t) + regulator_put(vreg_info->wlan_reg_sp2t); + regulator_put(vreg_info->wlan_reg); + if (vreg_info->wlan_reg_xtal) + regulator_put(vreg_info->wlan_reg_xtal); + if (vreg_info->wlan_reg_xtal_aon) + regulator_put(vreg_info->wlan_reg_xtal_aon); + if (vreg_info->wlan_reg_io) + regulator_put(vreg_info->wlan_reg_io); + if (vreg_info->wlan_reg_core) + regulator_put(vreg_info->wlan_reg_core); + vreg_info->state = VREG_OFF; +} + +static u8 cnss_get_pci_dev_bus_number(struct pci_dev *pdev) +{ + return pdev->bus->number; +} + +void cnss_setup_fw_files(u16 revision) +{ + switch (revision) { + case QCA6174_FW_1_1: + strlcpy(penv->fw_files.image_file, "qwlan11.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.board_data, "bdwlan11.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.otp_data, "otp11.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_file, "utf11.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_board_data, "utfbd11.bin", + CNSS_MAX_FILE_NAME); + break; + + case QCA6174_FW_1_3: + strlcpy(penv->fw_files.image_file, "qwlan13.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.board_data, "bdwlan13.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.otp_data, "otp13.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_file, "utf13.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_board_data, "utfbd13.bin", + CNSS_MAX_FILE_NAME); + break; + + case QCA6174_FW_2_0: + strlcpy(penv->fw_files.image_file, "qwlan20.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.board_data, "bdwlan20.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.otp_data, "otp20.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_file, "utf20.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_board_data, "utfbd20.bin", + CNSS_MAX_FILE_NAME); + break; + + case QCA6174_FW_3_0: + case QCA6174_FW_3_2: + strlcpy(penv->fw_files.image_file, "qwlan30.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.board_data, "bdwlan30.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.otp_data, "otp30.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_file, "utf30.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_board_data, "utfbd30.bin", + CNSS_MAX_FILE_NAME); + break; + + default: + strlcpy(penv->fw_files.image_file, "qwlan.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.board_data, "bdwlan.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.otp_data, "otp.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_file, "utf.bin", + CNSS_MAX_FILE_NAME); + strlcpy(penv->fw_files.utf_board_data, "utfbd.bin", + CNSS_MAX_FILE_NAME); + break; + } +} + +int cnss_get_fw_files(struct cnss_fw_files *pfw_files) +{ + if (!penv || !pfw_files) + return -ENODEV; + + *pfw_files = penv->fw_files; + + return 0; +} +EXPORT_SYMBOL(cnss_get_fw_files); + +#ifdef CONFIG_CNSS_SECURE_FW +static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev) +{ + penv->fw_mem = devm_kzalloc(&pdev->dev, MAX_FIRMWARE_SIZE, GFP_KERNEL); +} +#else +static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev) +{ +} +#endif + +static int get_image_file(const u8 *index_info, u8 *file_name, + u32 *type, u32 *segment_idx) +{ + if (!file_name || !index_info || !type) + return -EINVAL; + + memcpy(type, index_info, TYPE_LENGTH); + memcpy(segment_idx, index_info + TYPE_LENGTH, TYPE_LENGTH); + memcpy(file_name, index_info + TYPE_LENGTH + TYPE_LENGTH, + FW_FILENAME_LENGTH); + + pr_debug("%u: %u: %s", *type, *segment_idx, file_name); + + return PER_FILE_DATA; +} + +static void print_allocated_image_table(void) +{ + u32 seg = 0, count = 0; + u8 *dump_addr; + struct segment_memory *pseg_mem = penv->fw_seg_mem; + struct segment_memory *p_bdata_seg_mem = penv->bdata_seg_mem; + + pr_debug("%s: Dumping FW IMAGE\n", __func__); + while (seg++ < penv->fw_seg_count) { + dump_addr = (u8 *)pseg_mem->cpu_region + + sizeof(struct region_desc); + for (count = 0; count < pseg_mem->size - + sizeof(struct region_desc); count++) + pr_debug("%02x", dump_addr[count]); + + pseg_mem++; + } + + seg = 0; + pr_debug("%s: Dumping BOARD DATA\n", __func__); + while (seg++ < penv->bdata_seg_count) { + dump_addr = (u8 *)p_bdata_seg_mem->cpu_region + + sizeof(struct region_desc); + for (count = 0; count < p_bdata_seg_mem->size - + sizeof(struct region_desc); count++) + pr_debug("%02x ", dump_addr[count]); + + p_bdata_seg_mem++; + } +} + +static void free_allocated_image_table(void) +{ + struct device *dev = &penv->pdev->dev; + struct segment_memory *pseg_mem; + u32 seg = 0; + + /* free fw memroy */ + pseg_mem = penv->fw_seg_mem; + while (seg++ < penv->fw_seg_count) { + dma_free_coherent(dev, pseg_mem->size, + pseg_mem->cpu_region, pseg_mem->dma_region); + pseg_mem++; + } + if (penv->fw_cpu) + dma_free_coherent(dev, + sizeof(struct segment_desc) * + MAX_NUM_OF_SEGMENTS, + penv->fw_cpu, penv->fw_dma); + penv->fw_seg_count = 0; + penv->fw_dma = 0; + penv->fw_cpu = NULL; + penv->fw_dma_size = 0; + + /* free bdata memory */ + seg = 0; + pseg_mem = penv->bdata_seg_mem; + while (seg++ < penv->bdata_seg_count) { + dma_free_coherent(dev, pseg_mem->size, + pseg_mem->cpu_region, + pseg_mem->dma_region); + pseg_mem++; + } + if (penv->bdata_cpu) + dma_free_coherent(dev, + sizeof(struct segment_desc) * + MAX_NUM_OF_SEGMENTS, + penv->bdata_cpu, penv->bdata_dma); + penv->bdata_seg_count = 0; + penv->bdata_dma = 0; + penv->bdata_cpu = NULL; + penv->bdata_dma_size = 0; +} + +static int cnss_setup_fw_image_table(int mode) +{ + struct image_desc_hdr *image_hdr; + struct segment_desc *pseg = NULL; + const struct firmware *fw_index, *fw_image; + struct device *dev = NULL; + char reserved[3] = ""; + u8 image_file[FW_FILENAME_LENGTH] = ""; + u8 index_file[FW_FILENAME_LENGTH] = ""; + u8 index_info[MAX_INDEX_FILE_SIZE] = ""; + size_t image_desc_size = 0, file_size = 0; + size_t index_pos = 0, image_pos = 0; + struct region_desc *reg_desc = NULL; + u32 type = 0; + u32 segment_idx = 0; + uintptr_t address; + int ret = 0; + dma_addr_t dma_addr; + void *vaddr = NULL; + dma_addr_t paddr; + struct segment_memory *pseg_mem; + u32 *pseg_count; + + if (!penv || !penv->pdev) { + pr_err("cnss: invalid penv or pdev or dev\n"); + ret = -EINVAL; + goto err; + } + dev = &penv->pdev->dev; + + /* meta data file has image details */ + switch (mode) { + case FW_IMAGE_FTM: + ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qftm.bin"); + pseg_mem = penv->fw_seg_mem; + pseg_count = &penv->fw_seg_count; + break; + case FW_IMAGE_MISSION: + ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qwlan.bin"); + pseg_mem = penv->fw_seg_mem; + pseg_count = &penv->fw_seg_count; + break; + case FW_IMAGE_BDATA: + ret = scnprintf(index_file, FW_FILENAME_LENGTH, "bdwlan.bin"); + pseg_mem = penv->bdata_seg_mem; + pseg_count = &penv->bdata_seg_count; + break; + default: + pr_err("%s: Unknown meta data file type 0x%x\n", + __func__, mode); + ret = -EINVAL; + } + if (ret < 0) + goto err; + + image_desc_size = sizeof(struct image_desc_hdr) + + sizeof(struct segment_desc) * MAX_NUM_OF_SEGMENTS; + + vaddr = dma_alloc_coherent(dev, image_desc_size, + &paddr, GFP_KERNEL); + + if (!vaddr) { + pr_err("cnss: image desc allocation failure\n"); + ret = -ENOMEM; + goto err; + } + + memset(vaddr, 0, image_desc_size); + + image_hdr = (struct image_desc_hdr *)vaddr; + image_hdr->image_id = mode; + memcpy(image_hdr->reserved, reserved, 3); + + pr_err("cnss: request meta data file %s\n", index_file); + ret = request_firmware(&fw_index, index_file, dev); + if (ret || !fw_index || !fw_index->data || !fw_index->size) { + pr_err("cnss: meta data file open failure %s\n", index_file); + goto err_free; + } + + if (fw_index->size > MAX_INDEX_FILE_SIZE) { + pr_err("cnss: meta data file has invalid size %s: %zu\n", + index_file, fw_index->size); + release_firmware(fw_index); + goto err_free; + } + + memcpy(index_info, fw_index->data, fw_index->size); + file_size = fw_index->size; + release_firmware(fw_index); + + while (file_size >= PER_FILE_DATA && image_pos < image_desc_size && + image_hdr->segments_cnt < MAX_NUM_OF_SEGMENTS) { + ret = get_image_file(index_info + index_pos, + image_file, &type, &segment_idx); + if (ret == -EINVAL) + goto err_free; + + file_size -= ret; + index_pos += ret; + pseg = vaddr + image_pos + + sizeof(struct image_desc_hdr); + + switch (type) { + case SEG_METADATA: + case SEG_NON_PAGED: + case SEG_LOCKED_PAGE: + case SEG_UNLOCKED_PAGE: + case SEG_NON_SECURE_DATA: + + image_hdr->segments_cnt++; + pseg->segment_id = type; + pseg->segment_idx = (u8)(segment_idx & 0xff); + memcpy(pseg->flags, reserved, 2); + + ret = request_firmware(&fw_image, image_file, dev); + if (ret || !fw_image || !fw_image->data || + !fw_image->size) { + pr_err("cnss: image file read failed %s", + image_file); + goto err_free; + } + if (fw_image->size > MAX_IMAGE_SIZE) { + pr_err("cnss: %s: image file invalid size %zu\n", + image_file, fw_image->size); + release_firmware(fw_image); + ret = -EINVAL; + goto err_free; + } + reg_desc = + dma_alloc_coherent(dev, + sizeof(struct region_desc) + + fw_image->size, + &dma_addr, GFP_KERNEL); + if (!reg_desc) { + pr_err("cnss: region allocation failure\n"); + ret = -ENOMEM; + release_firmware(fw_image); + goto err_free; + } + address = (uintptr_t)dma_addr; + pseg->addr_low = address & 0xFFFFFFFF; + pseg->addr_high = 0x00; + /* one region for one image file */ + pseg->addr_count = 1; + memcpy((u8 *)reg_desc + sizeof(struct region_desc), + fw_image->data, fw_image->size); + address += sizeof(struct region_desc); + reg_desc->addr_low = address & 0xFFFFFFFF; + reg_desc->addr_high = 0x00; + reg_desc->reserved = 0; + reg_desc->size = fw_image->size; + + pseg_mem[*pseg_count].dma_region = dma_addr; + pseg_mem[*pseg_count].cpu_region = reg_desc; + pseg_mem[*pseg_count].size = + sizeof(struct region_desc) + fw_image->size; + + release_firmware(fw_image); + (*pseg_count)++; + break; + + default: + pr_err("cnss: Unknown segment %d", type); + ret = -EINVAL; + goto err_free; + } + image_pos += sizeof(struct segment_desc); + } + if (mode != FW_IMAGE_BDATA) { + penv->fw_cpu = vaddr; + penv->fw_dma = paddr; + penv->fw_dma_size = sizeof(struct image_desc_hdr) + + sizeof(struct segment_desc) * image_hdr->segments_cnt; + } else { + penv->bdata_cpu = vaddr; + penv->bdata_dma = paddr; + penv->bdata_dma_size = sizeof(struct image_desc_hdr) + + sizeof(struct segment_desc) * image_hdr->segments_cnt; + } + pr_info("%s: Mode %d: Image setup table built on host", __func__, mode); + + return file_size; +err_free: + free_allocated_image_table(); +err: + pr_err("cnss: image file setup failed %d\n", ret); + return ret; +} + +int cnss_get_fw_image(struct image_desc_info *image_desc_info) +{ + if (!image_desc_info || !penv || + !penv->fw_seg_count || !penv->bdata_seg_count) + return -EINVAL; + + mutex_lock(&penv->fw_setup_stat_lock); + image_desc_info->fw_addr = penv->fw_dma; + image_desc_info->fw_size = penv->fw_dma_size; + image_desc_info->bdata_addr = penv->bdata_dma; + image_desc_info->bdata_size = penv->bdata_dma_size; + mutex_unlock(&penv->fw_setup_stat_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_get_fw_image); + +static ssize_t wlan_setup_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!penv) + return -ENODEV; + + return scnprintf(buf, PAGE_SIZE, "%u\n", penv->revision_id); +} + +static DEVICE_ATTR(wlan_setup, 0400, + wlan_setup_show, NULL); + +static int cnss_wlan_is_codeswap_supported(u16 revision) +{ + switch (revision) { + case QCA6174_FW_3_0: + case QCA6174_FW_3_2: + return 0; + default: + return 1; + } +} + +static int cnss_smmu_init(struct device *dev) +{ + struct dma_iommu_mapping *mapping; + int atomic_ctx = 1; + int s1_bypass = 1; + int fast = 1; + int ret; + + mapping = arm_iommu_create_mapping(&platform_bus_type, + penv->smmu_iova_start, + penv->smmu_iova_len); + if (IS_ERR(mapping)) { + ret = PTR_ERR(mapping); + pr_err("%s: create mapping failed, err = %d\n", __func__, ret); + goto map_fail; + } + + if (penv->smmu_s1_bypass) { + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (ret) { + pr_err("%s: set s1 bypass attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + } else { + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_ATOMIC, + &atomic_ctx); + if (ret) { + pr_err("%s: set atomic_ctx attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_FAST, + &fast); + if (ret) { + pr_err("%s: set fast map attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + } + + ret = arm_iommu_attach_device(dev, mapping); + if (ret) { + pr_err("%s: attach device failed, err = %d\n", __func__, ret); + goto attach_fail; + } + + penv->smmu_mapping = mapping; + + return ret; + +attach_fail: +set_attr_fail: + arm_iommu_release_mapping(mapping); +map_fail: + return ret; +} + +static void cnss_smmu_remove(struct device *dev) +{ + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(penv->smmu_mapping); + + penv->smmu_mapping = NULL; +} + +#ifdef CONFIG_PCI_MSM +struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev) +{ + return pci_store_saved_state(dev); +} + +int cnss_msm_pcie_pm_control( + enum msm_pcie_pm_opt pm_opt, u32 bus_num, + struct pci_dev *pdev, u32 options) +{ + return msm_pcie_pm_control(pm_opt, bus_num, pdev, NULL, options); +} + +int cnss_pci_load_and_free_saved_state( + struct pci_dev *dev, struct pci_saved_state **state) +{ + return pci_load_and_free_saved_state(dev, state); +} + +int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable) +{ + return msm_pcie_shadow_control(dev, enable); +} + +int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg) +{ + return msm_pcie_deregister_event(reg); +} + +int cnss_msm_pcie_recover_config(struct pci_dev *dev) +{ + return msm_pcie_recover_config(dev); +} + +int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg) +{ + return msm_pcie_register_event(reg); +} + +int cnss_msm_pcie_enumerate(u32 rc_idx) +{ + return msm_pcie_enumerate(rc_idx); +} +#else /* !defined CONFIG_PCI_MSM */ + +struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev) +{ + return NULL; +} + +int cnss_msm_pcie_pm_control( + enum msm_pcie_pm_opt pm_opt, u32 bus_num, + struct pci_dev *pdev, u32 options) +{ + return -ENODEV; +} + +int cnss_pci_load_and_free_saved_state( + struct pci_dev *dev, struct pci_saved_state **state) +{ + return 0; +} + +int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable) +{ + return -ENODEV; +} + +int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg) +{ + return -ENODEV; +} + +int cnss_msm_pcie_recover_config(struct pci_dev *dev) +{ + return -ENODEV; +} + +int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg) +{ + return -ENODEV; +} + +int cnss_msm_pcie_enumerate(u32 rc_idx) +{ + return -EPROBE_DEFER; +} +#endif + +static void cnss_pcie_set_platform_ops(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops; + + pf_ops->request_bus_bandwidth = cnss_pci_request_bus_bandwidth; + pf_ops->get_virt_ramdump_mem = cnss_pci_get_virt_ramdump_mem; + pf_ops->device_self_recovery = cnss_pci_device_self_recovery; + pf_ops->schedule_recovery_work = cnss_pci_schedule_recovery_work; + pf_ops->device_crashed = cnss_pci_device_crashed; + pf_ops->get_wlan_mac_address = cnss_pci_get_wlan_mac_address; + pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address; + pf_ops->power_up = cnss_pcie_power_up; + pf_ops->power_down = cnss_pcie_power_down; + + dev->platform_data = pf_ops; +} + +static void cnss_pcie_reset_platform_ops(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops; + + memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops)); + dev->platform_data = NULL; +} + +static int cnss_wlan_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret = 0; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + void *cpu_addr; + dma_addr_t dma_handle; + struct codeswap_codeseg_info *cnss_seg_info = NULL; + struct device *dev = &pdev->dev; + + cnss_pcie_set_platform_ops(dev); + penv->pdev = pdev; + penv->id = id; + atomic_set(&penv->fw_available, 0); + penv->device_id = pdev->device; + + if (penv->smmu_iova_len) { + ret = cnss_smmu_init(&pdev->dev); + if (ret) { + pr_err("%s: SMMU init failed, err = %d\n", + __func__, ret); + } + } + + if (penv->pci_register_again) { + pr_debug("%s: PCI re-registration complete\n", __func__); + penv->pci_register_again = false; + return 0; + } + + switch (pdev->device) { + case QCA6180_DEVICE_ID: + pci_read_config_word(pdev, QCA6180_REV_ID_OFFSET, + &penv->revision_id); + break; + + case QCA6174_DEVICE_ID: + pci_read_config_word(pdev, QCA6174_REV_ID_OFFSET, + &penv->revision_id); + cnss_setup_fw_files(penv->revision_id); + break; + + default: + pr_err("cnss: unknown device found %d\n", pdev->device); + ret = -EPROBE_DEFER; + goto err_unknown; + } + + if (penv->pcie_link_state) { + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + + ret = cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS); + if (ret) { + pr_err("Failed to shutdown PCIe link\n"); + goto err_pcie_suspend; + } + penv->pcie_link_state = PCIE_LINK_DOWN; + } + + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF); + + if (ret) { + pr_err("can't turn off wlan vreg\n"); + goto err_pcie_suspend; + } + + mutex_lock(&penv->fw_setup_stat_lock); + cnss_wlan_fw_mem_alloc(pdev); + mutex_unlock(&penv->fw_setup_stat_lock); + + ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup); + + if (ret) { + pr_err("Can't Create Device file\n"); + goto err_pcie_suspend; + } + + if (cnss_wlan_is_codeswap_supported(penv->revision_id)) { + pr_debug("Code-swap not enabled: %d\n", penv->revision_id); + goto err_pcie_suspend; + } + + cpu_addr = dma_alloc_coherent(dev, EVICT_BIN_MAX_SIZE, + &dma_handle, GFP_KERNEL); + if (!cpu_addr || !dma_handle) { + pr_err("cnss: Memory Alloc failed for codeswap feature\n"); + goto err_pcie_suspend; + } + + memset(cpu_addr, 0, EVICT_BIN_MAX_SIZE); + cnss_seg_info = devm_kzalloc(dev, sizeof(*cnss_seg_info), + GFP_KERNEL); + if (!cnss_seg_info) + goto end_dma_alloc; + + memset(cnss_seg_info, 0, sizeof(*cnss_seg_info)); + cnss_seg_info->codeseg_busaddr[0] = (void *)dma_handle; + penv->codeseg_cpuaddr[0] = cpu_addr; + cnss_seg_info->codeseg_size = EVICT_BIN_MAX_SIZE; + cnss_seg_info->codeseg_total_bytes = EVICT_BIN_MAX_SIZE; + cnss_seg_info->num_codesegs = 1; + cnss_seg_info->codeseg_size_log2 = ilog2(EVICT_BIN_MAX_SIZE); + + penv->cnss_seg_info = cnss_seg_info; + pr_debug("%s: Successfully allocated memory for CODESWAP\n", __func__); + + return ret; + +end_dma_alloc: + dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle); +err_unknown: +err_pcie_suspend: + cnss_pcie_reset_platform_ops(dev); + return ret; +} + +static void cnss_wlan_pci_remove(struct pci_dev *pdev) +{ + struct device *dev; + + if (!penv) + return; + + dev = &penv->pldev->dev; + cnss_pcie_reset_platform_ops(dev); + device_remove_file(dev, &dev_attr_wlan_setup); + + if (penv->smmu_mapping) + cnss_smmu_remove(&pdev->dev); +} + +static int cnss_wlan_pci_suspend(struct device *dev) +{ + int ret = 0; + struct cnss_wlan_driver *wdriver; + struct pci_dev *pdev = to_pci_dev(dev); + + pm_message_t state = { .event = PM_EVENT_SUSPEND }; + + if (!penv) + goto out; + + if (!penv->pcie_link_state) + goto out; + + wdriver = penv->driver; + if (!wdriver) + goto out; + + if (wdriver->suspend) { + ret = wdriver->suspend(pdev, state); + + if (penv->pcie_link_state) { + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + } + } + penv->monitor_wake_intr = false; + +out: + return ret; +} + +static int cnss_wlan_pci_resume(struct device *dev) +{ + int ret = 0; + struct cnss_wlan_driver *wdriver; + struct pci_dev *pdev = to_pci_dev(dev); + + if (!penv) + goto out; + + if (!penv->pcie_link_state) + goto out; + + wdriver = penv->driver; + if (!wdriver) + goto out; + + if (wdriver->resume && !penv->pcie_link_down_ind) { + if (penv->saved_state) + cnss_pci_load_and_free_saved_state( + pdev, &penv->saved_state); + pci_restore_state(pdev); + + ret = wdriver->resume(pdev); + } + +out: + return ret; +} + +static int cnss_wlan_runtime_suspend(struct device *dev) +{ + int ret = 0; + struct cnss_wlan_driver *wdrv; + + if (!penv) + return -EAGAIN; + + if (penv->pcie_link_down_ind) { + pr_debug("PCI link down recovery is in progress\n"); + return -EAGAIN; + } + + pr_debug("cnss: runtime suspend start\n"); + + wdrv = penv->driver; + + if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_suspend) + ret = wdrv->runtime_ops->runtime_suspend(to_pci_dev(dev)); + + pr_info("cnss: runtime suspend status: %d\n", ret); + + return ret; +} + +static int cnss_wlan_runtime_resume(struct device *dev) +{ + struct cnss_wlan_driver *wdrv; + int ret = 0; + + if (!penv) + return -EAGAIN; + + if (penv->pcie_link_down_ind) { + pr_debug("PCI link down recovery is in progress\n"); + return -EAGAIN; + } + + pr_debug("cnss: runtime resume start\n"); + + wdrv = penv->driver; + + if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_resume) + ret = wdrv->runtime_ops->runtime_resume(to_pci_dev(dev)); + + pr_info("cnss: runtime resume status: %d\n", ret); + + return ret; +} + +static int cnss_wlan_runtime_idle(struct device *dev) +{ + pr_debug("cnss: runtime idle\n"); + + pm_request_autosuspend(dev); + + return -EBUSY; +} + +static DECLARE_RWSEM(cnss_pm_sem); + +static int cnss_pm_notify(struct notifier_block *b, + unsigned long event, void *p) +{ + switch (event) { + case PM_SUSPEND_PREPARE: + down_write(&cnss_pm_sem); + break; + + case PM_POST_SUSPEND: + up_write(&cnss_pm_sem); + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block cnss_pm_notifier = { + .notifier_call = cnss_pm_notify, +}; + +static const struct pci_device_id cnss_wlan_pci_id_table[] = { + { QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { QCA6174_VENDOR_ID, BEELINER_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { QCA6180_VENDOR_ID, QCA6180_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cnss_wlan_pci_id_table); + +#ifdef CONFIG_PM +static const struct dev_pm_ops cnss_wlan_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cnss_wlan_pci_suspend, cnss_wlan_pci_resume) + SET_RUNTIME_PM_OPS(cnss_wlan_runtime_suspend, cnss_wlan_runtime_resume, + cnss_wlan_runtime_idle) +}; +#endif + +struct pci_driver cnss_wlan_pci_driver = { + .name = "cnss_wlan_pci", + .id_table = cnss_wlan_pci_id_table, + .probe = cnss_wlan_pci_probe, + .remove = cnss_wlan_pci_remove, +#ifdef CONFIG_PM + .driver = { + .pm = &cnss_wlan_pm_ops, + }, +#endif +}; + +static ssize_t fw_image_setup_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!penv) + return -ENODEV; + + return scnprintf(buf, PAGE_SIZE, "%u\n", penv->fw_image_setup); +} + +static ssize_t fw_image_setup_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val; + int ret; + + if (!penv) + return -ENODEV; + + mutex_lock(&penv->fw_setup_stat_lock); + pr_info("%s: Firmware setup in progress\n", __func__); + + if (kstrtoint(buf, 0, &val)) { + mutex_unlock(&penv->fw_setup_stat_lock); + return -EINVAL; + } + + if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION || + val == FW_IMAGE_BDATA) { + pr_info("%s: fw image setup triggered %d\n", __func__, val); + ret = cnss_setup_fw_image_table(val); + if (ret != 0) { + pr_err("%s: Invalid parsing of FW image files %d\n", + __func__, ret); + mutex_unlock(&penv->fw_setup_stat_lock); + return -EINVAL; + } + penv->fw_image_setup = val; + } else if (val == FW_IMAGE_PRINT) { + print_allocated_image_table(); + } else if (val == BMI_TEST_SETUP) { + penv->bmi_test = val; + } + + pr_info("%s: Firmware setup completed\n", __func__); + mutex_unlock(&penv->fw_setup_stat_lock); + return count; +} + +static DEVICE_ATTR(fw_image_setup, 0600, + fw_image_setup_show, fw_image_setup_store); + +void cnss_pci_recovery_work_handler(struct work_struct *recovery) +{ + cnss_pci_device_self_recovery(); +} + +DECLARE_WORK(cnss_pci_recovery_work, cnss_pci_recovery_work_handler); + +void cnss_schedule_recovery_work(void) +{ + schedule_work(&cnss_pci_recovery_work); +} +EXPORT_SYMBOL(cnss_schedule_recovery_work); + +static inline void __cnss_disable_irq(void *data) +{ + struct pci_dev *pdev = data; + + disable_irq(pdev->irq); +} + +void cnss_pci_events_cb(struct msm_pcie_notify *notify) +{ + unsigned long flags; + + if (!notify) + return; + + switch (notify->event) { + case MSM_PCIE_EVENT_LINKDOWN: + if (pcie_link_down_panic) + panic("PCIe link is down\n"); + + spin_lock_irqsave(&pci_link_down_lock, flags); + if (penv->pcie_link_down_ind) { + pr_debug("PCI link down recovery is in progress, ignore\n"); + spin_unlock_irqrestore(&pci_link_down_lock, flags); + return; + } + penv->pcie_link_down_ind = true; + spin_unlock_irqrestore(&pci_link_down_lock, flags); + + pr_err("PCI link down, schedule recovery\n"); + __cnss_disable_irq(notify->user); + schedule_work(&cnss_pci_recovery_work); + break; + + case MSM_PCIE_EVENT_WAKEUP: + if (penv->monitor_wake_intr && + atomic_read(&penv->auto_suspended)) { + penv->monitor_wake_intr = false; + pm_request_resume(&penv->pdev->dev); + } + break; + + default: + pr_err("cnss: invalid event from PCIe callback %d\n", + notify->event); + } +} + +void cnss_wlan_pci_link_down(void) +{ + unsigned long flags; + + if (pcie_link_down_panic) + panic("PCIe link is down\n"); + + spin_lock_irqsave(&pci_link_down_lock, flags); + if (penv->pcie_link_down_ind) { + pr_debug("PCI link down recovery is in progress, ignore\n"); + spin_unlock_irqrestore(&pci_link_down_lock, flags); + return; + } + penv->pcie_link_down_ind = true; + spin_unlock_irqrestore(&pci_link_down_lock, flags); + + pr_err("PCI link down detected by host driver, schedule recovery\n"); + schedule_work(&cnss_pci_recovery_work); +} +EXPORT_SYMBOL(cnss_wlan_pci_link_down); + +int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable) +{ + return cnss_msm_pcie_shadow_control(dev, enable); +} +EXPORT_SYMBOL(cnss_pcie_shadow_control); + +int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg) +{ + struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info; + + mutex_lock(&penv->fw_setup_stat_lock); + if (!cnss_seg_info) { + swap_seg = NULL; + mutex_unlock(&penv->fw_setup_stat_lock); + return -ENOENT; + } + + if (!atomic_read(&penv->fw_available)) { + pr_debug("%s: fw is not available\n", __func__); + mutex_unlock(&penv->fw_setup_stat_lock); + return -ENOENT; + } + + *swap_seg = *cnss_seg_info; + mutex_unlock(&penv->fw_setup_stat_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_get_codeswap_struct); + +static void cnss_wlan_memory_expansion(void) +{ + struct device *dev; + const struct firmware *fw_entry; + const char *filename; + u32 fw_entry_size, size_left, dma_size_left, length; + char *fw_temp; + char *fw_data; + char *dma_virt_addr; + struct codeswap_codeseg_info *cnss_seg_info; + u32 total_length = 0; + struct pci_dev *pdev; + + mutex_lock(&penv->fw_setup_stat_lock); + filename = cnss_wlan_get_evicted_data_file(); + pdev = penv->pdev; + dev = &pdev->dev; + cnss_seg_info = penv->cnss_seg_info; + + if (!cnss_seg_info) { + pr_debug("cnss: cnss_seg_info is NULL\n"); + mutex_unlock(&penv->fw_setup_stat_lock); + goto end; + } + + if (atomic_read(&penv->fw_available)) { + pr_debug("cnss: fw code already copied to host memory\n"); + mutex_unlock(&penv->fw_setup_stat_lock); + goto end; + } + + if (request_firmware(&fw_entry, filename, dev) != 0) { + pr_debug("cnss: failed to get fw: %s\n", filename); + mutex_unlock(&penv->fw_setup_stat_lock); + goto end; + } + + if (!fw_entry || !fw_entry->data) { + pr_err("%s: INVALID FW entries\n", __func__); + mutex_unlock(&penv->fw_setup_stat_lock); + goto release_fw; + } + + dma_virt_addr = (char *)penv->codeseg_cpuaddr[0]; + fw_data = (u8 *)fw_entry->data; + fw_temp = fw_data; + fw_entry_size = fw_entry->size; + if (fw_entry_size > EVICT_BIN_MAX_SIZE) + fw_entry_size = EVICT_BIN_MAX_SIZE; + size_left = fw_entry_size; + dma_size_left = EVICT_BIN_MAX_SIZE; + while ((size_left && fw_temp) && (dma_size_left > 0)) { + fw_temp = fw_temp + 4; + size_left = size_left - 4; + length = *(int *)fw_temp; + if ((length > size_left || length <= 0) || + (dma_size_left <= 0 || length > dma_size_left)) { + pr_err("cnss: wrong length read:%d\n", + length); + break; + } + fw_temp = fw_temp + 4; + size_left = size_left - 4; + memcpy(dma_virt_addr, fw_temp, length); + dma_size_left = dma_size_left - length; + size_left = size_left - length; + fw_temp = fw_temp + length; + dma_virt_addr = dma_virt_addr + length; + total_length += length; + pr_debug("cnss: bytes_left to copy: fw:%d; dma_page:%d\n", + size_left, dma_size_left); + } + pr_debug("cnss: total_bytes copied: %d\n", total_length); + cnss_seg_info->codeseg_total_bytes = total_length; + + atomic_set(&penv->fw_available, 1); + mutex_unlock(&penv->fw_setup_stat_lock); + +release_fw: + release_firmware(fw_entry); +end: + return; +} + +/** + * cnss_get_wlan_mac_address() - API to return MAC addresses buffer + * @dev: struct device pointer + * @num: buffer for number of mac addresses supported + * + * API returns the pointer to the buffer filled with mac addresses and + * updates num with the number of mac addresses the buffer contains. + * + * Return: pointer to mac address buffer. + */ +u8 *cnss_pci_get_wlan_mac_address(u32 *num) +{ + struct cnss_wlan_mac_addr *addr = NULL; + + if (!penv) { + pr_err("%s: Invalid Platform Driver Context\n", __func__); + goto end; + } + + if (!penv->is_wlan_mac_set) { + pr_info("%s: Platform Driver doesn't have any mac address\n", + __func__); + goto end; + } + + addr = &penv->wlan_mac_addr; + *num = addr->no_of_mac_addr_set; + return &addr->mac_addr[0][0]; + +end: + *num = 0; + return NULL; +} + +/** + * cnss_get_wlan_mac_address() - API to return MAC addresses buffer + * @dev: struct device pointer + * @num: buffer for number of mac addresses supported + * + * API returns the pointer to the buffer filled with mac addresses and + * updates num with the number of mac addresses the buffer contains. + * + * Return: pointer to mac address buffer. + */ +u8 *cnss_get_wlan_mac_address(struct device *dev, u32 *num) +{ + struct cnss_wlan_mac_addr *addr = NULL; + + if (!penv) { + pr_err("%s: Invalid Platform Driver Context\n", __func__); + goto end; + } + + if (!penv->is_wlan_mac_set) { + pr_info("%s: Platform Driver doesn't have any mac address\n", + __func__); + goto end; + } + + addr = &penv->wlan_mac_addr; + *num = addr->no_of_mac_addr_set; + return &addr->mac_addr[0][0]; +end: + *num = 0; + return NULL; +} +EXPORT_SYMBOL(cnss_get_wlan_mac_address); + +/** + * cnss_pcie_set_wlan_mac_address() - API to get two wlan mac address + * @in: Input buffer with wlan mac addresses + * @len: Size of the buffer passed + * + * API to store wlan mac address passed by the caller. The stored mac + * addresses are used by the wlan functional driver to program wlan HW. + * + * Return: kernel error code. + */ +int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len) +{ + u32 no_of_mac_addr; + struct cnss_wlan_mac_addr *addr = NULL; + int iter = 0; + u8 *temp = NULL; + + if (len == 0 || (len % ETH_ALEN) != 0) { + pr_err("%s: Invalid Length:%d\n", __func__, len); + return -EINVAL; + } + + no_of_mac_addr = len / ETH_ALEN; + + if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) { + pr_err("%s: Num of supported MAC addresses are:%d given:%d\n", + __func__, MAX_NO_OF_MAC_ADDR, no_of_mac_addr); + return -EINVAL; + } + + if (!penv) { + pr_err("%s: Invalid CNSS Platform Context\n", __func__); + return -ENOENT; + } + + if (penv->is_wlan_mac_set) { + pr_info("%s: Already MAC address are configured\n", __func__); + return 0; + } + + penv->is_wlan_mac_set = true; + addr = &penv->wlan_mac_addr; + addr->no_of_mac_addr_set = no_of_mac_addr; + temp = &addr->mac_addr[0][0]; + + for (; iter < no_of_mac_addr; ++iter, temp += ETH_ALEN, in += + ETH_ALEN) { + ether_addr_copy(temp, in); + pr_debug("%s MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", + __func__, temp[0], temp[1], temp[2], temp[3], temp[4], + temp[5]); + } + return 0; +} + +int cnss_wlan_register_driver(struct cnss_wlan_driver *driver) +{ + int ret = 0; + int probe_again = 0; + struct cnss_wlan_driver *wdrv; + struct cnss_wlan_vreg_info *vreg_info; + struct cnss_wlan_gpio_info *gpio_info; + struct pci_dev *pdev; + + if (!penv) + return -ENODEV; + + vreg_info = &penv->vreg_info; + gpio_info = &penv->gpio_info; + pdev = penv->pdev; + + if (!penv->driver) { + penv->driver = driver; + wdrv = penv->driver; + } else { + pr_err("driver already registered\n"); + return -EEXIST; + } + +again: + ret = cnss_wlan_vreg_set(vreg_info, VREG_ON); + if (ret) { + pr_err("wlan vreg ON failed\n"); + goto err_wlan_vreg_on; + } + + msleep(POWER_ON_DELAY); + + if (penv->wlan_bootstrap_gpio > 0) { + gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH); + msleep(WLAN_BOOTSTRAP_DELAY); + } + + cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + + if (!pdev) { + pr_debug("%s: invalid pdev. register pci device\n", __func__); + ret = pci_register_driver(&cnss_wlan_pci_driver); + + if (ret) { + pr_err("%s: pci registration failed\n", __func__); + goto err_pcie_reg; + } + pdev = penv->pdev; + if (!pdev) { + pr_err("%s: pdev is still invalid\n", __func__); + goto err_pcie_reg; + } + } + + penv->event_reg.events = MSM_PCIE_EVENT_LINKDOWN | + MSM_PCIE_EVENT_WAKEUP; + penv->event_reg.user = pdev; + penv->event_reg.mode = MSM_PCIE_TRIGGER_CALLBACK; + penv->event_reg.callback = cnss_pci_events_cb; + penv->event_reg.options = MSM_PCIE_CONFIG_NO_RECOVERY; + ret = cnss_msm_pcie_register_event(&penv->event_reg); + if (ret) + pr_err("%s: PCIe event register failed %d\n", __func__, ret); + + if (!penv->pcie_link_state && !penv->pcie_link_down_ind) { + ret = cnss_msm_pcie_pm_control( + MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS); + if (ret) { + pr_err("PCIe link bring-up failed\n"); + goto err_pcie_link_up; + } + penv->pcie_link_state = PCIE_LINK_UP; + } else if (!penv->pcie_link_state && penv->pcie_link_down_ind) { + ret = cnss_msm_pcie_pm_control( + MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS_RESUME_LINK_DOWN); + + if (ret) { + pr_err("PCIe link bring-up failed (link down option)\n"); + goto err_pcie_link_up; + } + penv->pcie_link_state = PCIE_LINK_UP; + + ret = cnss_msm_pcie_recover_config(pdev); + if (ret) { + pr_err("cnss: PCI link failed to recover\n"); + goto err_pcie_link_up; + } + penv->pcie_link_down_ind = false; + } + + if (!cnss_wlan_is_codeswap_supported(penv->revision_id)) + cnss_wlan_memory_expansion(); + + if (wdrv->probe) { + if (penv->saved_state) + cnss_pci_load_and_free_saved_state( + pdev, &penv->saved_state); + + pci_restore_state(pdev); + + ret = wdrv->probe(pdev, penv->id); + if (ret) { + wcnss_prealloc_check_memory_leak(); + wcnss_pre_alloc_reset(); + + if (probe_again > 3) { + pr_err("Failed to probe WLAN\n"); + goto err_wlan_probe; + } + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + cnss_msm_pcie_deregister_event(&penv->event_reg); + cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, + cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS); + penv->pcie_link_state = PCIE_LINK_DOWN; + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_vreg_set(vreg_info, VREG_OFF); + msleep(POWER_ON_DELAY); + probe_again++; + goto again; + } + } + + if (penv->notify_modem_status && wdrv->modem_status) + wdrv->modem_status(pdev, penv->modem_current_status); + + return ret; + +err_wlan_probe: + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + +err_pcie_link_up: + cnss_msm_pcie_deregister_event(&penv->event_reg); + if (penv->pcie_link_state) { + cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS); + penv->pcie_link_state = PCIE_LINK_DOWN; + } + +err_pcie_reg: + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_vreg_set(vreg_info, VREG_OFF); + if (penv->pdev) { + pr_err("%d: Unregistering PCI device\n", __LINE__); + pci_unregister_driver(&cnss_wlan_pci_driver); + penv->pdev = NULL; + penv->pci_register_again = true; + } + +err_wlan_vreg_on: + penv->driver = NULL; + + return ret; +} +EXPORT_SYMBOL(cnss_wlan_register_driver); + +void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) +{ + struct cnss_wlan_driver *wdrv; + struct cnss_wlan_vreg_info *vreg_info; + struct cnss_wlan_gpio_info *gpio_info; + struct pci_dev *pdev; + + if (!penv) + return; + + wdrv = penv->driver; + vreg_info = &penv->vreg_info; + gpio_info = &penv->gpio_info; + pdev = penv->pdev; + + if (!wdrv) { + pr_err("driver not registered\n"); + return; + } + + if (penv->bus_client) + msm_bus_scale_client_update_request(penv->bus_client, + CNSS_BUS_WIDTH_NONE); + + if (!pdev) { + pr_err("%d: invalid pdev\n", __LINE__); + goto cut_power; + } + + if (wdrv->remove) + wdrv->remove(pdev); + + wcnss_prealloc_check_memory_leak(); + wcnss_pre_alloc_reset(); + + cnss_msm_pcie_deregister_event(&penv->event_reg); + + if (penv->pcie_link_state && !penv->pcie_link_down_ind) { + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + + if (cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS)) { + pr_err("Failed to shutdown PCIe link\n"); + return; + } + } else if (penv->pcie_link_state && penv->pcie_link_down_ind) { + penv->saved_state = NULL; + + if (cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) { + pr_err("Failed to shutdown PCIe link (with linkdown option)\n"); + return; + } + } + penv->pcie_link_state = PCIE_LINK_DOWN; + penv->driver_status = CNSS_UNINITIALIZED; + penv->monitor_wake_intr = false; + atomic_set(&penv->auto_suspended, 0); + +cut_power: + penv->driver = NULL; + + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) + pr_err("wlan vreg OFF failed\n"); +} +EXPORT_SYMBOL(cnss_wlan_unregister_driver); + +#ifdef CONFIG_PCI_MSM +int cnss_wlan_pm_control(bool vote) +{ + if (!penv || !penv->pdev) + return -ENODEV; + + return cnss_msm_pcie_pm_control( + vote ? MSM_PCIE_DISABLE_PC : MSM_PCIE_ENABLE_PC, + cnss_get_pci_dev_bus_number(penv->pdev), + penv->pdev, PM_OPTIONS); +} +EXPORT_SYMBOL(cnss_wlan_pm_control); +#endif + +void cnss_lock_pm_sem(void) +{ + down_read(&cnss_pm_sem); +} +EXPORT_SYMBOL(cnss_lock_pm_sem); + +void cnss_release_pm_sem(void) +{ + up_read(&cnss_pm_sem); +} +EXPORT_SYMBOL(cnss_release_pm_sem); + +void cnss_pci_schedule_recovery_work(void) +{ + schedule_work(&cnss_pci_recovery_work); +} + +void *cnss_pci_get_virt_ramdump_mem(unsigned long *size) +{ + if (!penv || !penv->pldev) + return NULL; + + *size = penv->ramdump_size; + + return penv->ramdump_addr; +} + +void cnss_pci_device_crashed(void) +{ + if (penv && penv->subsys) { + subsys_set_crash_status(penv->subsys, true); + subsystem_restart_dev(penv->subsys); + } +} + +void *cnss_get_virt_ramdump_mem(unsigned long *size) +{ + if (!penv || !penv->pldev) + return NULL; + + *size = penv->ramdump_size; + + return penv->ramdump_addr; +} +EXPORT_SYMBOL(cnss_get_virt_ramdump_mem); + +void cnss_device_crashed(void) +{ + if (penv && penv->subsys) { + subsys_set_crash_status(penv->subsys, true); + subsystem_restart_dev(penv->subsys); + } +} +EXPORT_SYMBOL(cnss_device_crashed); + +static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop) +{ + struct cnss_wlan_driver *wdrv; + struct pci_dev *pdev; + struct cnss_wlan_vreg_info *vreg_info; + struct cnss_wlan_gpio_info *gpio_info; + int ret = 0; + + if (!penv) + return -ENODEV; + + penv->recovery_in_progress = true; + wdrv = penv->driver; + pdev = penv->pdev; + vreg_info = &penv->vreg_info; + gpio_info = &penv->gpio_info; + + if (!pdev) { + ret = -EINVAL; + goto cut_power; + } + + if (wdrv && wdrv->shutdown) + wdrv->shutdown(pdev); + + if (penv->pcie_link_state) { + if (cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) { + pr_debug("cnss: Failed to shutdown PCIe link\n"); + ret = -EFAULT; + } + penv->saved_state = NULL; + penv->pcie_link_state = PCIE_LINK_DOWN; + } + +cut_power: + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) + pr_err("cnss: Failed to set WLAN VREG_OFF\n"); + + return ret; +} + +static int cnss_powerup(const struct subsys_desc *subsys) +{ + struct cnss_wlan_driver *wdrv; + struct pci_dev *pdev; + struct cnss_wlan_vreg_info *vreg_info; + struct cnss_wlan_gpio_info *gpio_info; + int ret = 0; + + if (!penv) + return -ENODEV; + + if (!penv->driver) + goto out; + + wdrv = penv->driver; + pdev = penv->pdev; + vreg_info = &penv->vreg_info; + gpio_info = &penv->gpio_info; + + ret = cnss_wlan_vreg_set(vreg_info, VREG_ON); + if (ret) { + pr_err("cnss: Failed to set WLAN VREG_ON\n"); + goto err_wlan_vreg_on; + } + + msleep(POWER_ON_DELAY); + cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + /** + * Some platforms have wifi and other PCIE card attached with PCIE + * switch on the same RC like P5459 board(ROME 3.2 PCIE card + Ethernet + * PCI), it will need extra time to stable the signals when do SSR, + * otherwise fail to create the PCIE link, so add PCIE_SWITCH_DELAY. + */ + msleep(PCIE_SWITCH_DELAY); + + if (!pdev) { + pr_err("%d: invalid pdev\n", __LINE__); + goto err_pcie_link_up; + } + + if (!penv->pcie_link_state) { + ret = cnss_msm_pcie_pm_control( + MSM_PCIE_RESUME, + cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS_RESUME_LINK_DOWN); + + if (ret) { + pr_err("cnss: Failed to bring-up PCIe link\n"); + goto err_pcie_link_up; + } + penv->pcie_link_state = PCIE_LINK_UP; + ret = cnss_msm_pcie_recover_config(penv->pdev); + if (ret) { + pr_err("cnss: PCI link failed to recover\n"); + goto err_pcie_link_up; + } + penv->pcie_link_down_ind = false; + } + + if (wdrv && wdrv->reinit) { + if (penv->saved_state) + cnss_pci_load_and_free_saved_state( + pdev, &penv->saved_state); + + pci_restore_state(pdev); + + ret = wdrv->reinit(pdev, penv->id); + if (ret) { + pr_err("%d: Failed to do reinit\n", __LINE__); + goto err_wlan_reinit; + } + } else { + pr_err("%d: wdrv->reinit is invalid\n", __LINE__); + goto err_pcie_link_up; + } + + if (penv->notify_modem_status && wdrv->modem_status) + wdrv->modem_status(pdev, penv->modem_current_status); + +out: + penv->recovery_in_progress = false; + return ret; + +err_wlan_reinit: + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, + cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS); + penv->pcie_link_state = PCIE_LINK_DOWN; + +err_pcie_link_up: + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_vreg_set(vreg_info, VREG_OFF); + if (penv->pdev) { + if (wdrv && wdrv->update_status) + wdrv->update_status(penv->pdev, CNSS_SSR_FAIL); + if (!penv->recovery_in_progress) { + pr_err("%d: Unregistering pci device\n", __LINE__); + pci_unregister_driver(&cnss_wlan_pci_driver); + penv->pdev = NULL; + penv->pci_register_again = true; + } + } + +err_wlan_vreg_on: + return ret; +} + +void cnss_pci_device_self_recovery(void) +{ + if (!penv) + return; + + if (penv->recovery_in_progress) { + pr_err("cnss: Recovery already in progress\n"); + return; + } + + if (penv->driver_status == CNSS_LOAD_UNLOAD) { + pr_err("cnss: load unload in progress\n"); + return; + } + + penv->recovery_count++; + penv->recovery_in_progress = true; + cnss_pm_wake_lock(&penv->ws); + cnss_shutdown(NULL, false); + msleep(WLAN_RECOVERY_DELAY); + cnss_powerup(NULL); + cnss_pm_wake_lock_release(&penv->ws); + penv->recovery_in_progress = false; +} + +static int cnss_ramdump(int enable, const struct subsys_desc *subsys) +{ + struct ramdump_segment segment; + + if (!penv) + return -ENODEV; + + if (!penv->ramdump_size) + return -ENOENT; + + if (!enable) + return 0; + + memset(&segment, 0, sizeof(segment)); + segment.v_address = penv->ramdump_addr; + segment.size = penv->ramdump_size; + + return do_ramdump(penv->ramdump_dev, &segment, 1); +} + +static void cnss_crash_shutdown(const struct subsys_desc *subsys) +{ + struct cnss_wlan_driver *wdrv; + struct pci_dev *pdev; + + if (!penv) + return; + + wdrv = penv->driver; + pdev = penv->pdev; + + if (pdev && wdrv && wdrv->crash_shutdown) + wdrv->crash_shutdown(pdev); +} + +void cnss_device_self_recovery(void) +{ + if (!penv) + return; + + if (penv->recovery_in_progress) { + pr_err("cnss: Recovery already in progress\n"); + return; + } + if (penv->driver_status == CNSS_LOAD_UNLOAD) { + pr_err("cnss: load unload in progress\n"); + return; + } + penv->recovery_count++; + penv->recovery_in_progress = true; + cnss_pm_wake_lock(&penv->ws); + cnss_shutdown(NULL, false); + msleep(WLAN_RECOVERY_DELAY); + cnss_powerup(NULL); + cnss_pm_wake_lock_release(&penv->ws); + penv->recovery_in_progress = false; +} +EXPORT_SYMBOL(cnss_device_self_recovery); + +static int cnss_modem_notifier_nb(struct notifier_block *this, + unsigned long code, + void *ss_handle) +{ + struct cnss_wlan_driver *wdrv; + struct pci_dev *pdev; + + pr_debug("%s: Modem-Notify: event %lu\n", __func__, code); + + if (!penv) + return NOTIFY_DONE; + + if (code == SUBSYS_AFTER_POWERUP) + penv->modem_current_status = 1; + else if (code == SUBSYS_BEFORE_SHUTDOWN) + penv->modem_current_status = 0; + else + return NOTIFY_DONE; + + wdrv = penv->driver; + pdev = penv->pdev; + + if (!wdrv || !pdev || !wdrv->modem_status) + return NOTIFY_DONE; + + wdrv->modem_status(pdev, penv->modem_current_status); + + return NOTIFY_OK; +} + +static struct notifier_block mnb = { + .notifier_call = cnss_modem_notifier_nb, +}; + +static int cnss_init_dump_entry(void) +{ + struct msm_dump_entry dump_entry; + + if (!penv) + return -ENODEV; + + if (!penv->ramdump_dynamic) + return 0; + + penv->dump_data.addr = penv->ramdump_phys; + penv->dump_data.len = penv->ramdump_size; + penv->dump_data.version = CNSS_DUMP_FORMAT_VER; + penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2; + strlcpy(penv->dump_data.name, CNSS_DUMP_NAME, + sizeof(penv->dump_data.name)); + dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN; + dump_entry.addr = virt_to_phys(&penv->dump_data); + + return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); +} + +struct dma_iommu_mapping *cnss_smmu_get_mapping(void) +{ + if (!penv) { + pr_err("Invalid penv: data %pK\n", penv); + return NULL; + } + + return penv->smmu_mapping; +} +EXPORT_SYMBOL(cnss_smmu_get_mapping); + +int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + unsigned long iova; + size_t len; + int ret = 0; + + if (!iova_addr) { + pr_err("iova_addr is NULL, paddr %pa, size %zu\n", + &paddr, size); + return -EINVAL; + } + + len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); + iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE); + + if (iova >= penv->smmu_iova_ipa_start + penv->smmu_iova_ipa_len) { + pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", + iova, + &penv->smmu_iova_ipa_start, + penv->smmu_iova_ipa_len); + return -ENOMEM; + } + + ret = iommu_map(penv->smmu_mapping->domain, iova, + rounddown(paddr, PAGE_SIZE), len, + IOMMU_READ | IOMMU_WRITE); + if (ret) { + pr_err("PA to IOVA mapping failed, ret %d\n", ret); + return ret; + } + + penv->smmu_iova_ipa_start = iova + len; + *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); + + return 0; +} +EXPORT_SYMBOL(cnss_smmu_map); + +static int cnss_probe(struct platform_device *pdev) +{ + int ret = 0; + struct esoc_desc *desc; + const char *client_desc; + struct device *dev = &pdev->dev; + u32 rc_num; + struct resource *res; + u32 ramdump_size = 0; + u32 smmu_iova_address[2]; + u32 smmu_iova_ipa[2]; + + if (penv) + return -ENODEV; + + penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL); + if (!penv) + return -ENOMEM; + + penv->pldev = pdev; + penv->esoc_desc = NULL; + + penv->gpio_info.name = WLAN_EN_GPIO_NAME; + penv->gpio_info.num = 0; + penv->gpio_info.state = WLAN_EN_LOW; + penv->gpio_info.init = WLAN_EN_LOW; + penv->gpio_info.prop = false; + penv->vreg_info.wlan_reg = NULL; + penv->vreg_info.state = VREG_OFF; + penv->pci_register_again = false; + mutex_init(&penv->fw_setup_stat_lock); + + ret = cnss_wlan_get_resources(pdev); + if (ret) + goto err_get_wlan_res; + + ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + if (ret) { + pr_err("%s: Failed to enable WLAN enable gpio\n", __func__); + goto err_get_rc; + } + + ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num); + if (ret) { + pr_err("%s: Failed to find PCIe RC number\n", __func__); + goto err_get_rc; + } + + ret = cnss_msm_pcie_enumerate(rc_num); + if (ret) { + pr_err("%s: Failed to enable PCIe RC%x\n", __func__, rc_num); + goto err_pcie_enumerate; + } + + penv->pcie_link_state = PCIE_LINK_UP; + + penv->notify_modem_status = + of_property_read_bool(dev->of_node, + "qcom,notify-modem-status"); + + if (penv->notify_modem_status) { + ret = of_property_read_string_index(dev->of_node, "esoc-names", + 0, &client_desc); + if (ret) { + pr_debug("%s: esoc-names is not defined in DT, SKIP\n", + __func__); + } else { + desc = devm_register_esoc_client(dev, client_desc); + if (IS_ERR_OR_NULL(desc)) { + ret = PTR_RET(desc); + pr_err("%s: can't find esoc desc\n", __func__); + goto err_esoc_reg; + } + penv->esoc_desc = desc; + } + } + + penv->subsysdesc.name = "AR6320"; + penv->subsysdesc.owner = THIS_MODULE; + penv->subsysdesc.shutdown = cnss_shutdown; + penv->subsysdesc.powerup = cnss_powerup; + penv->subsysdesc.ramdump = cnss_ramdump; + penv->subsysdesc.crash_shutdown = cnss_crash_shutdown; + penv->subsysdesc.dev = &pdev->dev; + penv->subsys = subsys_register(&penv->subsysdesc); + if (IS_ERR(penv->subsys)) { + ret = PTR_ERR(penv->subsys); + goto err_subsys_reg; + } + + penv->subsys_handle = subsystem_get(penv->subsysdesc.name); + + if (of_property_read_bool(dev->of_node, "qcom,is-dual-wifi-enabled")) + penv->dual_wifi_info.is_dual_wifi_enabled = true; + + if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic", + &ramdump_size) == 0) { + penv->ramdump_addr = dma_alloc_coherent(&pdev->dev, + ramdump_size, + &penv->ramdump_phys, + GFP_KERNEL); + + if (penv->ramdump_addr) + penv->ramdump_size = ramdump_size; + penv->ramdump_dynamic = true; + } else { + res = platform_get_resource_byname(penv->pldev, + IORESOURCE_MEM, "ramdump"); + if (res) { + penv->ramdump_phys = res->start; + ramdump_size = resource_size(res); + penv->ramdump_addr = ioremap(penv->ramdump_phys, + ramdump_size); + + if (penv->ramdump_addr) + penv->ramdump_size = ramdump_size; + + penv->ramdump_dynamic = false; + } + } + + pr_debug("%s: ramdump addr: %p, phys: %pa\n", __func__, + penv->ramdump_addr, &penv->ramdump_phys); + + if (penv->ramdump_size == 0) { + pr_info("%s: CNSS ramdump will not be collected\n", __func__); + goto skip_ramdump; + } + + ret = cnss_init_dump_entry(); + if (ret) { + pr_err("%s: Dump table setup failed: %d\n", __func__, ret); + goto err_ramdump_create; + } + + penv->ramdump_dev = create_ramdump_device(penv->subsysdesc.name, + penv->subsysdesc.dev); + if (!penv->ramdump_dev) { + ret = -ENOMEM; + goto err_ramdump_create; + } + +skip_ramdump: + penv->modem_current_status = 0; + + if (penv->notify_modem_status) { + penv->modem_notify_handler = + subsys_notif_register_notifier(penv->esoc_desc ? + penv->esoc_desc->name : + "modem", &mnb); + if (IS_ERR(penv->modem_notify_handler)) { + ret = PTR_ERR(penv->modem_notify_handler); + pr_err("%s: Register notifier Failed\n", __func__); + goto err_notif_modem; + } + } + + if (of_property_read_u32_array(dev->of_node, + "qcom,wlan-smmu-iova-address", + smmu_iova_address, 2) == 0) { + penv->smmu_iova_start = smmu_iova_address[0]; + penv->smmu_iova_len = smmu_iova_address[1]; + } + + if (of_property_read_u32_array(dev->of_node, + "qcom,wlan-smmu-iova-ipa", + smmu_iova_ipa, 2) == 0) { + penv->smmu_iova_ipa_start = smmu_iova_ipa[0]; + penv->smmu_iova_ipa_len = smmu_iova_ipa[1]; + } + + if (of_property_read_bool(dev->of_node, + "qcom,smmu-s1-bypass")) + penv->smmu_s1_bypass = true; + + ret = pci_register_driver(&cnss_wlan_pci_driver); + if (ret) + goto err_pci_reg; + + penv->bus_scale_table = 0; + penv->bus_scale_table = msm_bus_cl_get_pdata(pdev); + + if (penv->bus_scale_table) { + penv->bus_client = + msm_bus_scale_register_client(penv->bus_scale_table); + + if (!penv->bus_client) { + pr_err("Failed to register with bus_scale client\n"); + goto err_bus_reg; + } + } + cnss_pm_wake_lock_init(&penv->ws, "cnss_wlock"); + + register_pm_notifier(&cnss_pm_notifier); + +#ifdef CONFIG_CNSS_MAC_BUG + /* 0-4K memory is reserved for QCA6174 to address a MAC HW bug. + * MAC would do an invalid pointer fetch based on the data + * that was read from 0 to 4K. So fill it with zero's (to an + * address for which PCIe RC honored the read without any errors). + */ + memset(phys_to_virt(0), 0, SZ_4K); +#endif + + ret = device_create_file(dev, &dev_attr_fw_image_setup); + if (ret) { + pr_err("cnss: fw_image_setup sys file creation failed\n"); + goto err_bus_reg; + } + pr_debug("cnss: Platform driver probed successfully.\n"); + return ret; + +err_bus_reg: + if (penv->bus_scale_table) + msm_bus_cl_clear_pdata(penv->bus_scale_table); + pci_unregister_driver(&cnss_wlan_pci_driver); + +err_pci_reg: + if (penv->notify_modem_status) + subsys_notif_unregister_notifier + (penv->modem_notify_handler, &mnb); + +err_notif_modem: + if (penv->ramdump_dev) + destroy_ramdump_device(penv->ramdump_dev); + +err_ramdump_create: + if (penv->ramdump_addr) { + if (penv->ramdump_dynamic) { + dma_free_coherent(&pdev->dev, penv->ramdump_size, + penv->ramdump_addr, + penv->ramdump_phys); + } else { + iounmap(penv->ramdump_addr); + } + } + + if (penv->subsys_handle) + subsystem_put(penv->subsys_handle); + + subsys_unregister(penv->subsys); + +err_subsys_reg: + if (penv->esoc_desc) + devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc); + +err_esoc_reg: +err_pcie_enumerate: +err_get_rc: + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_release_resources(); + +err_get_wlan_res: + penv = NULL; + + return ret; +} + +static int cnss_remove(struct platform_device *pdev) +{ + unregister_pm_notifier(&cnss_pm_notifier); + device_remove_file(&pdev->dev, &dev_attr_fw_image_setup); + + cnss_pm_wake_lock_destroy(&penv->ws); + + if (penv->bus_client) + msm_bus_scale_unregister_client(penv->bus_client); + + if (penv->bus_scale_table) + msm_bus_cl_clear_pdata(penv->bus_scale_table); + + if (penv->ramdump_addr) { + if (penv->ramdump_dynamic) { + dma_free_coherent(&pdev->dev, penv->ramdump_size, + penv->ramdump_addr, + penv->ramdump_phys); + } else { + iounmap(penv->ramdump_addr); + } + } + + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + if (penv->wlan_bootstrap_gpio > 0) + gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW); + cnss_wlan_release_resources(); + + return 0; +} + +static const struct of_device_id cnss_dt_match[] = { + {.compatible = "qcom,cnss"}, + {} +}; + +MODULE_DEVICE_TABLE(of, cnss_dt_match); + +static struct platform_driver cnss_driver = { + .probe = cnss_probe, + .remove = cnss_remove, + .driver = { + .name = "cnss", + .owner = THIS_MODULE, + .of_match_table = cnss_dt_match, +#ifdef CONFIG_CNSS_ASYNC + .probe_type = PROBE_PREFER_ASYNCHRONOUS, +#endif + }, +}; + +static int __init cnss_initialize(void) +{ + return platform_driver_register(&cnss_driver); +} + +static void __exit cnss_exit(void) +{ + struct platform_device *pdev = penv->pldev; + + if (penv->ramdump_dev) + destroy_ramdump_device(penv->ramdump_dev); + if (penv->notify_modem_status) + subsys_notif_unregister_notifier(penv->modem_notify_handler, + &mnb); + subsys_unregister(penv->subsys); + if (penv->esoc_desc) + devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc); + platform_driver_unregister(&cnss_driver); +} + +void cnss_request_pm_qos_type(int latency_type, u32 qos_val) +{ + if (!penv) { + pr_err("%s: penv is NULL\n", __func__); + return; + } + + pm_qos_add_request(&penv->qos_request, latency_type, qos_val); +} +EXPORT_SYMBOL(cnss_request_pm_qos_type); + +void cnss_request_pm_qos(u32 qos_val) +{ + if (!penv) { + pr_err("%s: penv is NULL\n", __func__); + return; + } + + pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val); +} +EXPORT_SYMBOL(cnss_request_pm_qos); + +void cnss_remove_pm_qos(void) +{ + if (!penv) { + pr_err("%s: penv is NULL\n", __func__); + return; + } + + pm_qos_remove_request(&penv->qos_request); +} +EXPORT_SYMBOL(cnss_remove_pm_qos); + +void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val) +{ + if (!penv) { + pr_err("%s: penv is NULL\n", __func__); + return; + } + + pm_qos_add_request(&penv->qos_request, latency_type, qos_val); +} +EXPORT_SYMBOL(cnss_pci_request_pm_qos_type); + +void cnss_pci_request_pm_qos(u32 qos_val) +{ + if (!penv) { + pr_err("%s: penv is NULL\n", __func__); + return; + } + + pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val); +} +EXPORT_SYMBOL(cnss_pci_request_pm_qos); + +void cnss_pci_remove_pm_qos(void) +{ + if (!penv) { + pr_err("%s: penv is NULL\n", __func__); + return; + } + + pm_qos_remove_request(&penv->qos_request); +} +EXPORT_SYMBOL(cnss_pci_remove_pm_qos); + +int cnss_pci_request_bus_bandwidth(int bandwidth) +{ + int ret = 0; + + if (!penv) + return -ENODEV; + + if (!penv->bus_client) + return -EINVAL; + + switch (bandwidth) { + case CNSS_BUS_WIDTH_NONE: + case CNSS_BUS_WIDTH_LOW: + case CNSS_BUS_WIDTH_MEDIUM: + case CNSS_BUS_WIDTH_HIGH: + ret = msm_bus_scale_client_update_request( + penv->bus_client, bandwidth); + if (!ret) { + penv->current_bandwidth_vote = bandwidth; + } else { + pr_err("%s: could not set bus bandwidth %d, ret = %d\n", + __func__, bandwidth, ret); + } + break; + + default: + pr_err("%s: Invalid request %d\n", __func__, bandwidth); + ret = -EINVAL; + } + return ret; +} + +int cnss_request_bus_bandwidth(int bandwidth) +{ + int ret = 0; + + if (!penv) + return -ENODEV; + + if (!penv->bus_client) + return -EINVAL; + + switch (bandwidth) { + case CNSS_BUS_WIDTH_NONE: + case CNSS_BUS_WIDTH_LOW: + case CNSS_BUS_WIDTH_MEDIUM: + case CNSS_BUS_WIDTH_HIGH: + ret = msm_bus_scale_client_update_request( + penv->bus_client, bandwidth); + if (!ret) { + penv->current_bandwidth_vote = bandwidth; + } else { + pr_err("%s: could not set bus bandwidth %d, ret = %d\n", + __func__, bandwidth, ret); + } + break; + + default: + pr_err("%s: Invalid request %d\n", __func__, bandwidth); + ret = -EINVAL; + } + return ret; +} +EXPORT_SYMBOL(cnss_request_bus_bandwidth); + +int cnss_get_platform_cap(struct cnss_platform_cap *cap) +{ + if (!penv) + return -ENODEV; + + if (cap) + *cap = penv->cap; + + return 0; +} +EXPORT_SYMBOL(cnss_get_platform_cap); + +void cnss_set_driver_status(enum cnss_driver_status driver_status) +{ + penv->driver_status = driver_status; +} +EXPORT_SYMBOL(cnss_set_driver_status); + +int cnss_get_bmi_setup(void) +{ + if (!penv) + return -ENODEV; + + return penv->bmi_test; +} +EXPORT_SYMBOL(cnss_get_bmi_setup); + +#ifdef CONFIG_CNSS_SECURE_FW +int cnss_get_sha_hash(const u8 *data, u32 data_len, u8 *hash_idx, u8 *out) +{ + struct scatterlist sg; + struct hash_desc desc; + int ret = 0; + + if (!out) { + pr_err("memory for output buffer is not allocated\n"); + ret = -EINVAL; + goto end; + } + + desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + desc.tfm = crypto_alloc_hash(hash_idx, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(desc.tfm)) { + pr_err("crypto_alloc_hash failed:%ld\n", PTR_ERR(desc.tfm)); + ret = PTR_ERR(desc.tfm); + goto end; + } + + sg_init_one(&sg, data, data_len); + ret = crypto_hash_digest(&desc, &sg, sg.length, out); + crypto_free_hash(desc.tfm); +end: + return ret; +} +EXPORT_SYMBOL(cnss_get_sha_hash); + +void *cnss_get_fw_ptr(void) +{ + if (!penv) + return NULL; + + return penv->fw_mem; +} +EXPORT_SYMBOL(cnss_get_fw_ptr); +#endif + +int cnss_auto_suspend(void) +{ + int ret = 0; + struct pci_dev *pdev; + + if (!penv || !penv->driver) + return -ENODEV; + + pdev = penv->pdev; + + if (penv->pcie_link_state) { + pci_save_state(pdev); + penv->saved_state = cnss_pci_store_saved_state(pdev); + pci_disable_device(pdev); + ret = pci_set_power_state(pdev, PCI_D3hot); + if (ret) + pr_err("%s: Set D3Hot failed: %d\n", __func__, ret); + if (cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, + cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS)) { + pr_err("%s: Failed to shutdown PCIe link\n", __func__); + ret = -EAGAIN; + goto out; + } + } + atomic_set(&penv->auto_suspended, 1); + penv->monitor_wake_intr = true; + penv->pcie_link_state = PCIE_LINK_DOWN; + + msm_bus_scale_client_update_request(penv->bus_client, + CNSS_BUS_WIDTH_NONE); +out: + return ret; +} +EXPORT_SYMBOL(cnss_auto_suspend); + +int cnss_auto_resume(void) +{ + int ret = 0; + struct pci_dev *pdev; + + if (!penv || !penv->driver) + return -ENODEV; + + pdev = penv->pdev; + if (!penv->pcie_link_state) { + if (cnss_msm_pcie_pm_control( + MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS)) { + pr_err("%s: Failed to resume PCIe link\n", __func__); + ret = -EAGAIN; + goto out; + } + ret = pci_enable_device(pdev); + if (ret) + pr_err("%s: enable device failed: %d\n", __func__, ret); + penv->pcie_link_state = PCIE_LINK_UP; + } + + if (penv->saved_state) + cnss_pci_load_and_free_saved_state(pdev, &penv->saved_state); + + pci_restore_state(pdev); + pci_set_master(pdev); + + atomic_set(&penv->auto_suspended, 0); + + msm_bus_scale_client_update_request(penv->bus_client, + penv->current_bandwidth_vote); +out: + return ret; +} +EXPORT_SYMBOL(cnss_auto_resume); + +int cnss_pm_runtime_request(struct device *dev, + enum cnss_runtime_request request) +{ + int ret = 0; + + switch (request) { + case CNSS_PM_RUNTIME_GET: + ret = pm_runtime_get(dev); + break; + case CNSS_PM_RUNTIME_PUT: + ret = pm_runtime_put(dev); + break; + case CNSS_PM_RUNTIME_MARK_LAST_BUSY: + pm_runtime_mark_last_busy(dev); + break; + case CNSS_PM_RUNTIME_RESUME: + ret = pm_runtime_resume(dev); + break; + case CNSS_PM_RUNTIME_PUT_AUTO: + ret = pm_runtime_put_autosuspend(dev); + break; + case CNSS_PM_RUNTIME_PUT_NOIDLE: + pm_runtime_put_noidle(dev); + break; + case CNSS_PM_REQUEST_RESUME: + ret = pm_request_resume(dev); + break; + case CNSS_PM_GET_NORESUME: + pm_runtime_get_noresume(dev); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL(cnss_pm_runtime_request); + +void cnss_runtime_init(struct device *dev, int auto_delay) +{ + pm_runtime_set_autosuspend_delay(dev, auto_delay); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_noidle(dev); + pm_suspend_ignore_children(dev, true); +} +EXPORT_SYMBOL(cnss_runtime_init); + +void cnss_runtime_exit(struct device *dev) +{ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); +} +EXPORT_SYMBOL(cnss_runtime_exit); + +static void __cnss_set_pcie_monitor_intr(struct device *dev, bool val) +{ + penv->monitor_wake_intr = val; +} + +static void __cnss_set_auto_suspend(struct device *dev, int val) +{ + atomic_set(&penv->auto_suspended, val); +} + +static int __cnss_resume_link(struct device *dev, u32 flags) +{ + int ret; + struct pci_dev *pdev = to_pci_dev(dev); + u8 bus_num = cnss_get_pci_dev_bus_number(pdev); + + ret = cnss_msm_pcie_pm_control(MSM_PCIE_RESUME, bus_num, pdev, flags); + if (ret) + pr_err("%s: PCIe link resume failed with flags:%d bus_num:%d\n", + __func__, flags, bus_num); + + penv->pcie_link_state = PCIE_LINK_UP; + + return ret; +} + +static int __cnss_suspend_link(struct device *dev, u32 flags) +{ + struct pci_dev *pdev = to_pci_dev(dev); + u8 bus_num = cnss_get_pci_dev_bus_number(pdev); + int ret; + + if (!penv->pcie_link_state) + return 0; + + ret = cnss_msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus_num, pdev, flags); + if (ret) { + pr_err("%s: Failed to suspend link\n", __func__); + return ret; + } + + penv->pcie_link_state = PCIE_LINK_DOWN; + + return ret; +} + +static int __cnss_pcie_recover_config(struct device *dev) +{ + int ret; + + ret = cnss_msm_pcie_recover_config(to_pci_dev(dev)); + if (ret) + pr_err("%s: PCIe Recover config failed\n", __func__); + + return ret; +} + +static int __cnss_event_reg(struct device *dev) +{ + int ret; + struct msm_pcie_register_event *event_reg; + + event_reg = &penv->event_reg; + + event_reg->events = MSM_PCIE_EVENT_LINKDOWN | + MSM_PCIE_EVENT_WAKEUP; + event_reg->user = to_pci_dev(dev); + event_reg->mode = MSM_PCIE_TRIGGER_CALLBACK; + event_reg->callback = cnss_pci_events_cb; + event_reg->options = MSM_PCIE_CONFIG_NO_RECOVERY; + + ret = cnss_msm_pcie_register_event(event_reg); + if (ret) + pr_err("%s: PCIe event register failed %d\n", __func__, ret); + + return ret; +} + +static void __cnss_event_dereg(struct device *dev) +{ + cnss_msm_pcie_deregister_event(&penv->event_reg); +} + +static struct pci_dev *__cnss_get_pcie_dev(struct device *dev) +{ + int ret; + struct pci_dev *pdev = penv->pdev; + + if (pdev) + return pdev; + + ret = pci_register_driver(&cnss_wlan_pci_driver); + if (ret) { + pr_err("%s: pci re-registration failed\n", __func__); + return NULL; + } + + pdev = penv->pdev; + + return pdev; +} + +static int __cnss_pcie_power_up(struct device *dev) +{ + struct cnss_wlan_vreg_info *vreg_info; + struct cnss_wlan_gpio_info *gpio_info; + int ret; + + vreg_info = &penv->vreg_info; + gpio_info = &penv->gpio_info; + + ret = cnss_wlan_vreg_set(vreg_info, VREG_ON); + if (ret) { + pr_err("%s: WLAN VREG ON Failed\n", __func__); + return ret; + } + + msleep(POWER_ON_DELAY); + + if (penv->wlan_bootstrap_gpio > 0) { + gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH); + msleep(WLAN_BOOTSTRAP_DELAY); + } + + cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + return 0; +} + +static int __cnss_pcie_power_down(struct device *dev) +{ + struct cnss_wlan_vreg_info *vreg_info; + struct cnss_wlan_gpio_info *gpio_info; + int ret; + + vreg_info = &penv->vreg_info; + gpio_info = &penv->gpio_info; + + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + if (penv->wlan_bootstrap_gpio > 0) + gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW); + + ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF); + if (ret) + pr_err("%s: Failed to turn off 3.3V regulator\n", __func__); + + return ret; +} + +static int __cnss_suspend_link_state(struct device *dev) +{ + int ret; + struct pci_dev *pdev = to_pci_dev(dev); + int link_ind; + + if (!penv->pcie_link_state) { + pr_debug("%s: Link is already suspended\n", __func__); + return 0; + } + + link_ind = penv->pcie_link_down_ind; + + if (!link_ind) + pci_save_state(pdev); + + penv->saved_state = link_ind ? NULL : cnss_pci_store_saved_state(pdev); + + ret = link_ind ? __cnss_suspend_link(dev, PM_OPTIONS_SUSPEND_LINK_DOWN) + : __cnss_suspend_link(dev, PM_OPTIONS); + if (ret) { + pr_err("%s: Link Suspend failed in state:%s\n", __func__, + link_ind ? "LINK_DOWN" : "LINK_ACTIVE"); + return ret; + } + + penv->pcie_link_state = PCIE_LINK_DOWN; + + return 0; +} + +static int __cnss_restore_pci_config_space(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret = 0; + + if (penv->saved_state) + ret = cnss_pci_load_and_free_saved_state(pdev, + &penv->saved_state); + pci_restore_state(pdev); + + return ret; +} + +static int __cnss_resume_link_state(struct device *dev) +{ + int ret; + int link_ind; + + if (penv->pcie_link_state) { + pr_debug("%s: Link is already in active state\n", __func__); + return 0; + } + + link_ind = penv->pcie_link_down_ind; + + ret = link_ind ? __cnss_resume_link(dev, PM_OPTIONS_RESUME_LINK_DOWN) : + __cnss_resume_link(dev, PM_OPTIONS); + + if (ret) { + pr_err("%s: Resume Link failed in link state:%s\n", __func__, + link_ind ? "LINK_DOWN" : "LINK_ACTIVE"); + return ret; + } + + penv->pcie_link_state = PCIE_LINK_UP; + + ret = link_ind ? __cnss_pcie_recover_config(dev) : + __cnss_restore_pci_config_space(dev); + + if (ret) { + pr_err("%s: Link Recovery Config Failed link_state:%s\n", + __func__, link_ind ? "LINK_DOWN" : "LINK_ACTIVE"); + penv->pcie_link_state = PCIE_LINK_DOWN; + return ret; + } + + penv->pcie_link_down_ind = false; + return ret; +} + +int cnss_pcie_power_up(struct device *dev) +{ + int ret; + struct pci_dev *pdev; + + if (!penv) { + pr_err("%s: platform data is NULL\n", __func__); + return -ENODEV; + } + + ret = __cnss_pcie_power_up(dev); + if (ret) { + pr_err("%s: Power UP Failed\n", __func__); + return ret; + } + + pdev = __cnss_get_pcie_dev(dev); + if (!pdev) { + pr_err("%s: PCIe Dev is NULL\n", __func__); + goto power_down; + } + + ret = __cnss_event_reg(dev); + + if (ret) + pr_err("%s: PCIe event registration failed\n", __func__); + + ret = __cnss_resume_link_state(dev); + + if (ret) { + pr_err("%s: Link Bring Up Failed\n", __func__); + goto event_dereg; + } + + __cnss_set_pcie_monitor_intr(dev, true); + + return ret; + +event_dereg: + __cnss_event_dereg(dev); +power_down: + __cnss_pcie_power_down(dev); + pr_err("%s: Device Power Up Failed Fatal Error\n", __func__); + return ret; +} + +static void __cnss_vote_bus_width(struct device *dev, u32 option) +{ + if (penv->bus_client) + msm_bus_scale_client_update_request(penv->bus_client, option); +} + +int cnss_pcie_power_down(struct device *dev) +{ + int ret; + struct pci_dev *pdev = to_pci_dev(dev); + + if (!penv) { + pr_err("%s: Invalid Platform data\n", __func__); + return -ENODEV; + } + + if (!pdev) { + pr_err("%s: Invalid Pdev, Cut Power to device\n", __func__); + __cnss_pcie_power_down(dev); + return -ENODEV; + } + + __cnss_vote_bus_width(dev, CNSS_BUS_WIDTH_NONE); + __cnss_event_dereg(dev); + + ret = __cnss_suspend_link_state(dev); + + if (ret) { + pr_err("%s: Suspend Link failed\n", __func__); + return ret; + } + + __cnss_set_pcie_monitor_intr(dev, false); + __cnss_set_auto_suspend(dev, 0); + + ret = __cnss_pcie_power_down(dev); + if (ret) + pr_err("%s: Power Down Failed\n", __func__); + + return ret; +} + +module_init(cnss_initialize); +module_exit(cnss_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DEVICE "CNSS Driver"); diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..dd1819271962da93ef22d18062e345bb205dcc12 --- /dev/null +++ b/drivers/net/wireless/cnss/cnss_sdio.c @@ -0,0 +1,1607 @@ +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * + * This 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) "cnss_sdio:%s:%d:: " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cnss_common.h" +#include +#include +#include +#include +#include + +#define WLAN_VREG_NAME "vdd-wlan" +#define WLAN_VREG_DSRC_NAME "vdd-wlan-dsrc" +#define WLAN_VREG_IO_NAME "vdd-wlan-io" +#define WLAN_VREG_XTAL_NAME "vdd-wlan-xtal" +#define WLAN_GPIO_CAPTSF_NAME "qcom,cap-tsf-gpio" + +#define WLAN_VREG_IO_MAX 1800000 +#define WLAN_VREG_IO_MIN 1800000 +#define WLAN_VREG_XTAL_MAX 3465000 +#define WLAN_VREG_XTAL_MIN 1620000 +#define WLAN_VREG_XTAL_TYP 1800000 +#define POWER_ON_DELAY 4 + +/* Values for Dynamic Ramdump Collection*/ +#define CNSS_DUMP_FORMAT_VER 0x11 +#define CNSS_DUMP_MAGIC_VER_V2 0x42445953 +#define CNSS_DUMP_NAME "CNSS_WLAN_SDIO" +#define CNSS_PINCTRL_SLEEP_STATE "sleep" +#define CNSS_PINCTRL_ACTIVE_STATE "active" + +#define CNSS_HW_SLEEP 0 +#define CNSS_HW_ACTIVE 1 + +struct cnss_sdio_regulator { + struct regulator *wlan_io; + struct regulator *wlan_xtal; + struct regulator *wlan_vreg; + struct regulator *wlan_vreg_dsrc; +}; + +struct cnss_sdio_info { + struct cnss_sdio_wlan_driver *wdrv; + struct sdio_func *func; + struct mmc_card *card; + struct mmc_host *host; + struct device *dev; + const struct sdio_device_id *id; + bool skip_wlan_en_toggle; + bool cnss_hw_state; + struct cnss_cap_tsf_info cap_tsf_info; +}; + +struct cnss_ssr_info { + struct subsys_device *subsys; + struct subsys_desc subsysdesc; + void *subsys_handle; + struct ramdump_device *ramdump_dev; + unsigned long ramdump_size; + void *ramdump_addr; + phys_addr_t ramdump_phys; + struct msm_dump_data dump_data; + bool ramdump_dynamic; + char subsys_name[10]; +}; + +struct cnss_wlan_pinctrl_info { + bool is_antenna_shared; + struct pinctrl *pinctrl; + struct pinctrl_state *sleep; + struct pinctrl_state *active; +}; + +struct cnss_sdio_bus_bandwidth { + struct msm_bus_scale_pdata *bus_scale_table; + u32 bus_client; + int current_bandwidth_vote; +}; + +static struct cnss_sdio_data { + struct cnss_sdio_regulator regulator; + struct platform_device *pdev; + struct cnss_sdio_info cnss_sdio_info; + struct cnss_ssr_info ssr_info; + struct pm_qos_request qos_request; + struct cnss_wlan_pinctrl_info pinctrl_info; + struct cnss_sdio_bus_bandwidth bus_bandwidth; + struct cnss_dev_platform_ops platform_ops; +} *cnss_pdata; + +#define WLAN_RECOVERY_DELAY 1 +/* cnss sdio subsytem device name, required property */ +#define CNSS_SUBSYS_NAME_KEY "subsys-name" + +/* SDIO manufacturer ID and Codes */ +#define MANUFACTURER_ID_AR6320_BASE 0x500 +#define MANUFACTURER_ID_QCA9377_BASE 0x700 +#define MANUFACTURER_ID_QCA9379_BASE 0x800 +#define MANUFACTURER_CODE 0x271 + +static const struct sdio_device_id ar6k_id_table[] = { + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xF))}, + {}, +}; +MODULE_DEVICE_TABLE(sdio, ar6k_id_table); + +void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val) +{ + if (!cnss_pdata) + return; + + pr_debug("PM QoS value: %d\n", qos_val); + pm_qos_add_request(&cnss_pdata->qos_request, latency_type, qos_val); +} +EXPORT_SYMBOL(cnss_sdio_request_pm_qos_type); + +int cnss_sdio_request_bus_bandwidth(int bandwidth) +{ + int ret; + struct cnss_sdio_bus_bandwidth *bus_bandwidth; + + if (!cnss_pdata) + return -ENODEV; + + bus_bandwidth = &cnss_pdata->bus_bandwidth; + if (!bus_bandwidth->bus_client) + return -EINVAL; + + switch (bandwidth) { + case CNSS_BUS_WIDTH_NONE: + case CNSS_BUS_WIDTH_LOW: + case CNSS_BUS_WIDTH_MEDIUM: + case CNSS_BUS_WIDTH_HIGH: + ret = msm_bus_scale_client_update_request( + bus_bandwidth->bus_client, bandwidth); + if (!ret) { + bus_bandwidth->current_bandwidth_vote = bandwidth; + } else { + pr_debug( + "could not set bus bandwidth %d, ret = %d\n", + bandwidth, ret); + } + break; + default: + pr_debug("Invalid request %d\n", bandwidth); + ret = -EINVAL; + } + + return ret; +} + +void cnss_sdio_request_pm_qos(u32 qos_val) +{ + if (!cnss_pdata) + return; + + pr_debug("PM QoS value: %d\n", qos_val); + pm_qos_add_request( + &cnss_pdata->qos_request, + PM_QOS_CPU_DMA_LATENCY, qos_val); +} +EXPORT_SYMBOL(cnss_sdio_request_pm_qos); + +void cnss_sdio_remove_pm_qos(void) +{ + if (!cnss_pdata) + return; + + pm_qos_remove_request(&cnss_pdata->qos_request); + pr_debug("PM QoS removed\n"); +} +EXPORT_SYMBOL(cnss_sdio_remove_pm_qos); + +static int cnss_put_hw_resources(struct device *dev) +{ + int ret = -EINVAL; + struct cnss_sdio_info *info; + struct mmc_host *host; + + if (!cnss_pdata) + return ret; + + info = &cnss_pdata->cnss_sdio_info; + + if (info->skip_wlan_en_toggle) { + pr_debug("HW doesn't support wlan toggling\n"); + return 0; + } + + if (info->cnss_hw_state == CNSS_HW_SLEEP) { + pr_debug("HW resources are already released\n"); + return 0; + } + + host = info->host; + + if (!host) { + pr_err("MMC host is invalid\n"); + return ret; + } + + ret = mmc_power_save_host(host); + if (ret) { + pr_err("Failed to Power Save Host err:%d\n", + ret); + return ret; + } + + if (cnss_pdata->regulator.wlan_vreg) + regulator_disable(cnss_pdata->regulator.wlan_vreg); + else + pr_debug("wlan_vreg regulator is invalid\n"); + + info->cnss_hw_state = CNSS_HW_SLEEP; + + return ret; +} + +static int cnss_get_hw_resources(struct device *dev) +{ + int ret = -EINVAL; + struct mmc_host *host; + struct cnss_sdio_info *info; + + if (!cnss_pdata) + return ret; + + info = &cnss_pdata->cnss_sdio_info; + + if (info->skip_wlan_en_toggle) { + pr_debug("HW doesn't support wlan toggling\n"); + return 0; + } + + if (info->cnss_hw_state == CNSS_HW_ACTIVE) { + pr_debug("HW resources are already active\n"); + return 0; + } + + host = info->host; + + if (!host) { + pr_err("MMC Host is Invalid; Enumeration Failed\n"); + return ret; + } + + if (cnss_pdata->regulator.wlan_vreg) { + ret = regulator_enable(cnss_pdata->regulator.wlan_vreg); + if (ret) { + pr_err("Failed to enable wlan vreg\n"); + return ret; + } + } else { + pr_debug("wlan_vreg regulator is invalid\n"); + } + + ret = mmc_power_restore_host(host); + if (ret) { + pr_err("Failed to restore host power ret:%d\n", + ret); + if (cnss_pdata->regulator.wlan_vreg) + regulator_disable(cnss_pdata->regulator.wlan_vreg); + return ret; + } + + info->cnss_hw_state = CNSS_HW_ACTIVE; + return ret; +} + +static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop) +{ + struct cnss_sdio_info *cnss_info; + struct cnss_sdio_wlan_driver *wdrv; + int ret = 0; + + if (!cnss_pdata) + return -ENODEV; + + cnss_info = &cnss_pdata->cnss_sdio_info; + wdrv = cnss_info->wdrv; + if (!wdrv) + return 0; + if (!wdrv->shutdown) + return 0; + + wdrv->shutdown(cnss_info->func); + ret = cnss_put_hw_resources(cnss_info->dev); + + if (ret) + pr_err("Failed to put hw resources\n"); + + return ret; +} + +static int cnss_sdio_powerup(const struct subsys_desc *subsys) +{ + struct cnss_sdio_info *cnss_info; + struct cnss_sdio_wlan_driver *wdrv; + int ret = 0; + + if (!cnss_pdata) + return -ENODEV; + + cnss_info = &cnss_pdata->cnss_sdio_info; + wdrv = cnss_info->wdrv; + + if (!wdrv) + return 0; + + if (!wdrv->reinit) + return 0; + + ret = cnss_get_hw_resources(cnss_info->dev); + if (ret) { + pr_err("Failed to power up HW\n"); + return ret; + } + + ret = wdrv->reinit(cnss_info->func, cnss_info->id); + if (ret) + pr_err("wlan reinit error=%d\n", ret); + + return ret; +} + +static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys) +{ + struct cnss_sdio_info *cnss_info; + struct cnss_sdio_wlan_driver *wdrv; + + if (!cnss_pdata) + return; + + cnss_info = &cnss_pdata->cnss_sdio_info; + wdrv = cnss_info->wdrv; + if (wdrv && wdrv->crash_shutdown) + wdrv->crash_shutdown(cnss_info->func); +} + +static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys) +{ + struct cnss_ssr_info *ssr_info; + struct ramdump_segment segment; + int ret; + + if (!cnss_pdata) + return -ENODEV; + + if (!cnss_pdata->ssr_info.ramdump_size) + return -ENOENT; + + if (!enable) + return 0; + + ssr_info = &cnss_pdata->ssr_info; + + memset(&segment, 0, sizeof(segment)); + segment.v_address = ssr_info->ramdump_addr; + segment.size = ssr_info->ramdump_size; + ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1); + if (ret) + pr_err("do_ramdump failed error=%d\n", ret); + return ret; +} + +static int cnss_subsys_init(void) +{ + struct cnss_ssr_info *ssr_info; + int ret = 0; + + if (!cnss_pdata) + return -ENODEV; + + ssr_info = &cnss_pdata->ssr_info; + ssr_info->subsysdesc.name = ssr_info->subsys_name; + ssr_info->subsysdesc.owner = THIS_MODULE; + ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown; + ssr_info->subsysdesc.powerup = cnss_sdio_powerup; + ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump; + ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown; + ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev; + ssr_info->subsys = subsys_register(&ssr_info->subsysdesc); + if (IS_ERR(ssr_info->subsys)) { + ret = PTR_ERR(ssr_info->subsys); + ssr_info->subsys = NULL; + dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n", + ret); + goto err_subsys_reg; + } + ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name); + if (IS_ERR(ssr_info->subsys_handle)) { + ret = PTR_ERR(ssr_info->subsys_handle); + ssr_info->subsys_handle = NULL; + dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n", + ret); + goto err_subsys_get; + } + return 0; +err_subsys_get: + subsys_unregister(ssr_info->subsys); + ssr_info->subsys = NULL; +err_subsys_reg: + return ret; +} + +static void cnss_subsys_exit(void) +{ + struct cnss_ssr_info *ssr_info; + + if (!cnss_pdata) + return; + + ssr_info = &cnss_pdata->ssr_info; + if (ssr_info->subsys_handle) + subsystem_put(ssr_info->subsys_handle); + ssr_info->subsys_handle = NULL; + if (ssr_info->subsys) + subsys_unregister(ssr_info->subsys); + ssr_info->subsys = NULL; +} + +static int cnss_configure_dump_table(struct cnss_ssr_info *ssr_info) +{ + struct msm_dump_entry dump_entry; + int ret; + + ssr_info->dump_data.addr = ssr_info->ramdump_phys; + ssr_info->dump_data.len = ssr_info->ramdump_size; + ssr_info->dump_data.version = CNSS_DUMP_FORMAT_VER; + ssr_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2; + strlcpy(ssr_info->dump_data.name, CNSS_DUMP_NAME, + sizeof(ssr_info->dump_data.name)); + + dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN; + dump_entry.addr = virt_to_phys(&ssr_info->dump_data); + + ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); + if (ret) + pr_err("Dump table setup failed: %d\n", ret); + + return ret; +} + +static int cnss_configure_ramdump(void) +{ + struct cnss_ssr_info *ssr_info; + int ret = 0; + struct resource *res; + const char *name; + u32 ramdump_size = 0; + struct device *dev; + + if (!cnss_pdata) + return -ENODEV; + + dev = &cnss_pdata->pdev->dev; + + ssr_info = &cnss_pdata->ssr_info; + + ret = of_property_read_string(dev->of_node, CNSS_SUBSYS_NAME_KEY, + &name); + if (ret) { + pr_err("cnss missing DT key '%s'\n", + CNSS_SUBSYS_NAME_KEY); + ret = -ENODEV; + goto err_subsys_name_query; + } + + strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name)); + + if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic", + &ramdump_size) == 0) { + ssr_info->ramdump_addr = + dma_alloc_coherent(dev, ramdump_size, + &ssr_info->ramdump_phys, + GFP_KERNEL); + if (ssr_info->ramdump_addr) + ssr_info->ramdump_size = ramdump_size; + ssr_info->ramdump_dynamic = true; + } else { + res = platform_get_resource_byname(cnss_pdata->pdev, + IORESOURCE_MEM, "ramdump"); + if (res) { + ssr_info->ramdump_phys = res->start; + ramdump_size = resource_size(res); + ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys, + ramdump_size); + if (ssr_info->ramdump_addr) + ssr_info->ramdump_size = ramdump_size; + ssr_info->ramdump_dynamic = false; + } + } + + pr_info("ramdump addr: %p, phys: %pa subsys:'%s'\n", + ssr_info->ramdump_addr, &ssr_info->ramdump_phys, + ssr_info->subsys_name); + + if (ssr_info->ramdump_size == 0) { + pr_info("CNSS ramdump will not be collected\n"); + return 0; + } + + if (ssr_info->ramdump_dynamic) { + ret = cnss_configure_dump_table(ssr_info); + if (ret) + goto err_configure_dump_table; + } + + ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name, + dev); + if (!ssr_info->ramdump_dev) { + ret = -ENOMEM; + pr_err("ramdump dev create failed: error=%d\n", + ret); + goto err_configure_dump_table; + } + + return 0; + +err_configure_dump_table: + if (ssr_info->ramdump_dynamic) + dma_free_coherent(dev, ssr_info->ramdump_size, + ssr_info->ramdump_addr, + ssr_info->ramdump_phys); + else + iounmap(ssr_info->ramdump_addr); + + ssr_info->ramdump_addr = NULL; + ssr_info->ramdump_size = 0; +err_subsys_name_query: + return ret; +} + +static void cnss_ramdump_cleanup(void) +{ + struct cnss_ssr_info *ssr_info; + struct device *dev; + + if (!cnss_pdata) + return; + + dev = &cnss_pdata->pdev->dev; + ssr_info = &cnss_pdata->ssr_info; + if (ssr_info->ramdump_addr) { + if (ssr_info->ramdump_dynamic) + dma_free_coherent(dev, ssr_info->ramdump_size, + ssr_info->ramdump_addr, + ssr_info->ramdump_phys); + else + iounmap(ssr_info->ramdump_addr); + } + + ssr_info->ramdump_addr = NULL; + if (ssr_info->ramdump_dev) + destroy_ramdump_device(ssr_info->ramdump_dev); + ssr_info->ramdump_dev = NULL; +} + +void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size) +{ + if (!cnss_pdata || !cnss_pdata->pdev) + return NULL; + + *size = cnss_pdata->ssr_info.ramdump_size; + + return cnss_pdata->ssr_info.ramdump_addr; +} + +void cnss_sdio_device_self_recovery(void) +{ + cnss_sdio_shutdown(NULL, false); + msleep(WLAN_RECOVERY_DELAY); + cnss_sdio_powerup(NULL); +} + +void cnss_sdio_device_crashed(void) +{ + struct cnss_ssr_info *ssr_info; + + if (!cnss_pdata) + return; + ssr_info = &cnss_pdata->ssr_info; + if (ssr_info->subsys) { + subsys_set_crash_status(ssr_info->subsys, true); + subsystem_restart_dev(ssr_info->subsys); + } +} + +static void cnss_sdio_recovery_work_handler(struct work_struct *recovery) +{ + cnss_sdio_device_self_recovery(); +} + +DECLARE_WORK(cnss_sdio_recovery_work, cnss_sdio_recovery_work_handler); + +void cnss_sdio_schedule_recovery_work(void) +{ + schedule_work(&cnss_sdio_recovery_work); +} + +/** + * cnss_get_restart_level() - cnss get restart level API + * + * Wlan sdio function driver uses this API to get the current + * subsystem restart level. + * + * Return: CNSS_RESET_SOC - "SYSTEM", restart system + * CNSS_RESET_SUBSYS_COUPLED - "RELATED",restart subsystem + */ +int cnss_get_restart_level(void) +{ + struct cnss_ssr_info *ssr_info; + int level; + + if (!cnss_pdata) + return CNSS_RESET_SOC; + ssr_info = &cnss_pdata->ssr_info; + if (!ssr_info->subsys) + return CNSS_RESET_SOC; + level = subsys_get_restart_level(ssr_info->subsys); + switch (level) { + case RESET_SOC: + return CNSS_RESET_SOC; + case RESET_SUBSYS_COUPLED: + return CNSS_RESET_SUBSYS_COUPLED; + default: + return CNSS_RESET_SOC; + } +} +EXPORT_SYMBOL(cnss_get_restart_level); + +static inline int cnss_get_tsf_cap_irq(struct device *dev) +{ + int irq = -EINVAL; + int gpio; + + if (!dev) + return -ENODEV; + + gpio = of_get_named_gpio(dev->of_node, WLAN_GPIO_CAPTSF_NAME, 0); + if (gpio >= 0) + irq = gpio_to_irq(gpio); + + return irq; +} + +static int cnss_sdio_register_tsf_captured_handler(irq_handler_t handler, + void *ctx) +{ + struct cnss_cap_tsf_info *tsf_info; + + if (!cnss_pdata) + return -ENODEV; + + tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info; + if (tsf_info->irq_num < 0) + return -ENOTSUPP; + + tsf_info->irq_handler = handler; + tsf_info->context = ctx; + return 0; +} + +static int cnss_sdio_unregister_tsf_captured_handler(void *ctx) +{ + struct cnss_cap_tsf_info *tsf_info; + + if (!cnss_pdata) + return -ENODEV; + + tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info; + if (tsf_info->irq_num < 0) + return -ENOTSUPP; + + if (ctx == tsf_info->context) { + tsf_info->irq_handler = NULL; + tsf_info->context = NULL; + } + return 0; +} + +static irqreturn_t cnss_sdio_tsf_captured_handler(int irq, void *ctx) +{ + struct cnss_cap_tsf_info *tsf_info; + + if (!cnss_pdata) + return IRQ_HANDLED; + + tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info; + if (tsf_info->irq_num < 0 || tsf_info->irq_num != irq || + !tsf_info->irq_handler || !tsf_info->context) + return IRQ_HANDLED; + + return tsf_info->irq_handler(irq, tsf_info->context); +} + +static void cnss_sdio_tsf_init(struct device *dev, + struct cnss_cap_tsf_info *tsf_info) +{ + int ret, irq; + + tsf_info->irq_num = -EINVAL; + tsf_info->irq_handler = NULL; + tsf_info->context = NULL; + + irq = cnss_get_tsf_cap_irq(dev); + if (irq < 0) { + dev_err(dev, "%s: fail to get irq: %d\n", __func__, irq); + return; + } + + ret = request_irq(irq, cnss_sdio_tsf_captured_handler, + IRQF_SHARED | IRQF_TRIGGER_RISING, dev_name(dev), + (void *)tsf_info); + dev_err(dev, "%s: request irq[%d] for dev: %s, result: %d\n", + __func__, irq, dev_name(dev), ret); + if (!ret) + tsf_info->irq_num = irq; +} + +static void cnss_sdio_tsf_deinit(struct cnss_cap_tsf_info *tsf_info) +{ + int irq = tsf_info->irq_num; + + if (irq < 0) + return; + + free_irq(irq, (void *)tsf_info); + + tsf_info->irq_num = -EINVAL; + tsf_info->irq_handler = NULL; + tsf_info->context = NULL; +} + +static void cnss_sdio_set_platform_ops(struct device *dev) +{ + struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops; + + pf_ops->power_up = cnss_sdio_power_up; + pf_ops->power_down = cnss_sdio_power_down; + pf_ops->device_crashed = cnss_sdio_device_crashed; + pf_ops->get_virt_ramdump_mem = cnss_sdio_get_virt_ramdump_mem; + pf_ops->device_self_recovery = cnss_sdio_device_self_recovery; + pf_ops->get_wlan_mac_address = cnss_sdio_get_wlan_mac_address; + pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address; + pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work; + pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth; + pf_ops->register_tsf_captured_handler = + cnss_sdio_register_tsf_captured_handler; + pf_ops->unregister_tsf_captured_handler = + cnss_sdio_unregister_tsf_captured_handler; + dev->platform_data = pf_ops; +} + +static int cnss_sdio_wlan_inserted(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct cnss_sdio_info *info; + + if (!cnss_pdata) + return -ENODEV; + + info = &cnss_pdata->cnss_sdio_info; + + info->func = func; + info->card = func->card; + info->host = func->card->host; + info->id = id; + info->dev = &func->dev; + cnss_sdio_set_platform_ops(info->dev); + + cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev); + + pr_info("SDIO Device is Probed\n"); + return 0; +} + +static void cnss_sdio_wlan_removed(struct sdio_func *func) +{ + struct cnss_sdio_info *info; + + if (!cnss_pdata) + return; + + info = &cnss_pdata->cnss_sdio_info; + + info->host = NULL; + info->card = NULL; + info->func = NULL; + info->id = NULL; +} + +#if defined(CONFIG_PM) +static int cnss_sdio_wlan_suspend(struct device *dev) +{ + struct cnss_sdio_wlan_driver *wdrv; + struct cnss_sdio_bus_bandwidth *bus_bandwidth; + struct sdio_func *func; + + int error = 0; + + if (!cnss_pdata) + return -ENODEV; + + bus_bandwidth = &cnss_pdata->bus_bandwidth; + if (bus_bandwidth->bus_client) { + msm_bus_scale_client_update_request( + bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE); + } + + func = cnss_pdata->cnss_sdio_info.func; + wdrv = cnss_pdata->cnss_sdio_info.wdrv; + if (!wdrv) { + /* This can happen when no wlan driver loaded (no register to + * platform driver). + */ + sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + pr_debug("wlan driver not registered\n"); + return 0; + } + if (wdrv->suspend) { + error = wdrv->suspend(dev); + if (error) + pr_err("wlan suspend failed error=%d\n", error); + } + + return error; +} + +static int cnss_sdio_wlan_resume(struct device *dev) +{ + struct cnss_sdio_wlan_driver *wdrv; + struct cnss_sdio_bus_bandwidth *bus_bandwidth; + int error = 0; + + if (!cnss_pdata) + return -ENODEV; + + bus_bandwidth = &cnss_pdata->bus_bandwidth; + if (bus_bandwidth->bus_client) { + msm_bus_scale_client_update_request( + bus_bandwidth->bus_client, + bus_bandwidth->current_bandwidth_vote); + } + + wdrv = cnss_pdata->cnss_sdio_info.wdrv; + if (!wdrv) { + /* This can happen when no wlan driver loaded (no register to + * platform driver). + */ + pr_debug("wlan driver not registered\n"); + return 0; + } + if (wdrv->resume) { + error = wdrv->resume(dev); + if (error) + pr_err("wlan resume failed error=%d\n", error); + } + return error; +} +#endif + +#if defined(CONFIG_PM) +static const struct dev_pm_ops cnss_ar6k_device_pm_ops = { + .suspend = cnss_sdio_wlan_suspend, + .resume = cnss_sdio_wlan_resume, +}; +#endif /* CONFIG_PM */ + +static struct sdio_driver cnss_ar6k_driver = { + .name = "cnss_ar6k_wlan", + .id_table = ar6k_id_table, + .probe = cnss_sdio_wlan_inserted, + .remove = cnss_sdio_wlan_removed, +#if defined(CONFIG_PM) + .drv = { + .pm = &cnss_ar6k_device_pm_ops, + } +#endif +}; + +static int cnss_set_pinctrl_state(struct cnss_sdio_data *pdata, bool state) +{ + struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info; + + if (!info->is_antenna_shared) + return 0; + + if (!info->pinctrl) + return -EIO; + + return state ? pinctrl_select_state(info->pinctrl, info->active) : + pinctrl_select_state(info->pinctrl, info->sleep); +} + +int cnss_sdio_configure_spdt(bool state) +{ + if (!cnss_pdata) + return -ENODEV; + + return cnss_set_pinctrl_state(cnss_pdata, state); +} +EXPORT_SYMBOL(cnss_sdio_configure_spdt); + +/** + * cnss_sdio_wlan_register_driver() - cnss wlan register API + * @driver: sdio wlan driver interface from wlan driver. + * + * wlan sdio function driver uses this API to register callback + * functions to cnss_sido platform driver. The callback will + * be invoked by corresponding wrapper function of this cnss + * platform driver. + */ +int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver) +{ + struct cnss_sdio_info *cnss_info; + struct device *dev; + int error = -EINVAL; + + if (!cnss_pdata) + return -ENODEV; + + cnss_info = &cnss_pdata->cnss_sdio_info; + dev = cnss_info->dev; + + if (cnss_info->wdrv) { + pr_debug("wdrv already existed\n"); + return error; + } + + if (!driver) + return error; + + error = cnss_get_hw_resources(dev); + if (error) { + pr_err("Failed to restore power err:%d\n", error); + return error; + } + + error = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_ACTIVE); + if (error) { + pr_err("Fail to set pinctrl to active state\n"); + cnss_put_hw_resources(dev); + goto put_hw; + } + + /* The HW resources are released in unregister logic if probe fails */ + error = driver->probe ? driver->probe(cnss_info->func, + cnss_info->id) : error; + if (error) { + pr_err("wlan probe failed error=%d\n", error); + /** + * Check memory leak in skb pre-alloc memory pool + * Reset the skb memory pool + */ + goto pinctrl_sleep; + } + + cnss_info->wdrv = driver; + + return error; + +pinctrl_sleep: + cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP); +put_hw: + return error; +} +EXPORT_SYMBOL(cnss_sdio_wlan_register_driver); + +/** + * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API + * @driver: sdio wlan driver interface from wlan driver. + * + * wlan sdio function driver uses this API to detach it from cnss_sido + * platform driver. + */ +void +cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver) +{ + struct cnss_sdio_info *cnss_info; + struct cnss_sdio_bus_bandwidth *bus_bandwidth; + + if (!cnss_pdata) + return; + + bus_bandwidth = &cnss_pdata->bus_bandwidth; + if (bus_bandwidth->bus_client) { + msm_bus_scale_client_update_request( + bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE); + } + + cnss_info = &cnss_pdata->cnss_sdio_info; + if (!cnss_info->wdrv) { + pr_err("driver not registered\n"); + return; + } + + if (!driver) + return; + + if (!driver->remove) + return; + + driver->remove(cnss_info->func); + + cnss_info->wdrv = NULL; + cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP); + cnss_put_hw_resources(cnss_info->dev); +} +EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver); + +/** + * cnss_wlan_query_oob_status() - cnss wlan query oob status API + * + * Wlan sdio function driver uses this API to check whether oob is + * supported in platform driver. + * + * Return: 0 means oob is supported, others means unsupported. + */ +int cnss_wlan_query_oob_status(void) +{ + return -EINVAL; +} +EXPORT_SYMBOL(cnss_wlan_query_oob_status); + +/** + * cnss_wlan_register_oob_irq_handler() - cnss wlan register oob callback API + * @handler: oob callback function pointer which registered to platform driver. + * @pm_oob : parameter which registered to platform driver. + * + * Wlan sdio function driver uses this API to register oob callback + * function to platform driver. + * + * Return: 0 means register successfully, others means failure. + */ +int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, void *pm_oob) +{ + return -EINVAL; +} +EXPORT_SYMBOL(cnss_wlan_register_oob_irq_handler); + +/** + * cnss_wlan_unregister_oob_irq_handler() - unregister oob callback API + * @pm_oob: parameter which unregistered from platform driver. + * + * Wlan sdio function driver uses this API to unregister oob callback + * function from platform driver. + * + * Return: 0 means unregister successfully, others means failure. + */ +int cnss_wlan_unregister_oob_irq_handler(void *pm_oob) +{ + return -EINVAL; +} +EXPORT_SYMBOL(cnss_wlan_unregister_oob_irq_handler); + +static void cnss_sdio_reset_platform_ops(void) +{ + struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops; + struct cnss_sdio_info *sdio_info = &cnss_pdata->cnss_sdio_info; + + memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops)); + if (sdio_info->dev) + sdio_info->dev->platform_data = NULL; +} + +static int cnss_sdio_wlan_init(void) +{ + int error = 0; + + error = sdio_register_driver(&cnss_ar6k_driver); + if (error) { + cnss_sdio_reset_platform_ops(); + pr_err("registered fail error=%d\n", error); + } else { + pr_debug("registered success\n"); + } + + return error; +} + +static void cnss_sdio_wlan_exit(void) +{ + if (!cnss_pdata) + return; + + cnss_sdio_reset_platform_ops(); + sdio_unregister_driver(&cnss_ar6k_driver); +} + +static void cnss_sdio_deinit_bus_bandwidth(void) +{ + struct cnss_sdio_bus_bandwidth *bus_bandwidth; + + bus_bandwidth = &cnss_pdata->bus_bandwidth; + if (bus_bandwidth->bus_client) { + msm_bus_scale_client_update_request(bus_bandwidth->bus_client, + CNSS_BUS_WIDTH_NONE); + msm_bus_scale_unregister_client(bus_bandwidth->bus_client); + } +} + +static int cnss_sdio_configure_wlan_enable_regulator(void) +{ + int error; + struct device *dev = &cnss_pdata->pdev->dev; + + if (of_get_property( + cnss_pdata->pdev->dev.of_node, + WLAN_VREG_NAME "-supply", NULL)) { + cnss_pdata->regulator.wlan_vreg = regulator_get( + &cnss_pdata->pdev->dev, WLAN_VREG_NAME); + if (IS_ERR(cnss_pdata->regulator.wlan_vreg)) { + error = PTR_ERR(cnss_pdata->regulator.wlan_vreg); + dev_err(dev, "VDD-VREG get failed error=%d\n", error); + return error; + } + + error = regulator_enable(cnss_pdata->regulator.wlan_vreg); + if (error) { + dev_err(dev, "VDD-VREG enable failed error=%d\n", + error); + goto err_vdd_vreg_regulator; + } + } + + return 0; + +err_vdd_vreg_regulator: + regulator_put(cnss_pdata->regulator.wlan_vreg); + + return error; +} + +static int cnss_sdio_configure_wlan_enable_dsrc_regulator(void) +{ + int error; + struct device *dev = &cnss_pdata->pdev->dev; + + if (of_get_property( + cnss_pdata->pdev->dev.of_node, + WLAN_VREG_DSRC_NAME "-supply", NULL)) { + cnss_pdata->regulator.wlan_vreg_dsrc = regulator_get( + &cnss_pdata->pdev->dev, WLAN_VREG_DSRC_NAME); + if (IS_ERR(cnss_pdata->regulator.wlan_vreg_dsrc)) { + error = PTR_ERR(cnss_pdata->regulator.wlan_vreg_dsrc); + dev_err(dev, "VDD-VREG-DSRC get failed error=%d\n", + error); + return error; + } + + error = regulator_enable(cnss_pdata->regulator.wlan_vreg_dsrc); + if (error) { + dev_err(dev, "VDD-VREG-DSRC enable failed error=%d\n", + error); + goto err_vdd_vreg_dsrc_regulator; + } + } + + return 0; + +err_vdd_vreg_dsrc_regulator: + regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc); + + return error; +} + +static int cnss_sdio_configure_regulator(void) +{ + int error; + struct device *dev = &cnss_pdata->pdev->dev; + u32 vdd_xtal_min; + u32 vdd_xtal_max; + + if (of_get_property( + cnss_pdata->pdev->dev.of_node, + WLAN_VREG_IO_NAME "-supply", NULL)) { + cnss_pdata->regulator.wlan_io = regulator_get( + &cnss_pdata->pdev->dev, WLAN_VREG_IO_NAME); + if (IS_ERR(cnss_pdata->regulator.wlan_io)) { + error = PTR_ERR(cnss_pdata->regulator.wlan_io); + dev_err(dev, "VDD-IO get failed error=%d\n", error); + return error; + } + + error = regulator_set_voltage( + cnss_pdata->regulator.wlan_io, + WLAN_VREG_IO_MIN, WLAN_VREG_IO_MAX); + if (error) { + dev_err(dev, "VDD-IO set failed error=%d\n", error); + goto err_vdd_io_regulator; + } else { + error = regulator_enable(cnss_pdata->regulator.wlan_io); + if (error) { + dev_err(dev, "VDD-IO enable failed error=%d\n", + error); + goto err_vdd_io_regulator; + } + } + } + + if (of_get_property( + cnss_pdata->pdev->dev.of_node, + WLAN_VREG_XTAL_NAME "-supply", NULL)) { + cnss_pdata->regulator.wlan_xtal = regulator_get( + &cnss_pdata->pdev->dev, WLAN_VREG_XTAL_NAME); + if (IS_ERR(cnss_pdata->regulator.wlan_xtal)) { + error = PTR_ERR(cnss_pdata->regulator.wlan_xtal); + dev_err(dev, "VDD-XTAL get failed error=%d\n", error); + goto err_vdd_xtal_regulator; + } + + if (!of_property_read_u32(cnss_pdata->pdev->dev.of_node, + WLAN_VREG_XTAL_NAME "-min", + &vdd_xtal_min)) { + if (vdd_xtal_min < WLAN_VREG_XTAL_MIN || + vdd_xtal_min > WLAN_VREG_XTAL_MAX) + vdd_xtal_min = WLAN_VREG_XTAL_TYP; + } else { + vdd_xtal_min = WLAN_VREG_XTAL_TYP; + } + + if (!of_property_read_u32(cnss_pdata->pdev->dev.of_node, + WLAN_VREG_XTAL_NAME "-max", + &vdd_xtal_max)) { + if (vdd_xtal_max < WLAN_VREG_XTAL_MIN || + vdd_xtal_max > WLAN_VREG_XTAL_MAX) + vdd_xtal_max = WLAN_VREG_XTAL_TYP; + } else { + vdd_xtal_max = WLAN_VREG_XTAL_TYP; + } + + if (vdd_xtal_min > vdd_xtal_max) + vdd_xtal_min = vdd_xtal_max; + + error = regulator_set_voltage( + cnss_pdata->regulator.wlan_xtal, + vdd_xtal_min, vdd_xtal_max); + if (error) { + dev_err(dev, "VDD-XTAL set failed error=%d\n", error); + goto err_vdd_xtal_regulator; + } else { + error = regulator_enable( + cnss_pdata->regulator.wlan_xtal); + if (error) { + dev_err(dev, "VDD-XTAL enable failed err=%d\n", + error); + goto err_vdd_xtal_regulator; + } + } + } + + return 0; + +err_vdd_xtal_regulator: + regulator_put(cnss_pdata->regulator.wlan_xtal); +err_vdd_io_regulator: + regulator_put(cnss_pdata->regulator.wlan_io); + return error; +} + +static void cnss_sdio_release_resource(void) +{ + if (cnss_pdata->regulator.wlan_xtal) + regulator_put(cnss_pdata->regulator.wlan_xtal); + if (cnss_pdata->regulator.wlan_vreg) + regulator_put(cnss_pdata->regulator.wlan_vreg); + if (cnss_pdata->regulator.wlan_io) + regulator_put(cnss_pdata->regulator.wlan_io); + if (cnss_pdata->regulator.wlan_vreg_dsrc) + regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc); +} + +static int cnss_sdio_pinctrl_init(struct cnss_sdio_data *pdata, + struct platform_device *pdev) +{ + int ret = 0; + struct device *dev = &pdev->dev; + struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info; + + if (!of_find_property(dev->of_node, "qcom,is-antenna-shared", NULL)) + return 0; + + info->is_antenna_shared = true; + info->pinctrl = devm_pinctrl_get(dev); + if ((IS_ERR_OR_NULL(info->pinctrl))) { + dev_err(dev, "%s: Failed to get pinctrl\n", __func__); + return PTR_ERR(info->pinctrl); + } + + info->sleep = pinctrl_lookup_state(info->pinctrl, + CNSS_PINCTRL_SLEEP_STATE); + if (IS_ERR_OR_NULL(info->sleep)) { + dev_err(dev, "%s: Fail to get sleep state for pin\n", __func__); + ret = PTR_ERR(info->sleep); + goto release_pinctrl; + } + + info->active = pinctrl_lookup_state(info->pinctrl, + CNSS_PINCTRL_ACTIVE_STATE); + if (IS_ERR_OR_NULL(info->active)) { + dev_err(dev, "%s: Fail to get active state for pin\n", + __func__); + ret = PTR_ERR(info->active); + goto release_pinctrl; + } + + ret = cnss_set_pinctrl_state(pdata, PINCTRL_SLEEP); + + if (ret) { + dev_err(dev, "%s: Fail to set pin in sleep state\n", __func__); + goto release_pinctrl; + } + + return ret; + +release_pinctrl: + devm_pinctrl_put(info->pinctrl); + info->is_antenna_shared = false; + return ret; +} + +static int cnss_sdio_init_bus_bandwidth(void) +{ + int ret = 0; + struct cnss_sdio_bus_bandwidth *bus_bandwidth; + struct device *dev = &cnss_pdata->pdev->dev; + + bus_bandwidth = &cnss_pdata->bus_bandwidth; + bus_bandwidth->bus_scale_table = msm_bus_cl_get_pdata(cnss_pdata->pdev); + if (!bus_bandwidth->bus_scale_table) { + dev_err(dev, "Failed to get the bus scale platform data\n"); + ret = -EINVAL; + } + + bus_bandwidth->bus_client = msm_bus_scale_register_client( + bus_bandwidth->bus_scale_table); + if (!bus_bandwidth->bus_client) { + dev_err(dev, "Failed to register with bus_scale client\n"); + ret = -EINVAL; + } + + return ret; +} + +static int cnss_sdio_probe(struct platform_device *pdev) +{ + int error; + struct device *dev = &pdev->dev; + struct cnss_sdio_info *info; + + if (pdev->dev.of_node) { + cnss_pdata = devm_kzalloc( + &pdev->dev, sizeof(*cnss_pdata), GFP_KERNEL); + if (!cnss_pdata) + return -ENOMEM; + } else { + cnss_pdata = pdev->dev.platform_data; + } + + if (!cnss_pdata) + return -EINVAL; + + cnss_pdata->pdev = pdev; + info = &cnss_pdata->cnss_sdio_info; + + error = cnss_sdio_pinctrl_init(cnss_pdata, pdev); + if (error) { + dev_err(&pdev->dev, "Fail to configure pinctrl err:%d\n", + error); + return error; + } + + error = cnss_sdio_configure_regulator(); + if (error) { + dev_err(&pdev->dev, "Failed to configure voltage regulator error=%d\n", + error); + return error; + } + + if (of_get_property( + cnss_pdata->pdev->dev.of_node, + WLAN_VREG_NAME "-supply", NULL)) { + error = cnss_sdio_configure_wlan_enable_regulator(); + if (error) { + dev_err(&pdev->dev, + "Failed to enable wlan enable regulator error=%d\n", + error); + goto err_wlan_enable_regulator; + } + } + + if (of_get_property( + cnss_pdata->pdev->dev.of_node, + WLAN_VREG_DSRC_NAME "-supply", NULL)) { + error = cnss_sdio_configure_wlan_enable_dsrc_regulator(); + if (error) { + dev_err(&pdev->dev, + "Failed to enable wlan dsrc enable regulator\n"); + goto err_wlan_dsrc_enable_regulator; + } + } + + info->skip_wlan_en_toggle = of_property_read_bool(dev->of_node, + "qcom,skip-wlan-en-toggle"); + info->cnss_hw_state = CNSS_HW_ACTIVE; + + cnss_sdio_tsf_init(dev, &info->cap_tsf_info); + + error = cnss_sdio_wlan_init(); + if (error) { + dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error); + goto err_wlan_dsrc_enable_regulator; + } + + error = cnss_configure_ramdump(); + if (error) { + dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n", + error); + goto err_ramdump_create; + } + + error = cnss_subsys_init(); + if (error) { + dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n", + error); + goto err_subsys_init; + } + + if (of_property_read_bool( + pdev->dev.of_node, "qcom,cnss-enable-bus-bandwidth")) { + error = cnss_sdio_init_bus_bandwidth(); + if (error) { + dev_err(&pdev->dev, "Failed to init bus bandwidth\n"); + goto err_bus_bandwidth_init; + } + } + + dev_info(&pdev->dev, "CNSS SDIO Driver registered"); + return 0; + +err_bus_bandwidth_init: + cnss_subsys_exit(); +err_subsys_init: + cnss_ramdump_cleanup(); +err_ramdump_create: + cnss_sdio_wlan_exit(); +err_wlan_dsrc_enable_regulator: + info->cnss_hw_state = CNSS_HW_SLEEP; + regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc); +err_wlan_enable_regulator: + regulator_put(cnss_pdata->regulator.wlan_xtal); + regulator_put(cnss_pdata->regulator.wlan_io); + cnss_pdata = NULL; + return error; +} + +static int cnss_sdio_remove(struct platform_device *pdev) +{ + struct cnss_sdio_info *info; + struct cnss_cap_tsf_info *tsf_info; + + if (!cnss_pdata) + return -ENODEV; + + info = &cnss_pdata->cnss_sdio_info; + tsf_info = &info->cap_tsf_info; + + cnss_sdio_tsf_deinit(tsf_info); + cnss_sdio_deinit_bus_bandwidth(); + cnss_sdio_wlan_exit(); + cnss_subsys_exit(); + cnss_ramdump_cleanup(); + cnss_put_hw_resources(info->dev); + cnss_sdio_release_resource(); + cnss_pdata = NULL; + return 0; +} + +int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len) +{ + return 0; +} + +u8 *cnss_sdio_get_wlan_mac_address(u32 *num) +{ + *num = 0; + return NULL; +} + +int cnss_sdio_power_down(struct device *dev) +{ + return 0; +} + +int cnss_sdio_power_up(struct device *dev) +{ + return 0; +} + +static const struct of_device_id cnss_sdio_dt_match[] = { + {.compatible = "qcom,cnss_sdio"}, + {} +}; +MODULE_DEVICE_TABLE(of, cnss_sdio_dt_match); + +static struct platform_driver cnss_sdio_driver = { + .probe = cnss_sdio_probe, + .remove = cnss_sdio_remove, + .driver = { + .name = "cnss_sdio", + .owner = THIS_MODULE, + .of_match_table = cnss_sdio_dt_match, + }, +}; + +static int __init cnss_sdio_init(void) +{ + return platform_driver_register(&cnss_sdio_driver); +} + +static void __exit cnss_sdio_exit(void) +{ + platform_driver_unregister(&cnss_sdio_driver); +} + +module_init(cnss_sdio_init); +module_exit(cnss_sdio_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DEVICE "CNSS SDIO Driver"); diff --git a/drivers/net/wireless/cnss/logger/Kconfig b/drivers/net/wireless/cnss/logger/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..85b69921a6a4336107816283e51a1556a2fd0646 --- /dev/null +++ b/drivers/net/wireless/cnss/logger/Kconfig @@ -0,0 +1,6 @@ +config CNSS_LOGGER + tristate "CNSS Logging Service Driver" + ---help--- + This module adds support for the CNSS Logging Service for CLD + driver, including the netlink socket service registration, transmit, + event receive. diff --git a/drivers/net/wireless/cnss/logger/Makefile b/drivers/net/wireless/cnss/logger/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1e296a32df16521f51f306b1ba6dfc52eb6fbd9b --- /dev/null +++ b/drivers/net/wireless/cnss/logger/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_CNSS_LOGGER) += logger.o + +logger-y += main.o \ + nl_service.o + +logger-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/net/wireless/cnss/logger/debugfs.c b/drivers/net/wireless/cnss/logger/debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..d34dd819e06db35647904b335f20b2700f21e736 --- /dev/null +++ b/drivers/net/wireless/cnss/logger/debugfs.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * + * This 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 "logger.h" + +#define CNSS_LOGGER_STATE_DUMP_BUFFER (2 * 1024) /* 2KB */ + +static int logger_state_dump_device(struct logger_device *dev, char *buf, + int buf_len) +{ + int len = 0; + struct logger_event_handler *cur; + + len += scnprintf(buf + len, buf_len - len, + "==============================================\n"); + + len += scnprintf(buf + len, buf_len - len, + "driver [%s] is registered with radio index: %d\n", + dev->name, dev->radio_idx); + + if (list_empty(&dev->event_list)) { + len += scnprintf(buf + len, buf_len - len, + "No event registered\n"); + return len; + } + + list_for_each_entry(cur, &dev->event_list, list) { + len += scnprintf(buf + len, buf_len - len, + "\t event %d\n", cur->event); + } + len += scnprintf(buf + len, buf_len - len, "\n"); + + return len; +} + +static int logger_state_dump(struct logger_context *ctx, char *buf, int buf_len) +{ + int len = 0; + struct logger_device *cur; + + if (list_empty(&ctx->dev_list)) { + len += scnprintf(buf + len, buf_len - len, + "=======================\n"); + len += scnprintf(buf + len, buf_len - len, + "No driver registered\n"); + return 0; + } + + list_for_each_entry(cur, &ctx->dev_list, list) + len += logger_state_dump_device(cur, (buf + len), buf_len); + + return 0; +} + +static int logger_state_open(struct inode *inode, struct file *file) +{ + struct logger_context *ctx = inode->i_private; + void *buf; + int ret; + + mutex_lock(&ctx->con_mutex); + + buf = kmalloc(CNSS_LOGGER_STATE_DUMP_BUFFER, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error_unlock; + } + + ret = logger_state_dump(ctx, buf, CNSS_LOGGER_STATE_DUMP_BUFFER); + if (ret) + goto error_free; + + file->private_data = buf; + mutex_unlock(&ctx->con_mutex); + return 0; + +error_free: + kfree(buf); + +error_unlock: + mutex_unlock(&ctx->con_mutex); + + return ret; +} + +static int logger_state_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static ssize_t logger_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + const char *buf = file->private_data; + unsigned int len = strlen(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_logger_state = { + .open = logger_state_open, + .release = logger_state_release, + .read = logger_state_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void logger_debugfs_init(struct logger_context *ctx) +{ + if (!ctx->debugfs_entry) + ctx->debugfs_entry = debugfs_create_dir("cnss_logger", NULL); + + debugfs_create_file("state", 0400, ctx->debugfs_entry, ctx, + &fops_logger_state); +} + +void logger_debugfs_remove(struct logger_context *ctx) +{ + debugfs_remove(ctx->debugfs_entry); +} + diff --git a/drivers/net/wireless/cnss/logger/logger.h b/drivers/net/wireless/cnss/logger/logger.h new file mode 100644 index 0000000000000000000000000000000000000000..2c4060a85aea10e293d2be20616eedaeebe5143d --- /dev/null +++ b/drivers/net/wireless/cnss/logger/logger.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * + * This 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 _LOGGER_H_ +#define _LOGGER_H_ + +#include +#include +#include +#include +#include + +#define CNSS_LOGGER_NL_MCAST_GRP_ID 0x01 +#define CNSS_LOGGER_NL_MAX_PAYLOAD 256 +#define CNSS_LOGGER_BROADCAST_ID 255 + +/** + * struct aninlmsg - the wireless service message header + * @nlh: the netlink message header + * @radio: the radio index of this message + * @wmsg: the pointer to the wireless message data + */ +struct aninlmsg { + struct nlmsghdr *nlh; + int radio; + void *wmsg; +}; + +/** + * struct logger_event_handler - the logger event handler structure + * @list: the event list associated to the same device + * @event: the event number + * @radio_idx: the callback handler + */ +struct logger_event_handler { + struct list_head list; + + int event; + int (*cb)(struct sk_buff *skb); +}; + +/** + * struct logger_device - the logger device structure + * @list: the device list registered to logger module + * @event_list: the event list registered to this device + * @ctx: the pointer to the logger context + * @wiphy: the wiphy that associated to the device + * @name: the name of the device driver module + * @radio_idx: the radio index assigned to this device + */ +struct logger_device { + struct list_head list; + struct list_head event_list; + + struct logger_context *ctx; + struct wiphy *wiphy; + char name[MODULE_NAME_LEN]; + int radio_idx; +}; + +/** + * struct logger_context - the main context block for logger module + * @dev_list: this is the list to maintain the devices that registered + * to use the logger module feature + * @nl_sock: the netlink socket to share accros the module + * @con_mutex: the mutex to protect concurrent access + * @data_lock: the lock to protect shared data + * @radio_mask: this mask would maintain the radio index assign and release + */ +struct logger_context { + struct list_head dev_list; + + struct sock *nl_sock; + struct mutex con_mutex; /* concurrent access mutex */ + spinlock_t data_lock; + unsigned long radio_mask; /* support up to 4 drivers registration? */ +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_entry; +#endif +}; + +int logger_netlink_init(struct logger_context *ctx); +int logger_netlink_deinit(struct logger_context *ctx); +struct logger_context *logger_get_ctx(void); + +#ifdef CONFIG_DEBUG_FS +void logger_debugfs_init(struct logger_context *ctx); +void logger_debugfs_remove(struct logger_context *ctx); +#else +static inline void logger_debugfs_init(struct logger_context *ctx) {} +static inline void logger_debugfs_remove(struct logger_context *ctx) {} +#endif + +#endif /* _LOGGER_H_ */ diff --git a/drivers/net/wireless/cnss/logger/main.c b/drivers/net/wireless/cnss/logger/main.c new file mode 100644 index 0000000000000000000000000000000000000000..fc2c1822c7411caf770628c6eba4d8779d26e2de --- /dev/null +++ b/drivers/net/wireless/cnss/logger/main.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * + * This 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 "logger.h" + +static struct logger_context *ctx; + +struct logger_context *logger_get_ctx(void) +{ + return ctx; +} + +static int __init logger_module_init(void) +{ + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ret = logger_netlink_init(ctx); + + mutex_init(&ctx->con_mutex); + spin_lock_init(&ctx->data_lock); + logger_debugfs_init(ctx); + + return ret; +} + +static void __exit logger_module_exit(void) +{ + logger_debugfs_remove(ctx); + logger_netlink_deinit(ctx); + + kfree(ctx); +} + +module_init(logger_module_init); +module_exit(logger_module_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CNSS Logging Service Driver"); diff --git a/drivers/net/wireless/cnss/logger/nl_service.c b/drivers/net/wireless/cnss/logger/nl_service.c new file mode 100644 index 0000000000000000000000000000000000000000..a532e1f7c4d0dfd80dea3503f4eebb5d8b0ea00c --- /dev/null +++ b/drivers/net/wireless/cnss/logger/nl_service.c @@ -0,0 +1,476 @@ +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * + * This 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) "cnss_logger: %s: "fmt, __func__ + +#include +#include +#include +#include +#include +#include "logger.h" + +static DEFINE_MUTEX(logger_sem); + +/** + * logger_get_radio_idx() - to get the radio index + * @ctx: the logger context pointer + * + * Return: the first available radio index, otherwise failure code + */ +static int logger_get_radio_idx(struct logger_context *ctx) +{ + int i; + + for (i = 0; i < sizeof(ctx->radio_mask); i++) { + if (!test_and_set_bit(i, &ctx->radio_mask)) + return i; + } + return -EINVAL; +} + +/** + * logger_put_radio_idx() - to release the radio index + * @radio: the radio index to release + * + * Return: None + */ +static void logger_put_radio_idx(struct logger_context *ctx, int radio) +{ + clear_bit(radio, &ctx->radio_mask); +} + +/** + * logger_get_device() - to get the logger device per radio index + * @radio: the radio index + * + * Return: the logger_device pointer, otherwise return NULL. + */ +static struct logger_device *logger_get_device(int radio) +{ + struct logger_device *dev; + struct logger_context *ctx; + + ctx = logger_get_ctx(); + if (!ctx) + return NULL; + + list_for_each_entry(dev, &ctx->dev_list, list) { + if (dev->radio_idx == radio) + return dev; + } + return NULL; +} + +/** + * logger_device_is_registered() - to check if device has been registered + * @dev: pointer to logger device + * @wiphy: the wiphy pointer of the device to register + * + * This helper function is to check if this device has been registered. + * + * Return: NULL if it has not, otherwise return the logger_device pointer. + */ +static struct logger_device *logger_device_is_registered( + struct logger_context *ctx, + struct wiphy *wiphy) +{ + struct logger_device *dev; + + list_for_each_entry(dev, &ctx->dev_list, list) { + if (dev->wiphy == wiphy) + return dev; + } + return NULL; +} + +/** + * logger_dispatch_skb() - to dispatch the skb to devices + * @skb: the socket buffer received and to dispatch + * + * The function will look up the header of the skb, and dispatch the skb + * to the associated event and device that registered. + * + * Return: 0 if successfully dispatch, otherwise failure code + */ +static int logger_dispatch_skb(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + struct logger_context *ctx; + struct logger_device *cur; + struct logger_event_handler *evt; + int handled = 0; + + ctx = logger_get_ctx(); + if (!ctx) + return -ENOENT; + + pr_info("skb_len: %d, skb_data_len: %d\n", + skb->len, skb->data_len); + + if (skb->len < sizeof(struct nlmsghdr)) + return 0; + + nlh = (struct nlmsghdr *)skb->data; + list_for_each_entry(cur, &ctx->dev_list, list) { + list_for_each_entry(evt, &cur->event_list, list) { + if (nlh->nlmsg_type == evt->event) { + if (evt->cb) { + handled = 1; + evt->cb(skb); + } + /* Break inside loop, next dev */ + break; + } + } + } + + if (!handled) + pr_info("Not handled msg type: %d\n", nlh->nlmsg_type); + + return 0; +} + +/** + * logger_flush_event_handle() - to flush the event handle associate to device + * @dev: pointer to logger device + * + * The function will clean up all the event handle's resource, take it out + * from the list, and free the memory allocated. + * + * Return: None + */ +static void logger_flush_event_handle(struct logger_device *dev) +{ + struct list_head *pos, *temp; + struct logger_event_handler *cur; + + list_for_each_safe(pos, temp, &dev->event_list) { + cur = container_of(pos, struct logger_event_handler, list); + pr_info("radio: %d, event: %d unregistered\n", + dev->radio_idx, cur->event); + list_del(&cur->list); + kfree(cur); + } +} + +/** + * logger_flush_devices() - to flush the devices infomration + * @dev: pointer to logger device + * + * The helper function to flush the device information, all the device clean + * up prcoess should be starting from here. + * + * Return: None + */ +static void logger_flush_devices(struct logger_device *dev) +{ + pr_info("driver: [%s] and radio-%d is unregistered\n", + dev->name, dev->radio_idx); + logger_flush_event_handle(dev); + logger_put_radio_idx(dev->ctx, dev->radio_idx); + list_del(&dev->list); + kfree(dev); +} + +/** + * logger_register_device_event() - register the evet to device + * @dev: pointer to logger device + * @event: the event to register + * @cb: the callback associated to the device and event + * + * Return: 0 if register successfully, otherwise the failure code + */ +static int logger_register_device_event(struct logger_device *dev, int event, + int (*cb)(struct sk_buff *skb)) +{ + struct logger_event_handler *cur; + + list_for_each_entry(cur, &dev->event_list, list) { + if (cur->event == event) { + pr_info("event %d, is already added\n", event); + return 0; + } + } + + cur = kmalloc(sizeof(*cur), GFP_KERNEL); + if (!cur) + return -ENOMEM; + + cur->event = event; + cur->cb = cb; + + pr_info("radio: %d, event: %d\n", dev->radio_idx, cur->event); + list_add_tail(&cur->list, &dev->event_list); + + return 0; +} + +/** + * logger_unregister_device_event() - unregister the evet from device + * @dev: pointer to logger device + * @event: the event to unregister + * @cb: the callback associated to the device and event + * + * Return: 0 if unregister successfully, otherwise the failure code + */ +static int logger_unregister_device_event(struct logger_device *dev, int event, + int (*cb)(struct sk_buff *skb)) +{ + struct list_head *pos, *temp; + struct logger_event_handler *cur; + + list_for_each_safe(pos, temp, &dev->event_list) { + cur = container_of(pos, struct logger_event_handler, list); + if (cur->event == event && cur->cb == cb) { + pr_info("radio: %d, event: %d\n", + dev->radio_idx, cur->event); + list_del(&cur->list); + kfree(cur); + return 0; + } + } + return -ENOENT; +} + +/** + * logger_skb_input() - the callback to receive the skb + * @skb: the receive socket buffer + * + * Return: None + */ +static void logger_skb_input(struct sk_buff *skb) +{ + mutex_lock(&logger_sem); + logger_dispatch_skb(skb); + mutex_unlock(&logger_sem); +} + +/** + * cnss_logger_event_register() - register the event + * @radio: the radio index to register + * @event: the event to register + * @cb: the callback + * + * This function is used to register event associated to the radio index. + * + * Return: 0 if register success, otherwise failure code + */ +int cnss_logger_event_register(int radio, int event, + int (*cb)(struct sk_buff *skb)) +{ + int ret = -ENOENT; + struct logger_device *dev; + + dev = logger_get_device(radio); + if (dev) + ret = logger_register_device_event(dev, event, cb); + + return ret; +} +EXPORT_SYMBOL(cnss_logger_event_register); + +/** + * cnss_logger_event_unregister() - unregister the event + * @radio: the radio index to unregister + * @event: the event to unregister + * @cb: the callback + * + * This function is used to unregister the event from cnss logger module. + * + * Return: 0 if unregister success, otherwise failure code + */ +int cnss_logger_event_unregister(int radio, int event, + int (*cb)(struct sk_buff *skb)) +{ + int ret = -ENOENT; + struct logger_device *dev; + + dev = logger_get_device(radio); + if (dev) + ret = logger_unregister_device_event(dev, event, cb); + + return ret; +} +EXPORT_SYMBOL(cnss_logger_event_unregister); + +/** + * cnss_logger_device_register() - register the driver + * @wiphy: the wiphy device to unregister + * @name: the module name of the driver + * + * This function is used to register the driver to cnss logger module, + * this will indicate the existence of the driver, and also assign the + * radio index for further operation. + * + * Return: the radio index if register successful, otherwise failure code + */ +int cnss_logger_device_register(struct wiphy *wiphy, const char *name) +{ + int radio; + struct logger_context *ctx; + struct logger_device *new; + + ctx = logger_get_ctx(); + if (!ctx) + return -ENOENT; + + /* sanity check, already registered? */ + new = logger_device_is_registered(ctx, wiphy); + if (new) + return new->radio_idx; + + radio = logger_get_radio_idx(ctx); + if (radio < 0) { + pr_err("driver registration is full\n"); + return -ENOMEM; + } + + new = kmalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + logger_put_radio_idx(ctx, radio); + return -ENOMEM; + } + + new->radio_idx = radio; + new->wiphy = wiphy; + new->ctx = ctx; + strlcpy(new->name, name, sizeof(new->name)); + INIT_LIST_HEAD(&new->event_list); + + list_add(&new->list, &ctx->dev_list); + + pr_info("driver: [%s] is registered as radio-%d\n", + new->name, new->radio_idx); + + return new->radio_idx; +} +EXPORT_SYMBOL(cnss_logger_device_register); + +/** + * cnss_logger_device_unregister() - unregister the driver + * @radio: the radio to unregister + * @wiphy: the wiphy device to unregister + * + * This function is used to unregister the driver from cnss logger module. + * This will disable the driver to access the interface in cnss logger, + * and also all the related events that registered will be reset. + * + * Return: 0 if success, otherwise failure code + */ +int cnss_logger_device_unregister(int radio, struct wiphy *wiphy) +{ + struct logger_context *ctx; + struct logger_device *cur; + struct list_head *pos, *temp; + + ctx = logger_get_ctx(); + if (!ctx) + return -ENOENT; + + list_for_each_safe(pos, temp, &ctx->dev_list) { + cur = list_entry(pos, struct logger_device, list); + if (cur->radio_idx == radio && cur->wiphy == wiphy) { + logger_flush_devices(cur); + break; + } + } + return 0; +} +EXPORT_SYMBOL(cnss_logger_device_unregister); + +/** + * cnss_logger_nl_ucast() - nl interface to unicast the buffer + * @skb: the socket buffer to transmit + * @portid: netlink portid of the destination socket + * @flag: the flag to indicate if this is a nonblock call + * + * Return: 0 if success, otherwise failure code + */ +int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag) +{ + struct logger_context *ctx; + + ctx = logger_get_ctx(); + if (!ctx) { + dev_kfree_skb(skb); + return -ENOENT; + } + + return netlink_unicast(ctx->nl_sock, skb, portid, flag); +} +EXPORT_SYMBOL(cnss_logger_nl_ucast); + +/** + * cnss_logger_nl_bcast() - nl interface to broadcast the buffer + * @skb: the socket buffer to transmit + * @portid: netlink portid of the destination socket + * @flag: the gfp_t flag + * + * Return: 0 if success, otherwise failure code + */ +int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag) +{ + struct logger_context *ctx; + + ctx = logger_get_ctx(); + if (!ctx) { + dev_kfree_skb(skb); + return -ENOENT; + } + + return netlink_broadcast(ctx->nl_sock, skb, 0, portid, flag); +} +EXPORT_SYMBOL(cnss_logger_nl_bcast); + +/** + * logger_netlink_init() - initialize the netlink socket + * @ctx: the cnss logger context pointer + * + * Return: the netlink handle if success, otherwise failure code + */ +int logger_netlink_init(struct logger_context *ctx) +{ + struct netlink_kernel_cfg cfg = { + .groups = CNSS_LOGGER_NL_MCAST_GRP_ID, + .input = logger_skb_input, + }; + + ctx->nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg); + if (!ctx->nl_sock) { + pr_err("cnss_logger: Cannot create netlink socket"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&ctx->dev_list); + + return 0; +} + +/** + * logger_netlink_deinit() - release the netlink socket and other resource + * @ctx: the cnss logger context pointer + * + * Return: 0 if success, otherwise failure code + */ +int logger_netlink_deinit(struct logger_context *ctx) +{ + struct list_head *pos, *temp; + struct logger_device *dev; + + netlink_kernel_release(ctx->nl_sock); + list_for_each_safe(pos, temp, &ctx->dev_list) { + dev = container_of(pos, struct logger_device, list); + logger_flush_devices(dev); + } + return 0; +} diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 86eb7850c63ff6ce1f6485f170296abd884c8103..aa5a561684d9d8a2781522f87432ea5df18fcc6a 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -241,6 +241,9 @@ int cnss_wlan_enable(struct device *dev, struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); int ret = 0; + if (!plat_priv) + return -ENODEV; + if (plat_priv->device_id == QCA6174_DEVICE_ID) return 0; @@ -276,6 +279,9 @@ int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + if (!plat_priv) + return -ENODEV; + if (plat_priv->device_id == QCA6174_DEVICE_ID) return 0; @@ -348,6 +354,9 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + if (!plat_priv) + return -ENODEV; + if (plat_priv->device_id == QCA6174_DEVICE_ID) return 0; @@ -651,7 +660,7 @@ int cnss_idle_restart(struct device *dev) ret = cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_IDLE_RESTART, - CNSS_EVENT_SYNC, NULL); + CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); if (ret) goto out; @@ -705,7 +714,7 @@ int cnss_idle_shutdown(struct device *dev) skip_wait: return cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_IDLE_SHUTDOWN, - CNSS_EVENT_SYNC, NULL); + CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); } EXPORT_SYMBOL(cnss_idle_shutdown); diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index bba2189d01a7bc7910b69b991ff44628d863c74f..193dd20c036d7f76944b0c8361d0632c1480dcca 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -2714,8 +2714,8 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv) mhi_ctrl->iova_stop = pci_priv->smmu_iova_start + pci_priv->smmu_iova_len; } else { - mhi_ctrl->iova_start = memblock_start_of_DRAM(); - mhi_ctrl->iova_stop = memblock_end_of_DRAM(); + mhi_ctrl->iova_start = 0; + mhi_ctrl->iova_stop = 0; } mhi_ctrl->link_status = cnss_mhi_link_status; diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c index 0d28ebe3e6dc35f767b5fbdeb6af8e854d37a472..e93a84c76b257452435a4c760ccd8ed7b0cc0e44 100644 --- a/drivers/net/wireless/cnss2/usb.c +++ b/drivers/net/wireless/cnss2/usb.c @@ -185,7 +185,8 @@ int cnss_usb_call_driver_remove(struct cnss_usb_data *usb_priv) } static struct usb_driver cnss_usb_driver; -#define QCN7605_WLAN_INTERFACE_NUM 0x0000 +#define QCN7605_WLAN_STANDALONE_INTERFACE_NUM 0x0000 +#define QCN7605_WLAN_COMPOSITE_INTERFACE_NUM 0x0002 static int cnss_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) @@ -207,15 +208,6 @@ static int cnss_usb_probe(struct usb_interface *interface, goto out; } - if (interface->cur_altsetting->desc.bInterfaceNumber == - QCN7605_WLAN_INTERFACE_NUM) { - if (usb_driver_claim_interface(&cnss_usb_driver, - interface, - NULL)) { - ret = -ENODEV; - goto reset_priv; - } - } bcd_device = le16_to_cpu(usb_dev->descriptor.bcdDevice); usb_priv->plat_priv = plat_priv; usb_priv->usb_intf = interface; @@ -256,7 +248,6 @@ static int cnss_usb_probe(struct usb_interface *interface, cnss_unregister_subsys(plat_priv); reset_ctx: plat_priv->bus_priv = NULL; -reset_priv: devm_kfree(&usb_dev->dev, usb_priv); out: return ret; @@ -317,15 +308,13 @@ static int cnss_usb_reset_resume(struct usb_interface *interface) } static struct usb_device_id cnss_usb_id_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(QCN7605_USB_VENDOR_ID, - QCN7605_COMPOSITE_PRODUCT_ID, - QCN7605_WLAN_INTERFACE_NUM, - 0xFF, 0xFF) }, - { USB_DEVICE_AND_INTERFACE_INFO(QCN7605_USB_VENDOR_ID, - QCN7605_STANDALONE_PRODUCT_ID, - QCN7605_WLAN_INTERFACE_NUM, - 0xFF, 0xFF) }, - {} /* Terminating entry */ + { USB_DEVICE_INTERFACE_NUMBER(QCN7605_USB_VENDOR_ID, + QCN7605_COMPOSITE_PRODUCT_ID, + QCN7605_WLAN_COMPOSITE_INTERFACE_NUM) }, + { USB_DEVICE_INTERFACE_NUMBER(QCN7605_USB_VENDOR_ID, + QCN7605_STANDALONE_PRODUCT_ID, + QCN7605_WLAN_STANDALONE_INTERFACE_NUM) }, + {} /* Terminating entry */ }; static struct usb_driver cnss_usb_driver = { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 1f38c338ca7a11cc610e6ca14673da7caafb1060..2a25996d058d685cd1af16c91f313b5d9633e723 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -672,7 +672,6 @@ enum rt2x00_state_flags { CONFIG_CHANNEL_HT40, CONFIG_POWERSAVING, CONFIG_HT_DISABLED, - CONFIG_QOS_DISABLED, CONFIG_MONITORING, /* diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 6fe0c6abe0d6eca885b9a2be028de258c90f01d8..84728c281f463703bd3a62d436fd7fd59ea8f23e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -670,18 +670,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, rt2x00dev->intf_associated--; rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); - - clear_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags); } - /* - * Check for access point which do not support 802.11e . We have to - * generate data frames sequence number in S/W for such AP, because - * of H/W bug. - */ - if (changes & BSS_CHANGED_QOS && !bss_conf->qos) - set_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags); - /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index e1660b92b20c7793c88ea5d470e1d793f495bbf6..1b0f2da8a10d106c24d32aea9f04417453c5db3d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -200,15 +200,18 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_SW_SEQNO)) { /* * rt2800 has a H/W (or F/W) bug, device incorrectly increase - * seqno on retransmited data (non-QOS) frames. To workaround - * the problem let's generate seqno in software if QOS is - * disabled. + * seqno on retransmitted data (non-QOS) and management frames. + * To workaround the problem let's generate seqno in software. + * Except for beacons which are transmitted periodically by H/W + * hence hardware has to assign seqno for them. */ - if (test_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags)) - __clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - else + if (ieee80211_is_beacon(hdr->frame_control)) { + __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); /* H/W will generate sequence number */ return; + } + + __clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); } /* diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index e579d694d13cdc9e18b4af9964287df758b84666..21986ba56a3c899c3135079eb9e61f4de282bf2d 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -74,7 +74,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle) atomic_inc(&handle->thread_done); rsi_set_event(&handle->event); - wait_for_completion(&handle->completion); return kthread_stop(handle->task); } diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index 4f46155cf22ac410e672357857cbc1c8c9558ca5..19829a9a8623f34aed90e2e865e63b605acd88e9 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -841,6 +841,9 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) reset_enable_gpio: /* making sure that the NFCC starts in a clean state. */ + gpio_set_value(enable_gpio, 1);/* HPD : Enable*/ + /* hardware dependent delay */ + usleep_range(10000, 10100); gpio_set_value(enable_gpio, 0);/* ULPM: Disable */ /* hardware dependent delay */ usleep_range(10000, 10100); @@ -906,8 +909,12 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) } goto err_nfcc_reset_failed; } - /* hardware dependent delay */ - msleep(30); + nqx_enable_irq(nqx_dev); + ret = wait_event_interruptible(nqx_dev->read_wq, !nqx_dev->irq_enabled); + if (ret < 0) { + nqx_disable_irq(nqx_dev); + goto err_nfcc_hw_check; + } /* Read Response of RESET command */ ret = i2c_master_recv(client, nci_reset_rsp, NCI_RESET_RSP_LEN); @@ -919,9 +926,12 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) goto reset_enable_gpio; goto err_nfcc_hw_check; } - - /* hardware dependent delay */ - msleep(30); + nqx_enable_irq(nqx_dev); + ret = wait_event_interruptible(nqx_dev->read_wq, !nqx_dev->irq_enabled); + if (ret < 0) { + nqx_disable_irq(nqx_dev); + goto err_nfcc_hw_check; + } /* Read Notification of RESET command */ ret = i2c_master_recv(client, nci_reset_ntf, NCI_RESET_NTF_LEN); diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 5fa7856f6b344c1d5dbef76b6d72a9ca1aa88513..09a39f4aaf821f179406b50471be4873bdf30da1 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -746,6 +746,15 @@ bool nvmet_host_allowed(struct nvmet_req *req, struct nvmet_subsys *subsys, return __nvmet_host_allowed(subsys, hostnqn); } +static void nvmet_fatal_error_handler(struct work_struct *work) +{ + struct nvmet_ctrl *ctrl = + container_of(work, struct nvmet_ctrl, fatal_err_work); + + pr_err("ctrl %d fatal error occurred!\n", ctrl->cntlid); + ctrl->ops->delete_ctrl(ctrl); +} + u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp) { @@ -785,6 +794,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work); INIT_LIST_HEAD(&ctrl->async_events); + INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler); memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); @@ -887,21 +897,11 @@ void nvmet_ctrl_put(struct nvmet_ctrl *ctrl) kref_put(&ctrl->ref, nvmet_ctrl_free); } -static void nvmet_fatal_error_handler(struct work_struct *work) -{ - struct nvmet_ctrl *ctrl = - container_of(work, struct nvmet_ctrl, fatal_err_work); - - pr_err("ctrl %d fatal error occurred!\n", ctrl->cntlid); - ctrl->ops->delete_ctrl(ctrl); -} - void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl) { mutex_lock(&ctrl->lock); if (!(ctrl->csts & NVME_CSTS_CFS)) { ctrl->csts |= NVME_CSTS_CFS; - INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler); schedule_work(&ctrl->fatal_err_work); } mutex_unlock(&ctrl->lock); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index acf7dfb00840e116f1826ece28ebfbdf377b09d7..4b2536a05fbe16ec81524acf3f673add580e2f59 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -603,6 +603,52 @@ void *initial_boot_params; static u32 of_fdt_crc32; +/* + * Reserve memory via command line if needed. + */ +static int __init early_memory_reserve(char *p) +{ + phys_addr_t base, size; + int nomap; + char *endp = p; + + while (1) { + base = memparse(endp, &endp); + if (base && (*endp == ',')) { + size = memparse(endp + 1, &endp); + if (size && (*endp == ',')) { + if (memcmp(endp + 1, "nomap", 5) == 0) { + nomap = 1; + endp += 6; + } else if (memcmp(endp + 1, "map", 3) == 0) { + nomap = 0; + endp += 4; + } else + break; + + if (early_init_dt_reserve_memory_arch(base, + size, nomap) == 0) + pr_debug( + "Early reserved memory: region : base %pa, size %ld MiB\n", + &base, (unsigned long)size / SZ_1M); + else + pr_info( + "Early reserved memory: failed : base %pa, size %ld MiB\n", + &base, (unsigned long)size / SZ_1M); + + if (*endp == ';') + endp++; + else + break; + } else + break; + } else + break; + } + return 0; +} +early_param("memrsv", early_memory_reserve); + /** * res_mem_reserve_reg() - reserve all memory described in 'reg' property */ diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 3729fd1544b48f64134e1f4a3d55d988946d55f2..b2ea3b1b782d170eb859eabc6d8cfcad5cf0656e 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -26,7 +26,7 @@ #include #include -#define MAX_RESERVED_REGIONS 32 +#define MAX_RESERVED_REGIONS 64 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; static int reserved_mem_count; diff --git a/drivers/pci/host/pci-msm-msi.c b/drivers/pci/host/pci-msm-msi.c index 2e7e95d666fcd4860ab6e4b481462a3b3b1fa9cf..a09e4fd0bd96a0966df788c1a30290f1b5c2d3a9 100644 --- a/drivers/pci/host/pci-msm-msi.c +++ b/drivers/pci/host/pci-msm-msi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,6 @@ struct msm_msi_grp { void __iomem *int_mask_reg; void __iomem *int_status_reg; u32 mask; /* tracks masked/unmasked MSI */ - spinlock_t cfg_lock; /* lock for configuring Synopsys MSI registers */ struct msm_msi_irq irqs[MSI_IRQ_PER_GRP]; }; @@ -75,6 +75,8 @@ struct msm_msi { struct irq_domain *msi_domain; /* child domain; pci related */ phys_addr_t msi_addr; enum msi_type type; + spinlock_t cfg_lock; /* lock for configuring Synopsys MSI registers */ + bool cfg_access; /* control access to Synopsys MSI registers */ void __iomem *pcie_cfg; void (*mask_irq)(struct irq_data *data); @@ -94,9 +96,6 @@ static void msm_msi_snps_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct msm_msi *msi; - struct msm_msi_grp *msi_grp; - unsigned long val = 0; - u32 index; int i; chained_irq_enter(chip, desc); @@ -104,12 +103,25 @@ static void msm_msi_snps_handler(struct irq_desc *desc) msi = irq_desc_get_handler_data(desc); for (i = 0; i < msi->nr_grps; i++) { - msi_grp = &msi->grps[i]; - val = readl_relaxed(msi_grp->int_status_reg); - writel_relaxed(val, msi_grp->int_status_reg); + struct msm_msi_grp *msi_grp = &msi->grps[i]; + u32 mask = msi_grp->mask; + u32 status; + u32 index; + + status = readl_relaxed(msi_grp->int_status_reg); + if (!status) + continue; + + /* always update the mask set in msm_msi_snps_mask_irq */ + mask = msi_grp->mask; + writel_relaxed(mask, msi_grp->int_mask_reg); + + /* process only interrupts which are not masked */ + status ^= (status & mask); + writel_relaxed(status, msi_grp->int_status_reg); - for (index = 0; val; index++, val >>= 1) - if (val & 0x1) + for (index = 0; status; index++, status >>= 1) + if (status & 0x1) generic_handle_irq(msi_grp->irqs[index].virq); } @@ -136,12 +148,12 @@ static void msm_msi_snps_mask_irq(struct irq_data *data) { struct msm_msi_irq *msi_irq = irq_data_get_irq_chip_data(data); struct msm_msi_grp *msi_grp = msi_irq->grp; + struct msm_msi *msi = msi_irq->client->msi; unsigned long flags; - spin_lock_irqsave(&msi_grp->cfg_lock, flags); + spin_lock_irqsave(&msi->cfg_lock, flags); msi_grp->mask |= BIT(msi_irq->grp_index); - writel_relaxed(msi_grp->mask, msi_grp->int_mask_reg); - spin_unlock_irqrestore(&msi_grp->cfg_lock, flags); + spin_unlock_irqrestore(&msi->cfg_lock, flags); } static void msm_msi_qgic_mask_irq(struct irq_data *data) @@ -176,12 +188,16 @@ static void msm_msi_snps_unmask_irq(struct irq_data *data) { struct msm_msi_irq *msi_irq = irq_data_get_irq_chip_data(data); struct msm_msi_grp *msi_grp = msi_irq->grp; + struct msm_msi *msi = msi_irq->client->msi; unsigned long flags; - spin_lock_irqsave(&msi_grp->cfg_lock, flags); + spin_lock_irqsave(&msi->cfg_lock, flags); + msi_grp->mask &= ~BIT(msi_irq->grp_index); - writel_relaxed(msi_grp->mask, msi_grp->int_mask_reg); - spin_unlock_irqrestore(&msi_grp->cfg_lock, flags); + if (msi->cfg_access) + writel_relaxed(msi_grp->mask, msi_grp->int_mask_reg); + + spin_unlock_irqrestore(&msi->cfg_lock, flags); } static void msm_msi_qgic_unmask_irq(struct irq_data *data) @@ -457,6 +473,21 @@ static int msm_msi_alloc_domains(struct msm_msi *msi) return 0; } +/* control access to Synopsys PCIe MSI registers */ +void msm_msi_config_access(struct irq_domain *domain, bool allow) +{ + struct msm_msi *msi = domain->parent->host_data; + unsigned long flags; + + if (msi->type == MSM_MSI_TYPE_QCOM) + return; + + spin_lock_irqsave(&msi->cfg_lock, flags); + msi->cfg_access = allow; + spin_unlock_irqrestore(&msi->cfg_lock, flags); +} +EXPORT_SYMBOL(msm_msi_config_access); + /* configure Synopsys PCIe MSI registers */ void msm_msi_config(struct irq_domain *domain) { @@ -467,13 +498,20 @@ void msm_msi_config(struct irq_domain *domain) if (msi->type == MSM_MSI_TYPE_QCOM) return; + /* PCIe core driver sets to false during LPM */ + msm_msi_config_access(domain, true); + /* program MSI termination address */ writel_relaxed(msi->msi_addr, msi->pcie_cfg + PCIE_MSI_CTRL_ADDR_OFFS); writel_relaxed(0, msi->pcie_cfg + PCIE_MSI_CTRL_UPPER_ADDR_OFFS); - /* enable all interrupts for each group */ - for (i = 0; i < msi->nr_grps; i++) - writel_relaxed(~0, msi->grps[i].int_en_reg); + /* restore mask and enable all interrupts for each group */ + for (i = 0; i < msi->nr_grps; i++) { + struct msm_msi_grp *msi_grp = &msi->grps[i]; + + writel_relaxed(msi_grp->mask, msi_grp->int_mask_reg); + writel_relaxed(~0, msi_grp->int_en_reg); + } } EXPORT_SYMBOL(msm_msi_config); @@ -514,6 +552,7 @@ int msm_msi_init(struct device *dev) msi->dev = dev; msi->of_node = of_node; mutex_init(&msi->mutex); + spin_lock_init(&msi->cfg_lock); INIT_LIST_HEAD(&msi->clients); prop_val = of_get_address(msi->of_node, 0, NULL, NULL); @@ -613,7 +652,6 @@ int msm_msi_init(struct device *dev) for (i = 0; i < msi->nr_grps; i++) { msi_grp = &msi->grps[i]; - spin_lock_init(&msi_grp->cfg_lock); msi_grp->int_en_reg = msi->pcie_cfg + PCIE_MSI_CTRL_INT_N_EN_OFFS(i); msi_grp->int_mask_reg = msi->pcie_cfg + diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index d844142f5535a7f795d6b3dbdbabd72d2f54883d..992cdc9c29762e8d445b098d67f7da9617e7ca6e 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -4180,6 +4180,9 @@ static void msm_pcie_disable(struct msm_pcie_dev_t *dev, u32 options) return; } + /* suspend access to MSI register. resume access in msm_msi_config */ + msm_msi_config_access(dev_get_msi_domain(&dev->dev->dev), false); + dev->link_status = MSM_PCIE_LINK_DISABLED; dev->power_on = false; dev->link_turned_off_counter++; @@ -6335,6 +6338,7 @@ int msm_pci_probe(struct pci_dev *pci_dev, static struct pci_device_id msm_pci_device_id[] = { {PCI_DEVICE(0x17cb, 0x0108)}, + {PCI_DEVICE(0x17cb, 0x1000)}, {0}, }; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index ea69b4dbab6611455d1a45c03852724cf5539f0f..a394ebdc258c01b31b4868f378dcd255612b5777 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -799,6 +799,10 @@ static int pci_pm_suspend_noirq(struct device *dev) } } + /* if d3hot is not supported bail out */ + if (pci_dev->no_d3hot) + return 0; + if (!pci_dev->state_saved) { pci_save_state(pci_dev); if (pci_power_manageable(pci_dev)) @@ -831,7 +835,8 @@ static int pci_pm_resume_noirq(struct device *dev) struct device_driver *drv = dev->driver; int error = 0; - pci_pm_default_resume_early(pci_dev); + if (!pci_dev->no_d3hot) + pci_pm_default_resume_early(pci_dev); if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_resume_early(dev); @@ -1204,6 +1209,10 @@ static int pci_pm_runtime_suspend(struct device *dev) return 0; } + /* if d3hot is not supported bail out */ + if (pci_dev->no_d3hot) + return 0; + if (!pci_dev->state_saved) { pci_save_state(pci_dev); pci_finish_runtime_suspend(pci_dev); @@ -1218,6 +1227,10 @@ static int pci_pm_runtime_resume(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + /* we skipped d3hot processing so skip re-init */ + if (pci_dev->no_d3hot) + goto skip_restore; + /* * Restoring config space is necessary even if the device is not bound * to a driver because although we left it in D0, it may have gone to @@ -1235,6 +1248,7 @@ static int pci_pm_runtime_resume(struct device *dev) pci_enable_wake(pci_dev, PCI_D0, false); pci_fixup_device(pci_fixup_resume, pci_dev); +skip_restore: rc = pm->runtime_resume(dev); pci_dev->runtime_d3cold = false; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d442afa195ab6030c09ae70a67f750a33cd3c2d7..867056395d4801445a2b06f279d8148f8d8ae876 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3888,6 +3888,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9128, /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130, quirk_dma_func1_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9170, + quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c47 + c57 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172, quirk_dma_func1_alias); diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.h b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.h index 8d0183d87e2046b2489a2aa96f958544d9d3d942..b7655ea0cd5567261d42f6e1c8610e86798d3442 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016,2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -155,6 +155,7 @@ #define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP PHY_OFF(0xCC) #define UFS_PHY_LINECFG_DISABLE PHY_OFF(0x138) #define UFS_PHY_RX_SYM_RESYNC_CTRL PHY_OFF(0x13C) +#define UFS_PHY_RX_MIN_HIBERN8_TIME PHY_OFF(0x140) #define UFS_PHY_RX_SIGDET_CTRL2 PHY_OFF(0x148) #define UFS_PHY_RX_PWM_GEAR_BAND PHY_OFF(0x154) #define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168) @@ -274,6 +275,7 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_1[] = { UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_HIBERN8_TIME, 0x9A), /* 8 us */ }; static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index a462ca9acdba1c9f09e28a9b782cb4eded188617..f11e20b42e1fb5472b0bf9e6b68ae2df09a70819 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -41,7 +41,7 @@ config PINCTRL_IPQ8064 config PINCTRL_QCS405 tristate "QTI QCS405 pin controller driver" - depends on GPIOLIB && OF && (ARCH_QCS405 || COMPILE_TEST) + depends on GPIOLIB && OF && (ARCH_QCS405 || COMPILE_TEST || ARCH_QCS403) select PINCTRL_MSM help This is the pinctrl, pinmux, pinconf and gpiolib driver for the diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index e9c2795615bee98e75ff2cae876cea291ea19808..034d9d4c5674d7cb47eedc14afd8f024d591c74e 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013, Sony Mobile Communications AB. - * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,10 +40,27 @@ #include "../pinconf.h" #include "pinctrl-msm.h" #include "../pinctrl-utils.h" +#include +#ifdef CONFIG_HIBERNATION +#include +#endif #define MAX_NR_GPIO 300 #define PS_HOLD_OFFSET 0x820 +#ifdef CONFIG_HIBERNATION +struct msm_gpio_regs { + u32 ctl_reg; + u32 io_reg; + u32 intr_cfg_reg; + u32 intr_status_reg; +}; + +struct msm_tile { + u32 dir_con_regs[8]; +}; +#endif + /** * struct msm_pinctrl - state for a pinctrl-msm device * @dev: device handle. @@ -80,6 +97,10 @@ struct msm_pinctrl { #endif phys_addr_t spi_cfg_regs; phys_addr_t spi_cfg_end; +#ifdef CONFIG_HIBERNATION + struct msm_gpio_regs *gpio_regs; + struct msm_tile *msm_tile_regs; +#endif }; static struct msm_pinctrl *msm_pinctrl_data; @@ -1786,8 +1807,144 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) } #ifdef CONFIG_PM +#ifdef CONFIG_HIBERNATION +static bool hibernation; + +static int pinctrl_hibernation_notifier(struct notifier_block *nb, + unsigned long event, void *dummy) +{ + struct msm_pinctrl *pctrl = msm_pinctrl_data; + const struct msm_pinctrl_soc_data *soc = pctrl->soc; + + if (event == PM_HIBERNATION_PREPARE) { + pctrl->gpio_regs = kcalloc(soc->ngroups, + sizeof(*pctrl->gpio_regs), GFP_KERNEL); + if (pctrl->gpio_regs == NULL) + return -ENOMEM; + + if (soc->tile_count) { + pctrl->msm_tile_regs = kcalloc(soc->tile_count, + sizeof(*pctrl->msm_tile_regs), GFP_KERNEL); + if (pctrl->msm_tile_regs == NULL) { + kfree(pctrl->gpio_regs); + return -ENOMEM; + } + } + hibernation = true; + } else if (event == PM_POST_HIBERNATION) { + kfree(pctrl->gpio_regs); + kfree(pctrl->msm_tile_regs); + pctrl->gpio_regs = NULL; + pctrl->msm_tile_regs = NULL; + hibernation = false; + } + return NOTIFY_OK; +} + +static struct notifier_block pinctrl_notif_block = { + .notifier_call = pinctrl_hibernation_notifier, +}; + +static int msm_pinctrl_hibernation_suspend(void) +{ + const struct msm_pingroup *pgroup; + struct msm_pinctrl *pctrl = msm_pinctrl_data; + const struct msm_pinctrl_soc_data *soc = pctrl->soc; + void __iomem *base = NULL; + void __iomem *tile_addr = NULL; + u32 i, j; + + /* Save direction conn registers for hmss */ + for (i = 0; i < soc->tile_count; i++) { + base = reassign_pctrl_reg(soc, i); + tile_addr = base + soc->dir_conn_addr[i]; + for (j = 0; j < 8; j++) + pctrl->msm_tile_regs[i].dir_con_regs[j] = + readl_relaxed(tile_addr + j*4); + } + + /* All normal gpios will have common registers, first save them */ + for (i = 0; i < soc->ngpios; i++) { + pgroup = &soc->groups[i]; + base = reassign_pctrl_reg(soc, i); + pctrl->gpio_regs[i].ctl_reg = + readl_relaxed(base + pgroup->ctl_reg); + pctrl->gpio_regs[i].io_reg = + readl_relaxed(base + pgroup->io_reg); + pctrl->gpio_regs[i].intr_cfg_reg = + readl_relaxed(base + pgroup->intr_cfg_reg); + pctrl->gpio_regs[i].intr_status_reg = + readl_relaxed(base + pgroup->intr_status_reg); + } + + /* Save other special gpios. Variable i in fallthrough */ + for ( ; i < soc->ngroups; i++) { + pgroup = &soc->groups[i]; + base = reassign_pctrl_reg(soc, i); + if (pgroup->ctl_reg) + pctrl->gpio_regs[i].ctl_reg = + readl_relaxed(base + pgroup->ctl_reg); + if (pgroup->io_reg) + pctrl->gpio_regs[i].io_reg = + readl_relaxed(base + pgroup->io_reg); + } + return 0; +} + +static void msm_pinctrl_hibernation_resume(void) +{ + u32 i, j; + const struct msm_pingroup *pgroup; + struct msm_pinctrl *pctrl = msm_pinctrl_data; + const struct msm_pinctrl_soc_data *soc = pctrl->soc; + void __iomem *base = NULL; + void __iomem *tile_addr = NULL; + + if (!pctrl->gpio_regs || !pctrl->msm_tile_regs) + return; + + for (i = 0; i < soc->tile_count; i++) { + base = reassign_pctrl_reg(soc, i); + tile_addr = base + soc->dir_conn_addr[i]; + for (j = 0; j < 8; j++) + writel_relaxed(pctrl->msm_tile_regs[i].dir_con_regs[j], + tile_addr + j*4); + } + + /* Restore normal gpios */ + for (i = 0; i < soc->ngpios; i++) { + pgroup = &soc->groups[i]; + base = reassign_pctrl_reg(soc, i); + writel_relaxed(pctrl->gpio_regs[i].ctl_reg, + base + pgroup->ctl_reg); + writel_relaxed(pctrl->gpio_regs[i].io_reg, + base + pgroup->io_reg); + writel_relaxed(pctrl->gpio_regs[i].intr_cfg_reg, + base + pgroup->intr_cfg_reg); + writel_relaxed(pctrl->gpio_regs[i].intr_status_reg, + base + pgroup->intr_status_reg); + } + + /* Restore other special gpios. Variable i in fallthrough */ + for ( ; i < soc->ngroups; i++) { + pgroup = &soc->groups[i]; + base = reassign_pctrl_reg(soc, i); + if (pgroup->ctl_reg) + writel_relaxed(pctrl->gpio_regs[i].ctl_reg, + base + pgroup->ctl_reg); + if (pgroup->io_reg) + writel_relaxed(pctrl->gpio_regs[i].io_reg, + base + pgroup->io_reg); + } +} +#endif + static int msm_pinctrl_suspend(void) { +#ifdef CONFIG_HIBERNATION + if (unlikely(hibernation)) + msm_pinctrl_hibernation_suspend(); +#endif return 0; } @@ -1800,6 +1957,12 @@ static void msm_pinctrl_resume(void) const struct msm_pingroup *g; const char *name = "null"; struct msm_pinctrl *pctrl = msm_pinctrl_data; +#ifdef CONFIG_HIBERNATION + if (unlikely(hibernation)) { + msm_pinctrl_hibernation_resume(); + return; + } +#endif if (!msm_show_resume_irq_mask) return; @@ -1907,6 +2070,11 @@ int msm_pinctrl_probe(struct platform_device *pdev, platform_set_drvdata(pdev, pctrl); register_syscore_ops(&msm_pinctrl_pm_ops); +#ifdef CONFIG_HIBERNATION + ret = register_pm_notifier(&pinctrl_notif_block); + if (ret) + return ret; +#endif dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n"); return 0; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 4602e450c82c0134e4edef308dadbc4d27a071c9..4061ebcf0991e1e3b5fb1384fad44ea8f122ca99 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2013, Sony Mobile Communications AB. - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -177,6 +177,10 @@ struct msm_pinctrl_soc_data { struct msm_gpio_mux_input *gpio_mux_in; unsigned int n_gpio_mux_in; unsigned int n_pdc_mux_offset; +#ifdef CONFIG_HIBERNATION + u32 *dir_conn_addr; + u32 tile_count; +#endif #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE const u32 *tile_start; const u32 *tile_offsets; diff --git a/drivers/pinctrl/qcom/pinctrl-sdmshrike.c b/drivers/pinctrl/qcom/pinctrl-sdmshrike.c index e37d0f68890d2da027a245c8da140bc325de6329..e1b753d225b59f2813a9c325a728a636dc8e4770 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdmshrike.c +++ b/drivers/pinctrl/qcom/pinctrl-sdmshrike.c @@ -27,6 +27,7 @@ #define NORTH 0x900000 /* dummy tile info */ #define SOUTH 0xD00000 +#define SOUTH1 0xD1E000 /* dummy tile info */ #define WEST 0x100000 #define EAST 0x500000 #define DUMMY 0x0 @@ -54,6 +55,9 @@ .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \ .intr_status_reg = base + 0xc + REG_SIZE * id, \ .intr_target_reg = base + 0x8 + REG_SIZE * id, \ + .dir_conn_reg = (base == EAST) ? base + 0xcc000 : \ + ((base == WEST) ? base + 0xcc000 : \ + ((base == NORTH) ? EAST + 0xcc000 : base + 0xcd000)), \ .mux_bit = 2, \ .pull_bit = 0, \ .drv_bit = 6, \ @@ -68,6 +72,7 @@ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ .intr_detection_width = 2, \ + .dir_conn_en_bit = 8, \ } #define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ @@ -2212,33 +2217,44 @@ static const struct msm_pingroup sdmshrike_groups[] = { [175] = PINGROUP(175, SOUTH, pci_e2, NA, NA, NA, NA, NA, NA, NA, NA), [176] = PINGROUP(176, SOUTH, pci_e2, cci_async, NA, NA, NA, NA, NA, NA, NA), - [177] = PINGROUP(177, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - [178] = PINGROUP(178, SOUTH, pci_e3, cci_timer4, NA, NA, NA, NA, NA, + [177] = PINGROUP(177, SOUTH1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [178] = PINGROUP(178, SOUTH1, pci_e3, cci_timer4, NA, NA, NA, NA, NA, NA, NA), - [179] = PINGROUP(179, SOUTH, pci_e3, cam_mclk, NA, NA, NA, NA, NA, NA, + [179] = PINGROUP(179, SOUTH1, pci_e3, cam_mclk, NA, NA, NA, NA, NA, NA, NA), - [180] = PINGROUP(180, SOUTH, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA), - [181] = PINGROUP(181, SOUTH, qup19, cam_mclk, NA, NA, NA, NA, NA, NA, + [180] = PINGROUP(180, SOUTH1, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA), + [181] = PINGROUP(181, SOUTH1, qup19, cam_mclk, NA, NA, NA, NA, NA, NA, NA), - [182] = PINGROUP(182, SOUTH, qup19, cci_timer5, gcc_gp4, NA, NA, NA, + [182] = PINGROUP(182, SOUTH1, qup19, cci_timer5, gcc_gp4, NA, NA, NA, NA, NA, NA), - [183] = PINGROUP(183, SOUTH, qup19, cci_timer6, gcc_gp5, NA, NA, NA, + [183] = PINGROUP(183, SOUTH1, qup19, cci_timer6, gcc_gp5, NA, NA, NA, NA, NA, NA), - [184] = PINGROUP(184, SOUTH, qup19, cci_timer7, NA, NA, NA, NA, NA, NA, + [184] = PINGROUP(184, SOUTH1, qup19, cci_timer7, NA, NA, NA, NA, NA, NA, NA), - [185] = PINGROUP(185, SOUTH, cci_timer8, cci_async, NA, NA, NA, NA, NA, + [185] = PINGROUP(185, SOUTH1, cci_timer8, cci_async, NA, NA, NA, NA, NA, NA, NA), - [186] = PINGROUP(186, SOUTH, cci_timer9, cci_async, NA, NA, NA, NA, NA, + [186] = PINGROUP(186, SOUTH1, cci_timer9, cci_async, NA, NA, NA, NA, NA, NA, NA), - [187] = PINGROUP(187, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - [188] = PINGROUP(188, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - [189] = PINGROUP(189, SOUTH, dp_hot, NA, NA, NA, NA, NA, NA, NA, NA), + [187] = PINGROUP(187, SOUTH1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [188] = PINGROUP(188, SOUTH1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [189] = PINGROUP(189, SOUTH1, dp_hot, NA, NA, NA, NA, NA, NA, NA, NA), [190] = SDC_QDSD_PINGROUP(sdc2_clk, 0x9b2000, 14, 6), [191] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x9b2000, 11, 3), [192] = SDC_QDSD_PINGROUP(sdc2_data, 0x9b2000, 9, 0), [193] = UFS_RESET(ufs_reset, 0xdb6004), }; +static struct msm_dir_conn sdmshrike_dir_conn[] = { + {-1, 216}, + {-1, 215}, + {-1, 214}, + {-1, 213}, + {-1, 212}, + {-1, 211}, + {-1, 210}, + {-1, 209}, +}; + static const struct msm_pinctrl_soc_data sdmshrike_pinctrl = { .pins = sdmshrike_pins, .npins = ARRAY_SIZE(sdmshrike_pins), @@ -2247,6 +2263,9 @@ static const struct msm_pinctrl_soc_data sdmshrike_pinctrl = { .groups = sdmshrike_groups, .ngroups = ARRAY_SIZE(sdmshrike_groups), .ngpios = 190, + .dir_conn = sdmshrike_dir_conn, + .n_dir_conns = ARRAY_SIZE(sdmshrike_dir_conn), + .dir_conn_irq_base = 216, }; static int sdmshrike_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6150.c b/drivers/pinctrl/qcom/pinctrl-sm6150.c index 792ad988c07fe5b308cafd2f0e4184d3b3cd477a..62da60388784c23b0c23828b199905e9d893d4e1 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6150.c @@ -1642,7 +1642,7 @@ static struct msm_dir_conn sm6150_dir_conn[] = { {-1, 209}, }; -static const struct msm_pinctrl_soc_data sm6150_pinctrl = { +static struct msm_pinctrl_soc_data sm6150_pinctrl = { .pins = sm6150_pins, .npins = ARRAY_SIZE(sm6150_pins), .functions = sm6150_functions, @@ -1655,8 +1655,64 @@ static const struct msm_pinctrl_soc_data sm6150_pinctrl = { .dir_conn_irq_base = 216, }; +static int sm6150_pinctrl_dir_conn_probe(struct platform_device *pdev) +{ + const __be32 *prop; + struct msm_dir_conn *dir_conn_list; + uint32_t dir_conn_length, iterator = 0; + int i, length, *dir_conn_entries, num_dir_conns; + + prop = of_get_property(pdev->dev.of_node, "dirconn-list", + &length); + + dir_conn_length = length / sizeof(u32); + + dir_conn_entries = devm_kzalloc(&pdev->dev, + dir_conn_length*sizeof(uint32_t), GFP_KERNEL); + if (!dir_conn_entries) + return -ENOMEM; + + for (i = 0; i < dir_conn_length; i++) + dir_conn_entries[i] = be32_to_cpu(prop[i]); + + if (dir_conn_length % 3) { + dev_err(&pdev->dev, + "Can't parse an entry with fewer than three values\n"); + return -EINVAL; + }; + + num_dir_conns = (dir_conn_length / 3); + + dir_conn_list = devm_kzalloc(&pdev->dev, + num_dir_conns * sizeof(*dir_conn_list), GFP_KERNEL); + if (!dir_conn_list) + return -ENOMEM; + + for (i = 0; i < num_dir_conns; i++) { + dir_conn_list[i].gpio = dir_conn_entries[iterator++]; + dir_conn_list[i].hwirq = dir_conn_entries[iterator++]; + dir_conn_list[i].tlmm_dc = dir_conn_entries[iterator++]; + } + + sm6150_pinctrl.dir_conn = dir_conn_list; + sm6150_pinctrl.n_dir_conns = num_dir_conns; + + return 0; +} + static int sm6150_pinctrl_probe(struct platform_device *pdev) { + int len, ret; + + if (of_find_property(pdev->dev.of_node, "dirconn-list", &len)) { + ret = sm6150_pinctrl_dir_conn_probe(pdev); + if (ret) { + dev_err(&pdev->dev, + "Unable to parse TLMM direct connects\n"); + return ret; + } + } + return msm_pinctrl_probe(pdev, &sm6150_pinctrl); } diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c index ccd7091a0657f3639e0c752f0ddf0434a67dd628..c57d3a4deaca13214b8098ad6d9036b8ad1ae328 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,6 +29,11 @@ #define SOUTH 0x00D00000 #define WEST 0x00100000 #define EAST 0x00500000 +#define NORTH_PDC_OFFSET 0xbc000 +#define SOUTH_PDC_OFFSET 0xbe000 +#define WEST_PDC_OFFSET 0xbb000 +#define EAST_PDC_OFFSET 0xb7000 +#define NUM_TILES 4 #define REG_SIZE 0x1000 #define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ { \ @@ -53,9 +58,10 @@ .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \ .intr_status_reg = base + 0xc + REG_SIZE * id, \ .intr_target_reg = base + 0x8 + REG_SIZE * id, \ - .dir_conn_reg = (base == EAST) ? base + 0xb7000 : \ - ((base == WEST) ? base + 0xbb000 : \ - ((base == NORTH) ? base + 0xbc000 : base + 0xbe000)), \ + .dir_conn_reg = (base == EAST) ? base + EAST_PDC_OFFSET : \ + ((base == WEST) ? base + WEST_PDC_OFFSET : \ + ((base == NORTH) ? base + NORTH_PDC_OFFSET : \ + base + SOUTH_PDC_OFFSET)), \ .mux_bit = 2, \ .pull_bit = 0, \ .drv_bit = 6, \ @@ -1939,7 +1945,16 @@ static struct msm_dir_conn sm8150_dir_conn[] = { {-1, 209}, }; -static const struct msm_pinctrl_soc_data sm8150_pinctrl = { +#ifdef CONFIG_HIBERNATION +static u32 tile_dir_conn_addr[NUM_TILES] = { + [0] = NORTH + NORTH_PDC_OFFSET, + [1] = SOUTH + SOUTH_PDC_OFFSET, + [2] = WEST + WEST_PDC_OFFSET, + [3] = EAST + EAST_PDC_OFFSET +}; +#endif + +static struct msm_pinctrl_soc_data sm8150_pinctrl = { .pins = sm8150_pins, .npins = ARRAY_SIZE(sm8150_pins), .functions = sm8150_functions, @@ -1950,10 +1965,64 @@ static const struct msm_pinctrl_soc_data sm8150_pinctrl = { .dir_conn = sm8150_dir_conn, .n_dir_conns = ARRAY_SIZE(sm8150_dir_conn), .dir_conn_irq_base = 216, +#ifdef CONFIG_HIBERNATION + .dir_conn_addr = tile_dir_conn_addr, + .tile_count = ARRAY_SIZE(tile_dir_conn_addr), +#endif }; +static int sm8150_pinctrl_dir_conn_probe(struct platform_device *pdev) +{ + const __be32 *prop; + struct msm_dir_conn *dir_conn_list; + uint32_t dir_conn_length, iterator = 0; + int i, length, *dir_conn_entries, num_dir_conns; + + prop = of_get_property(pdev->dev.of_node, "dirconn-list", + &length); + + dir_conn_length = length / sizeof(u32); + + dir_conn_entries = devm_kzalloc(&pdev->dev, + dir_conn_length*sizeof(uint32_t), GFP_KERNEL); + if (!dir_conn_entries) + return -ENOMEM; + + for (i = 0; i < dir_conn_length; i++) + dir_conn_entries[i] = be32_to_cpu(prop[i]); + + num_dir_conns = (dir_conn_length / 3); + + dir_conn_list = devm_kzalloc(&pdev->dev, + num_dir_conns * sizeof(*dir_conn_list), GFP_KERNEL); + if (!dir_conn_list) + return -ENOMEM; + + for (i = 0; i < num_dir_conns; i++) { + dir_conn_list[i].gpio = dir_conn_entries[iterator++]; + dir_conn_list[i].hwirq = dir_conn_entries[iterator++]; + dir_conn_list[i].tlmm_dc = dir_conn_entries[iterator++]; + } + + sm8150_pinctrl.dir_conn = dir_conn_list; + sm8150_pinctrl.n_dir_conns = num_dir_conns; + + return 0; +} + static int sm8150_pinctrl_probe(struct platform_device *pdev) { + int len, ret; + + if (of_find_property(pdev->dev.of_node, "dirconn-list", &len)) { + ret = sm8150_pinctrl_dir_conn_probe(pdev); + if (ret) { + dev_err(&pdev->dev, + "Unable to parse TLMM direct connects\n"); + return ret; + } + } + return msm_pinctrl_probe(pdev, &sm8150_pinctrl); } diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 2d3da2b49754956d3524b3f482bcf2579ee32824..3544b625637e6f1ef1ef7574120875894c66d21d 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -398,6 +398,15 @@ struct ep_pcie_dev_t { extern struct ep_pcie_dev_t ep_pcie_dev; extern struct ep_pcie_hw hw_drv; +#if IS_ENABLED(CONFIG_QCOM_PCI_EDMA) +int qcom_edma_init(struct device *dev); +#else +static inline int qcom_edma_init(struct device *dev) +{ + return 0; +} +#endif + static inline void ep_pcie_write_mask(void __iomem *addr, u32 clear_mask, u32 set_mask) { @@ -436,6 +445,5 @@ extern bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev); extern void ep_pcie_reg_dump(struct ep_pcie_dev_t *dev, u32 sel, bool linkdown); extern void ep_pcie_debugfs_init(struct ep_pcie_dev_t *ep_dev); extern void ep_pcie_debugfs_exit(void); -extern int qcom_edma_init(struct device *dev); #endif diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 939b5296794ef086de5fbef9710a648610030062..407c96e690472e8ac6697c4e1e36397ed923638a 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -2854,12 +2854,14 @@ static int ep_pcie_probe(struct platform_device *pdev) } skip_mapping: ret = ep_pcie_enumeration(&ep_pcie_dev); - if (IS_ENABLED(CONFIG_QCOM_PCI_EDMA)) - qcom_edma_init(&pdev->dev); + if (ret && !ep_pcie_debug_keep_resource) + goto irq_deinit; - if (!ret || ep_pcie_debug_keep_resource) - return 0; + qcom_edma_init(&pdev->dev); + + return 0; +irq_deinit: ep_pcie_irq_deinit(&ep_pcie_dev); irq_failure: ep_pcie_gpio_deinit(&ep_pcie_dev); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index ddafc10cb6ed23b68664d41e345a8c9308f413f3..f51069f6d562e667f031823079a43831b5930c4d 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2395,7 +2395,8 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, if (erindex < GSI_EVT_RING_MAX) { ctx->evtr = &gsi_ctx->evtr[erindex]; - atomic_inc(&ctx->evtr->chan_ref_cnt); + if (props->prot != GSI_CHAN_PROT_GCI) + atomic_inc(&ctx->evtr->chan_ref_cnt); if (props->prot != GSI_CHAN_PROT_GCI && ctx->evtr->props.exclusive && atomic_read(&ctx->evtr->chan_ref_cnt) == 1) @@ -3109,7 +3110,7 @@ int gsi_dealloc_channel(unsigned long chan_hdl) } devm_kfree(gsi_ctx->dev, ctx->user_data); ctx->allocated = false; - if (ctx->evtr) + if (ctx->evtr && (ctx->props.prot != GSI_CHAN_PROT_GCI)) atomic_dec(&ctx->evtr->chan_ref_cnt); atomic_dec(&gsi_ctx->num_chan); @@ -3338,8 +3339,8 @@ int __gsi_get_gci_cookie(struct gsi_chan_ctx *ctx, uint16_t idx) * idx is not completed yet and it is getting reused by a new TRE. */ ctx->stats.userdata_in_use++; + end = ctx->ring.max_num_elem + 1; for (i = 0; i < GSI_VEID_MAX; i++) { - end = ctx->ring.max_num_elem + 1; if (!ctx->user_data[end + i].valid) { ctx->user_data[end + i].valid = true; return end + i; @@ -3348,7 +3349,7 @@ int __gsi_get_gci_cookie(struct gsi_chan_ctx *ctx, uint16_t idx) /* TODO: Increase escape buffer size if we hit this */ GSIERR("user_data is full\n"); - return -EPERM; + return 0xFFFF; } int __gsi_populate_gci_tre(struct gsi_chan_ctx *ctx, @@ -3379,7 +3380,7 @@ int __gsi_populate_gci_tre(struct gsi_chan_ctx *ctx, gci_tre.buf_len = xfer->len; gci_tre.re_type = GSI_RE_COAL; gci_tre.cookie = __gsi_get_gci_cookie(ctx, idx); - if (gci_tre.cookie < 0) + if (gci_tre.cookie > (ctx->ring.max_num_elem + GSI_VEID_MAX)) return -EPERM; /* write the TRE to ring */ @@ -3693,6 +3694,8 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) gsi_writel(1 << ctx->evtr->id, gsi_ctx->base + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(gsi_ctx->per.ee)); atomic_set(&ctx->poll_mode, mode); + if (ctx->props.prot == GSI_CHAN_PROT_GCI) + atomic_set(&ctx->evtr->chan->poll_mode, mode); GSIDBG("set gsi_ctx evtr_id %d to %d mode\n", ctx->evtr->id, mode); ctx->stats.callback_to_poll++; @@ -3701,6 +3704,8 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) if (curr == GSI_CHAN_MODE_POLL && mode == GSI_CHAN_MODE_CALLBACK) { atomic_set(&ctx->poll_mode, mode); + if (ctx->props.prot == GSI_CHAN_PROT_GCI) + atomic_set(&ctx->evtr->chan->poll_mode, mode); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0); GSIDBG("set gsi_ctx evtr_id %d to %d mode\n", ctx->evtr->id, mode); diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index 8a1d1a7201d89a9cb23b03cae2cdd99e3f7c1e47..453941d7d3c7582375f69731a5b44e7422d1260b 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -2530,17 +2530,6 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, if (orig_state != IPA_USB_SUSPENDED) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); - - /* Stop UL MHIP channel */ - if (ipa3_is_mhip_offload_enabled()) { - result = ipa_mpm_mhip_ul_start_stop_data( - MPM_MHIP_STOP, teth_prot); - if (result) { - IPA_USB_ERR("fail UL MHIP Data stop\n"); - goto bad_params; - } - } - /* Stop UL channel */ result = ipa3_xdci_disconnect(ul_clnt_hdl, true, @@ -2745,21 +2734,12 @@ static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { - /* Stop UL MHIP channel - enable HOLB */ - if (ipa3_is_mhip_offload_enabled()) { - result = ipa_mpm_mhip_ul_start_stop_data(MPM_MHIP_STOP, - teth_prot); - if (result) { - IPA_USB_ERR("fail UL MHIP Data stop\n"); - goto start_dl; - } - } /* Stop UL channel */ result = ipa3_xdci_disconnect(ul_clnt_hdl, true, ipa3_usb_ctx->qmi_req_id); if (result) { IPA_USB_ERR("failed disconnect UL channel\n"); - goto start_mhip; + goto start_dl; } ipa3_usb_ctx->qmi_req_id++; } @@ -2803,10 +2783,6 @@ static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, start_ul: if (!IPA3_USB_IS_TTYPE_DPL(ttype)) (void)ipa3_xdci_connect(ul_clnt_hdl); -start_mhip: - if (ipa3_is_mhip_offload_enabled() && !IPA3_USB_IS_TTYPE_DPL(ttype)) - (void)ipa_mpm_mhip_ul_start_stop_data(MPM_MHIP_START, - teth_prot); start_dl: (void)ipa3_xdci_connect(dl_clnt_hdl); fail_exit: @@ -2969,19 +2945,10 @@ static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, /* Start MHIP channel */ if (ipa3_is_mhip_offload_enabled()) { - if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { - /* Start UL MHIP channel */ - result = ipa_mpm_mhip_ul_start_stop_data(MPM_MHIP_START, - teth_prot); - if (result) { - IPA_USB_ERR("fail UL MHIP Data Start\n"); - goto stop_dl; - } - } result = ipa_mpm_mhip_xdci_pipe_enable(teth_prot); if (result) { IPA_USB_ERR("failed to enable MHIP pipe\n"); - goto stop_mhip_data; + goto stop_dl; } } /* Change state to CONNECTED */ @@ -2995,11 +2962,6 @@ static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, stop_mhip: if (ipa3_is_mhip_offload_enabled()) (void)ipa_mpm_mhip_xdci_pipe_disable(teth_prot); -stop_mhip_data: - /* Stop UL MHIP data */ - if (ipa3_is_mhip_offload_enabled() && !IPA3_USB_IS_TTYPE_DPL(ttype)) - (void)ipa_mpm_mhip_ul_start_stop_data(MPM_MHIP_STOP, - teth_prot); stop_dl: (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); stop_ul: @@ -3213,6 +3175,53 @@ static void ipa3_usb_exit(void) kfree(ipa3_usb_ctx); } +/** + * ipa3_get_usb_gsi_stats() - Query USB gsi stats from uc + * @stats: [inout] stats blob from client populated by driver + * + * Returns: 0 on success, negative on failure + * + * @note Cannot be called from atomic context + * + */ +int ipa3_get_usb_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats) +{ + int i; + + if (!ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio) { + IPAERR("bad parms NULL usb_gsi_stats_mmio\n"); + return -EINVAL; + } + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + for (i = 0; i < MAX_USB_CHANNELS; i++) { + stats->ring[i].ringFull = ioread32( + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGFULL_OFF); + stats->ring[i].ringEmpty = ioread32( + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGEMPTY_OFF); + stats->ring[i].ringUsageHigh = ioread32( + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGUSAGEHIGH_OFF); + stats->ring[i].ringUsageLow = ioread32( + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGUSAGELOW_OFF); + stats->ring[i].RingUtilCount = ioread32( + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGUTILCOUNT_OFF); + } + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + + return 0; +} + + arch_initcall(ipa3_usb_init); module_exit(ipa3_usb_exit); diff --git a/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c b/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c index 2a0d1eb551efdb4f9782ae459dcc44a7f2c2ccbc..879c31adccaa857ea61d694594b4b8709d8aedf3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c +++ b/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c @@ -667,7 +667,7 @@ static struct reg_access_funcs_s *get_access_funcs(u32 addr) for (i = 0; i < ARRAY_SIZE(mem_access_map); i++) { if (addr >= mem_access_map[i].addr_range_begin && - addr <= mem_access_map[i].addr_range_end) { + addr < mem_access_map[i].addr_range_end) { return mem_access_map[i].access[asub]; } } diff --git a/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.h b/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.h index 3eddb514f0c8e85eff3988bbb47491944fe59819..5fe97e4c2981bf7258d9031c064e829593473f36 100644 --- a/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.h +++ b/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.h @@ -20,16 +20,6 @@ #include "ipa_pkt_cntxt.h" #include "ipa_hw_common_ex.h" -/* - * The following macros are used to peek and poke register values and - * are required by some of the macros and include files that follow... - */ -#define my_in_dword(addr) \ - (readl(addr)) - -#define my_out_dword(addr, val) \ - ({ __iowmb(); writel_relaxed((val), (addr)); }) - #define IPA_0_IPA_WRAPPER_BASE 0 /* required by following includes */ #include "ipa_hwio.h" @@ -93,6 +83,8 @@ #define HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_RD_WR_2 (0x35) #define HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_RD_WR_3 (0x36) #define HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_CSR (0x3A) +#define HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_SDMA_0 (0x3C) +#define HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_SDMA_1 (0x3D) #define IPA_DEBUG_TESTBUS_DEF_EXTERNAL 50 #define IPA_DEBUG_TESTBUS_DEF_INTERNAL 6 @@ -947,6 +939,8 @@ static u32 ipa_reg_save_gsi_ch_test_bus_selector_array[] = { HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_RD_WR_2, HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_RD_WR_3, HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_CSR, + HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_SDMA_0, + HWIO_GSI_DEBUG_TEST_BUS_SELECTOR_SDMA_1, }; /* @@ -1253,7 +1247,7 @@ struct regs_save_hierarchy_s { static inline u32 act_read(void __iomem *addr) { - u32 val = my_in_dword(addr); + u32 val = ioread32(addr); return val; } @@ -1264,7 +1258,7 @@ act_read(void __iomem *addr) static inline void act_write(void __iomem *addr, u32 val) { - my_out_dword(addr, val); + iowrite32(val, addr); } /* diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/Makefile b/drivers/platform/msm/ipa/ipa_v3/ethernet/Makefile index ea66a4d6df39ba1f191943d3d9d8c462e349502d..7bb1bf9430b0d5fe403a4e27e487ae9641778dbb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/Makefile +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/Makefile @@ -6,6 +6,7 @@ ipa-eth-y := \ ipa_eth.o \ ipa_eth_ep.o \ ipa_eth_gsi.o \ + ipa_eth_net.o \ ipa_eth_offload.o \ ipa_eth_pci.o \ ipa_eth_pm.o \ diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/aquantia/Kconfig b/drivers/platform/msm/ipa/ipa_v3/ethernet/aquantia/Kconfig index 8fdbbbc475bdd382c63e048a6534b8de7c15babd..b1abbc2db8f6aa43dd64d3f3feaee6405dbf94c2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/aquantia/Kconfig +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/aquantia/Kconfig @@ -11,6 +11,7 @@ config AQC_IPA choice prompt "Default Rx Interrupt Proxy Method" + depends on AQC_IPA default AQC_IPA_PROXY_HOST config AQC_IPA_PROXY_UC diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c index 09e2d7c06ba1d9f5a7801c1fec87070e71f96326..91c8222eefced7f256dfeb1f6cecb25650a8450d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c @@ -244,7 +244,9 @@ static void __ipa_eth_refresh_device(struct work_struct *work) if (initable(eth_dev)) { if (eth_dev->of_state == IPA_ETH_OF_ST_DEINITED) { + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); (void) ipa_eth_init_device(eth_dev); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); if (eth_dev->of_state != IPA_ETH_OF_ST_INITED) { ipa_eth_dev_err(eth_dev, @@ -255,7 +257,9 @@ static void __ipa_eth_refresh_device(struct work_struct *work) } if (startable(eth_dev)) { + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); (void) ipa_eth_start_device(eth_dev); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); if (eth_dev->of_state != IPA_ETH_OF_ST_STARTED) { ipa_eth_dev_err(eth_dev, "Failed to start device"); @@ -269,7 +273,9 @@ static void __ipa_eth_refresh_device(struct work_struct *work) ipa_eth_dev_log(eth_dev, "Start is disallowed for the device"); if (eth_dev->of_state == IPA_ETH_OF_ST_STARTED) { + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); ipa_eth_stop_device(eth_dev); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); if (eth_dev->of_state != IPA_ETH_OF_ST_INITED) { ipa_eth_dev_err(eth_dev, @@ -282,7 +288,9 @@ static void __ipa_eth_refresh_device(struct work_struct *work) if (!initable(eth_dev)) { ipa_eth_dev_log(eth_dev, "Init is disallowed for the device"); + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); ipa_eth_deinit_device(eth_dev); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); if (eth_dev->of_state != IPA_ETH_OF_ST_DEINITED) { ipa_eth_dev_err(eth_dev, "Failed to deinit device"); @@ -382,18 +390,6 @@ static void ipa_eth_ipa_ready_cb(void *data) ipa_eth_refresh_devices(); } -struct ipa_eth_device *ipa_eth_find_device(struct device *dev) -{ - struct ipa_eth_device *eth_dev; - - list_for_each_entry(eth_dev, &ipa_eth_devices, device_list) { - if (eth_dev->dev == dev) - return eth_dev; - } - - return NULL; -} - static ssize_t ipa_eth_dev_write_init(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -626,6 +622,8 @@ static void ipa_eth_unpair_devices(struct ipa_eth_offload_driver *od) int ipa_eth_register_device(struct ipa_eth_device *eth_dev) { + int rc; + if (!eth_dev->dev) { ipa_eth_dev_err(eth_dev, "Device is NULL"); return -EINVAL; @@ -640,8 +638,23 @@ int ipa_eth_register_device(struct ipa_eth_device *eth_dev) eth_dev->pm_handle = IPA_PM_MAX_CLIENTS; INIT_WORK(ð_dev->refresh, __ipa_eth_refresh_device); + INIT_LIST_HEAD(ð_dev->rx_channels); + INIT_LIST_HEAD(ð_dev->tx_channels); + eth_dev->init = eth_dev->start = !ipa_eth_noauto; + rc = ipa_eth_net_open_device(eth_dev); + if (rc) { + ipa_eth_dev_err(eth_dev, "Failed to open network device"); + return rc; + } + + if (!eth_dev->net_dev) { + ipa_eth_dev_err(eth_dev, "Netdev info is missing"); + ipa_eth_net_close_device(eth_dev); + return -EFAULT; + } + mutex_lock(&ipa_eth_devices_lock); list_add(ð_dev->device_list, &ipa_eth_devices); @@ -661,10 +674,11 @@ void ipa_eth_unregister_device(struct ipa_eth_device *eth_dev) __ipa_eth_unpair_device(eth_dev); list_del(ð_dev->device_list); - - ipa_eth_dev_log(eth_dev, "Unregistered device"); + ipa_eth_net_close_device(eth_dev); mutex_unlock(&ipa_eth_devices_lock); + + ipa_eth_dev_log(eth_dev, "Unregistered device"); } static phys_addr_t ipa_eth_vmalloc_to_pa(void *vaddr) @@ -979,7 +993,7 @@ void *ipa_eth_get_ipc_logbuf_dbg(void) } EXPORT_SYMBOL(ipa_eth_get_ipc_logbuf_dbg); -#define IPA_ETH_IPC_LOG_PAGES 50 +#define IPA_ETH_IPC_LOG_PAGES 128 static int ipa_eth_ipc_log_init(void) { @@ -1000,11 +1014,41 @@ static void ipa_eth_ipc_log_cleanup(void) } } +static int ipa_eth_panic_save_device(struct ipa_eth_device *eth_dev) +{ + ipa_eth_net_save_regs(eth_dev); + ipa_eth_offload_save_regs(eth_dev); + + return 0; +} + +static int ipa_eth_panic_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct ipa_eth_device *eth_dev; + + mutex_lock(&ipa_eth_devices_lock); + + list_for_each_entry(eth_dev, &ipa_eth_devices, device_list) + ipa_eth_panic_save_device(eth_dev); + + mutex_unlock(&ipa_eth_devices_lock); + + return NOTIFY_DONE; +} + +static struct notifier_block ipa_eth_panic_nb = { + .notifier_call = ipa_eth_panic_notifier, +}; + int ipa_eth_init(void) { int rc; unsigned int wq_flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE; + (void) atomic_notifier_chain_register( + &panic_notifier_list, &ipa_eth_panic_nb); + rc = ipa_eth_ipc_log_init(); if (rc) { ipa_eth_err("Failed to initialize IPC logging"); @@ -1073,6 +1117,8 @@ int ipa_eth_init(void) err_dbgfs: ipa_eth_ipc_log_cleanup(); err_ipclog: + (void) atomic_notifier_chain_unregister( + &panic_notifier_list, &ipa_eth_panic_nb); return rc; } @@ -1093,4 +1139,7 @@ void ipa_eth_exit(void) ipa_eth_debugfs_cleanup(); ipa_eth_ipc_log_cleanup(); + + (void) atomic_notifier_chain_unregister( + &panic_notifier_list, &ipa_eth_panic_nb); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_bus.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_bus.c index eaccf5ee28a06d9e026c84edc917514119b766c5..b41a7a81936da06d2148ca328b9c04fd103069ad 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_bus.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_bus.c @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include + #include "ipa_eth_i.h" static bool ipa_eth_bus_is_ready; diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_ep.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_ep.c index a75970d2f6be4d8f2a281c011ee1c012cd79f241..72199565ffdc16e474d3854c1b184f9fbe433fce 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_ep.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_ep.c @@ -95,7 +95,7 @@ static void ipa_eth_init_vlan_header_v4(struct ipa_eth_device *eth_dev, eth_hdr.h_vlan_proto = htons(ETH_P_8021Q); eth_hdr.h_vlan_encapsulated_proto = htons(ETH_P_IP); - hdr_add->hdr_len = ETH_HLEN; + hdr_add->hdr_len = VLAN_ETH_HLEN; memcpy(hdr_add->hdr, ð_hdr, hdr_add->hdr_len); ipa_eth_init_header_common(eth_dev, hdr_add); @@ -113,7 +113,7 @@ static void ipa_eth_init_vlan_header_v6(struct ipa_eth_device *eth_dev, eth_hdr.h_vlan_proto = htons(ETH_P_8021Q); eth_hdr.h_vlan_encapsulated_proto = htons(ETH_P_IPV6); - hdr_add->hdr_len = ETH_HLEN; + hdr_add->hdr_len = VLAN_ETH_HLEN; memcpy(hdr_add->hdr, ð_hdr, hdr_add->hdr_len); ipa_eth_init_header_common(eth_dev, hdr_add); @@ -131,7 +131,7 @@ int ipa_eth_ep_init_headers(struct ipa_eth_device *eth_dev) { int rc = 0; bool vlan_mode; - const size_t num_hdrs = 2; // one each for IPv4 and IPv6 + const size_t num_hdrs = 2; /* one each for IPv4 and IPv6 */ size_t hdr_alloc_sz = sizeof(struct ipa_ioc_add_hdr) + num_hdrs * sizeof(struct ipa_hdr_add); struct ipa_hdr_add *hdr_v4 = NULL; @@ -156,7 +156,7 @@ int ipa_eth_ep_init_headers(struct ipa_eth_device *eth_dev) hdrs->commit = 1; hdrs->num_hdrs = num_hdrs; - // Initialize IPv4 headers + /* Initialize IPv4 headers */ snprintf(hdr_v4->name, sizeof(hdr_v4->name), "%s_ipv4", eth_dev->net_dev->name); @@ -165,7 +165,7 @@ int ipa_eth_ep_init_headers(struct ipa_eth_device *eth_dev) else ipa_eth_init_vlan_header_v4(eth_dev, hdr_v4); - // Initialize IPv6 headers + /* Initialize IPv6 headers */ snprintf(hdr_v6->name, sizeof(hdr_v6->name), "%s_ipv6", eth_dev->net_dev->name); @@ -184,10 +184,11 @@ int ipa_eth_ep_init_headers(struct ipa_eth_device *eth_dev) } static void ipa_eth_ep_init_tx_props_v4(struct ipa_eth_device *eth_dev, - struct ipa_ioc_tx_intf_prop *props) + struct ipa_eth_channel *ch, + struct ipa_ioc_tx_intf_prop *props) { props->ip = IPA_IP_v4; - props->dst_pipe = eth_dev->ch_tx->ipa_client; + props->dst_pipe = ch->ipa_client; props->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; snprintf(props->hdr_name, sizeof(props->hdr_name), "%s_ipv4", @@ -196,10 +197,11 @@ static void ipa_eth_ep_init_tx_props_v4(struct ipa_eth_device *eth_dev, } static void ipa_eth_ep_init_tx_props_v6(struct ipa_eth_device *eth_dev, - struct ipa_ioc_tx_intf_prop *props) + struct ipa_eth_channel *ch, + struct ipa_ioc_tx_intf_prop *props) { props->ip = IPA_IP_v6; - props->dst_pipe = eth_dev->ch_tx->ipa_client; + props->dst_pipe = ch->ipa_client; props->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; snprintf(props->hdr_name, sizeof(props->hdr_name), "%s_ipv6", @@ -207,25 +209,79 @@ static void ipa_eth_ep_init_tx_props_v6(struct ipa_eth_device *eth_dev, } static void ipa_eth_ep_init_rx_props_v4(struct ipa_eth_device *eth_dev, - struct ipa_ioc_rx_intf_prop *props) + struct ipa_eth_channel *ch, + struct ipa_ioc_rx_intf_prop *props) { props->ip = IPA_IP_v4; - props->src_pipe = eth_dev->ch_rx->ipa_client; + props->src_pipe = ch->ipa_client; props->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - - // TODO: what about attrib? } static void ipa_eth_ep_init_rx_props_v6(struct ipa_eth_device *eth_dev, - struct ipa_ioc_rx_intf_prop *props) + struct ipa_eth_channel *ch, + struct ipa_ioc_rx_intf_prop *props) { props->ip = IPA_IP_v6; - props->src_pipe = eth_dev->ch_rx->ipa_client; + props->src_pipe = ch->ipa_client; props->hdr_l2_type = IPA_HDR_L2_ETHERNET_II; +} + +static int ipa_eth_ep_init_tx_intf(struct ipa_eth_device *eth_dev, + struct ipa_tx_intf *tx_intf) +{ + u32 num_props; + struct list_head *l; + struct ipa_eth_channel *ch; + + num_props = 0; + list_for_each(l, ð_dev->tx_channels) + num_props += 2; /* one each for IPv4 and IPv6 */ + + tx_intf->prop = kcalloc(num_props, sizeof(*tx_intf->prop), GFP_KERNEL); + if (!tx_intf->prop) { + ipa_eth_dev_err(eth_dev, "Failed to alloc tx props"); + return -ENOMEM; + } + + tx_intf->num_props = 0; + list_for_each_entry(ch, ð_dev->tx_channels, channel_list) { + ipa_eth_ep_init_tx_props_v4(eth_dev, ch, + &tx_intf->prop[tx_intf->num_props++]); + ipa_eth_ep_init_tx_props_v6(eth_dev, ch, + &tx_intf->prop[tx_intf->num_props++]); + } + + return 0; +} + +static int ipa_eth_ep_init_rx_intf(struct ipa_eth_device *eth_dev, + struct ipa_rx_intf *rx_intf) +{ + u32 num_props; + struct list_head *l; + struct ipa_eth_channel *ch; + + num_props = 0; + list_for_each(l, ð_dev->rx_channels) + num_props += 2; /* one each for IPv4 and IPv6 */ + + rx_intf->prop = kcalloc(num_props, sizeof(*rx_intf->prop), GFP_KERNEL); + if (!rx_intf->prop) { + ipa_eth_dev_err(eth_dev, "Failed to alloc rx props"); + return -ENOMEM; + } - // TODO: what about attrib? + rx_intf->num_props = 0; + list_for_each_entry(ch, ð_dev->rx_channels, channel_list) { + ipa_eth_ep_init_rx_props_v4(eth_dev, ch, + &rx_intf->prop[rx_intf->num_props++]); + ipa_eth_ep_init_rx_props_v6(eth_dev, ch, + &rx_intf->prop[rx_intf->num_props++]); + } + + return 0; } /** @@ -240,27 +296,28 @@ static void ipa_eth_ep_init_rx_props_v6(struct ipa_eth_device *eth_dev, */ int ipa_eth_ep_register_interface(struct ipa_eth_device *eth_dev) { + int rc; struct ipa_tx_intf tx_intf; struct ipa_rx_intf rx_intf; - const size_t num_props = 2; // one each for IPv4 and IPv6 - struct ipa_ioc_tx_intf_prop tx_props[num_props]; - struct ipa_ioc_rx_intf_prop rx_props[num_props]; - memset(&tx_props, 0, sizeof(tx_props)); - ipa_eth_ep_init_tx_props_v4(eth_dev, &tx_props[0]); - ipa_eth_ep_init_tx_props_v6(eth_dev, &tx_props[1]); + memset(&tx_intf, 0, sizeof(tx_intf)); + memset(&rx_intf, 0, sizeof(rx_intf)); - tx_intf.num_props = num_props; - tx_intf.prop = tx_props; + rc = ipa_eth_ep_init_tx_intf(eth_dev, &tx_intf); + if (rc) + goto free_and_exit; - memset(&rx_props, 0, sizeof(rx_props)); - ipa_eth_ep_init_rx_props_v4(eth_dev, &rx_props[0]); - ipa_eth_ep_init_rx_props_v6(eth_dev, &rx_props[1]); + rc = ipa_eth_ep_init_rx_intf(eth_dev, &rx_intf); + if (rc) + goto free_and_exit; + + rc = ipa_register_intf(eth_dev->net_dev->name, &tx_intf, &rx_intf); - rx_intf.num_props = num_props; - rx_intf.prop = rx_props; +free_and_exit: + kzfree(tx_intf.prop); + kzfree(rx_intf.prop); - return ipa_register_intf(eth_dev->net_dev->name, &tx_intf, &rx_intf); + return rc; } /** @@ -274,44 +331,16 @@ int ipa_eth_ep_unregister_interface(struct ipa_eth_device *eth_dev) } /** - * ipa_eth_ep_init - Initialize IPA endpoint for a channel - * @ch: Channel for which EP need to be initialized - * - * Return: 0 on success, negative errno otherwise + * ipa_eth_ep_init_ctx - Initialize IPA endpoint context for a channel + * @ch: Channel for which EP ctx need to be initialized + * @vlan_mode: true if VLAN mode is enabled for the EP */ -int ipa_eth_ep_init(struct ipa_eth_channel *ch) +void ipa_eth_ep_init_ctx(struct ipa_eth_channel *ch, bool vlan_mode) { - int rc = 0; - bool vlan_mode; - const bool client_prod = IPA_CLIENT_IS_PROD(ch->ipa_client); - const int ep_num = ipa_get_ep_mapping(ch->ipa_client); - - struct ipa3_ep_context *ep_ctx = NULL; - - if (ep_num == IPA_EP_NOT_ALLOCATED) { - ipa_eth_dev_err(ch->eth_dev, - "Could not determine EP number for client %d", - ch->ipa_client); - rc = -EFAULT; - goto err_exit; - } - - ch->ipa_ep_num = ep_num; - - rc = ipa3_is_vlan_mode(IPA_VLAN_IF_ETH, &vlan_mode); - if (rc) { - ipa_eth_dev_err(ch->eth_dev, - "Could not determine IPA VLAN mode"); - goto err_exit; - } + struct ipa3_ep_context *ep_ctx = &ipa3_ctx->ep[ch->ipa_ep_num]; - ep_ctx = &ipa3_ctx->ep[ep_num]; - if (ep_ctx->valid) { - ipa_eth_dev_err(ch->eth_dev, - "EP context is already initialiazed"); - rc = -EEXIST; - goto err_exit; - } + if (ep_ctx->valid) + return; memset(ep_ctx, 0, offsetof(typeof(*ep_ctx), sys)); @@ -320,30 +349,57 @@ int ipa_eth_ep_init(struct ipa_eth_channel *ch) ep_ctx->client_notify = ipa_ep_client_notifier; ep_ctx->priv = ch; - ep_ctx->cfg.nat.nat_en = client_prod ? IPA_SRC_NAT : IPA_BYPASS_NAT; + ep_ctx->cfg.nat.nat_en = IPA_CLIENT_IS_PROD(ch->ipa_client) ? + IPA_SRC_NAT : IPA_BYPASS_NAT; ep_ctx->cfg.hdr.hdr_len = vlan_mode ? VLAN_ETH_HLEN : ETH_HLEN; - ep_ctx->cfg.mode.mode = IPA_BASIC; +} + +/** + * ipa_eth_ep_deinit_ctx - Deinitialize IPA endpoint context for a channel + * @ch: Channel for which EP ctx need to be deinitialized + */ +void ipa_eth_ep_deinit_ctx(struct ipa_eth_channel *ch) +{ + struct ipa3_ep_context *ep_ctx = &ipa3_ctx->ep[ch->ipa_ep_num]; + + if (!ep_ctx->valid) + return; + + ep_ctx->valid = false; + + memset(ep_ctx, 0, offsetof(typeof(*ep_ctx), sys)); +} + +/** + * ipa_eth_ep_init - Initialize IPA endpoint for a channel + * @ch: Channel for which EP need to be initialized + * + * Return: 0 on success, negative errno otherwise + */ +int ipa_eth_ep_init(struct ipa_eth_channel *ch) +{ + int rc = 0; + struct ipa3_ep_context *ep_ctx = NULL; -#ifdef IPA_ETH_DMA_MODE - if (IPA_ETH_CH_IS_RX(ch)) { - ep_ctx->cfg.mode.mode = IPA_DMA; - ep_ctx->cfg.mode.dst = IPA_CLIENT_AQC_ETHERNET_CONS; + ep_ctx = &ipa3_ctx->ep[ch->ipa_ep_num]; + if (!ep_ctx->valid) { + ipa_eth_dev_bug(ch->eth_dev, "EP context is not initialiazed"); + return -EFAULT; } -#endif IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - rc = ipa3_cfg_ep(ep_num, &ep_ctx->cfg); + rc = ipa3_cfg_ep(ch->ipa_ep_num, &ep_ctx->cfg); if (rc) { ipa_eth_dev_err(ch->eth_dev, - "Failed to configure EP %d", ep_num); + "Failed to configure EP %d", ch->ipa_ep_num); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); goto err_exit; } - if (IPA_ETH_CH_IS_RX(ch)) - ipa3_install_dflt_flt_rules(ep_num); + if (IPA_CLIENT_IS_PROD(ch->ipa_client)) + ipa3_install_dflt_flt_rules(ch->ipa_ep_num); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c index ebdc5a297e581a217815d888eca6df76eb224dfa..8f3983dd7c7d725f96c73c60a0d4f56bc4c6fb04 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_gsi.c @@ -222,6 +222,14 @@ int ipa_eth_gsi_dealloc(struct ipa_eth_channel *ch) } if (ep_ctx->gsi_chan_hdl != ~0) { + gsi_rc = gsi_reset_channel(ep_ctx->gsi_chan_hdl); + if (gsi_rc != GSI_STATUS_SUCCESS) { + ipa_eth_dev_err(ch->eth_dev, + "Failed to reset channel %u", + ep_ctx->gsi_chan_hdl); + return gsi_rc; + } + gsi_rc = gsi_dealloc_channel(ep_ctx->gsi_chan_hdl); if (gsi_rc != GSI_STATUS_SUCCESS) { ipa_eth_dev_err(ch->eth_dev, diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h index 5f431f08da9f0c891b0aa804186ab82fcf56476b..9b7212bd726c53dfec1810411107cbef5ca917fa 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h @@ -13,7 +13,8 @@ #ifndef _IPA_ETH_I_H_ #define _IPA_ETH_I_H_ -#include +#define IPA_ETH_NET_DRIVER +#define IPA_ETH_OFFLOAD_DRIVER #include #include "../ipa_i.h" @@ -97,6 +98,14 @@ struct ipa_eth_bus { extern struct ipa_eth_bus ipa_eth_pci_bus; +struct ipa_eth_cb_map_param { + bool map; + bool sym; + int iommu_prot; + enum dma_data_direction dma_dir; + const struct ipa_smmu_cb_ctx *cb_ctx; +}; + int ipa_eth_register_device(struct ipa_eth_device *eth_dev); void ipa_eth_unregister_device(struct ipa_eth_device *eth_dev); @@ -137,9 +146,18 @@ int ipa_eth_offload_deinit(struct ipa_eth_device *eth_dev); int ipa_eth_offload_start(struct ipa_eth_device *eth_dev); int ipa_eth_offload_stop(struct ipa_eth_device *eth_dev); +int ipa_eth_offload_save_regs(struct ipa_eth_device *eth_dev); + +int ipa_eth_net_open_device(struct ipa_eth_device *eth_dev); +void ipa_eth_net_close_device(struct ipa_eth_device *eth_dev); + +int ipa_eth_net_save_regs(struct ipa_eth_device *eth_dev); + int ipa_eth_ep_init_headers(struct ipa_eth_device *eth_dev); int ipa_eth_ep_register_interface(struct ipa_eth_device *eth_dev); int ipa_eth_ep_unregister_interface(struct ipa_eth_device *eth_dev); +void ipa_eth_ep_init_ctx(struct ipa_eth_channel *ch, bool vlan_mode); +void ipa_eth_ep_deinit_ctx(struct ipa_eth_channel *ch); int ipa_eth_pm_register(struct ipa_eth_device *eth_dev); int ipa_eth_pm_unregister(struct ipa_eth_device *eth_dev); diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_net.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_net.c new file mode 100644 index 0000000000000000000000000000000000000000..1c4b502f94422fc37e8431aa5efde9f777c8c27e --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_net.c @@ -0,0 +1,1070 @@ +/* Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * This 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_eth_i.h" + +#define ipa_eth_nd_op(eth_dev, op, args...) (eth_dev->nd->ops->op(args)) + +int ipa_eth_net_open_device(struct ipa_eth_device *eth_dev) +{ + return ipa_eth_nd_op(eth_dev, open_device, eth_dev); +} + +void ipa_eth_net_close_device(struct ipa_eth_device *eth_dev) +{ + return ipa_eth_nd_op(eth_dev, close_device, eth_dev); +} + +static phys_addr_t ipa_eth_dma_pgaddr(struct ipa_eth_device *eth_dev, + const void *vaddr) +{ + return page_to_phys(vmalloc_to_page(vaddr)); +} + +static phys_addr_t ipa_eth_dma_paddr(struct ipa_eth_device *eth_dev, + const void *vaddr) +{ + return ipa_eth_dma_pgaddr(eth_dev, vaddr) | + ((phys_addr_t)vaddr & ~PAGE_MASK); +} + +static int ipa_eth_dma_alloc(struct ipa_eth_device *eth_dev, + size_t size, gfp_t gfp, struct ipa_eth_resource *mem) +{ + if (!eth_dev || !eth_dev->dev) { + ipa_eth_dev_err(eth_dev, "eth_dev is invalid"); + return -EFAULT; + } + + if (!mem) { + ipa_eth_dev_err(eth_dev, "Missing mem parameter"); + return -EINVAL; + } + + memset(mem, 0, sizeof(*mem)); + + mem->vaddr = dma_alloc_coherent(eth_dev->dev, size, &mem->daddr, gfp); + if (!mem->vaddr) { + ipa_eth_dev_err(eth_dev, + "Failed to allocate memory of size %zu", size); + return -ENOMEM; + } + + mem->size = size; + mem->paddr = ipa_eth_dma_paddr(eth_dev, mem->vaddr); + + ipa_eth_dev_log(eth_dev, + "Allocated memory of size %zu at [%pK,%pad,%pap]", + mem->size, mem->vaddr, &mem->daddr, &mem->paddr); + + return 0; +} + +static void ipa_eth_dma_free(struct ipa_eth_device *eth_dev, + struct ipa_eth_resource *mem) +{ + dma_free_coherent(eth_dev->dev, mem->size, mem->vaddr, mem->daddr); +} + +static size_t ipa_eth_dma_walk(struct ipa_eth_device *eth_dev, + const struct ipa_eth_resource *mem, + ipa_eth_mem_it_t it, void *arg) +{ + struct ipa_eth_resource cmem = { + .size = PAGE_SIZE, + .vaddr = (void *) rounddown((unsigned long) mem->vaddr, + PAGE_SIZE), + .daddr = rounddown(mem->daddr, PAGE_SIZE), + }; + + if ((mem->daddr - cmem.daddr) != (mem->vaddr - cmem.vaddr)) { + ipa_eth_dev_err(eth_dev, + "Alignment mismatch between daddr and addr"); + return 0; + } + + if (cmem.daddr != mem->daddr) + ipa_eth_dev_dbg(eth_dev, "Daddr %pad is realigned to %pad", + mem->daddr, &cmem.daddr); + + if (cmem.vaddr != mem->vaddr) + ipa_eth_dev_dbg(eth_dev, "Vaddr %pK is realigned to %pK", + mem->vaddr, cmem.vaddr); + + while (cmem.vaddr < (mem->vaddr + mem->size)) { + cmem.paddr = ipa_eth_dma_paddr(eth_dev, cmem.vaddr); + + if (it(eth_dev, &cmem, arg)) { + ipa_eth_dev_err(eth_dev, + "Remap failed for page at [%pK,%pad,%pap]", + cmem.vaddr, &cmem.daddr, &cmem.paddr); + break; + } + + cmem.vaddr += PAGE_SIZE; + cmem.daddr += PAGE_SIZE; + } + + return clamp_val(cmem.vaddr, mem->vaddr, mem->vaddr + mem->size) - + mem->vaddr; +} + +static struct ipa_eth_dma_allocator default_dma_allocator = { + .name = "ipa_eth_dma_alloc_coherent", + .paddr = ipa_eth_dma_paddr, + .alloc = ipa_eth_dma_alloc, + .free = ipa_eth_dma_free, + .walk = ipa_eth_dma_walk, +}; + +static int ipa_eth_net_process_skb(struct ipa_eth_channel *ch, + struct sk_buff *skb) +{ + if (likely(IPA_ETH_CH_IS_RX(ch))) + return ipa_eth_net_receive_skb(ch->eth_dev, skb); + else + return ipa_eth_net_transmit_skb(ch->eth_dev, skb); +} + +static enum ipa_smmu_cb_type ipa_eth_hw_to_cb_type( + struct ipa_eth_channel *ch, + enum ipa_eth_hw_type hw_type) +{ + enum ipa_smmu_cb_type cb_type = IPA_SMMU_CB_MAX; + + switch (hw_type) { + case IPA_ETH_HW_UC: + cb_type = IPA_SMMU_CB_UC; + break; + + case IPA_ETH_HW_GSI: + case IPA_ETH_HW_IPA: /* All current ethernet client EPs uses GSI CB */ + cb_type = IPA_SMMU_CB_AP; + break; + + default: + ipa_eth_bug("Unknown Eth CB type %d", hw_type); + break; + } + + return cb_type; +} + +static struct ipa_smmu_cb_ctx *ipa_eth_get_smmu_ctx( + enum ipa_smmu_cb_type cb_type) +{ + struct ipa_smmu_cb_ctx *cb; + + if (cb_type >= IPA_SMMU_CB_MAX) + return NULL; + + cb = ipa3_get_smmu_ctx(cb_type); + + if (!cb || !cb->valid) + return NULL; + + return cb; +} + +static int ipa_eth_hw_to_cb_map_one(struct ipa_eth_channel *ch, + enum ipa_eth_hw_type hw_type, + struct ipa_eth_hw_map_param *hw_map_param, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + struct ipa_smmu_cb_ctx *cb_ctx = ipa_eth_get_smmu_ctx(cb_type); + + if (!cb_ctx) { + ipa_eth_dev_err(ch->eth_dev, + "Failed to get smmu ctx for hw type %d", + hw_type); + return -EFAULT; + } + + /* One CB can be shared between multiple HW. Make sure the parameters + * for CB are aggregated to a common denominator. + */ + cb_map_param->map = cb_map_param->map || hw_map_param->map; + cb_map_param->sym = cb_map_param->sym || hw_map_param->sym; + cb_map_param->iommu_prot |= hw_map_param->read ? IOMMU_READ : 0; + cb_map_param->iommu_prot |= hw_map_param->write ? IOMMU_WRITE : 0; + + switch (cb_map_param->iommu_prot) { + case IOMMU_READ: + cb_map_param->dma_dir = DMA_TO_DEVICE; + break; + case IOMMU_WRITE: + cb_map_param->dma_dir = DMA_FROM_DEVICE; + break; + case 0: + cb_map_param->dma_dir = DMA_NONE; + break; + default: + cb_map_param->dma_dir = DMA_BIDIRECTIONAL; + break; + } + + cb_map_param->cb_ctx = cb_ctx; + + return 0; +} + +/** + * ipa_eth_hw_to_cb_map() - Translate memory mapping parameters from IPA + * hardware types to context bank types + * @ch: Channel to which the parameters belong + * @hw_map_params: Mapping parameters for various hardware types + * @cb_map_params: Translated mapping parameters output for context banks + * + * Return: 0 if successful, non-zero otherwise + */ +static int ipa_eth_hw_to_cb_map(struct ipa_eth_channel *ch, + struct ipa_eth_hw_map_param *hw_map_params, + struct ipa_eth_cb_map_param *cb_map_params) +{ + int rc; + enum ipa_eth_hw_type hw_type; + + for (hw_type = 0; hw_type < IPA_ETH_HW_MAX; hw_type++) { + enum ipa_smmu_cb_type cb_type = + ipa_eth_hw_to_cb_type(ch, hw_type); + + rc = ipa_eth_hw_to_cb_map_one(ch, + hw_type, &hw_map_params[hw_type], + cb_type, &cb_map_params[cb_type]); + if (rc) { + ipa_eth_dev_err(ch->eth_dev, + "Failed to convert from hw to cb map params"); + return rc; + } + } + + return 0; +} + +static int ipa_eth_cb_mapper_sym(struct ipa_eth_device *eth_dev, + const struct ipa_eth_resource *cmem, void *arg) +{ + int rc; + struct ipa_eth_cb_map_param *cb_map_param = arg; + const struct ipa_smmu_cb_ctx *cb_ctx = cb_map_param->cb_ctx; + + if (!cb_map_param->map) { + ipa_eth_dev_bug(eth_dev, "CB map is not enabled"); + return -EFAULT; + } + + if (!cmem->size) { + ipa_eth_dev_bug(eth_dev, "Requested CB mapping of size 0"); + return -EINVAL; + } + + rc = ipa3_iommu_map(cb_ctx->mapping->domain, + cmem->daddr, cmem->paddr, cmem->size, cb_map_param->iommu_prot); + if (rc) { + ipa_eth_dev_err(eth_dev, + "Failed to map %zu bytes into CB %s at [%pK,%pad,%pap]", + cmem->size, cb_ctx->iommu->name, + cmem->vaddr, &cmem->daddr, &cmem->paddr); + } + + return rc; +} + +static int ipa_eth_cb_unmapper_sym(struct ipa_eth_device *eth_dev, + const struct ipa_eth_resource *cmem, void *arg) +{ + size_t size; + struct ipa_eth_cb_map_param *cb_map_param = arg; + const struct ipa_smmu_cb_ctx *cb_ctx = cb_map_param->cb_ctx; + + if (!cmem->size) { + ipa_eth_dev_err(eth_dev, "Requested CB unmapping of size 0"); + return -EINVAL; + } + + size = iommu_unmap(cb_ctx->mapping->domain, cmem->daddr, cmem->size); + if (size != cmem->size) { + ipa_eth_dev_err(eth_dev, + "Failed to unmap %zu bytes in domain %s at daddr %pad", + cmem->size, dev_name(cb_ctx->dev), &cmem->daddr); + return -EFAULT; + } + + return 0; +} + +static size_t ipa_eth_net_remap(struct ipa_eth_device *eth_dev, + const struct ipa_eth_resource *mem, + struct ipa_eth_dma_allocator *allocator, + ipa_eth_mem_it_t map_op, + struct ipa_eth_cb_map_param *cb_map_param) +{ + return allocator->walk(eth_dev, mem, map_op, cb_map_param); +} + +/** + * ipa_eth_net_cb_map_sym() - Symmetrically map a channel memory to a given IPA + * SMMU context bank + * @eth_dev: Device to which the channel memory belong + * @ch_mem: Channel memory that need to be mapped + * @allocator: Allocator used for allocating the channel memory + * @cb_type: IPA SMMU context bank to which to map the memory + * @cb_map_param: Parameters for mapping memory to the given context bank + * + * Symmetric mapping creates the same DADDR->PADDR memory mapping in the + * given IPA context bank as in the original channel memory @ch_mem. Use this + * API if any of the IPA hardware need to use the same IO virtual address as + * the network device. + * + * Return: 0 on successful mapping to the given @cb_type, non-zero otherwise. + */ +static int ipa_eth_net_cb_map_sym(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + size_t size; + struct ipa_eth_resource *cb_mem = &ch_mem->cb_mem[cb_type]; + const struct ipa_smmu_cb_ctx *cb_ctx = cb_map_param->cb_ctx; + + if (!ch_mem->mem.daddr) { + ipa_eth_dev_err(eth_dev, + "Symmetric mapping requires a valid DMA address"); + return -EFAULT; + } + + ipa_eth_dev_log(eth_dev, + "Mapping %zu bytes into domain %s at [%pK,%pad,%pap]", + ch_mem->mem.size, dev_name(cb_ctx->dev), + ch_mem->mem.vaddr, &ch_mem->mem.daddr, &ch_mem->mem.paddr); + + size = ipa_eth_net_remap(eth_dev, &ch_mem->mem, allocator, + ipa_eth_cb_mapper_sym, cb_map_param); + if (size != ch_mem->mem.size) { + /* Unmap any partially mapped memory */ + struct ipa_eth_resource unmap_mem = { + .size = size, + .vaddr = ch_mem->mem.vaddr, + .daddr = ch_mem->mem.daddr, + .paddr = ch_mem->mem.paddr, + }; + + ipa_eth_dev_err(eth_dev, + "Failed to map %zu bytes to domain %s, undo mapping", + ch_mem->mem.size - size, dev_name(cb_ctx->dev)); + + (void) ipa_eth_net_remap(eth_dev, &unmap_mem, allocator, + ipa_eth_cb_unmapper_sym, cb_map_param); + + return -EFAULT; + } + + *cb_mem = ch_mem->mem; + + ipa_eth_dev_log(eth_dev, + "Mapped %zu bytes into domain %s at [%pK,%pad,%pap]", + cb_mem->size, dev_name(cb_ctx->dev), + cb_mem->vaddr, &cb_mem->daddr, &cb_mem->paddr); + + return 0; +} + +/** + * ipa_eth_net_cb_map_asym() - Map a channel memory to a context bank, not + * necessarily using the same IO virtual address + * @eth_dev: Device to which the channel memory belong + * @ch_mem: Channel memory that need to be mapped + * @allocator: Allocator used for allocating the channel memory + * @cb_type: IPA SMMU context bank to which to map the memory + * @cb_map_param: Parameters for mapping memory to the given context bank + * + * Use this API if symmetric mapping is not required for a channel memory. See + * ipa_eth_net_cb_map_sym() for more details on symmetric mapping. + * + * Note that since assymmetric mapping uses dma_map_single(), it can only be + * used to map memory that was allocated using kmalloc(). Memory allocated from + * vmalloc region (like dma_alloc_coherent() on ARM targets) can not be mapped + * again using this API. + * + * Return: 0 on success, non-zero otherwise + */ +static int ipa_eth_net_cb_map_asym(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + struct ipa_eth_resource *cb_mem = &ch_mem->cb_mem[cb_type]; + const struct ipa_smmu_cb_ctx *cb_ctx = cb_map_param->cb_ctx; + + if (is_vmalloc_addr(ch_mem->mem.vaddr)) { + ipa_eth_dev_err(eth_dev, + "Asymmetric mapping cannot use vmalloc address"); + return -EFAULT; + } + + ipa_eth_dev_log(eth_dev, + "Mapping %zu bytes into device %s from [%pK,%pad,%pap]", + ch_mem->mem.size, dev_name(cb_ctx->dev), + ch_mem->mem.vaddr, &ch_mem->mem.daddr, &ch_mem->mem.paddr); + + *cb_mem = ch_mem->mem; + + cb_mem->daddr = dma_map_single(cb_ctx->dev, + ch_mem->mem.vaddr, ch_mem->mem.size, + cb_map_param->dma_dir); + if (dma_mapping_error(cb_ctx->dev, cb_mem->daddr)) { + cb_mem->size = 0; + ipa_eth_dev_err(eth_dev, "Failed to map buffer to device %s", + dev_name(cb_ctx->dev)); + return -EFAULT; + } + + ipa_eth_dev_log(eth_dev, + "Mapped %zu bytes into device %s at [%pK,%pad,%pap]", + cb_mem->size, dev_name(cb_ctx->dev), + cb_mem->vaddr, &cb_mem->daddr, &cb_mem->paddr); + + return 0; +} + +static int ipa_eth_net_cb_map_one(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + if (cb_map_param->sym) + return ipa_eth_net_cb_map_sym( + eth_dev, ch_mem, allocator, cb_type, cb_map_param); + else + return ipa_eth_net_cb_map_asym( + eth_dev, ch_mem, allocator, cb_type, cb_map_param); +} + +static void ipa_eth_net_cb_unmap_sym(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + struct ipa_eth_resource *cb_mem = &ch_mem->cb_mem[cb_type]; + const struct ipa_smmu_cb_ctx *cb_ctx = cb_map_param->cb_ctx; + + if (!cb_mem->size) + return; + + ipa_eth_dev_log(eth_dev, + "Unmapping %zu bytes in domain %s from daddr %pad", + cb_mem->size, dev_name(cb_ctx->dev), &cb_mem->daddr); + + (void) ipa_eth_net_remap(eth_dev, &ch_mem->mem, allocator, + ipa_eth_cb_unmapper_sym, cb_map_param); + + ipa_eth_dev_log(eth_dev, + "Unmapped %zu bytes in domain %s from daddr %pad", + cb_mem->size, dev_name(cb_ctx->dev), &cb_mem->daddr); + + cb_mem->size = 0; +} + +static void ipa_eth_net_cb_unmap_asym(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + struct ipa_eth_resource *cb_mem = &ch_mem->cb_mem[cb_type]; + const struct ipa_smmu_cb_ctx *cb_ctx = cb_map_param->cb_ctx; + + if (!cb_mem->size) + return; + + ipa_eth_dev_log(eth_dev, + "Unmapping %zu bytes in device %s from daddr %pad", + cb_mem->size, dev_name(cb_ctx->dev), &cb_mem->daddr); + + dma_unmap_single(cb_ctx->dev, cb_mem->daddr, cb_mem->size, + cb_map_param->dma_dir); + + ipa_eth_dev_log(eth_dev, + "Unmapped %zu bytes in device %s from daddr %pad", + cb_mem->size, dev_name(cb_ctx->dev), &cb_mem->daddr); + + cb_mem->size = 0; +} + +static void ipa_eth_net_cb_unmap_one(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + enum ipa_smmu_cb_type cb_type, + struct ipa_eth_cb_map_param *cb_map_param) +{ + if (cb_map_param->sym) + return ipa_eth_net_cb_unmap_sym( + eth_dev, ch_mem, allocator, cb_type, cb_map_param); + else + return ipa_eth_net_cb_unmap_asym( + eth_dev, ch_mem, allocator, cb_type, cb_map_param); +} + +/** + * ipa_eth_net_cb_unmap_ch_mem() - Unmap one channel memory from one of more + * IPA context banks + * @eth_dev: Device to which the channel memory belong + * @ch_mem: Channel memory that need to be unmapped + * @allocator: Allocator used for allocating the channel memory + * @cb_map_params: Mapping parameters for all known IPA context banks + * + * Use this API to unmap a channel memory from various IPA context banks that + * was previously mapped using ipa_eth_net_cb_map_ch_mem(). + */ +static void ipa_eth_net_cb_unmap_ch_mem(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + struct ipa_eth_cb_map_param *cb_map_params) +{ + enum ipa_smmu_cb_type cb_type; + + if (!ch_mem->cb_mem) + return; + + for (cb_type = 0; cb_type < IPA_SMMU_CB_MAX; cb_type++) { + if (!cb_map_params[cb_type].map) + continue; + + ipa_eth_net_cb_unmap_one(eth_dev, ch_mem, allocator, + cb_type, &cb_map_params[cb_type]); + } + + kfree(ch_mem->cb_mem); + ch_mem->cb_mem = NULL; +} + +/** + * ipa_eth_net_cb_map_ch_mem() - Map one channel memory to one or more IPA + * context banks + * @eth_dev: Device to which the channel memory belong + * @ch_mem: Channel memory that need to be mapped + * @allocator: Allocator used for allocating the channel memory + * @cb_map_params: Mapping parameters for all known IPA context banks + * + * Return: 0 on success, non-zero otherwise + */ +static int ipa_eth_net_cb_map_ch_mem(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel_mem *ch_mem, + struct ipa_eth_dma_allocator *allocator, + struct ipa_eth_cb_map_param *cb_map_params) +{ + int rc; + enum ipa_smmu_cb_type cb_type; + + if (ch_mem->cb_mem) { + ipa_eth_dev_err(eth_dev, "CB mem is already initialized"); + return -EEXIST; + } + + ch_mem->cb_mem = kzalloc(sizeof(*ch_mem->cb_mem) * IPA_SMMU_CB_MAX, + GFP_KERNEL); + if (!ch_mem->cb_mem) { + ipa_eth_dev_err(eth_dev, "Failed to alloc CB mem resource"); + return -ENOMEM; + } + + for (cb_type = 0; cb_type < IPA_SMMU_CB_MAX; cb_type++) { + if (!cb_map_params[cb_type].map) + continue; + + rc = ipa_eth_net_cb_map_one(eth_dev, ch_mem, allocator, + cb_type, &cb_map_params[cb_type]); + if (rc) + goto err_map; + } + + return 0; + +err_map: + ipa_eth_net_cb_unmap_ch_mem(eth_dev, ch_mem, allocator, cb_map_params); + return -ENOMEM; +} + +/** + * ipa_eth_net_hw_unmap_desc_mem() - Unmap all descriptor memory from various + * IPA hardware types + * @eth_dev: Device to which the channel belong + * @ch: Channel whose descriptor memory need to be unmapped + * + * Use this API to unmap any descriptor memory previously mapped to any of the + * IPA hardware types. + */ +static void ipa_eth_net_hw_unmap_desc_mem(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel *ch) +{ + int rc; + struct ipa_eth_channel_mem *ch_mem; + struct ipa_eth_cb_map_param cb_map_params[IPA_SMMU_CB_MAX]; + + memset(cb_map_params, 0, sizeof(cb_map_params)); + + rc = ipa_eth_hw_to_cb_map(ch, + ch->mem_params.desc.hw_map_params, cb_map_params); + if (rc) { + ipa_eth_dev_err(eth_dev, + "Failed to convert map params from hw to cb"); + return; + } + + list_for_each_entry(ch_mem, &ch->desc_mem, mem_list_entry) { + ipa_eth_net_cb_unmap_ch_mem(eth_dev, ch_mem, + ch->mem_params.desc.allocator, cb_map_params); + } +} + +/** + * ipa_eth_net_hw_map_desc_mem() - Map all descriptor memory to various IPA + * hadware types + * @eth_dev: Device to which the channel belong + * @ch: Channel from which the descriptor memory need to be mapped + * + * The API uses hardware mapping parameters listed in hw_map_params[] of struct + * ipa_eth_desc_params to determine how the mapping need to be perfomed. The + * actual SMMU context banks used by each hardware type is determined by using + * the ipa_eth_hw_to_cb_map() API. + * + * Return: 0 on success, non-zero otherwise + */ +static int ipa_eth_net_hw_map_desc_mem(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel *ch) +{ + int rc; + struct ipa_eth_channel_mem *ch_mem; + struct ipa_eth_cb_map_param cb_map_params[IPA_SMMU_CB_MAX]; + + memset(cb_map_params, 0, sizeof(cb_map_params)); + + rc = ipa_eth_hw_to_cb_map(ch, + ch->mem_params.desc.hw_map_params, cb_map_params); + if (rc) { + ipa_eth_dev_err(eth_dev, + "Failed to convert map params from hw to cb"); + return rc; + } + + list_for_each_entry(ch_mem, &ch->desc_mem, mem_list_entry) { + rc = ipa_eth_net_cb_map_ch_mem(eth_dev, ch_mem, + ch->mem_params.desc.allocator, cb_map_params); + if (rc) + goto err_map; + } + + return 0; + +err_map: + ipa_eth_net_hw_unmap_desc_mem(eth_dev, ch); + return rc; +} + +/** + * ipa_eth_net_hw_unmap_buff_mem() - Unmap all buffer memory from various IPA + * hardware types + * @eth_dev: Device to which the channel belong + * @ch: Channel whose buffer memory need to be unmapped + * + * Use this API to unmap any buffer memory previously mapped to any of the IPA + * hardware types. + */ +static void ipa_eth_net_hw_unmap_buff_mem(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel *ch) +{ + int rc; + struct ipa_eth_channel_mem *ch_mem; + struct ipa_eth_cb_map_param cb_map_params[IPA_SMMU_CB_MAX]; + + memset(cb_map_params, 0, sizeof(cb_map_params)); + + rc = ipa_eth_hw_to_cb_map(ch, + ch->mem_params.buff.hw_map_params, cb_map_params); + if (rc) { + ipa_eth_dev_err(eth_dev, + "Failed to convert map params from hw to cb"); + return; + } + + list_for_each_entry(ch_mem, &ch->buff_mem, mem_list_entry) { + ipa_eth_net_cb_unmap_ch_mem(eth_dev, ch_mem, + ch->mem_params.buff.allocator, cb_map_params); + } +} + +/** + * ipa_eth_net_hw_map_buff_mem() - Map all buffer memory to various IPA hadware + * types + * @eth_dev: Device to which the channel belong + * @ch: Channel from which the buffer memory need to be mapped + * + * The API uses hardware mapping parameters listed in hw_map_params[] of struct + * ipa_eth_buff_params to determine how the mapping need to be perfomed. The + * actual SMMU context banks used by each hardware type is determined by using + * the ipa_eth_hw_to_cb_map() API. + * + * Return: 0 on success, non-zero otherwise + */ +static int ipa_eth_net_hw_map_buff_mem(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel *ch) +{ + int rc; + struct ipa_eth_channel_mem *ch_mem; + struct ipa_eth_cb_map_param cb_map_params[IPA_SMMU_CB_MAX]; + + memset(cb_map_params, 0, sizeof(cb_map_params)); + + rc = ipa_eth_hw_to_cb_map(ch, + ch->mem_params.buff.hw_map_params, cb_map_params); + if (rc) { + ipa_eth_dev_err(eth_dev, + "Failed to convert map params from hw to cb"); + return rc; + } + + list_for_each_entry(ch_mem, &ch->buff_mem, mem_list_entry) { + rc = ipa_eth_net_cb_map_ch_mem(eth_dev, ch_mem, + ch->mem_params.buff.allocator, cb_map_params); + if (rc) + goto err_map; + } + + return 0; + +err_map: + ipa_eth_net_hw_unmap_buff_mem(eth_dev, ch); + return rc; +} + +/** + * ipa_eth_net_hw_map_channel() - Map all the channel memory to various IPA + * hardware types + * @eth_dev: Device to which the channel belong + * @ch: Channel whose memory need to be mapped + * + * Return: 0 if successful, non-zero otherwise + */ +static int ipa_eth_net_hw_map_channel(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel *ch) +{ + int rc; + + rc = ipa_eth_net_hw_map_desc_mem(eth_dev, ch); + if (rc) + return rc; + + rc = ipa_eth_net_hw_map_buff_mem(eth_dev, ch); + if (rc) { + ipa_eth_net_hw_unmap_desc_mem(eth_dev, ch); + return rc; + } + + return 0; +} + +/** + * ipa_eth_net_cb_unmap_channel() - Unmap channel descriptor and buffer memory + * from IPA CBs + * @eth_dev: Ethernet device + * @ch: Ethernet device channel + */ +static void ipa_eth_net_hw_unmap_channel(struct ipa_eth_device *eth_dev, + struct ipa_eth_channel *ch) +{ + ipa_eth_net_hw_unmap_desc_mem(eth_dev, ch); + ipa_eth_net_hw_unmap_buff_mem(eth_dev, ch); +} + +/** + * ipa_eth_net_alloc_channel() - Allocate and initialize ipa_eth_channel + * @eth_dev: Ethernet device + * @dir: Channel direction + * @events: Supported events + * @featues: Supported features + * @mem_params: Channel memory allocation parameters + * + * This API is expected to be called by network driver .request_channel() + * callback implementation. + * + * Return: Pointer to the allocated ipa_eth_channel, NULL if the allocation + * fails + */ +struct ipa_eth_channel *ipa_eth_net_alloc_channel( + struct ipa_eth_device *eth_dev, enum ipa_eth_channel_dir dir, + unsigned long events, unsigned long features, + const struct ipa_eth_channel_mem_params *mem_params) +{ + struct ipa_eth_channel *channel; + + if (!mem_params) { + ipa_eth_dev_err(eth_dev, "Missing channel mem params"); + return NULL; + } + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return NULL; + + channel->eth_dev = eth_dev; + channel->direction = dir; + channel->events = events; + channel->features = features; + + channel->mem_params = *mem_params; + + INIT_LIST_HEAD(&channel->desc_mem); + INIT_LIST_HEAD(&channel->buff_mem); + + return channel; +} +EXPORT_SYMBOL(ipa_eth_net_alloc_channel); + +/** + * ipa_eth_net_free_channel() - Deallocate an ipa_eth_channel previously + * allocated by ipa_eth_net_alloc_channel() + * @channel: Channel to be deallocated + */ +void ipa_eth_net_free_channel(struct ipa_eth_channel *channel) +{ + struct ipa_eth_device *eth_dev = channel->eth_dev; + + if (!list_empty(&channel->desc_mem)) + ipa_eth_dev_bug(eth_dev, "Descriptor memory still in use"); + + if (!list_empty(&channel->desc_mem)) + ipa_eth_dev_bug(eth_dev, "Buffer memory still in use"); + + kzfree(channel); +} +EXPORT_SYMBOL(ipa_eth_net_free_channel); + + +/** + * ipa_eth_net_request_channel() - Request a channel from network device to be + * used for a specific end-point + * @eth_dev: Ethernet device + * @ipa_client: IPA EP client enum that also determines the channel direction + * @events: Refer documentation of ipa_eth_net_ops.request_channel() + * @features: Refer documentation of ipa_eth_net_ops.request_channel() + * @mem_params: Refer documentation of ipa_eth_net_ops.request_channel() + * + * Offload drivers should use this API in order to invoke the network driver API + * ipa_eth_net_ops.request_channel(). The function also initializes EP context + * and maps channel memory to various IPA SMMU context banks. + * + * Return: Allocated channel if the allocation succeeds. NULL otherwise. + */ +struct ipa_eth_channel *ipa_eth_net_request_channel( + struct ipa_eth_device *eth_dev, enum ipa_client_type ipa_client, + unsigned long events, unsigned long features, + const struct ipa_eth_channel_mem_params *mem_params) +{ + int rc; + bool vlan_mode; + int ipa_ep_num; + struct ipa_eth_channel *ch; + enum ipa_eth_channel_dir dir; + struct ipa_eth_channel_mem_params params; + struct ipa3_ep_context *ep_ctx = NULL; + + if (!mem_params) { + ipa_eth_dev_err(eth_dev, "Missing channel mem params"); + return NULL; + } + + params = *mem_params; + + if (!params.desc.allocator) + params.desc.allocator = &default_dma_allocator; + + if (!params.buff.allocator) + params.buff.allocator = &default_dma_allocator; + + dir = IPA_CLIENT_IS_PROD(ipa_client) ? IPA_ETH_DIR_RX : IPA_ETH_DIR_TX; + + ipa_ep_num = ipa_get_ep_mapping(ipa_client); + if (ipa_ep_num == IPA_EP_NOT_ALLOCATED) { + ipa_eth_dev_err(eth_dev, + "Could not determine EP number for client %d", + ipa_client); + return NULL; + } + + ep_ctx = &ipa3_ctx->ep[ipa_ep_num]; + if (ep_ctx->valid) { + ipa_eth_dev_err(eth_dev, + "EP context is already initialiazed"); + return NULL; + } + + rc = ipa3_is_vlan_mode(IPA_VLAN_IF_ETH, &vlan_mode); + if (rc) { + ipa_eth_dev_err(eth_dev, + "Could not determine IPA VLAN mode"); + return NULL; + } + + ch = ipa_eth_nd_op(eth_dev, request_channel, + eth_dev, dir, events, features, ¶ms); + if (IS_ERR_OR_NULL(ch)) { + ipa_eth_dev_err(eth_dev, + "Failed to request channel from net driver %s", + eth_dev->nd->name); + return ch; + } + + ch->ipa_ep_num = ipa_ep_num; + ch->ipa_client = ipa_client; + ch->process_skb = ipa_eth_net_process_skb; + ch->eth_dev = eth_dev; + + if (ipa_eth_net_hw_map_channel(eth_dev, ch)) { + ipa_eth_dev_err(eth_dev, + "Failed to map channel memory to IPA CBs"); + ipa_eth_nd_op(eth_dev, release_channel, ch); + return NULL; + } + + ipa_eth_ep_init_ctx(ch, vlan_mode); + + if (dir == IPA_ETH_CH_DIR_RX) + list_add(&ch->channel_list, ð_dev->rx_channels); + else + list_add(&ch->channel_list, ð_dev->tx_channels); + + return ch; +} +EXPORT_SYMBOL(ipa_eth_net_request_channel); + +/** + * ipa_eth_net_release_channel() - Releases a channel presiously allocated using + * ipa_eth_net_request_channel() + * @ch: Channel to be released + */ +void ipa_eth_net_release_channel(struct ipa_eth_channel *ch) +{ + list_del(&ch->channel_list); + ipa_eth_ep_deinit_ctx(ch); + ipa_eth_net_hw_unmap_channel(ch->eth_dev, ch); + return ipa_eth_nd_op(ch->eth_dev, release_channel, ch); +} +EXPORT_SYMBOL(ipa_eth_net_release_channel); + +int ipa_eth_net_enable_channel(struct ipa_eth_channel *ch) +{ + return ipa_eth_nd_op(ch->eth_dev, enable_channel, ch); +} +EXPORT_SYMBOL(ipa_eth_net_enable_channel); + +int ipa_eth_net_disable_channel(struct ipa_eth_channel *ch) +{ + return ipa_eth_nd_op(ch->eth_dev, disable_channel, ch); +} +EXPORT_SYMBOL(ipa_eth_net_disable_channel); + +int ipa_eth_net_request_event(struct ipa_eth_channel *ch, unsigned long event, + phys_addr_t addr, u64 data) +{ + return ipa_eth_nd_op(ch->eth_dev, request_event, ch, event, addr, data); +} +EXPORT_SYMBOL(ipa_eth_net_request_event); + +void ipa_eth_net_release_event(struct ipa_eth_channel *ch, unsigned long event) +{ + return ipa_eth_nd_op(ch->eth_dev, release_event, ch, event); +} +EXPORT_SYMBOL(ipa_eth_net_release_event); + +int ipa_eth_net_enable_event(struct ipa_eth_channel *ch, unsigned long event) +{ + return ipa_eth_nd_op(ch->eth_dev, enable_event, ch, event); +} +EXPORT_SYMBOL(ipa_eth_net_enable_event); + +int ipa_eth_net_disable_event(struct ipa_eth_channel *ch, unsigned long event) +{ + return ipa_eth_nd_op(ch->eth_dev, disable_event, ch, event); +} +EXPORT_SYMBOL(ipa_eth_net_disable_event); + +int ipa_eth_net_moderate_event(struct ipa_eth_channel *ch, unsigned long event, + u64 min_count, u64 max_count, + u64 min_usecs, u64 max_usecs) +{ + return ipa_eth_nd_op(ch->eth_dev, moderate_event, ch, event, + min_count, max_count, min_usecs, max_usecs); +} +EXPORT_SYMBOL(ipa_eth_net_moderate_event); + +int ipa_eth_net_receive_skb(struct ipa_eth_device *eth_dev, + struct sk_buff *skb) +{ + return ipa_eth_nd_op(eth_dev, receive_skb, eth_dev, skb); +} +EXPORT_SYMBOL(ipa_eth_net_receive_skb); + +int ipa_eth_net_transmit_skb(struct ipa_eth_device *eth_dev, + struct sk_buff *skb) +{ + return ipa_eth_nd_op(eth_dev, transmit_skb, eth_dev, skb); +} +EXPORT_SYMBOL(ipa_eth_net_transmit_skb); + +/** + * ipa_eth_net_ch_to_cb_mem() - Provides memory mapping of a specific channel + * memory on an IPA hardware type + * @ch: Channel to which the memory belong + * @ch_mem: Channel memory whose hardware mapping need to be found out + * @hw_type: Hardware for which the mapping need to be determined + * + * The SMMU context bank used by each hw_type could vary based on channel. Use + * this API to correctly identify the context bank and the mapping made for the + * channel memory to it. + * + * Return: Memory mapping info for the given @hw_type if a mapping was + * previously made via one of ipa_eth_net_*() APIs. NULL if no mapping + * was made before to the context bank associated with a @hw_type. + */ +struct ipa_eth_resource *ipa_eth_net_ch_to_cb_mem( + struct ipa_eth_channel *ch, + struct ipa_eth_channel_mem *ch_mem, + enum ipa_eth_hw_type hw_type) +{ + struct ipa_eth_resource *cb_mem; + enum ipa_smmu_cb_type cb_type = ipa_eth_hw_to_cb_type(ch, hw_type); + + if (ch_mem->cb_mem == NULL || cb_type >= IPA_SMMU_CB_MAX) + return NULL; + + cb_mem = &ch_mem->cb_mem[cb_type]; + if (!cb_mem->size) + return NULL; + + return cb_mem; +} +EXPORT_SYMBOL(ipa_eth_net_ch_to_cb_mem); + +int ipa_eth_net_save_regs(struct ipa_eth_device *eth_dev) +{ + struct ipa_eth_net_driver *nd = eth_dev->nd; + + if (nd && nd->ops->save_regs) + return ipa_eth_nd_op(eth_dev, save_regs, eth_dev, NULL, NULL); + + return 0; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c index b4ce9439efe3ad420efa846a1751520d5f87f8df..89acc788609cf97bb1d0e6eb274fa65d5cf8974f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_offload.c @@ -112,7 +112,7 @@ int ipa_eth_offload_stop(struct ipa_eth_device *eth_dev) static int __try_pair_device(struct ipa_eth_device *eth_dev, struct ipa_eth_offload_driver *od) { - int rc = od->bus_ops->probe(eth_dev); + int rc = od->ops->pair(eth_dev); if (rc) { ipa_eth_dev_dbg(eth_dev, @@ -122,19 +122,9 @@ static int __try_pair_device(struct ipa_eth_device *eth_dev, } ipa_eth_dev_log(eth_dev, - "Offload driver %s successfully probed device from %s", + "Offload driver %s is paired with device from %s", od->name, eth_dev->nd->name); - if (!eth_dev->net_dev) { - ipa_eth_dev_err(eth_dev, - "Offload driver %s did not fill net_dev field", - od->name); - - od->bus_ops->remove(eth_dev); - - return -EFAULT; - } - eth_dev->od = od; ipa_eth_dev_log(eth_dev, @@ -182,12 +172,7 @@ void ipa_eth_offload_unpair_device(struct ipa_eth_device *eth_dev) eth_dev->od = NULL; - if (od->bus_ops->remove) - od->bus_ops->remove(eth_dev); - else - ipa_eth_dev_dbg(eth_dev, - "Bus remove is unsupported by the offload driver %s", - od->name); + od->ops->unpair(eth_dev); } int ipa_eth_offload_register_driver(struct ipa_eth_offload_driver *od) @@ -197,8 +182,8 @@ int ipa_eth_offload_register_driver(struct ipa_eth_offload_driver *od) return -EINVAL; } - if (!od->bus_ops || !od->bus_ops->probe || !od->bus_ops->remove) { - ipa_eth_err("Bus ops missing for offload driver %s", od->name); + if (!od->ops || !od->ops->pair || !od->ops->unpair) { + ipa_eth_err("Pair ops missing for offload driver %s", od->name); return -EINVAL; } @@ -227,6 +212,16 @@ void ipa_eth_offload_unregister_driver(struct ipa_eth_offload_driver *od) mutex_unlock(&ipa_eth_offload_drivers_lock); } +int ipa_eth_offload_save_regs(struct ipa_eth_device *eth_dev) +{ + struct ipa_eth_offload_driver *od = eth_dev->od; + + if (od && od->ops->save_regs) + return eth_dev->od->ops->save_regs(eth_dev, NULL, NULL); + + return 0; +} + int ipa_eth_offload_modinit(struct dentry *dbgfs_root) { int rc; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 65050073a9eb146eae01137199f5c545ed965f3c..c58d9582c0647f77428309dcfd60bff9bfadf1b6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -259,6 +259,24 @@ static int ipa3_clean_modem_rule(void) return val; } +static int ipa3_clean_mhip_dl_rule(void) +{ + struct ipa_remove_offload_connection_req_msg_v01 req; + + memset(&req, 0, sizeof(struct + ipa_remove_offload_connection_req_msg_v01)); + + req.clean_all_rules_valid = true; + req.clean_all_rules = true; + + if (ipa3_qmi_rmv_offload_request_send(&req)) { + IPAWANDBG("clean dl rule cache failed\n"); + return -EFAULT; + } + + return 0; +} + static int ipa3_active_clients_panic_notifier(struct notifier_block *this, unsigned long event, void *ptr) { @@ -1862,7 +1880,10 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) memset(&nat_del, 0, sizeof(nat_del)); nat_del.table_index = 0; retval = ipa3_nat_del_cmd(&nat_del); - retval = ipa3_clean_modem_rule(); + if (ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ) + retval = ipa3_clean_mhip_dl_rule(); + else + retval = ipa3_clean_modem_rule(); ipa3_counter_id_remove_all(); break; @@ -2911,6 +2932,12 @@ static void ipa3_q6_avoid_holb(void) ipahal_write_reg_n_fields( IPA_ENDP_INIT_HOL_BLOCK_EN_n, ep_idx, &ep_holb); + + /* IPA4.5 issue requires HOLB_EN to be written twice */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_EN_n, + ep_idx, &ep_holb); } } } @@ -4483,8 +4510,8 @@ void ipa3_enable_clks(void) if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, ipa3_get_bus_vote())) WARN(1, "bus scaling failed"); - atomic_set(&ipa3_ctx->ipa_clk_vote, 1); ipa3_ctx->ctrl->ipa3_enable_clks(); + atomic_set(&ipa3_ctx->ipa_clk_vote, 1); } @@ -6210,6 +6237,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->ipa_endp_delay_wa = resource_p->ipa_endp_delay_wa; ipa3_ctx->secure_debug_check_action = resource_p->secure_debug_check_action; + ipa3_ctx->ipa_mhi_proxy = resource_p->ipa_mhi_proxy; if (ipa3_ctx->secure_debug_check_action == USE_SCM) { if (ipa_is_mem_dump_allowed()) @@ -7007,6 +7035,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->tethered_flow_control ? "True" : "False"); + ipa_drv_res->ipa_mhi_proxy = + of_property_read_bool(pdev->dev.of_node, + "qcom,ipa-mhi-proxy"); + IPADBG(": Use mhi proxy = %s\n", + ipa_drv_res->ipa_mhi_proxy + ? "True" : "False"); + /* Get IPA wrapper address */ resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ipa-base"); @@ -7276,12 +7311,16 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) /* assume this failure is because iommu driver is not ready */ return -EPROBE_DEFER; } + + cb->is_cache_coherent = of_property_read_bool(dev->of_node, + "dma-coherent"); cb->valid = true; if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") || ipa3_ctx->ipa_config_is_mhi) { smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = true; + cb->is_cache_coherent = false; if (iommu_domain_set_attr(cb->iommu, DOMAIN_ATTR_S1_BYPASS, @@ -7413,6 +7452,8 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) /* assume this failure is because iommu driver is not ready */ return -EPROBE_DEFER; } + cb->is_cache_coherent = of_property_read_bool(dev->of_node, + "dma-coherent"); IPADBG("SMMU mapping created\n"); cb->valid = true; @@ -7422,6 +7463,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) ipa3_ctx->ipa_config_is_mhi) { smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = true; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = true; + cb->is_cache_coherent = false; if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_S1_BYPASS, @@ -7542,6 +7584,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) } } + cb->is_cache_coherent = of_property_read_bool(dev->of_node, + "dma-coherent"); cb->dev = dev; cb->mapping = arm_iommu_create_mapping(dev->bus, cb->va_start, cb->va_size); @@ -7557,6 +7601,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) "qcom,smmu-s1-bypass") || ipa3_ctx->ipa_config_is_mhi) { smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = true; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] = true; + cb->is_cache_coherent = false; + if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_S1_BYPASS, &bypass)) { @@ -8029,6 +8075,7 @@ int ipa3_iommu_map(struct iommu_domain *domain, { struct ipa_smmu_cb_ctx *ap_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); struct ipa_smmu_cb_ctx *uc_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC); + struct ipa_smmu_cb_ctx *wlan_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_WLAN); IPADBG_LOW("domain =0x%pK iova 0x%lx\n", domain, iova); IPADBG_LOW("paddr =0x%pa size 0x%x\n", &paddr, (u32)size); @@ -8040,20 +8087,29 @@ int ipa3_iommu_map(struct iommu_domain *domain, ipa_assert(); return -EFAULT; } + if (ap_cb->is_cache_coherent) + prot |= IOMMU_CACHE; } else if (domain == ipa3_get_wlan_smmu_domain()) { /* wlan is one time map */ + if (wlan_cb->is_cache_coherent) + prot |= IOMMU_CACHE; } else if (domain == ipa3_get_uc_smmu_domain()) { if (iova >= uc_cb->va_start && iova < uc_cb->va_end) { IPAERR("iommu uC overlap addr 0x%lx\n", iova); ipa_assert(); return -EFAULT; } + if (uc_cb->is_cache_coherent) + prot |= IOMMU_CACHE; } else { IPAERR("Unexpected domain 0x%pK\n", domain); ipa_assert(); return -EFAULT; } - + /* + * IOMMU_CACHE is needed in prot to make the entries cachable + * if cache coherency is enabled in dtsi. + */ return iommu_map(domain, iova, paddr, size, prot); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 5caf30a78bc43e243f77caf9d496b7026a00a8a9..8496e360302ab75559d0eb06dccbbffd04d2b768 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -36,6 +36,7 @@ static int ipa3_is_xdci_channel_empty(struct ipa3_ep_context *ep, bool *is_empty); +static void ipa3_start_gsi_debug_monitor(u32 clnt_hdl); int ipa3_enable_data_path(u32 clnt_hdl) { @@ -254,6 +255,70 @@ static bool ipa3_is_legal_params(struct ipa_request_gsi_channel_params *params) return true; } +static void ipa3_start_gsi_debug_monitor(u32 clnt_hdl) +{ + struct IpaHwOffloadStatsAllocCmdData_t *gsi_info; + struct ipa3_ep_context *ep; + enum ipa_client_type client_type; + + IPADBG("entry\n"); + if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || + ipa3_ctx->ep[clnt_hdl].valid == 0) { + IPAERR("Bad parameters.\n"); + return; + } + + ep = &ipa3_ctx->ep[clnt_hdl]; + client_type = ipa3_get_client_mapping(clnt_hdl); + + /* start uC gsi dbg stats monitor */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) { + switch (client_type) { + case IPA_CLIENT_MHI_PRIME_TETH_PROD: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[0].ch_id = ep->gsi_chan_hdl; + gsi_info->ch_id_info[0].dir = DIR_PRODUCER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_MHI_PRIME_TETH_CONS: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[1].ch_id = ep->gsi_chan_hdl; + gsi_info->ch_id_info[1].dir = DIR_CONSUMER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_MHI_PRIME_RMNET_PROD: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[2].ch_id = ep->gsi_chan_hdl; + gsi_info->ch_id_info[2].dir = DIR_PRODUCER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_MHI_PRIME_RMNET_CONS: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[3].ch_id = ep->gsi_chan_hdl; + gsi_info->ch_id_info[3].dir = DIR_CONSUMER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_USB_PROD: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_USB]; + gsi_info->ch_id_info[0].ch_id = ep->gsi_chan_hdl; + gsi_info->ch_id_info[0].dir = DIR_PRODUCER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_USB_CONS: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_USB]; + gsi_info->ch_id_info[1].ch_id = ep->gsi_chan_hdl; + gsi_info->ch_id_info[1].dir = DIR_CONSUMER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + default: + IPADBG("client_type %d not supported\n", + client_type); + } + } +} + int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map, enum ipa_smmu_cb_type cb_type) { @@ -756,6 +821,7 @@ int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid) IPAERR("Error starting channel: %d\n", gsi_res); goto write_chan_scratch_fail; } + ipa3_start_gsi_debug_monitor(clnt_hdl); if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); @@ -1236,6 +1302,12 @@ int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, ipahal_write_reg_n_fields( IPA_ENDP_INIT_HOL_BLOCK_EN_n, pipe_idx, &ep_holb); + + /* IPA4.5 issue requires HOLB_EN to be written twice */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_EN_n, + pipe_idx, &ep_holb); } client_lock_unlock_cb(client, false); return 0; @@ -1511,6 +1583,7 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, start_dl_and_exit: gsi_start_channel(dl_ep->gsi_chan_hdl); + ipa3_start_gsi_debug_monitor(dl_clnt_hdl); unsuspend_dl_and_exit: if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) { /* Unsuspend the DL EP */ @@ -1528,6 +1601,7 @@ int ipa3_start_gsi_channel(u32 clnt_hdl) struct ipa3_ep_context *ep; int result = -EFAULT; enum gsi_status gsi_res; + enum ipa_client_type client_type; IPADBG("entry\n"); if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || @@ -1537,18 +1611,19 @@ int ipa3_start_gsi_channel(u32 clnt_hdl) } ep = &ipa3_ctx->ep[clnt_hdl]; - + client_type = ipa3_get_client_mapping(clnt_hdl); if (!ep->keep_ipa_awake) - IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); + IPA_ACTIVE_CLIENTS_INC_EP(client_type); gsi_res = gsi_start_channel(ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) { IPAERR("Error starting channel: %d\n", gsi_res); goto start_chan_fail; } + ipa3_start_gsi_debug_monitor(clnt_hdl); if (!ep->keep_ipa_awake) - IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); + IPA_ACTIVE_CLIENTS_DEC_EP(client_type); IPADBG("exit\n"); return 0; @@ -1593,12 +1668,14 @@ int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl) gsi_res = gsi_start_channel(dl_ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) IPAERR("Error starting DL channel: %d\n", gsi_res); + ipa3_start_gsi_debug_monitor(dl_clnt_hdl); /* Start UL channel */ if (!is_dpl) { gsi_res = gsi_start_channel(ul_ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) IPAERR("Error starting UL channel: %d\n", gsi_res); + ipa3_start_gsi_debug_monitor(ul_clnt_hdl); } IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(dl_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 8785495316294f164441076a11d90538bdfacf5c..d56d3d2621839a0addb6e06488e521341ed758e8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -356,15 +356,15 @@ static ssize_t ipa3_write_keep_awake(struct file *file, const char __user *buf, break; case 2: IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - bw_mbps = 350; + bw_mbps = 700; break; case 3: IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - bw_mbps = 690; + bw_mbps = 3000; break; case 4: IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - bw_mbps = 1200; + bw_mbps = 7000; break; default: pr_err("Not support this vote (%d)\n", option); @@ -1988,7 +1988,9 @@ static ssize_t ipa3_read_wdi_gsi_stats(struct file *file, int nbytes; int cnt = 0; - if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5 + && (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1 + || ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) { nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "This feature only support on IPA4.5+\n"); cnt += nbytes; @@ -2036,7 +2038,9 @@ static ssize_t ipa3_read_wdi3_gsi_stats(struct file *file, int nbytes; int cnt = 0; - if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5 + && (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1 + || ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) { nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "This feature only support on IPA4.5+\n"); cnt += nbytes; @@ -2083,7 +2087,9 @@ static ssize_t ipa3_read_11ad_gsi_stats(struct file *file, int nbytes; int cnt = 0; - if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5 + && (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1 + || ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) { nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "This feature only support on IPA4.5+\n"); cnt += nbytes; @@ -2100,7 +2106,9 @@ static ssize_t ipa3_read_aqc_gsi_stats(struct file *file, int nbytes; int cnt = 0; - if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5 + && (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1 + || ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) { nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "This feature only support on IPA4.5+\n"); cnt += nbytes; @@ -2111,6 +2119,130 @@ static ssize_t ipa3_read_aqc_gsi_stats(struct file *file, return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } +static ssize_t ipa3_read_mhip_gsi_stats(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos) +{ + struct ipa3_uc_dbg_ring_stats stats; + int nbytes; + int cnt = 0; + + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5 + && (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1 + || ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "This feature only support on IPA4.5+\n"); + cnt += nbytes; + goto done; + } + if (!ipa3_get_mhip_gsi_stats(&stats)) { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "IPA_CLIENT_MHI_PRIME_TETH_CONS ringFull=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_CONS ringEmpty=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_CONS ringUsageHigh=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_CONS ringUsageLow=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_CONS RingUtilCount=%u\n", + stats.ring[1].ringFull, + stats.ring[1].ringEmpty, + stats.ring[1].ringUsageHigh, + stats.ring[1].ringUsageLow, + stats.ring[1].RingUtilCount); + cnt += nbytes; + nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, + "IPA_CLIENT_MHI_PRIME_TETH_PROD ringFull=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_PROD ringEmpty=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_PROD ringUsageHigh=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_PROD ringUsageLow=%u\n" + "IPA_CLIENT_MHI_PRIME_TETH_PROD RingUtilCount=%u\n", + stats.ring[0].ringFull, + stats.ring[0].ringEmpty, + stats.ring[0].ringUsageHigh, + stats.ring[0].ringUsageLow, + stats.ring[0].RingUtilCount); + cnt += nbytes; + nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, + "IPA_CLIENT_MHI_PRIME_RMNET_CONS ringFull=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_CONS ringEmpty=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_CONS ringUsageHigh=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_CONS ringUsageLow=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_CONS RingUtilCount=%u\n", + stats.ring[3].ringFull, + stats.ring[3].ringEmpty, + stats.ring[3].ringUsageHigh, + stats.ring[3].ringUsageLow, + stats.ring[3].RingUtilCount); + cnt += nbytes; + nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, + "IPA_CLIENT_MHI_PRIME_RMNET_PROD ringFull=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_PROD ringEmpty=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_PROD ringUsageHigh=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_PROD ringUsageLow=%u\n" + "IPA_CLIENT_MHI_PRIME_RMNET_PROD RingUtilCount=%u\n", + stats.ring[2].ringFull, + stats.ring[2].ringEmpty, + stats.ring[2].ringUsageHigh, + stats.ring[2].ringUsageLow, + stats.ring[2].RingUtilCount); + cnt += nbytes; + } else { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "Fail to read WDI GSI stats\n"); + cnt += nbytes; + } + +done: + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); +} + +static ssize_t ipa3_read_usb_gsi_stats(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos) +{ + struct ipa3_uc_dbg_ring_stats stats; + int nbytes; + int cnt = 0; + + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5 + && (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1 + || ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "This feature only support on IPA4.5+\n"); + cnt += nbytes; + goto done; + } + if (!ipa3_get_usb_gsi_stats(&stats)) { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "TX ringFull=%u\n" + "TX ringEmpty=%u\n" + "TX ringUsageHigh=%u\n" + "TX ringUsageLow=%u\n" + "TX RingUtilCount=%u\n", + stats.ring[1].ringFull, + stats.ring[1].ringEmpty, + stats.ring[1].ringUsageHigh, + stats.ring[1].ringUsageLow, + stats.ring[1].RingUtilCount); + cnt += nbytes; + nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, + "RX ringFull=%u\n" + "RX ringEmpty=%u\n" + "RX ringUsageHigh=%u\n" + "RX ringUsageLow=%u\n" + "RX RingUtilCount=%u\n", + stats.ring[0].ringFull, + stats.ring[0].ringEmpty, + stats.ring[0].ringUsageHigh, + stats.ring[0].ringUsageLow, + stats.ring[0].RingUtilCount); + cnt += nbytes; + } else { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "Fail to read WDI GSI stats\n"); + cnt += nbytes; + } + +done: + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); +} + static void ipa_dump_status(struct ipahal_pkt_status *status) { IPA_DUMP_STATUS_FIELD(status_opcode); @@ -2401,6 +2533,14 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "aqc_gsi_stats", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_aqc_gsi_stats, } + }, { + "mhip_gsi_stats", IPA_READ_ONLY_MODE, NULL, { + .read = ipa3_read_mhip_gsi_stats, + } + }, { + "usb_gsi_stats", IPA_READ_ONLY_MODE, NULL, { + .read = ipa3_read_usb_gsi_stats, + } } }; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index f72dd6c41e97c6249b40a52945eb23d919fa80ea..6091efb8ca18fb88ac675cfffde1e5601de26c21 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -118,8 +118,6 @@ static int ipa_gsi_setup_event_ring(struct ipa3_ep_context *ep, u32 ring_size, gfp_t mem_flag); static int ipa_gsi_setup_transfer_ring(struct ipa3_ep_context *ep, u32 ring_size, struct ipa3_sys_context *user_data, gfp_t mem_flag); -static int ipa_setup_coal_def_pipe(struct ipa_sys_connect_params *sys_in, - struct ipa3_ep_context *ep_coalescing); static int ipa3_teardown_coal_def_pipe(u32 clnt_hdl); static int ipa_populate_tag_field(struct ipa3_desc *desc, struct ipa3_tx_pkt_wrapper *tx_pkt, @@ -924,7 +922,7 @@ static void ipa_pm_sys_pipe_cb(void *p, enum ipa_pm_cb_event event) int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) { struct ipa3_ep_context *ep; - int i, ipa_ep_idx; + int i, ipa_ep_idx, wan_handle; int result = -EINVAL; struct ipahal_reg_coal_qmap_cfg qmap_cfg; struct ipahal_reg_coal_evict_lru evict_lru; @@ -1098,10 +1096,6 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) atomic_set(&ep->sys->repl->pending, 0); ep->sys->repl->capacity = ep->sys->rx_pool_sz + 1; - /*double for wan_coal since it will be shared between 2 pipes */ - if (sys_in->client == IPA_CLIENT_APPS_WAN_COAL_CONS) - ep->sys->repl->capacity *= 2; - ep->sys->repl->cache = kcalloc(ep->sys->repl->capacity, sizeof(void *), GFP_KERNEL); if (!ep->sys->repl->cache) { @@ -1166,7 +1160,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) sys_in->client = IPA_CLIENT_APPS_WAN_CONS; sys_in->ipa_ep_cfg = ep_cfg_copy; - result = ipa_setup_coal_def_pipe(sys_in, ep); + result = ipa3_setup_sys_pipe(sys_in, &wan_handle); if (result) { IPAERR("failed to setup default coalescing pipe\n"); goto fail_repl; @@ -1197,137 +1191,6 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) return result; } -/** - * ipa3_setup_coal_def_pipe() - Setup a crippled default pipe in addition to the - * coalescing pipe. - * - * @sys_in: [in] input needed to setup the pipe and configure EP - * @ep_coalescing [in] the ep context of the coal pipe - * - * - configure the end-point registers with the supplied - * parameters from the user. - * - Creates a GPI connection with IPA. - * - allocate descriptor FIFO - * - * Returns: 0 on success, negative on failure - */ -static int ipa_setup_coal_def_pipe(struct ipa_sys_connect_params *sys_in, - struct ipa3_ep_context *ep_coalescing) -{ - struct ipa3_ep_context *ep; - int result = -EINVAL; - int ipa_ep_idx; - - ipa_ep_idx = ipa3_get_ep_mapping(sys_in->client); - - if (ipa_ep_idx == IPA_EP_NOT_ALLOCATED) { - IPAERR("failed to get idx"); - goto fail_gen; - } - - ep = &ipa3_ctx->ep[ipa_ep_idx]; - if (ep->valid == 1) { - IPAERR("EP %d already allocated.\n", ipa_ep_idx); - goto fail_gen; - } - - memset(ep, 0, offsetof(struct ipa3_ep_context, sys)); - - if (!ep->sys) { - ep->sys = kzalloc(sizeof(struct ipa3_sys_context), GFP_KERNEL); - if (!ep->sys) { - IPAERR("failed to sys ctx for client %d\n", - IPA_CLIENT_APPS_WAN_CONS); - result = -ENOMEM; - goto fail_wq; - } - - ep->sys->ep = ep; - ep->sys->wq = ep_coalescing->sys->wq; - ep->sys->repl_wq = ep_coalescing->sys->repl_wq; - - spin_lock_init(&ep->sys->spinlock); - hrtimer_init(&ep->sys->db_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - ep->sys->db_timer.function = ipa3_ring_doorbell_timer_fn; - } else { - memset(ep->sys, 0, offsetof(struct ipa3_sys_context, ep)); - } - - ep->skip_ep_cfg = ep_coalescing->skip_ep_cfg; - - if (ipa3_assign_policy(sys_in, ep->sys)) { - IPAERR("failed to sys ctx for client %d\n", - IPA_CLIENT_APPS_WAN_CONS); - result = -ENOMEM; - goto fail_wq; - } - - ep->valid = 1; - ep->client = sys_in->client; - ep->client_notify = ep_coalescing->client_notify; - ep->priv = ep_coalescing->priv; - ep->keep_ipa_awake = ep_coalescing->keep_ipa_awake; - atomic_set(&ep->avail_fifo_desc, - ((sys_in->desc_fifo_sz / IPA_FIFO_ELEMENT_SIZE) - 1)); - - if (!ep->skip_ep_cfg) { - if (ipa3_cfg_ep(ipa_ep_idx, &sys_in->ipa_ep_cfg)) { - IPAERR("fail to configure EP.\n"); - goto fail_wq; - } - - if (ep->status.status_en) { - IPAERR("status should be disabled for this EP.\n"); - goto fail_wq; - } - - if (ipa3_cfg_ep_status(ipa_ep_idx, &ep->status)) { - IPAERR("fail to configure status of EP.\n"); - goto fail_wq; - } - IPADBG("ep %d configuration successful\n", ipa_ep_idx); - } else { - IPADBG("skipping ep %d configuration\n", ipa_ep_idx); - } - - result = ipa_gsi_setup_coal_def_channel(sys_in, ep, ep_coalescing); - if (result) { - IPAERR("Failed to setup default coal GSI channel\n"); - goto fail_wq; - } - - ep->sys->repl = ep_coalescing->sys->repl; - ipa3_replenish_rx_cache(ep->sys); - - ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg; - - result = ipa3_enable_data_path(ipa_ep_idx); - if (result) { - IPAERR("enable data path failed res=%d ep=%d.\n", result, - ipa_ep_idx); - goto fail_wq; - } - - result = gsi_start_channel(ep->gsi_chan_hdl); - if (result != GSI_STATUS_SUCCESS) - goto fail_start_channel; - - IPADBG("client %d (ep: %d) connected sys=%pK\n", ep->client, - ipa_ep_idx, ep->sys); - - return 0; - -/* the rest of the fails are handled by ipa3_setup_sys_pipe */ -fail_start_channel: - ipa3_disable_data_path(ipa_ep_idx); -fail_wq: - kfree(ep->sys); - memset(&ipa3_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa3_ep_context)); -fail_gen: - return result; -} - /** * ipa3_teardown_sys_pipe() - Teardown the GPI pipe and cleanup IPA EP * @clnt_hdl: [in] the handle obtained from ipa3_setup_sys_pipe @@ -1523,6 +1386,17 @@ static int ipa3_teardown_coal_def_pipe(u32 clnt_hdl) ipa_assert(); return result; } + + if (IPA_CLIENT_IS_CONS(ep->client)) + cancel_delayed_work_sync(&ep->sys->replenish_rx_work); + + flush_workqueue(ep->sys->wq); + + if (ep->sys->repl_wq) + flush_workqueue(ep->sys->repl_wq); + if (IPA_CLIENT_IS_CONS(ep->client)) + ipa3_cleanup_rx(ep->sys); + ep->valid = 0; IPADBG("client (ep: %d) disconnected\n", clnt_hdl); @@ -1640,8 +1514,8 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, sys = ipa3_ctx->ep[src_ep_idx].sys; if (!sys || !sys->ep->valid) { - IPAERR_RL("pipe not valid\n"); - goto fail_gen; + IPAERR_RL("pipe %d not valid\n", src_ep_idx); + goto fail_pipe_not_valid; } num_frags = skb_shinfo(skb)->nr_frags; @@ -1809,6 +1683,8 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, kfree(desc); fail_gen: return -EFAULT; +fail_pipe_not_valid: + return -EPIPE; } static void ipa3_wq_handle_rx(struct work_struct *work) @@ -2401,6 +2277,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys) * provided to gsi */ + spin_lock_bh(&sys->spinlock); list_for_each_entry_safe(rx_pkt, r, &sys->rcycl_list, link) { list_del(&rx_pkt->link); @@ -2409,6 +2286,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys) sys->free_skb(rx_pkt->data.skb); kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt); } + spin_unlock_bh(&sys->spinlock); if (sys->repl) { head = atomic_read(&sys->repl->head_idx); @@ -3241,11 +3119,14 @@ static int ipa3_odu_rx_pyld_hdlr(struct sk_buff *rx_skb, 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")) + if (WARN(!sys->ep->client_notify, "sys->ep->client_notify is NULL\n")) { dev_kfree_skb_any(rx_skb); - else + } else { sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, (unsigned long)(rx_skb)); + /*Recycle the SKB before reusing it*/ + ipa3_skb_recycle(rx_skb); + } return 0; } @@ -4059,7 +3940,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, u32 ring_size; int result; gfp_t mem_flag = GFP_KERNEL; - + u32 coale_ep_idx; if (in->client == IPA_CLIENT_APPS_WAN_CONS || in->client == IPA_CLIENT_APPS_WAN_COAL_CONS || @@ -4070,6 +3951,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, IPAERR("EP context is empty\n"); return -EINVAL; } + coale_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS); /* * GSI ring length is calculated based on the desc_fifo_sz * which was meant to define the BAM desc fifo. GSI descriptors @@ -4088,8 +3970,19 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, } ipa3_ctx->gsi_evt_comm_ring_rem -= (ring_size); ep->gsi_evt_ring_hdl = ipa3_ctx->gsi_evt_comm_hdl; + } else if (in->client == IPA_CLIENT_APPS_WAN_CONS && + coale_ep_idx != IPA_EP_NOT_ALLOCATED && + ipa3_ctx->ep[coale_ep_idx].valid == 1) { + IPADBG("Wan consumer pipe configured\n"); + result = ipa_gsi_setup_coal_def_channel(in, ep, + &ipa3_ctx->ep[coale_ep_idx]); + if (result) { + IPAERR("Failed to setup default coal GSI channel\n"); + goto fail_setup_event_ring; + } + return result; } else if (ep->sys->policy != IPA_POLICY_NOINTR_MODE || - IPA_CLIENT_IS_CONS(ep->client)) { + IPA_CLIENT_IS_CONS(ep->client)) { result = ipa_gsi_setup_event_ring(ep, ring_size, mem_flag); if (result) goto fail_setup_event_ring; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index dd46cce45d08c516a07fc39c43382fbd50ab4c4b..c45bc1a1ed998fa7a56c57352999b8c6e57fa24c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -41,6 +41,7 @@ #include "ipa_defs.h" #include #include +#include #define IPA_DEV_NAME_MAX_LEN 15 #define DRV_NAME "ipa" @@ -225,11 +226,6 @@ enum { NUM_SMEM_SUBSYSTEMS, }; -enum ipa_mpm_start_stop_type { - MPM_MHIP_STOP, - MPM_MHIP_START, -}; - #define IPA_WDI_RX_RING_RES 0 #define IPA_WDI_RX_RING_RP_RES 1 #define IPA_WDI_RX_COMP_RING_RES 2 @@ -474,6 +470,7 @@ struct ipa_smmu_cb_ctx { u32 va_start; u32 va_size; u32 va_end; + bool is_cache_coherent; }; /** @@ -1483,6 +1480,20 @@ struct ipa3_wdi3_ctx { struct ipa3_uc_dbg_stats dbg_stats; }; +/** + * struct ipa3_usb_ctx - IPA usb context + */ +struct ipa3_usb_ctx { + struct ipa3_uc_dbg_stats dbg_stats; +}; + +/** + * struct ipa3_mhip_ctx - IPA mhip context + */ +struct ipa3_mhip_ctx { + struct ipa3_uc_dbg_stats dbg_stats; +}; + /** * struct ipa3_transport_pm - transport power management related members * @transport_pm_mutex: Mutex to protect the transport_pm functionality. @@ -1881,6 +1892,8 @@ struct ipa3_context { struct ipa3_wdi2_ctx wdi2_ctx; struct ipa3_pc_mbox_data pc_mbox; struct ipa3_wdi3_ctx wdi3_ctx; + struct ipa3_usb_ctx usb_ctx; + struct ipa3_mhip_ctx mhip_ctx; atomic_t ipa_clk_vote; int gsi_chk_intset_value; int uc_mailbox17_chk; @@ -1891,6 +1904,7 @@ struct ipa3_context { bool fw_loaded; struct IpaHwOffloadStatsAllocCmdData_t gsi_info[IPA_HW_PROTOCOL_MAX]; + bool ipa_mhi_proxy; }; struct ipa3_plat_drv_res { @@ -1936,6 +1950,7 @@ struct ipa3_plat_drv_res { bool do_non_tn_collection_on_crash; bool ipa_endp_delay_wa; u32 secure_debug_check_action; + bool ipa_mhi_proxy; }; /** @@ -2473,6 +2488,8 @@ int ipa3_resume_wdi_pipe(u32 clnt_hdl); int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl); int ipa3_suspend_wdi_pipe(u32 clnt_hdl); int ipa3_get_wdi_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats); +int ipa3_get_wdi3_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats); +int ipa3_get_usb_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats); int ipa3_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats); u16 ipa3_get_smem_restr_bytes(void); int ipa3_broadcast_wdi_quota_reach_ind(uint32_t fid, uint64_t num_bytes); @@ -2783,7 +2800,6 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id); int ipa3_write_qmapid_wdi3_gsi_pipe(u32 clnt_hdl, u8 qmap_id); int ipa3_tag_process(struct ipa3_desc *desc, int num_descs, unsigned long timeout); -int ipa3_get_wdi3_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats); void ipa3_q6_pre_shutdown_cleanup(void); void ipa3_q6_post_shutdown_cleanup(void); @@ -2986,14 +3002,12 @@ int ipa3_get_gsi_chan_info(struct gsi_chan_info *gsi_chan_info, #ifdef CONFIG_IPA3_MHI_PRIME_MANAGER int ipa_mpm_mhip_xdci_pipe_enable(enum ipa_usb_teth_prot prot); int ipa_mpm_mhip_xdci_pipe_disable(enum ipa_usb_teth_prot xdci_teth_prot); -int ipa_mpm_notify_wan_state(void); -int ipa_mpm_mhip_ul_start_stop_data( - enum ipa_mpm_start_stop_type start_stop, - enum ipa_usb_teth_prot xdci_teth_prot); +int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state); int ipa3_is_mhip_offload_enabled(void); int ipa_mpm_reset_dma_mode(enum ipa_client_type src_pipe, enum ipa_client_type dst_pipe); int ipa_mpm_panic_handler(char *buf, int size); +int ipa3_get_mhip_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats); #else static inline int ipa_mpm_mhip_xdci_pipe_enable( enum ipa_usb_teth_prot prot) @@ -3005,13 +3019,8 @@ static inline int ipa_mpm_mhip_xdci_pipe_disable( { return 0; } -static inline int ipa_mpm_notify_wan_state(void) -{ - return 0; -} -static inline int ipa_mpm_mhip_ul_start_stop_data( - enum ipa_mpm_start_stop_type start_stop, - enum ipa_usb_teth_prot xdci_teth_prot) +static inline int ipa_mpm_notify_wan_state( + struct wan_ioctl_notify_wan_state *state) { return 0; } @@ -3029,6 +3038,16 @@ static inline int ipa_mpm_panic_handler(char *buf, int size) return 0; } +static inline int ipa3_get_mhip_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats) +{ + return 0; +} + +static inline void *alloc_and_init(u32 size, u32 init_val) +{ + return 0; +} + #endif /* CONFIG_IPA3_MHI_PRIME_MANAGER */ /* query ipa APQ mode*/ 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 0b46190e35f3ac81f9d071fabdd5983679207831..a565de73aacde602bb5c5e0a9d1a3fdbba70de36 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c @@ -389,12 +389,8 @@ static int __imp_configure_mhi_device( resp->alloc_resp_arr_len = ridx; resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; /* return INCOMPATIBLE_STATE in any case */ - if (mhi_is_active(imp_ctx->md.mhi_dev)) - resp->resp.error = - IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; - else - resp->resp.error = - IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; + resp->resp.error = + IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; return -EINVAL; } @@ -558,10 +554,7 @@ struct ipa_mhi_alloc_channel_resp_msg_v01 *imp_handle_allocate_channel_req( resp->alloc_resp_arr_len++; resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; /* return INCOMPATIBLE_STATE in any case */ - if (mhi_is_active(imp_ctx->md.mhi_dev)) - resp->resp.error = IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; - else - resp->resp.error = IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; + resp->resp.error = IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; goto fail_smmu; } @@ -655,21 +648,17 @@ struct ipa_mhi_clk_vote_resp_msg_v01 * executed from mhi context. */ if (vote) { - ret = mhi_device_get_sync(imp_ctx->md.mhi_dev); + ret = mhi_device_get_sync(imp_ctx->md.mhi_dev, MHI_VOTE_BUS); if (ret) { IMP_ERR("mhi_sync_get failed %d\n", ret); resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; /* return INCOMPATIBLE_STATE in any case */ - if (mhi_is_active(imp_ctx->md.mhi_dev)) - resp->resp.error = - IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; - else - resp->resp.error = + resp->resp.error = IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; return resp; } } else { - mhi_device_put(imp_ctx->md.mhi_dev); + mhi_device_put(imp_ctx->md.mhi_dev, MHI_VOTE_BUS); } mutex_lock(&imp_ctx->mutex); @@ -706,7 +695,8 @@ static void imp_mhi_shutdown(void) IMP_FUNC_ENTRY(); - if (imp_ctx->state == IMP_STARTED) { + if (imp_ctx->state == IMP_STARTED || + imp_ctx->state == IMP_READY) { req.cleanup_valid = true; req.cleanup = true; ipa3_qmi_send_mhi_cleanup_request(&req); @@ -729,7 +719,7 @@ static void imp_mhi_shutdown(void) false); } if (imp_ctx->lpm_disabled) { - mhi_device_put(imp_ctx->md.mhi_dev); + mhi_device_put(imp_ctx->md.mhi_dev, MHI_VOTE_BUS); imp_ctx->lpm_disabled = false; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c index 94001267992153750d9743e2fc03c518f35702fd..717bc6928e6c0f9a7f32bb287c296ad131e30f73 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c @@ -133,6 +133,10 @@ enum mhip_smmu_domain_type { MHIP_SMMU_DOMAIN_NONE, }; +enum ipa_mpm_start_stop_type { + MPM_MHIP_STOP, + MPM_MHIP_START, +}; /* each pair of UL/DL channels are defined below */ static const struct mhi_device_id mhi_driver_match_table[] = { { .chan = "IP_HW_MHIP_0" }, /* for rndis/Wifi teth pipes */ @@ -297,6 +301,7 @@ struct ipa_mpm_dev_info { struct ipa_mpm_iova_addr data; u32 chdb_base; u32 erdb_base; + bool is_cache_coherent; }; struct ipa_mpm_event_props { @@ -368,9 +373,20 @@ struct ipa_mpm_mhi_driver { struct ipa_mpm_channel dl_cons; enum ipa_mpm_mhip_client_type mhip_client; enum ipa_mpm_teth_state teth_state; - struct mutex mutex; bool init_complete; + /* General MPM mutex to protect concurrent update of MPM GSI states */ + struct mutex mutex; + /* + * Mutex to protect IPA clock vote/unvote to make sure IPA isn't double + * devoted for concurrency scenarios such as SSR and LPM mode CB + * concurrency. + */ struct mutex lpm_mutex; + /* + * Mutex to protect mhi_dev update/ access, for concurrency such as + * 5G SSR and USB disconnect/connect. + */ + struct mutex mhi_mutex; bool in_lpm; struct ipa_mpm_clk_cnt_type clk_cnt; }; @@ -490,6 +506,12 @@ static dma_addr_t ipa_mpm_smmu_map(void *va_addr, unsigned long carved_iova = roundup(cb->next_addr, IPA_MPM_PAGE_SIZE); int ret = 0; + /* check cache coherent */ + if (ipa_mpm_ctx->dev_info.is_cache_coherent) { + IPA_MPM_DBG(" enable cache coherent\n"); + prot |= IOMMU_CACHE; + } + if (carved_iova >= cb->va_end) { IPA_MPM_ERR("running out of carved_iova %x\n", carved_iova); ipa_assert(); @@ -642,6 +664,12 @@ static u32 ipa_mpm_smmu_map_doorbell(enum mhip_smmu_domain_type smmu_domain, u32 iova = 0; u64 offset = 0; + /* check cache coherent */ + if (ipa_mpm_ctx->dev_info.is_cache_coherent) { + IPA_MPM_DBG(" enable cache coherent\n"); + prot |= IOMMU_CACHE; + } + if (carved_iova >= cb->va_end) { IPA_MPM_ERR("running out of carved_iova %x\n", carved_iova); ipa_assert(); @@ -990,7 +1018,6 @@ static int ipa_mpm_connect_mhip_gsi_pipe(enum ipa_client_type mhip_client, ipa_mpm_change_gsi_state(mhi_idx, IPA_MPM_MHIP_CHAN_UL, GSI_ALLOCATED); - result = ipa3_start_gsi_channel(ipa_ep_idx); if (result) { IPA_MPM_ERR("start MHIP channel %d failed\n", mhip_client); @@ -1292,8 +1319,10 @@ static void ipa_mpm_mhip_shutdown(int mhip_idx) ipa_mpm_ctx->md[mhip_idx].in_lpm = true; } mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex); + mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex); ipa_mpm_ctx->md[mhip_idx].mhi_dev = NULL; ipa_mpm_ctx->md[mhip_idx].init_complete = false; + mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex); IPA_MPM_FUNC_EXIT(); } @@ -1316,8 +1345,10 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote, return -EINVAL; } + mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); if (ipa_mpm_ctx->md[probe_id].mhi_dev == NULL) { IPA_MPM_ERR("MHI not initialized yet\n"); + mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); return 0; } @@ -1327,10 +1358,11 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote, if (vote == CLK_ON) { result = mhi_device_get_sync( - ipa_mpm_ctx->md[probe_id].mhi_dev); + ipa_mpm_ctx->md[probe_id].mhi_dev, MHI_VOTE_BUS); if (result) { IPA_MPM_ERR("mhi_sync_get failed for probe_id %d\n", result, probe_id); + mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); return result; } @@ -1344,14 +1376,16 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote, IPA_MPM_DBG("probe_id %d PCIE clock already devoted\n", probe_id); WARN_ON(1); + mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); return 0; } - mhi_device_put(ipa_mpm_ctx->md[probe_id].mhi_dev); + mhi_device_put(ipa_mpm_ctx->md[probe_id].mhi_dev, MHI_VOTE_BUS); IPA_MPM_DBG("probe_id %d PCIE clock off\n", probe_id); atomic_dec(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt); atomic_dec(&ipa_mpm_ctx->pcie_clk_total_cnt); } + mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); return result; } @@ -1540,15 +1574,17 @@ static enum mhip_status_type ipa_mpm_start_stop_mhip_chan( return MHIP_STATUS_FAIL; } -int ipa_mpm_notify_wan_state(void) +int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state) { int probe_id = IPA_MPM_MHIP_CH_ID_MAX; int i; static enum mhip_status_type status; int ret = 0; - enum ipa_client_type ul_chan, dl_chan; enum ipa_mpm_mhip_client_type mhip_client = IPA_MPM_MHIP_TETH; + if (!state) + return -EPERM; + if (!ipa3_is_mhip_offload_enabled()) return -EPERM; @@ -1565,53 +1601,85 @@ int ipa_mpm_notify_wan_state(void) } IPA_MPM_DBG("WAN backhaul available for probe_id = %d\n", probe_id); - get_ipa3_client(probe_id, &ul_chan, &dl_chan); - - /* Start UL MHIP channel for offloading the tethering connection */ - ret = ipa_mpm_vote_unvote_pcie_clk(CLK_ON, probe_id); - if (ret) { - IPA_MPM_ERR("Error cloking on PCIe clk, err = %d\n", ret); - return ret; - } - - status = ipa_mpm_start_stop_mhip_chan( - IPA_MPM_MHIP_CHAN_UL, probe_id, MPM_MHIP_START); - switch (status) { - case MHIP_STATUS_SUCCESS: - case MHIP_STATUS_NO_OP: - ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_CONNECTED); - ret = ipa_mpm_start_stop_ul_mhip_data_path(probe_id, - MPM_MHIP_START); + if (state->up) { + /* Start UL MHIP channel for offloading tethering connection */ + ret = ipa_mpm_vote_unvote_pcie_clk(CLK_ON, probe_id); if (ret) { - IPA_MPM_ERR("Couldnt start UL GSI channel"); - ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); + IPA_MPM_ERR("Error cloking on PCIe clk, err = %d\n", + ret); return ret; } - - if (status == MHIP_STATUS_NO_OP) { - /* Channels already have been started, - * we can devote for pcie clocks - */ + status = ipa_mpm_start_stop_mhip_chan( + IPA_MPM_MHIP_CHAN_UL, probe_id, MPM_MHIP_START); + switch (status) { + case MHIP_STATUS_SUCCESS: + ipa_mpm_ctx->md[probe_id].teth_state = + IPA_MPM_TETH_CONNECTED; + ret = ipa_mpm_start_stop_ul_mhip_data_path( + probe_id, MPM_MHIP_START); + if (ret) { + IPA_MPM_ERR("err UL chan start\n"); + ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); + return ret; + } + break; + case MHIP_STATUS_EP_NOT_READY: + case MHIP_STATUS_NO_OP: + IPA_MPM_DBG("UL chan already start, status = %d\n", + status); + ret = ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); + return ret; + case MHIP_STATUS_FAIL: + case MHIP_STATUS_BAD_STATE: + case MHIP_STATUS_EP_NOT_FOUND: + IPA_MPM_ERR("UL chan start err =%d\n", status); + ret = ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); + ipa_assert(); + return -EFAULT; + default: + IPA_MPM_ERR("Err not found\n"); ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); + ret = -EFAULT; + break; } - break; - case MHIP_STATUS_EP_NOT_READY: - ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_INPROGRESS); - break; - case MHIP_STATUS_FAIL: - case MHIP_STATUS_BAD_STATE: - case MHIP_STATUS_EP_NOT_FOUND: - IPA_MPM_ERR("UL chan cant be started err =%d\n", status); + ipa_mpm_ctx->md[probe_id].mhip_client = mhip_client; + } else { + status = ipa_mpm_start_stop_mhip_chan( + IPA_MPM_MHIP_CHAN_UL, probe_id, + MPM_MHIP_STOP); + switch (status) { + case MHIP_STATUS_SUCCESS: + ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_INIT); + ipa_mpm_start_stop_ul_mhip_data_path(probe_id, + MPM_MHIP_STOP); + break; + case MHIP_STATUS_NO_OP: + case MHIP_STATUS_EP_NOT_READY: + IPA_MPM_DBG("UL chan already stop, status = %d\n", + status); + break; + case MHIP_STATUS_FAIL: + case MHIP_STATUS_BAD_STATE: + case MHIP_STATUS_EP_NOT_FOUND: + IPA_MPM_ERR("UL chan cant be stopped err =%d\n", + status); + ipa_assert(); + return -EFAULT; + default: + IPA_MPM_ERR("Err not found\n"); + return -EFAULT; + } + /* Stop UL MHIP channel for offloading tethering connection */ ret = ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); - return -EFAULT; - default: - IPA_MPM_ERR("Err not found\n"); - ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); - ret = -EFAULT; - break; - } + if (ret) { + IPA_MPM_ERR("Error cloking on PCIe clk, err = %d\n", + ret); + return ret; + } + ipa_mpm_ctx->md[probe_id].mhip_client = IPA_MPM_MHIP_NONE; + } return ret; } @@ -1789,7 +1857,7 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev, if (ipa_mpm_ctx->md[probe_id].init_complete) { IPA_MPM_ERR("Probe initialization already done, returning\n"); - return -EPERM; + return 0; } IPA_MPM_DBG("Received probe for id=%d\n", probe_id); @@ -1946,7 +2014,17 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev, ret = mhi_prepare_for_transfer(ipa_mpm_ctx->md[probe_id].mhi_dev); if (ret) { IPA_MPM_ERR("mhi_prepare_for_transfer failed %d\n", ret); - goto fail_smmu; + WARN_ON(1); + /* + * WA to handle prepare_for_tx failures. + * Though prepare for transfer fails, indicate success + * to MHI driver. remove_cb will be called eventually when + * Device side comes from where pending cleanup happens. + */ + atomic_inc(&ipa_mpm_ctx->probe_cnt); + ipa_mpm_ctx->md[probe_id].init_complete = true; + IPA_MPM_FUNC_EXIT(); + return 0; } /* @@ -2196,8 +2274,8 @@ static void ipa_mpm_mhi_remove_cb(struct mhi_device *mhi_dev) } IPA_MPM_DBG("remove_cb for mhip_idx = %d", mhip_idx); - ipa_mpm_mhip_shutdown(mhip_idx); + atomic_dec(&ipa_mpm_ctx->probe_cnt); if (atomic_read(&ipa_mpm_ctx->probe_cnt) == 0) { @@ -2262,10 +2340,7 @@ static void ipa_mpm_mhi_status_cb(struct mhi_device *mhi_dev, IPA_MPM_DBG("Already out of lpm\n"); } break; - case MHI_CB_EE_RDDM: - case MHI_CB_PENDING_DATA: - case MHI_CB_SYS_ERROR: - case MHI_CB_FATAL_ERROR: + default: IPA_MPM_ERR("unexpected event %d\n", mhi_cb); break; } @@ -2362,7 +2437,7 @@ int ipa_mpm_mhip_xdci_pipe_enable(enum ipa_usb_teth_prot xdci_teth_prot) } IPA_MPM_DBG("Connect xdci prot %d -> mhip_client = %d probe_id = %d\n", - xdci_teth_prot, mhip_client, probe_id); + xdci_teth_prot, mhip_client, probe_id); ipa_mpm_ctx->md[probe_id].mhip_client = mhip_client; @@ -2377,16 +2452,19 @@ int ipa_mpm_mhip_xdci_pipe_enable(enum ipa_usb_teth_prot xdci_teth_prot) ipa_mpm_set_dma_mode(IPA_CLIENT_USB_PROD, IPA_CLIENT_MHI_PRIME_RMNET_CONS); break; - case IPA_MPM_MHIP_TETH: - IPA_MPM_DBG("Teth for prot %d\n", mhip_client); - return 0; case IPA_MPM_MHIP_USB_DPL: IPA_MPM_DBG("connecting DPL prot %d\n", mhip_client); ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_CONNECTED); return 0; default: - IPA_MPM_ERR("mhip_client = %d not supported\n", mhip_client); - break; + IPA_MPM_DBG("mhip_client = %d not processed\n", mhip_client); + ret = ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id); + if (ret) { + IPA_MPM_ERR("Error unvoting on PCIe clk, err = %d\n", + ret); + return ret; + } + return 0; } if (mhip_client != IPA_MPM_MHIP_USB_DPL) @@ -2431,51 +2509,6 @@ int ipa_mpm_mhip_xdci_pipe_enable(enum ipa_usb_teth_prot xdci_teth_prot) return ret; } -int ipa_mpm_mhip_ul_start_stop_data(enum ipa_mpm_start_stop_type start_stop, - enum ipa_usb_teth_prot xdci_teth_prot) -{ - int probe_id = IPA_MPM_MHIP_CH_ID_MAX; - int i; - enum ipa_mpm_mhip_client_type mhip_client; - int ret = 0; - - if (ipa_mpm_ctx == NULL) { - IPA_MPM_ERR("MPM not platform probed, returning ..\n"); - return 0; - } - - ipa_mpm_mhip_map_prot(xdci_teth_prot, &mhip_client); - - for (i = 0; i < IPA_MPM_MHIP_CH_ID_MAX; i++) { - if (ipa_mpm_pipes[i].mhip_client == mhip_client) { - probe_id = i; - break; - } - } - - if (probe_id == IPA_MPM_MHIP_CH_ID_MAX) { - IPA_MPM_ERR("Invalid probe_id\n"); - return 0; - } - - IPA_MPM_DBG("Map xdci prot %d to mhip_client = %d probe_id = %d\n", - xdci_teth_prot, mhip_client, probe_id); - - if (start_stop == MPM_MHIP_STOP) { - ret = ipa_mpm_start_stop_ul_mhip_data_path(probe_id, - MPM_MHIP_STOP); - if (ret) - IPA_MPM_ERR("Error stopping UL path, err = %d\n", ret); - } else if (start_stop == MPM_MHIP_START) { - ret = ipa_mpm_start_stop_ul_mhip_data_path(probe_id, - MPM_MHIP_START); - if (ret) - IPA_MPM_ERR("Error starting UL path, err = %d\n", ret); - } - - return ret; -} - int ipa_mpm_mhip_xdci_pipe_disable(enum ipa_usb_teth_prot xdci_teth_prot) { int probe_id = IPA_MPM_MHIP_CH_ID_MAX; @@ -2516,8 +2549,8 @@ int ipa_mpm_mhip_xdci_pipe_disable(enum ipa_usb_teth_prot xdci_teth_prot) } break; case IPA_MPM_MHIP_TETH: - IPA_MPM_DBG("Teth Disconnecting for prot %d\n", mhip_client); - break; + IPA_MPM_DBG("Rndis Disconnect, wait for wan_state ioctl\n"); + return 0; case IPA_MPM_MHIP_USB_DPL: IPA_MPM_DBG("Teth Disconnecting for DPL\n"); ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_INIT); @@ -2590,6 +2623,8 @@ static int ipa_mpm_populate_smmu_info(struct platform_device *pdev) ipa_mpm_ctx->dev_info.ipa_smmu_enabled = smmu_out.smmu_enable; + /* get cache_coherent enable or not */ + ipa_mpm_ctx->dev_info.is_cache_coherent = ap_cb->is_cache_coherent; if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iova-mapping", carved_iova_ap_mapping, 2)) { IPA_MPM_ERR("failed to read of_node %s\n", @@ -2659,6 +2694,7 @@ static int ipa_mpm_probe(struct platform_device *pdev) for (i = 0; i < IPA_MPM_MHIP_CH_ID_MAX; i++) { mutex_init(&ipa_mpm_ctx->md[i].mutex); + mutex_init(&ipa_mpm_ctx->md[i].mhi_mutex); mutex_init(&ipa_mpm_ctx->md[i].lpm_mutex); } @@ -2787,6 +2823,54 @@ int ipa_mpm_panic_handler(char *buf, int size) } return cnt; } + +/** + * ipa3_get_mhip_gsi_stats() - Query MHIP gsi stats from uc + * @stats: [inout] stats blob from client populated by driver + * + * Returns: 0 on success, negative on failure + * + * @note Cannot be called from atomic context + * + */ +int ipa3_get_mhip_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats) +{ + int i; + + if (!ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio) { + IPAERR("bad parms NULL mhip_gsi_stats_mmio\n"); + return -EINVAL; + } + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + for (i = 0; i < MAX_MHIP_CHANNELS; i++) { + stats->ring[i].ringFull = ioread32( + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGFULL_OFF); + stats->ring[i].ringEmpty = ioread32( + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGEMPTY_OFF); + stats->ring[i].ringUsageHigh = ioread32( + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGUSAGEHIGH_OFF); + stats->ring[i].ringUsageLow = ioread32( + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGUSAGELOW_OFF); + stats->ring[i].RingUtilCount = ioread32( + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio + + i * IPA3_UC_DEBUG_STATS_OFF + + IPA3_UC_DEBUG_STATS_RINGUTILCOUNT_OFF); + } + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + + return 0; +} + + late_initcall(ipa_mpm_init); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MHI Proxy Manager Driver"); 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 a8b530c77642de57e534699b2294c88775a33e99..141ae9daa47c45c9140f735e563001f75f42b23a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -1048,7 +1048,7 @@ int ipa3_qmi_rmv_offload_request_send( ipa3_qmi_ctx->num_ipa_offload_connection); /* max as num_ipa_offload_connection */ - if (req->filter_handle_list_len >= + if (req->filter_handle_list_len > ipa3_qmi_ctx->num_ipa_offload_connection) { IPAWANDBG( "cur(%d), req_rmv(%d)\n", @@ -1088,6 +1088,15 @@ int ipa3_qmi_rmv_offload_request_send( req_desc.msg_id = QMI_IPA_REMOVE_OFFLOAD_CONNECTION_REQ_V01; req_desc.ei_array = ipa_remove_offload_connection_req_msg_v01_ei; + /* clean the Dl rules in the cache if flag is set */ + if (req->clean_all_rules) { + for (i = 0; i < QMI_IPA_MAX_FILTERS_V01; i++) + if (ipa3_qmi_ctx->ipa_offload_cache[i].valid) + ipa3_qmi_ctx->ipa_offload_cache[i].valid = + false; + } + + memset(&resp, 0, sizeof(struct ipa_remove_offload_connection_resp_msg_v01)); resp_desc.max_msg_len = @@ -1335,13 +1344,25 @@ int ipa3_qmi_filter_notify_send( return -EINVAL; } + if (req->rule_id_ex_len == 0) { + IPAWANDBG(" delete UL filter rule for pipe %d\n", + req->source_pipe_index); + } else if (req->rule_id_ex_len > QMI_IPA_MAX_FILTERS_EX2_V01) { + IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n", + req->source_pipe_index, + req->rule_id_ex_len); + return -EINVAL; + } + if (req->install_status != IPA_QMI_RESULT_SUCCESS_V01) { IPAWANERR(" UL filter rule for pipe %d install_status = %d\n", req->source_pipe_index, req->install_status); return -EINVAL; - } else if (req->rule_id_valid != 1) { - IPAWANERR(" UL filter rule for pipe %d rule_id_valid = %d\n", - req->source_pipe_index, req->rule_id_valid); + } else if ((req->rule_id_valid != 1) && + (req->rule_id_ex_valid != 1)) { + IPAWANERR(" UL filter rule for pipe %d rule_id_valid = %d/%d\n", + req->source_pipe_index, req->rule_id_valid, + req->rule_id_ex_valid); return -EINVAL; } else if (req->source_pipe_index >= ipa3_ctx->ipa_num_pipes) { IPAWANDBG( @@ -2224,6 +2245,22 @@ int ipa3_qmi_send_mhi_cleanup_request(struct ipa_mhi_cleanup_req_msg_v01 *req) resp.resp.error, "ipa_mhi_cleanup_req_msg"); } +int ipa3_qmi_send_rsc_pipe_indication( + struct ipa_endp_desc_indication_msg_v01 *req) +{ + IPAWANDBG("Sending QMI_IPA_ENDP_DESC_INDICATION_V01\n"); + + if (unlikely(!ipa3_svc_handle)) + return -ETIMEDOUT; + + return qmi_send_indication(ipa3_svc_handle, + &ipa3_qmi_ctx->client_sq, + QMI_IPA_ENDP_DESC_INDICATION_V01, + IPA_ENDP_DESC_INDICATION_MSG_V01_MAX_MSG_LEN, + ipa_endp_desc_indication_msg_v01_ei, + req); +} + void ipa3_qmi_init(void) { mutex_init(&ipa3_qmi_lock); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index e94f6e1968a9eaa1bb305a3fd3dbe5cafced8372..6cb54267899dee51db4e125e1ee68d226ad4f452 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -116,6 +116,9 @@ struct ipa3_qmi_context { int num_ipa_offload_connection; struct ipa_offload_connection_val ipa_offload_cache[QMI_IPA_MAX_FILTERS_V01]; + uint8_t ul_firewall_indices_list_valid; + uint32_t ul_firewall_indices_list_len; + uint32_t ul_firewall_indices_list[QMI_IPA_MAX_FILTERS_V01]; }; struct ipa3_rmnet_mux_val { @@ -343,6 +346,9 @@ int ipa3_qmi_get_per_client_packet_stats( int ipa3_qmi_send_mhi_ready_indication( struct ipa_mhi_ready_indication_msg_v01 *req); +int ipa3_qmi_send_rsc_pipe_indication( + struct ipa_endp_desc_indication_msg_v01 *req); + int ipa3_qmi_send_mhi_cleanup_request(struct ipa_mhi_cleanup_req_msg_v01 *req); void ipa3_qmi_init(void); @@ -485,6 +491,12 @@ static inline int ipa3_qmi_send_mhi_ready_indication( return -EPERM; } +static int ipa3_qmi_send_rsc_pipe_indication( + struct ipa_endp_desc_indication_msg_v01 *req) +{ + return -EPERM; +} + static inline int ipa3_qmi_send_mhi_cleanup_request( struct ipa_mhi_cleanup_req_msg_v01 *req) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c index 6d79e4c36c9d2f4df395a2baf495c9df6e38a415..eb402beffe85c40a5a2b30f76e898d464539c853 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c @@ -2304,7 +2304,7 @@ struct qmi_elem_info ipa3_fltr_installed_notif_req_msg_data_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, - .elem_size = sizeof(uint8_t), + .elem_size = sizeof(uint32_t), .is_array = NO_ARRAY, .tlv_type = 0x19, .offset = offsetof( @@ -4948,6 +4948,26 @@ struct qmi_elem_info ipa_add_offload_connection_req_msg_v01_ei[] = { struct ipa_add_offload_connection_req_msg_v01, embedded_call_mux_id), }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof( + struct ipa_add_offload_connection_req_msg_v01, + default_mhi_path_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof( + struct ipa_add_offload_connection_req_msg_v01, + default_mhi_path), + }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, @@ -5041,6 +5061,26 @@ struct qmi_elem_info ipa_remove_offload_connection_req_msg_v01_ei[] = { .ei_array = ipa3_filter_rule_identifier_to_handle_map_data_v01_ei, }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct ipa_remove_offload_connection_req_msg_v01, + clean_all_rules_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct ipa_remove_offload_connection_req_msg_v01, + clean_all_rules), + }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c index 2bb9d9b3456d9a7f538813e67d7d8c7fd051ce74..85f7e0bef7e083c42cae0da3c5d1e0ccf4550bdd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c @@ -257,6 +257,16 @@ static void ipa3_uc_save_dbg_stats(u32 size) break; case IPA_HW_PROTOCOL_ETH: break; + case IPA_HW_PROTOCOL_MHIP: + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_size = size; + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_ofst = addr_offset; + ipa3_ctx->mhip_ctx.dbg_stats.uc_dbg_stats_mmio = mmio; + break; + case IPA_HW_PROTOCOL_USB: + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_size = size; + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_ofst = addr_offset; + ipa3_ctx->usb_ctx.dbg_stats.uc_dbg_stats_mmio = mmio; + break; default: IPAERR("unknown protocols %d\n", protocol_id); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h index cd908921f1fb9e51dfd11470f55416c9a2f651ef..42c6feea800033c970704a2a96019e6edf844ece 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h @@ -30,6 +30,12 @@ #define DIR_CONSUMER 0 #define DIR_PRODUCER 1 +#define MAX_AQC_CHANNELS 2 +#define MAX_11AD_CHANNELS 5 +#define MAX_WDI2_CHANNELS 2 +#define MAX_WDI3_CHANNELS 2 +#define MAX_MHIP_CHANNELS 4 +#define MAX_USB_CHANNELS 2 /** * @brief Enum value determined based on the feature it @@ -78,6 +84,8 @@ enum ipa3_hw_features { * @IPA_HW_PROTOCOL_WDI : protocol related to WDI operation in IPA HW * @IPA_HW_PROTOCOL_WDI3: protocol related to WDI3 operation in IPA HW * @IPA_HW_PROTOCOL_ETH : protocol related to ETH operation in IPA HW +* @IPA_HW_PROTOCOL_MHIP: protocol related to MHIP operation in IPA HW +* @IPA_HW_PROTOCOL_USB : protocol related to USB operation in IPA HW */ enum ipa4_hw_protocol { IPA_HW_PROTOCOL_COMMON = 0x0, @@ -86,6 +94,8 @@ enum ipa4_hw_protocol { IPA_HW_PROTOCOL_WDI = 0x3, IPA_HW_PROTOCOL_WDI3 = 0x4, IPA_HW_PROTOCOL_ETH = 0x5, + IPA_HW_PROTOCOL_MHIP = 0x6, + IPA_HW_PROTOCOL_USB = 0x7, IPA_HW_PROTOCOL_MAX }; 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 fe083401ec91840cfaa5ee879bd47fcb9682f91b..4e44e94e4ac0468c494c139c17887f284e3b053a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -427,17 +427,15 @@ static void ipa3_uc_wdi_event_handler(struct IpaHwSharedMemCommonMapping_t */ int ipa3_get_wdi_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats) { - int i, num_chs; + int i; if (!ipa3_ctx->wdi2_ctx.dbg_stats.uc_dbg_stats_mmio) { IPAERR("bad NULL parms for wdi_gsi_stats\n"); return -EINVAL; } - num_chs = ipa3_ctx->wdi2_ctx.dbg_stats.uc_dbg_stats_size - / sizeof(struct IpaHwRingStats_t); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - for (i = 0; i < num_chs; i++) { + for (i = 0; i < MAX_WDI2_CHANNELS; i++) { stats->ring[i].ringFull = ioread32( ipa3_ctx->wdi2_ctx.dbg_stats.uc_dbg_stats_mmio + i * IPA3_UC_DEBUG_STATS_OFF + @@ -2099,7 +2097,9 @@ int ipa3_disconnect_gsi_wdi_pipe(u32 clnt_hdl) ipa3_ctx->uc_wdi_ctx.stats_notify = NULL; else IPADBG("uc_wdi_ctx.stats_notify already null\n"); - if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) ipa3_uc_debug_stats_dealloc(IPA_HW_PROTOCOL_WDI); IPADBG("client (ep: %d) disconnected\n", clnt_hdl); @@ -2480,7 +2480,9 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl) } pcmd_t = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI]; /* start uC gsi dbg stats monitor */ - if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) { if (IPA_CLIENT_IS_PROD(ep->client)) { pcmd_t->ch_id_info[0].ch_id = ep->gsi_chan_hdl; @@ -2656,7 +2658,9 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl) } pcmd_t = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI]; /* stop uC gsi dbg stats monitor */ - if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) { if (IPA_CLIENT_IS_PROD(ep->client)) { pcmd_t->ch_id_info[0].ch_id = 0xff; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index dc5e7317a30742c07722b90c3f5d467c689387f6..b335a44129053e19c089d8255eafa74c62343389 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -2825,21 +2825,19 @@ static struct ipa3_mem_partition ipa_4_5_mem_part = { .apps_hdr_size = 0x200, .apps_hdr_size_ddr = 0x800, .modem_hdr_proc_ctx_ofst = 0xad0, - .modem_hdr_proc_ctx_size = 0xac0, - .apps_hdr_proc_ctx_ofst = 0x1590, + .modem_hdr_proc_ctx_size = 0xb20, + .apps_hdr_proc_ctx_ofst = 0x15f0, .apps_hdr_proc_ctx_size = 0x200, .apps_hdr_proc_ctx_size_ddr = 0x0, - .nat_tbl_ofst = 0x17a0, + .nat_tbl_ofst = 0x1800, .nat_tbl_size = 0x800, - .nat_index_tbl_ofst = 0x1fa0, + .nat_index_tbl_ofst = 0x2000, .nat_index_tbl_size = 0x100, - .nat_exp_tbl_ofst = 0x20a0, + .nat_exp_tbl_ofst = 0x2100, .nat_exp_tbl_size = 0x400, - .pdn_config_ofst = 0x24a8, - .pdn_config_size = 0x50, - .stats_quota_ofst = 0x2500, + .stats_quota_ofst = 0x2510, .stats_quota_size = 0x78, - .stats_tethering_ofst = 0x2578, + .stats_tethering_ofst = 0x2588, .stats_tethering_size = 0x238, .stats_flt_v4_ofst = 0, .stats_flt_v4_size = 0, @@ -2849,13 +2847,13 @@ static struct ipa3_mem_partition ipa_4_5_mem_part = { .stats_rt_v4_size = 0, .stats_rt_v6_ofst = 0, .stats_rt_v6_size = 0, - .stats_fnr_ofst = 0x27b0, + .stats_fnr_ofst = 0x27c0, .stats_fnr_size = 0x800, - .stats_drop_ofst = 0x2fb0, + .stats_drop_ofst = 0x2fc0, .stats_drop_size = 0x20, .modem_comp_decomp_ofst = 0x0, .modem_comp_decomp_size = 0x0, - .modem_ofst = 0x2fd8, + .modem_ofst = 0x2fe8, .modem_size = 0x800, .apps_v4_flt_hash_ofst = 0x2718, .apps_v4_flt_hash_size = 0x0, @@ -2875,7 +2873,9 @@ static struct ipa3_mem_partition ipa_4_5_mem_part = { .apps_v6_rt_nhash_size = 0x0, .uc_descriptor_ram_ofst = 0x3800, .uc_descriptor_ram_size = 0x1000, - .end_ofst = 0x4800, + .pdn_config_ofst = 0x4800, + .pdn_config_size = 0x50, + .end_ofst = 0x4850, }; @@ -3528,7 +3528,7 @@ static void ipa_cfg_qtime(void) memset(&gran_cfg, 0, sizeof(gran_cfg)); gran_cfg.gran_0 = IPA_TIMERS_TIME_GRAN_100_USEC; gran_cfg.gran_1 = IPA_TIMERS_TIME_GRAN_1_MSEC; - gran_cfg.gran_2 = IPA_TIMERS_TIME_GRAN_10_USEC; + gran_cfg.gran_2 = IPA_TIMERS_TIME_GRAN_1_MSEC; val = ipahal_read_reg(IPA_TIMERS_PULSE_GRAN_CFG); IPADBG("timer pulse granularity before cfg: 0x%x\n", val); ipahal_write_reg_fields(IPA_TIMERS_PULSE_GRAN_CFG, &gran_cfg); @@ -4885,6 +4885,11 @@ int ipa3_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ep_holb) ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, clnt_hdl, ep_holb); + /* IPA4.5 issue requires HOLB_EN to be written twice */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + /* Configure timer */ if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_2) { ipa3_cal_ep_holb_scale_base_val(ep_holb->tmr_val, @@ -7134,6 +7139,8 @@ static int __ipa3_stop_gsi_channel(u32 clnt_hdl) int res = 0; int i; struct ipa3_ep_context *ep; + enum ipa_client_type client_type; + struct IpaHwOffloadStatsAllocCmdData_t *gsi_info; if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || ipa3_ctx->ep[clnt_hdl].valid == 0) { @@ -7142,8 +7149,55 @@ static int __ipa3_stop_gsi_channel(u32 clnt_hdl) } ep = &ipa3_ctx->ep[clnt_hdl]; + client_type = ipa3_get_client_mapping(clnt_hdl); memset(&mem, 0, sizeof(mem)); + /* stop uC gsi dbg stats monitor */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) { + switch (client_type) { + case IPA_CLIENT_MHI_PRIME_TETH_PROD: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[0].ch_id = 0xff; + gsi_info->ch_id_info[0].dir = DIR_PRODUCER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_MHI_PRIME_TETH_CONS: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[1].ch_id = 0xff; + gsi_info->ch_id_info[1].dir = DIR_CONSUMER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_MHI_PRIME_RMNET_PROD: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[2].ch_id = 0xff; + gsi_info->ch_id_info[2].dir = DIR_PRODUCER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_MHI_PRIME_RMNET_CONS: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_MHIP]; + gsi_info->ch_id_info[3].ch_id = 0xff; + gsi_info->ch_id_info[3].dir = DIR_CONSUMER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_USB_PROD: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_USB]; + gsi_info->ch_id_info[0].ch_id = 0xff; + gsi_info->ch_id_info[0].dir = DIR_PRODUCER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + case IPA_CLIENT_USB_CONS: + gsi_info = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_USB]; + gsi_info->ch_id_info[1].ch_id = 0xff; + gsi_info->ch_id_info[1].dir = DIR_CONSUMER; + ipa3_uc_debug_stats_alloc(*gsi_info); + break; + default: + IPADBG("client_type %d not supported\n", + client_type); + } + } if (IPA_CLIENT_IS_PROD(ep->client)) { IPADBG("Calling gsi_stop_channel ch:%lu\n", ep->gsi_chan_hdl); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c index 77e9281ad639300fb57cd80aaaaeeb02ec34dd6d..9fd231fbe967b50d0ba5efb8293638780216978c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -698,7 +698,9 @@ int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) goto exit; } - if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) ipa3_uc_debug_stats_dealloc(IPA_HW_PROTOCOL_WDI3); ipa3_delete_dflt_flt_rules(ipa_ep_idx_rx); memset(ep_rx, 0, sizeof(struct ipa3_ep_context)); @@ -729,23 +731,38 @@ int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(ipa_ep_idx_tx)); + /* enable data path */ + result = ipa3_enable_data_path(ipa_ep_idx_rx); + if (result) { + IPAERR("enable data path failed res=%d clnt=%d\n", result, + ipa_ep_idx_rx); + goto exit; + } + + result = ipa3_enable_data_path(ipa_ep_idx_tx); + if (result) { + IPAERR("enable data path failed res=%d clnt=%d\n", result, + ipa_ep_idx_tx); + goto fail_enable_path1; + } + /* start gsi tx channel */ result = gsi_start_channel(ep_tx->gsi_chan_hdl); if (result) { IPAERR("failed to start gsi tx channel\n"); - result = -EFAULT; - goto exit; + goto fail_enable_path2; } /* start gsi rx channel */ result = gsi_start_channel(ep_rx->gsi_chan_hdl); if (result) { IPAERR("failed to start gsi rx channel\n"); - result = -EFAULT; - goto exit; + goto fail_start_channel1; } /* start uC gsi dbg stats monitor */ - if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) { ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI3].ch_id_info[0].ch_id = ep_rx->gsi_chan_hdl; ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI3].ch_id_info[0].dir @@ -757,23 +774,14 @@ int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) ipa3_uc_debug_stats_alloc( ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI3]); } - /* enable data path */ - result = ipa3_enable_data_path(ipa_ep_idx_rx); - if (result) { - IPAERR("enable data path failed res=%d clnt=%d.\n", result, - ipa_ep_idx_rx); - result = -EFAULT; - goto exit; - } - - result = ipa3_enable_data_path(ipa_ep_idx_tx); - if (result) { - IPAERR("enable data path failed res=%d clnt=%d.\n", result, - ipa_ep_idx_tx); - result = -EFAULT; - goto exit; - } + goto exit; +fail_start_channel1: + gsi_stop_channel(ep_tx->gsi_chan_hdl); +fail_enable_path2: + ipa3_disable_data_path(ipa_ep_idx_tx); +fail_enable_path1: + ipa3_disable_data_path(ipa_ep_idx_rx); exit: IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(ipa_ep_idx_tx)); return result; @@ -852,7 +860,9 @@ int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) goto fail; } /* stop uC gsi dbg stats monitor */ - if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 || + (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1 && + ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ)) { ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI3].ch_id_info[0].ch_id = 0xff; ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI3].ch_id_info[0].dir @@ -930,17 +940,15 @@ int ipa3_write_qmapid_wdi3_gsi_pipe(u32 clnt_hdl, u8 qmap_id) */ int ipa3_get_wdi3_gsi_stats(struct ipa3_uc_dbg_ring_stats *stats) { - int i, num_chs; + int i; if (!ipa3_ctx->wdi3_ctx.dbg_stats.uc_dbg_stats_mmio) { IPAERR("bad NULL parms for wdi3_gsi_stats\n"); return -EINVAL; } - num_chs = ipa3_ctx->wdi3_ctx.dbg_stats.uc_dbg_stats_size - / sizeof(struct IpaHwRingStats_t); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - for (i = 0; i < num_chs; i++) { + for (i = 0; i < MAX_WDI3_CHANNELS; i++) { stats->ring[i].ringFull = ioread32( ipa3_ctx->wdi3_ctx.dbg_stats.uc_dbg_stats_mmio + i * IPA3_UC_DEBUG_STATS_OFF + diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index d21f58558ce5493efb0c40485626ed6f03d7796a..5dea042ba9b9135b6de84ac6ccef36fccc2e0ca7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -691,6 +691,41 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 } } } + + if (rule_req->ul_firewall_indices_list_valid) { + IPAWANDBG("Receive ul_firewall_indices_list_len = (%d)", + rule_req->ul_firewall_indices_list_len); + + if (rule_req->ul_firewall_indices_list_len > + rmnet_ipa3_ctx->num_q6_rules) { + IPAWANERR("UL rule indices are not valid: (%d/%d)\n", + rule_req->xlat_filter_indices_list_len, + rmnet_ipa3_ctx->num_q6_rules); + goto failure; + } + + ipa3_qmi_ctx->ul_firewall_indices_list_valid = 1; + ipa3_qmi_ctx->ul_firewall_indices_list_len = + rule_req->ul_firewall_indices_list_len; + + for (i = 0; i < rule_req->ul_firewall_indices_list_len; i++) { + ipa3_qmi_ctx->ul_firewall_indices_list[i] = + rule_req->ul_firewall_indices_list[i]; + } + + for (i = 0; i < rule_req->ul_firewall_indices_list_len; i++) { + if (rule_req->ul_firewall_indices_list[i] + >= rmnet_ipa3_ctx->num_q6_rules) { + IPAWANERR("UL rule idx is wrong: %d\n", + rule_req->ul_firewall_indices_list[i]); + goto failure; + } else { + ipa3_qmi_ctx->q6_ul_filter_rule + [rule_req->ul_firewall_indices_list[i]] + .replicate_needed = 1; + } + } + } goto success; failure: @@ -1284,9 +1319,16 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); dev->stats.tx_dropped++; spin_unlock_irqrestore(&wwan_ptr->lock, flags); - return -EFAULT; + return NETDEV_TX_OK; } + /* + * increase the outstanding_pkts count first + * to avoid suspend happens in parallel + * after unlock + */ + atomic_inc(&wwan_ptr->outstanding_pkts); /* IPA_RM checking end */ + spin_unlock_irqrestore(&wwan_ptr->lock, flags); /* * both data packets and command will be routed to @@ -1294,11 +1336,18 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) */ ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL); if (ret) { + atomic_dec(&wwan_ptr->outstanding_pkts); + if (ret == -EPIPE) { + IPAWANERR_RL("[%s] fatal: pipe is not valid\n", + dev->name); + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } ret = NETDEV_TX_BUSY; goto out; } - atomic_inc(&wwan_ptr->outstanding_pkts); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; ret = NETDEV_TX_OK; @@ -1312,7 +1361,6 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) IPA_RM_RESOURCE_WWAN_0_PROD); } } - spin_unlock_irqrestore(&wwan_ptr->lock, flags); return ret; } @@ -1430,6 +1478,26 @@ static void apps_ipa_packet_receive_notify(void *priv, } } +/* Send RSC endpoint info to modem using QMI indication message */ + +static int ipa_send_rsc_pipe_ind_to_modem(void) +{ + struct ipa_endp_desc_indication_msg_v01 req; + struct ipa_ep_id_type_v01 *ep_info; + + memset(&req, 0, sizeof(struct ipa_endp_desc_indication_msg_v01)); + req.ep_info_len = 1; + req.ep_info_valid = true; + req.num_eps_valid = true; + req.num_eps = 1; + ep_info = &req.ep_info[req.ep_info_len - 1]; + ep_info->ep_id = rmnet_ipa3_ctx->ipa3_to_apps_hdl; + ep_info->ic_type = DATA_IC_TYPE_AP_V01; + ep_info->ep_type = DATA_EP_DESC_TYPE_RSC_PROD_V01; + ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; + return ipa3_qmi_send_rsc_pipe_indication(&req); +} + static int handle3_ingress_format(struct net_device *dev, struct rmnet_ioctl_extended_s *in) { @@ -1531,6 +1599,9 @@ static int handle3_ingress_format(struct net_device *dev, if (ret) ipa3_del_a7_qmap_hdr(); + /* Sending QMI indication message share RSC pipe details*/ + if (dev->features & NETIF_F_GRO_HW) + ipa_send_rsc_pipe_ind_to_modem(); end: if (ret) IPAWANERR("failed to configure ingress\n"); @@ -2161,16 +2232,39 @@ static int rmnet_ipa_send_coalesce_notification(uint8_t qmap_id, int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state) { + uint32_t bw_mbps = 0; + int ret = 0; + if (!state) return -EINVAL; if (!ipa_pm_is_used()) return 0; - if (state->up) - return ipa_pm_activate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl); - else - return ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl); + if (state->up) { + if (rmnet_ipa3_ctx->ipa_config_is_apq) { + bw_mbps = 5200; + ret = ipa3_vote_for_bus_bw(&bw_mbps); + if (ret) { + IPAERR("Failed to vote for bus BW (%u)\n", + bw_mbps); + return ret; + } + } + ret = ipa_pm_activate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl); + } else { + if (rmnet_ipa3_ctx->ipa_config_is_apq) { + bw_mbps = 0; + ret = ipa3_vote_for_bus_bw(&bw_mbps); + if (ret) { + IPAERR("Failed to vote for bus BW (%u)\n", + bw_mbps); + return ret; + } + } + ret = ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl); + } + return ret; } /** @@ -2219,18 +2313,10 @@ int ipa3_wwan_set_modem_perf_profile(int throughput) { struct ipa_rm_perf_profile profile; int ret; - int tether_bridge_handle = 0; IPAWANDBG("throughput: %d\n", throughput); if (ipa3_ctx->use_ipa_pm) { - /* query rmnet-tethering handle */ - tether_bridge_handle = ipa3_teth_bridge_get_pm_hdl(); - if (tether_bridge_handle > 0) { - /* only update with valid handle*/ - ret = ipa_pm_set_throughput(tether_bridge_handle, - throughput); - } /* for TETH MODEM on softap/rndis */ ret = ipa_pm_set_throughput(rmnet_ipa3_ctx->q6_teth_pm_hdl, throughput); @@ -2803,6 +2889,7 @@ static int ipa3_wwan_remove(struct platform_device *pdev) if (ipa3_rmnet_res.ipa_napi_enable) netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi)); mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard); + IPAWANINFO("rmnet_ipa unregister_netdev\n"); unregister_netdev(IPA_NETDEV()); if (ipa3_ctx->use_ipa_pm) ipa3_wwan_deregister_netdev_pm_client(); @@ -3014,7 +3101,8 @@ static int ipa3_lcl_mdm_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 (ipa3_ctx->ipa_mhi_proxy) + 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(); @@ -3764,13 +3852,13 @@ static int rmnet_ipa3_query_tethering_stats_hw( con_stats->client[index].num_ipv6_bytes); /* update the wlan UL stats */ - data->ipv4_tx_packets = + data->ipv4_tx_packets += con_stats->client[index].num_ipv4_pkts; - data->ipv6_tx_packets = + data->ipv6_tx_packets += con_stats->client[index].num_ipv6_pkts; - data->ipv4_tx_bytes = + data->ipv4_tx_bytes += con_stats->client[index].num_ipv4_bytes; - data->ipv6_tx_bytes = + data->ipv6_tx_bytes += con_stats->client[index].num_ipv6_bytes; /* wlan UL stats on cv2 */ @@ -4041,8 +4129,8 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) */ rmnet_ipa_get_network_stats_and_update(); } - - imp_handle_modem_ready(); + if (ipa3_ctx->ipa_mhi_proxy) + imp_handle_modem_ready(); } static inline bool rmnet_ipa3_check_any_client_inited diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index d43913026090ea074785fa0bd8ae5442c0afb05f..8c53d5df1e6f36fd6f720ab508de9e5783c94da2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -445,7 +445,8 @@ static long ipa3_wan_ioctl(struct file *filp, break; } - if (ipa_mpm_notify_wan_state()) { + if (ipa_mpm_notify_wan_state( + (struct wan_ioctl_notify_wan_state *)param)) { IPAWANERR("WAN_IOC_NOTIFY_WAN_STATE failed\n"); retval = -EPERM; } diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c index 71482e4eeac75fa96a891da82588002d995ffc74..87c268d79daa7f4c58a735b3a3fa986b0c61bed5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c +++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -191,7 +191,10 @@ int ipa3_teth_bridge_connect(struct teth_bridge_connect_params *connect_params) TETH_ERR("fail to register with PM %d\n", res); return res; } - + /* vote for turbo in case of MHIP channels*/ + if (ipa3_is_apq()) + res = ipa_pm_set_throughput(ipa3_teth_ctx->modem_pm_hdl, + 5200); res = ipa_pm_activate_sync(ipa3_teth_ctx->modem_pm_hdl); goto bail; } diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d76c65aba883836dfaa173583a01ba3cbb1d1a1b..ec1b67976b3df10a808620bbf6574f9e7983563a 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -27,11 +27,14 @@ #include #include #include +#include +#include +#include #include "mhi.h" #define MHI_NET_DRIVER_NAME "mhi_dev_net_drv" -#define MHI_NET_DEV_NAME "mhi_dev_net%d" +#define MHI_NET_DEV_NAME "mhi_swip%d" #define MHI_NET_DEFAULT_MTU 8192 #define MHI_NET_IPC_PAGES (100) #define MHI_MAX_RX_REQ (128) @@ -90,6 +93,7 @@ struct mhi_dev_net_client { u32 out_chan; /* read channel - always odd */ u32 in_chan; + bool eth_iface; struct mhi_dev_client *out_handle; struct mhi_dev_client *in_handle; /*process pendig packets */ @@ -113,6 +117,7 @@ struct mhi_dev_net_client { struct mhi_dev_net_ctxt { struct mhi_dev_net_chan_attr chan_attr[MHI_MAX_SOFTWARE_CHANNELS]; struct mhi_dev_net_client *client_handle; + struct platform_device *pdev; void (*net_event_notifier)(struct mhi_dev_client_cb_reason *cb); }; @@ -247,8 +252,12 @@ static void mhi_dev_net_read_completion_cb(void *req) unsigned long flags; skb->len = mreq->transfer_len; - skb->protocol = - mhi_dev_net_eth_type_trans(skb); + + if (net_handle->eth_iface) + skb->protocol = eth_type_trans(skb, net_handle->dev); + else + skb->protocol = mhi_dev_net_eth_type_trans(skb); + skb_put(skb, mreq->transfer_len); net_handle->dev->stats.rx_packets++; skb->dev = net_handle->dev; @@ -433,12 +442,15 @@ static const struct net_device_ops mhi_dev_net_ops_ip = { .ndo_change_mtu = mhi_dev_net_change_mtu, }; -static void mhi_dev_net_setup(struct net_device *dev) +static void mhi_dev_net_rawip_setup(struct net_device *dev) { dev->netdev_ops = &mhi_dev_net_ops_ip; ether_setup(dev); + mhi_dev_net_log(MHI_INFO, + "mhi_dev_net Raw IP setup\n"); /* set this after calling ether_setup */ + dev->header_ops = NULL; dev->type = ARPHRD_RAWIP; dev->hard_header_len = 0; dev->mtu = MHI_NET_DEFAULT_MTU; @@ -446,6 +458,14 @@ static void mhi_dev_net_setup(struct net_device *dev) dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); } +static void mhi_dev_net_ether_setup(struct net_device *dev) +{ + dev->netdev_ops = &mhi_dev_net_ops_ip; + ether_setup(dev); + mhi_dev_net_log(MHI_INFO, + "mhi_dev_net Ethernet setup\n"); +} + static int mhi_dev_net_enable_iface(struct mhi_dev_net_client *mhi_dev_net_ptr) { int ret = 0; @@ -462,12 +482,20 @@ static int mhi_dev_net_enable_iface(struct mhi_dev_net_client *mhi_dev_net_ptr) "mhi_dev_net interface registration\n"); netdev = alloc_netdev(sizeof(struct mhi_dev_net_client), MHI_NET_DEV_NAME, NET_NAME_PREDICTABLE, - mhi_dev_net_setup); + mhi_net_ctxt.client_handle->eth_iface ? + mhi_dev_net_ether_setup : + mhi_dev_net_rawip_setup); if (!netdev) { pr_err("Failed to allocate netdev for mhi_dev_net\n"); goto net_dev_alloc_fail; } + if (mhi_net_ctxt.client_handle->eth_iface) { + eth_random_addr(netdev->dev_addr); + if (!is_valid_ether_addr(netdev->dev_addr)) + return -EADDRNOTAVAIL; + } + mhi_dev_net_ctxt = netdev_priv(netdev); mhi_dev_net_ptr->dev = netdev; *mhi_dev_net_ctxt = mhi_dev_net_ptr; @@ -621,6 +649,12 @@ int mhi_dev_net_interface_init(void) "Failed to create IPC logging for mhi_dev_net\n"); mhi_net_ctxt.client_handle = mhi_net_client; + if (mhi_net_ctxt.pdev) + mhi_net_ctxt.client_handle->eth_iface = + of_property_read_bool + ((&mhi_net_ctxt.pdev->dev)->of_node, + "qcom,mhi-ethernet-interface"); + /*Process pending packet work queue*/ mhi_net_client->pending_pckt_wq = create_singlethread_workqueue("pending_xmit_pckt_wq"); @@ -665,3 +699,47 @@ void __exit mhi_dev_net_exit(void) mhi_dev_net_close(); } EXPORT_SYMBOL(mhi_dev_net_exit); + +static int mhi_dev_net_probe(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + mhi_net_ctxt.pdev = pdev; + mhi_dev_net_log(MHI_INFO, + "MHI Network probe success"); + } + + return 0; +} + +static int mhi_dev_net_remove(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id mhi_dev_net_match_table[] = { + { .compatible = "qcom,msm-mhi-dev-net" }, + {} +}; + +static struct platform_driver mhi_dev_net_driver = { + .driver = { + .name = "qcom,msm-mhi-dev-net", + .of_match_table = mhi_dev_net_match_table, + }, + .probe = mhi_dev_net_probe, + .remove = mhi_dev_net_remove, +}; + +static int __init mhi_dev_net_init(void) +{ + return platform_driver_register(&mhi_dev_net_driver); +} +subsys_initcall(mhi_dev_net_init); + +static void __exit mhi_dev_exit(void) +{ + platform_driver_unregister(&mhi_dev_net_driver); +} +module_exit(mhi_dev_net_exit); diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c index 145dfd9ad5ad7ddd5e1c83056c0b883d7ca86efb..835899e37842a3ca4cdeb2dbb47e758449c08ed7 100644 --- a/drivers/platform/msm/qcom-geni-se.c +++ b/drivers/platform/msm/qcom-geni-se.c @@ -127,9 +127,6 @@ struct geni_se_device { bool vote_for_bw; }; -/* Offset of QUPV3 Hardware Version Register */ -#define QUPV3_HW_VER (0x4) - #define HW_VER_MAJOR_MASK GENMASK(31, 28) #define HW_VER_MAJOR_SHFT 28 #define HW_VER_MINOR_MASK GENMASK(27, 16) @@ -1571,6 +1568,8 @@ void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, { u32 m_cmd0 = 0; u32 m_irq_status = 0; + u32 s_cmd0 = 0; + u32 s_irq_status = 0; u32 geni_status = 0; u32 geni_ios = 0; u32 dma_rx_irq = 0; @@ -1597,10 +1596,12 @@ void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, } m_cmd0 = geni_read_reg(base, SE_GENI_M_CMD0); m_irq_status = geni_read_reg(base, SE_GENI_M_IRQ_STATUS); + s_cmd0 = geni_read_reg(base, SE_GENI_S_CMD0); + s_irq_status = geni_read_reg(base, SE_GENI_S_IRQ_STATUS); geni_status = geni_read_reg(base, SE_GENI_STATUS); geni_ios = geni_read_reg(base, SE_GENI_IOS); - dma_rx_irq = geni_read_reg(base, SE_DMA_TX_IRQ_STAT); - dma_tx_irq = geni_read_reg(base, SE_DMA_RX_IRQ_STAT); + dma_tx_irq = geni_read_reg(base, SE_DMA_TX_IRQ_STAT); + dma_rx_irq = geni_read_reg(base, SE_DMA_RX_IRQ_STAT); rx_fifo_status = geni_read_reg(base, SE_GENI_RX_FIFO_STATUS); tx_fifo_status = geni_read_reg(base, SE_GENI_TX_FIFO_STATUS); se_dma_dbg = geni_read_reg(base, SE_DMA_DEBUG_REG0); diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index 77bac859342de60b3b8253addbb9998b719bf62a..75f69cf0d45fad64568d4355b4f96e9487ba90f2 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -421,11 +422,27 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc) } #endif /* CONFIG_DEBUG_FS */ +/* + * Some systems need one or more of their pmc_plt_clks to be + * marked as critical. + */ +static const struct dmi_system_id critclk_systems[] __initconst = { + { + .ident = "MPL CEC1x", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MPL AG"), + DMI_MATCH(DMI_PRODUCT_NAME, "CEC10 Family"), + }, + }, + { /*sentinel*/ } +}; + static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap, const struct pmc_data *pmc_data) { struct platform_device *clkdev; struct pmc_clk_data *clk_data; + const struct dmi_system_id *d = dmi_first_match(critclk_systems); clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); if (!clk_data) @@ -433,6 +450,10 @@ static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap, clk_data->base = pmc_regmap; /* offset is added by client */ clk_data->clks = pmc_data->clks; + if (d) { + clk_data->critical = true; + pr_info("%s critclks quirk enabled\n", d->ident); + } clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom", PLATFORM_DEVID_NONE, diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 34ec8a565d89eecfb964a70d8a0ee1903d662e93..3789e3bf5e471869542218d11945016087252ced 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -155,6 +155,9 @@ static ssize_t power_supply_show_property(struct device *dev, else if (off == POWER_SUPPLY_PROP_CONNECTOR_HEALTH) return scnprintf(buf, PAGE_SIZE, "%s\n", power_supply_health_text[value.intval]); + else if (off == POWER_SUPPLY_PROP_SKIN_HEALTH) + return scnprintf(buf, PAGE_SIZE, "%s\n", + power_supply_health_text[value.intval]); else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) return sprintf(buf, "%s\n", value.strval); @@ -399,6 +402,11 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(voltage_max_limit), POWER_SUPPLY_ATTR(real_capacity), POWER_SUPPLY_ATTR(esr_sw_control), + POWER_SUPPLY_ATTR(force_main_icl), + POWER_SUPPLY_ATTR(force_main_fcc), + POWER_SUPPLY_ATTR(comp_clamp_level), + POWER_SUPPLY_ATTR(adapter_cc_mode), + POWER_SUPPLY_ATTR(skin_health), /* Charge pump properties */ POWER_SUPPLY_ATTR(cp_status1), POWER_SUPPLY_ATTR(cp_status2), diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 4ce909b22b24a2254119f36d5cb7140c4195ea15..31fb9e013da039db80ca18d06dd57f3ee2aebb98 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -48,6 +48,7 @@ #define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" #define FCC_VOTER "FCC_VOTER" +#define MAIN_FCC_VOTER "MAIN_FCC_VOTER" struct pl_data { int pl_mode; @@ -67,6 +68,7 @@ struct pl_data { struct votable *pl_enable_votable_indirect; struct votable *cp_ilim_votable; struct votable *cp_disable_votable; + struct votable *fcc_main_votable; struct delayed_work status_change_work; struct work_struct pl_disable_forever_work; struct work_struct pl_taper_work; @@ -99,6 +101,7 @@ struct pl_data { bool cp_disabled; int taper_entry_fv; int main_fcc_max; + u32 float_voltage_uv; }; struct pl_data *the_chip; @@ -559,31 +562,21 @@ static void get_main_fcc_config(struct pl_data *chip, int *total_fcc) static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, int parallel_fcc_ua) { - union power_supply_propval pval = {0, }; - int rc; - /* Read current FCC of main charger */ - rc = power_supply_get_property(chip->main_psy, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't get main charger current fcc, rc=%d\n", rc); - return; - } - chip->main_fcc_ua = pval.intval; - - chip->main_step_fcc_dir = (main_fcc_ua > pval.intval) ? + chip->main_fcc_ua = get_effective_result(chip->fcc_main_votable); + chip->main_step_fcc_dir = (main_fcc_ua > chip->main_fcc_ua) ? STEP_UP : STEP_DOWN; - chip->main_step_fcc_count = abs((main_fcc_ua - pval.intval) / + chip->main_step_fcc_count = abs((main_fcc_ua - chip->main_fcc_ua) / + FCC_STEP_SIZE_UA); + chip->main_step_fcc_residual = abs((main_fcc_ua - chip->main_fcc_ua) % FCC_STEP_SIZE_UA); - chip->main_step_fcc_residual = (main_fcc_ua - pval.intval) % - FCC_STEP_SIZE_UA; chip->parallel_step_fcc_dir = (parallel_fcc_ua > chip->slave_fcc_ua) ? STEP_UP : STEP_DOWN; chip->parallel_step_fcc_count = abs((parallel_fcc_ua - chip->slave_fcc_ua) / FCC_STEP_SIZE_UA); - chip->parallel_step_fcc_residual = (parallel_fcc_ua - - chip->slave_fcc_ua) % FCC_STEP_SIZE_UA; + chip->parallel_step_fcc_residual = abs((parallel_fcc_ua - + chip->slave_fcc_ua)) % FCC_STEP_SIZE_UA; if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual || chip->main_step_fcc_count || chip->main_step_fcc_residual) @@ -690,6 +683,31 @@ static void pl_taper_work(struct work_struct *work) vote(chip->pl_awake_votable, TAPER_END_VOTER, false, 0); } +static bool is_main_available(struct pl_data *chip) +{ + if (chip->main_psy) + return true; + + chip->main_psy = power_supply_get_by_name("main"); + + return !!chip->main_psy; +} + +static int pl_fcc_main_vote_callback(struct votable *votable, void *data, + int fcc_main_ua, const char *client) +{ + struct pl_data *chip = data; + union power_supply_propval pval = {0,}; + + if (!is_main_available(chip)) + return 0; + + pval.intval = fcc_main_ua; + return power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + &pval); +} + static int pl_fcc_vote_callback(struct votable *votable, void *data, int total_fcc_ua, const char *client) { @@ -738,6 +756,13 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, } rerun_election(chip->pl_disable_votable); + /* When FCC changes, trigger psy changed event for CC mode */ + if (!chip->cp_master_psy) + chip->cp_master_psy = + power_supply_get_by_name("charge_pump_master"); + + if (chip->cp_master_psy) + power_supply_changed(chip->cp_master_psy); return 0; } @@ -794,14 +819,7 @@ static void fcc_stepper_work(struct work_struct *work) } main_fcc = get_effective_result_locked(chip->fcc_votable); - pval.intval = main_fcc; - rc = power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't set main charger fcc, rc=%d\n", rc); - goto out; - } - + vote(chip->fcc_main_votable, FCC_STEPPER_VOTER, true, main_fcc); goto stepper_exit; } @@ -862,22 +880,10 @@ static void fcc_stepper_work(struct work_struct *work) } /* Set main FCC */ - pval.intval = main_fcc; - rc = power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't set main charger fcc, rc=%d\n", rc); - goto out; - } + vote(chip->fcc_main_votable, FCC_STEPPER_VOTER, true, main_fcc); } else { /* Set main FCC */ - pval.intval = main_fcc; - rc = power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't set main charger fcc, rc=%d\n", rc); - goto out; - } + vote(chip->fcc_main_votable, FCC_STEPPER_VOTER, true, main_fcc); /* Set parallel FCC */ if (chip->pl_psy) { @@ -933,6 +939,17 @@ static void fcc_stepper_work(struct work_struct *work) vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0); } +static bool is_batt_available(struct pl_data *chip) +{ + if (!chip->batt_psy) + chip->batt_psy = power_supply_get_by_name("battery"); + + if (!chip->batt_psy) + return false; + + return true; +} + #define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000 static int pl_fv_vote_callback(struct votable *votable, void *data, int fv_uv, const char *client) @@ -966,6 +983,31 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, } } + /* + * check for termination at reduced float voltage and re-trigger + * charging if new float voltage is above last FV. + */ + if ((chip->float_voltage_uv < fv_uv) && is_batt_available(chip)) { + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &pval); + if (rc < 0) { + pr_err("Couldn't get battery status rc=%d\n", rc); + } else { + if (pval.intval == POWER_SUPPLY_STATUS_FULL) { + pr_debug("re-triggering charging\n"); + pval.intval = 1; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_FORCE_RECHARGE, + &pval); + if (rc < 0) + pr_err("Couldn't set force recharge rc=%d\n", + rc); + } + } + } + + chip->float_voltage_uv = fv_uv; + return 0; } @@ -1063,27 +1105,6 @@ static void pl_awake_work(struct work_struct *work) vote(chip->pl_awake_votable, PL_VOTER, false, 0); } -static bool is_main_available(struct pl_data *chip) -{ - if (chip->main_psy) - return true; - - chip->main_psy = power_supply_get_by_name("main"); - - return !!chip->main_psy; -} - -static bool is_batt_available(struct pl_data *chip) -{ - if (!chip->batt_psy) - chip->batt_psy = power_supply_get_by_name("battery"); - - if (!chip->batt_psy) - return false; - - return true; -} - static int pl_disable_vote_callback(struct votable *votable, void *data, int pl_disable, const char *client) { @@ -1184,16 +1205,8 @@ static int pl_disable_vote_callback(struct votable *votable, * 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; - } - + vote(chip->fcc_main_votable, MAIN_FCC_VOTER, + true, master_fcc_ua); pval.intval = slave_fcc_ua; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, @@ -1217,16 +1230,8 @@ static int pl_disable_vote_callback(struct votable *votable, } 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; - } + vote(chip->fcc_main_votable, MAIN_FCC_VOTER, + true, master_fcc_ua); } /* @@ -1288,15 +1293,8 @@ static int pl_disable_vote_callback(struct votable *votable, } /* main psy gets all share */ - pval.intval = total_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; - } - + vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true, + total_fcc_ua); cp_configure_ilim(chip, FCC_VOTER, total_fcc_ua / 2); /* reset parallel FCC */ @@ -1711,13 +1709,22 @@ int qcom_batt_init(int smb_version) if (!chip->pl_ws) goto cleanup; + chip->fcc_main_votable = create_votable("FCC_MAIN", VOTE_MIN, + pl_fcc_main_vote_callback, + chip); + if (IS_ERR(chip->fcc_main_votable)) { + rc = PTR_ERR(chip->fcc_main_votable); + chip->fcc_main_votable = NULL; + goto release_wakeup_source; + } + chip->fcc_votable = create_votable("FCC", VOTE_MIN, pl_fcc_vote_callback, chip); if (IS_ERR(chip->fcc_votable)) { rc = PTR_ERR(chip->fcc_votable); chip->fcc_votable = NULL; - goto release_wakeup_source; + goto destroy_votable; } chip->fv_votable = create_votable("FV", VOTE_MIN, @@ -1813,6 +1820,7 @@ int qcom_batt_init(int smb_version) destroy_votable(chip->pl_disable_votable); destroy_votable(chip->fv_votable); destroy_votable(chip->fcc_votable); + destroy_votable(chip->fcc_main_votable); destroy_votable(chip->usb_icl_votable); release_wakeup_source: wakeup_source_unregister(chip->pl_ws); @@ -1840,6 +1848,7 @@ void qcom_batt_deinit(void) destroy_votable(chip->pl_disable_votable); destroy_votable(chip->fv_votable); destroy_votable(chip->fcc_votable); + destroy_votable(chip->fcc_main_votable); wakeup_source_unregister(chip->pl_ws); the_chip = NULL; kfree(chip); diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c index b2237a4c405d8bfddf3c5f7852c9101eff67ef0e..a382d60299d9f8d83e0489935dd4c6f8445bdf69 100644 --- a/drivers/power/supply/qcom/fg-alg.c +++ b/drivers/power/supply/qcom/fg-alg.c @@ -1110,7 +1110,7 @@ static int get_time_to_full_locked(struct ttf *ttf, int *val) /* Calculate OCV for each window */ if (power_approx) { - i_step = pbatt_avg / max((u32)MILLI_UNIT, + i_step = pbatt_avg / max(MILLI_UNIT, (step_chg_cfg[i].high_threshold / MILLI_UNIT)); } else { diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index ec35ded03e4d093aa5ce99017d68a4465de7b80f..eb85b4e1ee3693f76c58acc0e9029b121777af26 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -42,6 +42,10 @@ struct qg_dt { int s2_vbat_low_fifo_length; int s2_acc_length; int s2_acc_intvl_ms; + int sleep_s2_fifo_length; + int sleep_s2_acc_length; + int sleep_s2_acc_intvl_ms; + int fast_chg_s2_fifo_length; int ocv_timer_expiry_min; int ocv_tol_threshold_uv; int s3_entry_fifo_length; @@ -57,6 +61,8 @@ struct qg_dt { int esr_disable_soc; int esr_min_ibat_ua; int shutdown_soc_threshold; + int min_sleep_time_secs; + int sys_min_volt_mv; bool hold_soc_while_full; bool linearize_soc; bool cl_disable; @@ -65,6 +71,8 @@ struct qg_dt { bool esr_discharge_enable; bool qg_ext_sense; bool use_s7_ocv; + bool qg_sleep_config; + bool qg_fast_chg_cfg; }; struct qg_esr_data { @@ -89,6 +97,7 @@ struct qpnp_qg { struct work_struct udata_work; struct work_struct scale_soc_work; struct work_struct qg_status_change_work; + struct delayed_work qg_sleep_exit_work; struct notifier_block nb; struct mutex bus_lock; struct mutex data_lock; @@ -139,9 +148,12 @@ struct qpnp_qg { u32 charge_counter_uah; u32 esr_avg; u32 esr_last; + u32 s2_state; + u32 s2_state_mask; ktime_t last_user_update_time; ktime_t last_fifo_update_time; unsigned long last_maint_soc_update_time; + unsigned long suspend_time; struct iio_channel *batt_therm_chan; struct iio_channel *batt_id_chan; @@ -184,6 +196,13 @@ enum ocv_type { PON_OCV_MAX, }; +enum s2_state { + S2_FAST_CHARGING = BIT(0), + S2_LOW_VBAT = BIT(1), + S2_SLEEP = BIT(2), + S2_DEFAULT = BIT(3), +}; + enum debug_mask { QG_DEBUG_PON = BIT(0), QG_DEBUG_PROFILE = BIT(1), diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index c398c697e0144b50edbcc476b6ba335c3c43ec89..ed6a2ce25e61489e216dc8f3738b4198730c873e 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2018,2019 The Linux Foundation. All rights reserved. * * This 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,6 +35,8 @@ #define PROFILE_IRQ_DISABLE "NO_PROFILE_IRQ_DISABLE" #define QG_INIT_STATE_IRQ_DISABLE "QG_INIT_STATE_IRQ_DISABLE" #define TTF_AWAKE_VOTER "TTF_AWAKE_VOTER" +#define SLEEP_EXIT_DATA_VOTER "SLEEP_EXIT_DATA_VOTER" +#define SLEEP_EXIT_VOTER "SLEEP_EXIT_VOTER" #define V_RAW_TO_UV(V_RAW) div_u64(194637ULL * (u64)V_RAW, 1000) #define FIFO_V_RESET_VAL 0x8000 diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 5a0d4bd96359918cb8ae604d023e4e09d4e8a4e9..0df0636a034d82af3f1e632ff68f2af69dee7378 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include "fg-core.h" @@ -255,6 +256,7 @@ struct fg_gen4_chip { struct cycle_counter *counter; struct cap_learning *cl; struct ttf *ttf; + struct device_node *pbs_dev; struct nvmem_device *fg_nvmem; struct votable *delta_esr_irq_en_votable; struct votable *pl_disable_votable; @@ -289,6 +291,7 @@ struct fg_gen4_chip { int vbatt_res; int scale_timer; int current_now; + int calib_level; bool first_profile_load; bool ki_coeff_dischg_en; bool slope_limit_en; @@ -1026,6 +1029,61 @@ static int fg_gen4_get_prop_soc_scale(struct fg_gen4_chip *chip) return rc; } +#define SDAM1_MEM_124_REG 0xB0BC +static int fg_gen4_set_calibrate_level(struct fg_gen4_chip *chip, int val) +{ + struct fg_dev *fg = &chip->fg; + int rc; + u8 buf; + + if (!chip->pbs_dev) + return -ENODEV; + + if (val < 0 || val > 0x83) { + pr_err("Incorrect calibration level %d\n", val); + return -EINVAL; + } + + if (val == chip->calib_level) + return 0; + + buf = (u8)val; + rc = fg_write(fg, SDAM1_MEM_124_REG, &buf, 1); + if (rc < 0) { + pr_err("Error in writing to 0x%04X, rc=%d\n", + SDAM1_MEM_124_REG, rc); + return rc; + } + + buf = 0x1; + rc = qpnp_pbs_trigger_event(chip->pbs_dev, buf); + if (rc < 0) { + pr_err("Error in triggering PBS rc=%d\n", rc); + return rc; + } + + rc = fg_read(fg, SDAM1_MEM_124_REG, &buf, 1); + if (rc < 0) { + pr_err("Error in reading from 0x%04X, rc=%d\n", + SDAM1_MEM_124_REG, rc); + return rc; + } + + if (buf) { + pr_err("Incorrect return value: %x\n", buf); + return -EINVAL; + } + + if (is_parallel_charger_available(fg)) { + cancel_work_sync(&chip->pl_current_en_work); + schedule_work(&chip->pl_current_en_work); + } + + chip->calib_level = val; + fg_dbg(fg, FG_POWER_SUPPLY, "Set calib_level to %x\n", val); + return 0; +} + /* ALG callback functions below */ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) @@ -4225,6 +4283,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_POWER_AVG: rc = fg_gen4_get_power(chip, &pval->intval, true); break; + case POWER_SUPPLY_PROP_CALIBRATE: + pval->intval = chip->calib_level; + break; default: pr_err("unsupported property %d\n", psp); rc = -EINVAL; @@ -4314,6 +4375,9 @@ static int fg_psy_set_property(struct power_supply *psy, chip->batt_age_level = pval->intval; schedule_delayed_work(&fg->profile_load_work, 0); break; + case POWER_SUPPLY_PROP_CALIBRATE: + rc = fg_gen4_set_calibrate_level(chip, pval->intval); + break; default: break; } @@ -4333,6 +4397,7 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_SOH: case POWER_SUPPLY_PROP_CLEAR_SOH: case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: + case POWER_SUPPLY_PROP_CALIBRATE: return 1; default: break; @@ -4377,6 +4442,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_SCALE_MODE_EN, + POWER_SUPPLY_PROP_CALIBRATE, }; static const struct power_supply_desc fg_psy_desc = { @@ -5313,6 +5379,14 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) return -EINVAL; } + if (of_find_property(node, "qcom,pmic-pbs", NULL)) { + chip->pbs_dev = of_parse_phandle(node, "qcom,pmic-pbs", 0); + if (!chip->pbs_dev) { + pr_err("Missing qcom,pmic-pbs property\n"); + return -ENODEV; + } + } + rc = fg_gen4_parse_nvmem_dt(chip); if (rc < 0) return rc; @@ -5628,6 +5702,7 @@ static int fg_gen4_probe(struct platform_device *pdev) chip->ki_coeff_full_soc[0] = -EINVAL; chip->ki_coeff_full_soc[1] = -EINVAL; chip->esr_soh_cycle_count = -EINVAL; + chip->calib_level = -EINVAL; fg->regmap = dev_get_regmap(fg->dev->parent, NULL); if (!fg->regmap) { dev_err(fg->dev, "Parent regmap is unavailable\n"); diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 78ed630a8ed6a7eeead7b5ff90f668f958f0cd9e..e9005c45747075ba36d6fa7380138836c2845acf 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,8 @@ module_param_named( esr_count, qg_esr_count, int, 0600 ); +static int qg_process_rt_fifo(struct qpnp_qg *chip); + static bool is_battery_present(struct qpnp_qg *chip) { u8 reg = 0; @@ -146,7 +149,7 @@ static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length) pr_err("Failed to write S2 FIFO length, rc=%d\n", rc); /* update the S3 FIFO length, when S2 length is updated */ - if (length > 3) + if (length > 3 && !chip->dt.qg_sleep_config) s3_entry_fifo_length = (chip->dt.s3_entry_fifo_length > 0) ? chip->dt.s3_entry_fifo_length : DEFAULT_S3_FIFO_LENGTH; else /* Use S3 length as 1 for any S2 length <= 3 */ @@ -275,6 +278,111 @@ static int qg_store_soc_params(struct qpnp_qg *chip) return rc; } +static int qg_config_s2_state(struct qpnp_qg *chip, + enum s2_state requested_state, bool state_enable, + bool process_fifo) +{ + int rc, acc_interval, acc_length; + u8 fifo_length, reg = 0, state = S2_DEFAULT; + + if ((chip->s2_state_mask & requested_state) && (state_enable == true)) + return 0; /* No change in state */ + + if (!(chip->s2_state_mask & requested_state) && (state_enable == false)) + return 0; /* No change in state */ + + if (state_enable) + chip->s2_state_mask |= requested_state; + else + chip->s2_state_mask &= ~requested_state; + + /* define the priority of the states */ + if (chip->s2_state_mask & S2_FAST_CHARGING) + state = S2_FAST_CHARGING; + else if (chip->s2_state_mask & S2_LOW_VBAT) + state = S2_LOW_VBAT; + else if (chip->s2_state_mask & S2_SLEEP) + state = S2_SLEEP; + else + state = S2_DEFAULT; + + if (state == chip->s2_state) + return 0; + + switch (state) { + case S2_FAST_CHARGING: + fifo_length = chip->dt.fast_chg_s2_fifo_length; + acc_interval = chip->dt.s2_acc_intvl_ms; + acc_length = chip->dt.s2_acc_length; + break; + case S2_LOW_VBAT: + fifo_length = chip->dt.s2_vbat_low_fifo_length; + acc_interval = chip->dt.s2_acc_intvl_ms; + acc_length = chip->dt.s2_acc_length; + break; + case S2_SLEEP: + fifo_length = chip->dt.sleep_s2_fifo_length; + acc_interval = chip->dt.sleep_s2_acc_intvl_ms; + acc_length = chip->dt.sleep_s2_acc_length; + break; + case S2_DEFAULT: + fifo_length = chip->dt.s2_fifo_length; + acc_interval = chip->dt.s2_acc_intvl_ms; + acc_length = chip->dt.s2_acc_length; + break; + default: + pr_err("Invalid S2 state %d\n", state); + return -EINVAL; + } + + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + return rc; + } + + if (process_fifo) { + rc = qg_process_rt_fifo(chip); + if (rc < 0) { + pr_err("Failed to process FIFO real-time, rc=%d\n", rc); + goto done; + } + } + + rc = qg_update_fifo_length(chip, fifo_length); + if (rc < 0) { + pr_err("Failed to update S2 fifo-length, rc=%d\n", rc); + goto done; + } + + reg = acc_interval / 10; + rc = qg_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL3_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to update S2 acc intrvl, rc=%d\n", rc); + goto done; + } + + reg = ilog2(acc_length) - 1; + rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG, + NUM_OF_ACCUM_MASK, reg); + if (rc < 0) { + pr_err("Failed to update S2 ACC length, rc=%d\n", rc); + goto done; + } + + chip->s2_state = state; + + qg_dbg(chip, QG_DEBUG_STATUS, "S2 New state=%x fifo_length=%d interval=%d acc_length=%d\n", + state, fifo_length, acc_interval, acc_length); + +done: + qg_master_hold(chip, false); + /* FIFO restarted */ + chip->last_fifo_update_time = ktime_get_boottime(); + return rc; +} + static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length) { int rc = 0, i, j = 0, temp; @@ -309,9 +417,10 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length) /* * If there is pending data from suspend, append the new FIFO - * data to it. + * data to it. Only do this if we can accomadate 8 FIFOs */ - if (chip->suspend_data) { + if (chip->suspend_data && + (chip->kdata.fifo_length < (MAX_FIFO_LENGTH / 2))) { j = chip->kdata.fifo_length; /* append the data */ chip->suspend_data = false; qg_dbg(chip, QG_DEBUG_FIFO, @@ -380,7 +489,7 @@ static int qg_process_accumulator(struct qpnp_qg *chip) return rc; } - if (!count) { + if (!count || count < 10) { /* Ignore small accumulator data */ pr_debug("No ACCUMULATOR data!\n"); return 0; } @@ -412,6 +521,8 @@ static int qg_process_accumulator(struct qpnp_qg *chip) chip->kdata.fifo[index].interval = sample_interval; chip->kdata.fifo[index].count = count; chip->kdata.fifo_length++; + if (chip->kdata.fifo_length == MAX_FIFO_LENGTH) + chip->kdata.fifo_length = MAX_FIFO_LENGTH - 1; if (chip->kdata.fifo_length == 1) /* Only accumulator data */ chip->kdata.seq_no = chip->seq_no++ % U32_MAX; @@ -456,7 +567,7 @@ static int qg_process_rt_fifo(struct qpnp_qg *chip) static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb) { int rc = 0; - ktime_t now = ktime_get(); + ktime_t now = ktime_get_boottime(); s64 time_delta; /* @@ -501,7 +612,7 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb) goto done; } /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); + chip->last_fifo_update_time = ktime_get_boottime(); /* signal the read thread */ chip->data_ready = true; @@ -523,7 +634,7 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb) static int qg_vbat_low_wa(struct qpnp_qg *chip) { int rc, i, temp = 0; - u32 vbat_low_uv = 0, fifo_length = 0; + u32 vbat_low_uv = 0; if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) { rc = qg_get_battery_temp(chip, &temp); @@ -553,37 +664,11 @@ static int qg_vbat_low_wa(struct qpnp_qg *chip) } } - rc = get_fifo_length(chip, &fifo_length, false); - if (rc < 0) { - pr_err("Failed to get FIFO length, rc=%d\n", rc); - return rc; - } - - if (chip->vbat_low && fifo_length == chip->dt.s2_vbat_low_fifo_length) - return 0; - - if (!chip->vbat_low && fifo_length == chip->dt.s2_fifo_length) - return 0; - - rc = qg_master_hold(chip, true); - if (rc < 0) { - pr_err("Failed to hold master, rc=%d\n", rc); - goto done; - } - - fifo_length = chip->vbat_low ? chip->dt.s2_vbat_low_fifo_length : - chip->dt.s2_fifo_length; - - rc = qg_update_fifo_length(chip, fifo_length); + rc = qg_config_s2_state(chip, S2_LOW_VBAT, + chip->vbat_low ? true : false, false); if (rc < 0) - goto done; + pr_err("Failed to configure for VBAT_LOW rc=%d\n", rc); - qg_dbg(chip, QG_DEBUG_STATUS, "FIFO length updated to %d vbat_low=%d\n", - fifo_length, chip->vbat_low); -done: - qg_master_hold(chip, false); - /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); return rc; } @@ -654,6 +739,22 @@ static int qg_vbat_thresholds_config(struct qpnp_qg *chip) return rc; } +static int qg_fast_charge_config(struct qpnp_qg *chip) +{ + int rc = 0; + + if (!chip->dt.qg_fast_chg_cfg) + return 0; + + rc = qg_config_s2_state(chip, S2_FAST_CHARGING, + (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) + ? true : false, false); + if (rc < 0) + pr_err("Failed to exit S2_SLEEP rc=%d\n", rc); + + return rc; +} + static void qg_retrieve_esr_params(struct qpnp_qg *chip) { u32 data = 0; @@ -999,7 +1100,7 @@ static int qg_esr_estimate(struct qpnp_qg *chip) goto done; } /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); + chip->last_fifo_update_time = ktime_get_boottime(); if (chip->esr_avg) { chip->kdata.param[QG_ESR].data = chip->esr_avg; @@ -1086,7 +1187,7 @@ static void process_udata_work(struct work_struct *work) #define MAX_FIFO_DELTA_PERCENT 10 static irqreturn_t qg_fifo_update_done_handler(int irq, void *data) { - ktime_t now = ktime_get(); + ktime_t now = ktime_get_boottime(); int rc, hw_delta_ms = 0, margin_ms = 0; u32 fifo_length = 0; s64 time_delta_ms = 0; @@ -1117,6 +1218,10 @@ static irqreturn_t qg_fifo_update_done_handler(int irq, void *data) if (rc < 0) pr_err("Failed to apply VBAT EMPTY config rc=%d\n", rc); + rc = qg_fast_charge_config(chip); + if (rc < 0) + pr_err("Failed to apply fast-charge config rc=%d\n", rc); + rc = qg_vbat_low_wa(chip); if (rc < 0) { pr_err("Failed to apply VBAT LOW WA, rc=%d\n", rc); @@ -1576,6 +1681,54 @@ static int qg_get_charge_counter(struct qpnp_qg *chip, int *charge_counter) return 0; } +static int qg_get_power(struct qpnp_qg *chip, int *val, bool average) +{ + int rc, v_min, v_ocv, rbatt = 0, esr = 0; + s64 power; + + if (is_debug_batt_id(chip)) { + *val = -EINVAL; + return 0; + } + + v_min = chip->dt.sys_min_volt_mv * 1000; + + rc = qg_sdam_read(SDAM_OCV_UV, &v_ocv); + if (rc < 0) { + pr_err("Failed to read OCV rc=%d\n", rc); + return rc; + } + + rc = qg_sdam_read(SDAM_RBAT_MOHM, &rbatt); + if (rc < 0) { + pr_err("Failed to read T_RBAT rc=%d\n", rc); + return rc; + } + + rbatt *= 1000; /* uohms */ + esr = chip->esr_last * 1000; + + if (rbatt <= 0 || esr <= 0) { + pr_debug("Invalid rbatt/esr rbatt=%d esr=%d\n", rbatt, esr); + *val = -EINVAL; + return 0; + } + + power = (s64)v_min * (v_ocv - v_min); + + if (average) + power = div_s64(power, rbatt); + else + power = div_s64(power, esr); + + *val = power; + + qg_dbg(chip, QG_DEBUG_STATUS, "v_min=%d v_ocv=%d rbatt=%d esr=%d power=%lld\n", + v_min, v_ocv, rbatt, esr, power); + + return 0; +} + static int qg_get_ttf_param(void *data, enum ttf_param param, int *val) { union power_supply_propval prop = {0, }; @@ -1809,6 +1962,9 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: rc = qg_get_battery_capacity(chip, &pval->intval); break; + case POWER_SUPPLY_PROP_CAPACITY_RAW: + pval->intval = chip->sys_soc; + break; case POWER_SUPPLY_PROP_REAL_CAPACITY: rc = qg_get_battery_capacity_real(chip, &pval->intval); break; @@ -1906,6 +2062,12 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_AVG: rc = qg_get_vbat_avg(chip, &pval->intval); break; + case POWER_SUPPLY_PROP_POWER_NOW: + rc = qg_get_power(chip, &pval->intval, false); + break; + case POWER_SUPPLY_PROP_POWER_AVG: + rc = qg_get_power(chip, &pval->intval, true); + break; default: pr_debug("Unsupported property %d\n", psp); break; @@ -1932,6 +2094,7 @@ static int qg_property_is_writeable(struct power_supply *psy, static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_RAW, POWER_SUPPLY_PROP_REAL_CAPACITY, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -1961,6 +2124,8 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_FG_RESET, POWER_SUPPLY_PROP_CC_SOC, POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_POWER_NOW, }; static const struct power_supply_desc qg_psy_desc = { @@ -2216,6 +2381,33 @@ static int qg_battery_status_update(struct qpnp_qg *chip) return rc; } +static void qg_sleep_exit_work(struct work_struct *work) +{ + int rc; + struct qpnp_qg *chip = container_of(work, + struct qpnp_qg, qg_sleep_exit_work.work); + + vote(chip->awake_votable, SLEEP_EXIT_VOTER, true, 0); + + mutex_lock(&chip->data_lock); + /* + * if this work is executing, the system has been active + * for a while. So, force back the S2 active configuration + */ + qg_dbg(chip, QG_DEBUG_STATUS, "sleep_exit_work: exit S2_SLEEP\n"); + rc = qg_config_s2_state(chip, S2_SLEEP, false, true); + if (rc < 0) + pr_err("Failed to exit S2_SLEEP rc=%d\n", rc); + + vote(chip->awake_votable, SLEEP_EXIT_DATA_VOTER, true, 0); + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + + mutex_unlock(&chip->data_lock); + + vote(chip->awake_votable, SLEEP_EXIT_VOTER, false, 0); +} static void qg_status_change_work(struct work_struct *work) { @@ -2390,6 +2582,7 @@ static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count, vote(chip->awake_votable, FIFO_DONE_VOTER, false, 0); vote(chip->awake_votable, FIFO_RT_DONE_VOTER, false, 0); vote(chip->awake_votable, SUSPEND_DATA_VOTER, false, 0); + vote(chip->awake_votable, SLEEP_EXIT_DATA_VOTER, false, 0); qg_dbg(chip, QG_DEBUG_DEVICE, "QG device read complete Seq_no=%u Size=%ld\n", @@ -2732,7 +2925,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) bool use_pon_ocv = true; unsigned long rtc_sec = 0; u32 ocv_uv = 0, soc = 0, pon_soc = 0, full_soc = 0, cutoff_soc = 0; - u32 shutdown[SDAM_MAX] = {0}; + u32 shutdown[SDAM_MAX] = {0}, soc_raw = 0; char ocv_type[20] = "NONE"; if (!chip->profile_loaded) { @@ -2811,6 +3004,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) use_pon_ocv = false; ocv_uv = shutdown[SDAM_OCV_UV]; soc = shutdown[SDAM_SOC]; + soc_raw = shutdown[SDAM_SOC] * 100; strlcpy(ocv_type, "SHUTDOWN_SOC", 20); qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n"); @@ -2878,7 +3072,9 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) soc = DIV_ROUND_UP(((pon_soc - cutoff_soc) * 100), (full_soc - cutoff_soc)); soc = CAP(0, 100, soc); + soc_raw = soc * 100; } else { + soc_raw = pon_soc * 100; soc = pon_soc; } @@ -2892,6 +3088,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) return rc; } + chip->cc_soc = chip->sys_soc = soc_raw; chip->last_adj_ssoc = chip->catch_up_soc = chip->msoc = soc; chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv; chip->kdata.param[QG_PON_OCV_UV].valid = true; @@ -3005,6 +3202,8 @@ static int qg_hw_init(struct qpnp_qg *chip) } } + chip->s2_state = S2_DEFAULT; + chip->s2_state_mask |= S2_DEFAULT; /* signal the read thread */ chip->data_ready = true; wake_up_interruptible(&chip->qg_wait_q); @@ -3015,7 +3214,7 @@ static int qg_hw_init(struct qpnp_qg *chip) pr_err("Failed to release master, rc=%d\n", rc); return rc; } - chip->last_fifo_update_time = ktime_get(); + chip->last_fifo_update_time = ktime_get_boottime(); if (chip->dt.ocv_timer_expiry_min != -EINVAL) { if (chip->dt.ocv_timer_expiry_min < 2) @@ -3340,6 +3539,9 @@ static int qg_alg_init(struct qpnp_qg *chip) #define DEFAULT_S2_VBAT_LOW_LENGTH 2 #define DEFAULT_S2_ACC_LENGTH 128 #define DEFAULT_S2_ACC_INTVL_MS 100 +#define DEFAULT_SLEEP_S2_FIFO_LENGTH 8 +#define DEFAULT_SLEEP_S2_ACC_LENGTH 256 +#define DEFAULT_SLEEP_S2_ACC_INTVL_MS 200 #define DEFAULT_DELTA_SOC 1 #define DEFAULT_SHUTDOWN_SOC_SECS 360 #define DEFAULT_COLD_TEMP_THRESHOLD 0 @@ -3357,6 +3559,9 @@ static int qg_alg_init(struct qpnp_qg *chip) #define DEFAULT_ESR_QUAL_VBAT_UV 7000 #define DEFAULT_ESR_DISABLE_SOC 1000 #define ESR_CHG_MIN_IBAT_UA (-450000) +#define DEFAULT_SLEEP_TIME_SECS 1800 /* 30 mins */ +#define DEFAULT_SYS_MIN_VOLT_MV 2800 +#define DEFAULT_FAST_CHG_S2_FIFO_LENGTH 1 static int qg_parse_dt(struct qpnp_qg *chip) { int rc = 0; @@ -3593,10 +3798,64 @@ static int qg_parse_dt(struct qpnp_qg *chip) else chip->dt.shutdown_soc_threshold = temp; + rc = of_property_read_u32(node, "qcom,qg-sys-min-voltage", &temp); + if (rc < 0) + chip->dt.sys_min_volt_mv = DEFAULT_SYS_MIN_VOLT_MV; + else + chip->dt.sys_min_volt_mv = temp; + + if (of_property_read_bool(node, "qcom,qg-sleep-config")) { + + chip->dt.qg_sleep_config = true; + + rc = of_property_read_u32(node, + "qcom,sleep-s2-fifo-length", &temp); + if (rc < 0) + chip->dt.sleep_s2_fifo_length = + DEFAULT_SLEEP_S2_FIFO_LENGTH; + else + chip->dt.sleep_s2_fifo_length = temp; + + rc = of_property_read_u32(node, + "qcom,sleep-s2-acc-length", &temp); + if (rc < 0) + chip->dt.sleep_s2_acc_length = + DEFAULT_SLEEP_S2_ACC_LENGTH; + else + chip->dt.sleep_s2_acc_length = temp; + + rc = of_property_read_u32(node, + "qcom,sleep-s2-acc-intvl-ms", &temp); + if (rc < 0) + chip->dt.sleep_s2_acc_intvl_ms = + DEFAULT_SLEEP_S2_ACC_INTVL_MS; + else + chip->dt.sleep_s2_acc_intvl_ms = temp; + } + + if (of_property_read_bool(node, "qcom,qg-fast-chg-config")) { + + chip->dt.qg_fast_chg_cfg = true; + + rc = of_property_read_u32(node, + "qcom,fast-chg-s2-fifo-length", &temp); + if (rc < 0) + chip->dt.fast_chg_s2_fifo_length = + DEFAULT_FAST_CHG_S2_FIFO_LENGTH; + else + chip->dt.fast_chg_s2_fifo_length = temp; + } + chip->dt.qg_ext_sense = of_property_read_bool(node, "qcom,qg-ext-sns"); chip->dt.use_s7_ocv = of_property_read_bool(node, "qcom,qg-use-s7-ocv"); + rc = of_property_read_u32(node, "qcom,min-sleep-time-secs", &temp); + if (rc < 0) + chip->dt.min_sleep_time_secs = DEFAULT_SLEEP_TIME_SECS; + else + chip->dt.min_sleep_time_secs = temp; + /* Capacity learning params*/ if (!chip->dt.cl_disable) { chip->dt.cl_feedback_on = of_property_read_bool(node, @@ -3682,6 +3941,7 @@ static int process_suspend(struct qpnp_qg *chip) return 0; cancel_delayed_work_sync(&chip->ttf->ttf_work); + cancel_delayed_work_sync(&chip->qg_sleep_exit_work); chip->suspend_data = false; @@ -3690,6 +3950,13 @@ static int process_suspend(struct qpnp_qg *chip) /* ignore any suspend processing if we are charging */ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { + /* Reset the sleep config if we are charging */ + if (chip->dt.qg_sleep_config) { + qg_dbg(chip, QG_DEBUG_STATUS, "Suspend: Charging - Exit S2_SLEEP\n"); + rc = qg_config_s2_state(chip, S2_SLEEP, false, true); + if (rc < 0) + pr_err("Failed to exit S2-sleep rc=%d\n", rc); + } qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n"); return 0; } @@ -3707,12 +3974,23 @@ static int process_suspend(struct qpnp_qg *chip) return rc; } sleep_fifo_length &= SLEEP_IBAT_QUALIFIED_LENGTH_MASK; - /* - * If the real-time FIFO count is greater than - * the the #fifo to enter sleep, save the FIFO data - * and reset the fifo count. - */ - if (fifo_rt_length >= (chip->dt.s2_fifo_length - sleep_fifo_length)) { + + if (chip->dt.qg_sleep_config) { + qg_dbg(chip, QG_DEBUG_STATUS, "Suspend: Forcing S2_SLEEP\n"); + rc = qg_config_s2_state(chip, S2_SLEEP, true, true); + if (rc < 0) + pr_err("Failed to config S2_SLEEP rc=%d\n", rc); + if (chip->kdata.fifo_length > 0) + chip->suspend_data = true; + } else if (fifo_rt_length >= + (chip->dt.s2_fifo_length - sleep_fifo_length)) { + /* + * If the real-time FIFO count is greater than + * the the #fifo to enter sleep, save the FIFO data + * and reset the fifo count. This is avoid a gauranteed wakeup + * due to fifo_done event as the curent FIFO length is already + * beyond the sleep length. + */ rc = qg_master_hold(chip, true); if (rc < 0) { pr_err("Failed to hold master, rc=%d\n", rc); @@ -3732,29 +4010,40 @@ static int process_suspend(struct qpnp_qg *chip) return rc; } /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); + chip->last_fifo_update_time = ktime_get_boottime(); chip->suspend_data = true; } - qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d\n", + get_rtc_time(&chip->suspend_time); + + qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d time=%d\n", fifo_rt_length, sleep_fifo_length, - chip->dt.s2_fifo_length, chip->suspend_data); + chip->dt.s2_fifo_length, chip->suspend_data, + chip->suspend_time); return rc; } +#define QG_SLEEP_EXIT_TIME_MS 15000 /* 15 secs */ static int process_resume(struct qpnp_qg *chip) { u8 status2 = 0, rt_status = 0; u32 ocv_uv = 0, ocv_raw = 0; int rc; - unsigned long rtc_sec = 0; + unsigned long rtc_sec = 0, sleep_time_secs = 0; /* skip if profile is not loaded */ if (!chip->profile_loaded) return 0; + get_rtc_time(&rtc_sec); + sleep_time_secs = rtc_sec - chip->suspend_time; + + if (chip->dt.qg_sleep_config) + schedule_delayed_work(&chip->qg_sleep_exit_work, + msecs_to_jiffies(QG_SLEEP_EXIT_TIME_MS)); + rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status2, 1); if (rc < 0) { pr_err("Failed to read status2 register, rc=%d\n", rc); @@ -3770,12 +4059,15 @@ static int process_resume(struct qpnp_qg *chip) /* Clear suspend data as there has been a GOOD OCV */ memset(&chip->kdata, 0, sizeof(chip->kdata)); - get_rtc_time(&rtc_sec); chip->kdata.fifo_time = (u32)rtc_sec; chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; chip->kdata.param[QG_GOOD_OCV_UV].valid = true; chip->suspend_data = false; + /* allow SOC jump if we have slept longer */ + if (sleep_time_secs >= chip->dt.min_sleep_time_secs) + chip->force_soc = true; + qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n", ocv_uv); } @@ -3788,9 +4080,10 @@ static int process_resume(struct qpnp_qg *chip) } rt_status &= FIFO_UPDATE_DONE_INT_LAT_STS_BIT; - qg_dbg(chip, QG_DEBUG_PM, "FIFO_DONE_STS=%d suspend_data=%d good_ocv=%d\n", + qg_dbg(chip, QG_DEBUG_PM, "FIFO_DONE_STS=%d suspend_data=%d good_ocv=%d sleep_time=%d secs\n", !!rt_status, chip->suspend_data, - chip->kdata.param[QG_GOOD_OCV_UV].valid); + chip->kdata.param[QG_GOOD_OCV_UV].valid, + sleep_time_secs); /* * If this is not a wakeup from FIFO-done, * process the data immediately if - we have data from @@ -3918,6 +4211,7 @@ static int qpnp_qg_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); INIT_WORK(&chip->udata_work, process_udata_work); INIT_WORK(&chip->qg_status_change_work, qg_status_change_work); + INIT_DELAYED_WORK(&chip->qg_sleep_exit_work, qg_sleep_exit_work); mutex_init(&chip->bus_lock); mutex_init(&chip->soc_lock); mutex_init(&chip->data_lock); @@ -4078,6 +4372,7 @@ static int qpnp_qg_remove(struct platform_device *pdev) qg_batterydata_exit(); qg_soc_exit(chip); + cancel_delayed_work_sync(&chip->qg_sleep_exit_work); cancel_work_sync(&chip->udata_work); cancel_work_sync(&chip->qg_status_change_work); device_destroy(chip->qg_class, chip->dev_no); diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index ebcc2e1b4738591563e28b5a24d8758e14946f4f..a5205a669a02743ef06fc66c60bfe984fee7136f 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -255,6 +255,11 @@ enum { SMB_THERM, }; +static const struct clamp_config clamp_levels[] = { + { {0x11C6, 0x11F9, 0x13F1}, {0x60, 0x2E, 0x90} }, + { {0x11C6, 0x11F9, 0x13F1}, {0x60, 0x2B, 0x9C} }, +}; + #define PMI632_MAX_ICL_UA 3000000 #define PM6150_MAX_FCC_UA 3000000 static int smb5_chg_config_init(struct smb5 *chip) @@ -556,10 +561,17 @@ static int smb5_parse_dt(struct smb5 *chip) chg->hw_skin_temp_mitigation = of_property_read_bool(node, "qcom,hw-skin-temp-mitigation"); + chg->en_skin_therm_mitigation = of_property_read_bool(node, + "qcom,en-skin-therm-mitigation"); + chg->connector_pull_up = -EINVAL; of_property_read_u32(node, "qcom,connector-internal-pull-kohm", &chg->connector_pull_up); + chg->smb_pull_up = -EINVAL; + of_property_read_u32(node, "qcom,smb-internal-pull-kohm", + &chg->smb_pull_up); + chip->dt.adc_based_aicl = of_property_read_bool(node, "qcom,adc-based-aicl"); @@ -612,6 +624,33 @@ static int smb5_parse_dt(struct smb5 *chip) return 0; } +static int smb5_set_prop_comp_clamp_level(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc = 0, i; + struct clamp_config clamp_config; + enum comp_clamp_levels level; + + level = val->intval; + if (level >= MAX_CLAMP_LEVEL) { + pr_err("Invalid comp clamp level=%d\n", val->intval); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(clamp_config.reg); i++) { + rc = smblib_write(chg, clamp_levels[level].reg[i], + clamp_levels[level].val[i]); + if (rc < 0) + dev_err(chg->dev, + "Failed to configure comp clamp settings for reg=0x%04x rc=%d\n", + clamp_levels[level].reg[i], rc); + } + + chg->comp_clamp_level = val->intval; + + return rc; +} + /************************ * USB PSY REGISTRATION * ************************/ @@ -643,12 +682,14 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT, POWER_SUPPLY_PROP_SMB_EN_MODE, POWER_SUPPLY_PROP_SMB_EN_REASON, + POWER_SUPPLY_PROP_ADAPTER_CC_MODE, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_MOISTURE_DETECTED, POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, POWER_SUPPLY_PROP_VOLTAGE_VPH, POWER_SUPPLY_PROP_THERM_ICL_LIMIT, + POWER_SUPPLY_PROP_SKIN_HEALTH, }; static int smb5_usb_get_prop(struct power_supply *psy, @@ -820,6 +861,12 @@ static int smb5_usb_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->usb_icl_votable, THERMAL_THROTTLE_VOTER); break; + case POWER_SUPPLY_PROP_ADAPTER_CC_MODE: + val->intval = chg->adapter_cc_mode; + break; + case POWER_SUPPLY_PROP_SKIN_HEALTH: + val->intval = smblib_get_skin_temp_status(chg); + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -906,6 +953,9 @@ static int smb5_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT: smblib_set_prop_usb_voltage_max_limit(chg, val); break; + case POWER_SUPPLY_PROP_ADAPTER_CC_MODE: + chg->adapter_cc_mode = val->intval; + break; default: pr_err("set prop %d is not supported\n", psp); rc = -EINVAL; @@ -923,6 +973,7 @@ static int smb5_usb_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: case POWER_SUPPLY_PROP_THERM_ICL_LIMIT: case POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT: + case POWER_SUPPLY_PROP_ADAPTER_CC_MODE: return 1; default: break; @@ -1074,6 +1125,10 @@ static enum power_supply_property smb5_usb_main_props[] = { POWER_SUPPLY_PROP_TOGGLE_STAT, POWER_SUPPLY_PROP_MAIN_FCC_MAX, POWER_SUPPLY_PROP_IRQ_STATUS, + POWER_SUPPLY_PROP_FORCE_MAIN_FCC, + POWER_SUPPLY_PROP_FORCE_MAIN_ICL, + POWER_SUPPLY_PROP_COMP_CLAMP_LEVEL, + POWER_SUPPLY_PROP_HEALTH, }; static int smb5_usb_main_get_prop(struct power_supply *psy, @@ -1122,6 +1177,21 @@ static int smb5_usb_main_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_IRQ_STATUS: rc = smblib_get_irq_status(chg, val); break; + case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: + rc = smblib_get_charge_param(chg, &chg->param.fcc, + &val->intval); + break; + case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: + rc = smblib_get_charge_param(chg, &chg->param.usb_icl, + &val->intval); + break; + case POWER_SUPPLY_PROP_COMP_CLAMP_LEVEL: + val->intval = chg->comp_clamp_level; + break; + /* Use this property to report SMB health */ + case POWER_SUPPLY_PROP_HEALTH: + val->intval = smblib_get_prop_smb_health(chg); + break; default: pr_debug("get prop %d is not supported in usb-main\n", psp); rc = -EINVAL; @@ -1192,6 +1262,17 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, chg->main_fcc_max = val->intval; rerun_election(chg->fcc_votable); break; + case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: + vote_override(chg->fcc_main_votable, CC_MODE_VOTER, + (val->intval < 0) ? false : true, val->intval); + break; + case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: + vote_override(chg->usb_icl_votable, CC_MODE_VOTER, + (val->intval < 0) ? false : true, val->intval); + break; + case POWER_SUPPLY_PROP_COMP_CLAMP_LEVEL: + rc = smb5_set_prop_comp_clamp_level(chg, val); + break; default: pr_err("set prop %d is not supported\n", psp); rc = -EINVAL; @@ -1209,6 +1290,9 @@ static int smb5_usb_main_prop_is_writeable(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_TOGGLE_STAT: case POWER_SUPPLY_PROP_MAIN_FCC_MAX: + case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: + case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: + case POWER_SUPPLY_PROP_COMP_CLAMP_LEVEL: rc = 1; break; default: @@ -1399,6 +1483,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_QNOVO, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TECHNOLOGY, @@ -1493,6 +1578,9 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->fcc_votable, BATT_PROFILE_VOTER); break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + val->intval = get_effective_result(chg->fcc_votable); + break; case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: rc = smblib_get_prop_batt_iterm(chg, val); break; @@ -2251,13 +2339,15 @@ static int smb5_configure_iterm_thresholds(struct smb5 *chip) switch (chip->dt.term_current_src) { case ITERM_SRC_ADC: - rc = smblib_masked_write(chg, CHGR_ADC_TERM_CFG_REG, - TERM_BASED_ON_SYNC_CONV_OR_SAMPLE_CNT, - TERM_BASED_ON_SAMPLE_CNT); - if (rc < 0) { - dev_err(chg->dev, "Couldn't configure ADC_ITERM_CFG rc=%d\n", - rc); - return rc; + if (chip->chg.smb_version == PM8150B_SUBTYPE) { + rc = smblib_masked_write(chg, CHGR_ADC_TERM_CFG_REG, + TERM_BASED_ON_SYNC_CONV_OR_SAMPLE_CNT, + TERM_BASED_ON_SAMPLE_CNT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure ADC_ITERM_CFG rc=%d\n", + rc); + return rc; + } } rc = smb5_configure_iterm_thresholds_adc(chip); break; @@ -2756,6 +2846,17 @@ static int smb5_init_hw(struct smb5 *chip) } } + if (chg->smb_pull_up != -EINVAL) { + rc = smb5_configure_internal_pull(chg, SMB_THERM, + get_valid_pullup(chg->smb_pull_up)); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure SMB pull-up rc=%d\n", + rc); + return rc; + } + } + return rc; } diff --git a/drivers/power/supply/qcom/smb1390-charger-psy.c b/drivers/power/supply/qcom/smb1390-charger-psy.c index 1014e49d8f42c9f8d4b1db772b05584b7a21d8ef..5a37125dcd45f60f2fe03796e47c9a893bc378fa 100644 --- a/drivers/power/supply/qcom/smb1390-charger-psy.c +++ b/drivers/power/supply/qcom/smb1390-charger-psy.c @@ -74,6 +74,7 @@ #define CORE_FTRIM_CTRL_REG 0x1031 #define TEMP_ALERT_LVL_MASK GENMASK(6, 5) #define TEMP_ALERT_LVL_SHIFT 5 +#define TEMP_BUFFER_OUTPUT_BIT BIT(7) #define CORE_FTRIM_LVL_REG 0x1033 #define CFG_WIN_HI_MASK GENMASK(3, 2) @@ -81,6 +82,7 @@ #define CORE_FTRIM_MISC_REG 0x1034 #define TR_WIN_1P5X_BIT BIT(0) +#define TR_IREV_BIT BIT(1) #define WINDOW_DETECTION_DELTA_X1P0 0 #define WINDOW_DETECTION_DELTA_X1P5 1 @@ -103,11 +105,18 @@ #define SWITCHER_TOGGLE_VOTER "SWITCHER_TOGGLE_VOTER" #define SOC_LEVEL_VOTER "SOC_LEVEL_VOTER" #define HW_DISABLE_VOTER "HW_DISABLE_VOTER" +#define CC_MODE_VOTER "CC_MODE_VOTER" +#define MAIN_DISABLE_VOTER "MAIN_DISABLE_VOTER" +#define TAPER_MAIN_ICL_LIMIT_VOTER "TAPER_MAIN_ICL_LIMIT_VOTER" #define CP_MASTER 0 #define CP_SLAVE 1 #define THERMAL_SUSPEND_DECIDEGC 1400 #define MAX_ILIM_UA 3200000 +#define MAX_ILIM_DUAL_CP_UA 6400000 +#define CC_MODE_TAPER_DELTA_UA 200000 +#define DEFAULT_TAPER_DELTA_UA 100000 +#define CC_MODE_TAPER_MAIN_ICL_UA 500000 #define smb1390_dbg(chip, reason, fmt, ...) \ do { \ @@ -176,6 +185,8 @@ struct smb1390 { struct votable *fcc_votable; struct votable *fv_votable; struct votable *cp_awake_votable; + struct votable *slave_disable_votable; + struct votable *usb_icl_votable; /* power supplies */ struct power_supply *cps_psy; @@ -202,6 +213,9 @@ struct smb1390 { u32 pl_output_mode; u32 cp_role; enum isns_mode current_capability; + bool batt_soc_validated; + int cp_slave_thr_taper_ua; + int cc_mode_taper_main_icl_ua; }; struct smb_cfg { @@ -321,6 +335,14 @@ static bool is_psy_voter_available(struct smb1390 *chip) } } + if (!chip->usb_icl_votable) { + chip->usb_icl_votable = find_votable("USB_ICL"); + if (!chip->usb_icl_votable) { + smb1390_dbg(chip, PR_EXT_DEPENDENCY, "Couldn't find ICL votable\n"); + return false; + } + } + if (!chip->disable_votable) { smb1390_dbg(chip, PR_MISC, "Couldn't find CP DISABLE votable\n"); return false; @@ -356,6 +378,28 @@ static int smb1390_isns_mode_control(struct smb1390 *chip, enum isns_mode mode) return rc; } +static bool smb1390_is_adapter_cc_mode(struct smb1390 *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) + return false; + } + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_ADAPTER_CC_MODE, + &pval); + if (rc < 0) { + pr_err("Couldn't get PPS CC mode status rc=%d\n", rc); + return false; + } + + return pval.intval; +} + static bool is_cps_available(struct smb1390 *chip) { if (!chip->cps_psy) @@ -697,6 +741,30 @@ static int smb1390_get_isns_slave(struct smb1390 *chip, return rc; } +static int smb1390_get_cp_ilim(struct smb1390 *chip, + union power_supply_propval *val) +{ + int rc = 0, status; + + if (is_cps_available(chip)) { + if (!chip->ilim_votable) { + chip->ilim_votable = find_votable("CP_ILIM"); + if (!chip->ilim_votable) + return -EINVAL; + } + + val->intval = get_effective_result(chip->ilim_votable); + } else { + rc = smb1390_read(chip, CORE_FTRIM_ILIM_REG, &status); + if (!rc) + val->intval = + ((status & CFG_ILIM_MASK) * 100000) + + 500000; + } + + return rc; +} + static int smb1390_is_batt_soc_valid(struct smb1390 *chip) { int rc; @@ -787,15 +855,16 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, { struct smb1390 *chip = data; int rc = 0; - u8 mask, val; if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; - mask = CMD_EN_SWITCHER_BIT | CMD_EN_SL_BIT; - val = is_cps_available(chip) ? mask : CMD_EN_SWITCHER_BIT; - rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, mask, - disable ? 0 : val); + if (is_cps_available(chip)) + vote(chip->slave_disable_votable, MAIN_DISABLE_VOTER, + disable ? true : false, 0); + + rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, + disable ? 0 : CMD_EN_SWITCHER_BIT); if (rc < 0) { pr_err("Couldn't write CORE_CONTROL1_REG, rc=%d\n", rc); return rc; @@ -809,6 +878,21 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, return rc; } +static int smb1390_slave_disable_vote_cb(struct votable *votable, void *data, + int disable, const char *client) +{ + struct smb1390 *chip = data; + int rc; + + rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SL_BIT, + disable ? 0 : CMD_EN_SL_BIT); + if (rc < 0) + pr_err("Couldn't %s slave rc=%d\n", + disable ? "disable" : "enable", rc); + + return rc; +} + static int smb1390_ilim_vote_cb(struct votable *votable, void *data, int ilim_uA, const char *client) { @@ -825,7 +909,8 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, return -EINVAL; } - ilim_uA = min(ilim_uA, MAX_ILIM_UA); + ilim_uA = min(ilim_uA, (is_cps_available(chip) ? + MAX_ILIM_DUAL_CP_UA : MAX_ILIM_UA)); /* ILIM less than min_ilim_ua, disable charging */ if (ilim_uA < chip->min_ilim_ua) { smb1390_dbg(chip, PR_INFO, "ILIM %duA is too low to allow charging\n", @@ -926,8 +1011,9 @@ static void smb1390_status_change_work(struct work_struct *work) if (!is_psy_voter_available(chip)) goto out; - vote(chip->disable_votable, SOC_LEVEL_VOTER, - smb1390_is_batt_soc_valid(chip) ? false : true, 0); + if (!smb1390_is_adapter_cc_mode(chip)) + vote(chip->disable_votable, SOC_LEVEL_VOTER, + smb1390_is_batt_soc_valid(chip) ? false : true, 0); rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_SMB_EN_MODE, &pval); @@ -944,7 +1030,14 @@ static void smb1390_status_change_work(struct work_struct *work) goto out; } + /* Check for SOC threshold only once before enabling CP */ vote(chip->disable_votable, SRC_VOTER, false, 0); + if (!chip->batt_soc_validated) { + vote(chip->disable_votable, SOC_LEVEL_VOTER, + smb1390_is_batt_soc_valid(chip) ? + false : true, 0); + chip->batt_soc_validated = true; + } if (pval.intval == POWER_SUPPLY_CP_WIRELESS) { vote(chip->ilim_votable, ICL_VOTER, false, 0); @@ -1014,10 +1107,16 @@ static void smb1390_status_change_work(struct work_struct *work) } } } else { + chip->batt_soc_validated = false; vote(chip->disable_votable, SRC_VOTER, true, 0); vote(chip->disable_votable, TAPER_END_VOTER, false, 0); vote(chip->fcc_votable, CP_VOTER, false, 0); vote(chip->disable_votable, SOC_LEVEL_VOTER, true, 0); + vote_override(chip->ilim_votable, CC_MODE_VOTER, false, 0); + vote(chip->slave_disable_votable, TAPER_END_VOTER, false, 0); + vote(chip->slave_disable_votable, MAIN_DISABLE_VOTER, true, 0); + vote_override(chip->usb_icl_votable, TAPER_MAIN_ICL_LIMIT_VOTER, + false, 0); } out: @@ -1025,11 +1124,39 @@ static void smb1390_status_change_work(struct work_struct *work) chip->status_change_running = false; } +static int smb1390_validate_slave_chg_taper(struct smb1390 *chip, int fcc_uA) +{ + int rc = 0; + + /* + * In Collapse mode, while in Taper, Disable the slave SMB1390 + * when FCC drops below a specified threshold. + */ + if (fcc_uA < (chip->cp_slave_thr_taper_ua) && is_cps_available(chip)) { + vote(chip->slave_disable_votable, TAPER_END_VOTER, + true, 0); + /* + * Set ILIM of master SMB1390 to Max value = 3.2A once slave is + * disabled to prevent ILIM irq storm. + */ + smb1390_dbg(chip, PR_INFO, "Set Master ILIM to MAX, post Slave disable in taper, fcc=%d\n", + fcc_uA); + vote_override(chip->ilim_votable, CC_MODE_VOTER, + true, MAX_ILIM_DUAL_CP_UA); + if (chip->usb_icl_votable) + vote_override(chip->usb_icl_votable, + TAPER_MAIN_ICL_LIMIT_VOTER, + true, chip->cc_mode_taper_main_icl_ua); + } + + return rc; +} + static void smb1390_taper_work(struct work_struct *work) { struct smb1390 *chip = container_of(work, struct smb1390, taper_work); union power_supply_propval pval = {0, }; - int rc, fcc_uA; + int rc, fcc_uA, delta_fcc_uA; if (!is_psy_voter_available(chip)) goto out; @@ -1053,15 +1180,34 @@ static void smb1390_taper_work(struct work_struct *work) } if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) { + delta_fcc_uA = + (smb1390_is_adapter_cc_mode(chip) ? + CC_MODE_TAPER_DELTA_UA : + DEFAULT_TAPER_DELTA_UA); fcc_uA = get_effective_result(chip->fcc_votable) - - 100000; + - delta_fcc_uA; smb1390_dbg(chip, PR_INFO, "taper work reducing FCC to %duA\n", fcc_uA); vote(chip->fcc_votable, CP_VOTER, true, fcc_uA); + rc = smb1390_validate_slave_chg_taper(chip, fcc_uA); + if (rc < 0) { + pr_err("Couldn't Disable slave in Taper, rc=%d\n", + rc); + goto out; + } if (fcc_uA < (chip->min_ilim_ua * 2)) { vote(chip->disable_votable, TAPER_END_VOTER, true, 0); + /* + * When master CP is disabled, reset all votes + * on ICL to enable Main charger to pump + * charging current. + */ + if (chip->usb_icl_votable) + vote_override(chip->usb_icl_votable, + TAPER_MAIN_ICL_LIMIT_VOTER, + false, 0); goto out; } } else { @@ -1090,6 +1236,7 @@ static enum power_supply_property smb1390_charge_pump_props[] = { POWER_SUPPLY_PROP_CHIP_VERSION, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, POWER_SUPPLY_PROP_MIN_ICL, + POWER_SUPPLY_PROP_MODEL_NAME, }; static int smb1390_get_prop(struct power_supply *psy, @@ -1174,10 +1321,7 @@ static int smb1390_get_prop(struct power_supply *psy, val->intval |= status; break; case POWER_SUPPLY_PROP_CP_ILIM: - rc = smb1390_read(chip, CORE_FTRIM_ILIM_REG, &status); - if (!rc) - val->intval = ((status & CFG_ILIM_MASK) * 100000) - + 500000; + rc = smb1390_get_cp_ilim(chip, val); break; case POWER_SUPPLY_PROP_CHIP_VERSION: val->intval = chip->pmic_rev_id->rev4; @@ -1188,6 +1332,10 @@ static int smb1390_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_MIN_ICL: val->intval = chip->min_ilim_ua; break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = (chip->pmic_rev_id->rev4 > 2) ? "SMB1390_V3" : + "SMB1390_V2"; + break; default: smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n", prop); @@ -1215,6 +1363,11 @@ static int smb1390_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CP_IRQ_STATUS: chip->irq_status = val->intval; break; + case POWER_SUPPLY_PROP_CP_ILIM: + if (chip->ilim_votable) + vote_override(chip->ilim_votable, CC_MODE_VOTER, + true, val->intval); + break; default: smb1390_dbg(chip, PR_MISC, "charge pump power supply set prop %d not supported\n", prop); @@ -1233,6 +1386,7 @@ static int smb1390_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CP_IRQ_STATUS: case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: + case POWER_SUPPLY_PROP_CP_ILIM: return 1; default: break; @@ -1307,6 +1461,16 @@ static int smb1390_parse_dt(struct smb1390 *chip) chip->pl_output_mode = POWER_SUPPLY_PL_OUTPUT_VPH; of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode", &chip->pl_output_mode); + + chip->cp_slave_thr_taper_ua = chip->min_ilim_ua * 3; + of_property_read_u32(chip->dev->of_node, "qcom,cp-slave-thr-taper-ua", + &chip->cp_slave_thr_taper_ua); + + chip->cc_mode_taper_main_icl_ua = CC_MODE_TAPER_MAIN_ICL_UA; + of_property_read_u32(chip->dev->of_node, + "qcom,cc-mode-taper-main-icl-ua", + &chip->cc_mode_taper_main_icl_ua); + return 0; } @@ -1330,6 +1494,11 @@ static int smb1390_create_votables(struct smb1390 *chip) if (IS_ERR(chip->ilim_votable)) return PTR_ERR(chip->ilim_votable); + chip->slave_disable_votable = create_votable("CP_SLAVE_DISABLE", + VOTE_SET_ANY, smb1390_slave_disable_vote_cb, chip); + if (IS_ERR(chip->slave_disable_votable)) + return PTR_ERR(chip->slave_disable_votable); + /* * charge pump is initially disabled; this indirectly votes to allow * traditional parallel charging if present @@ -1399,6 +1568,12 @@ static int smb1390_init_hw(struct smb1390 *chip) return rc; } + /* Configure IREV threshold to 200mA */ + rc = smb1390_masked_write(chip, CORE_FTRIM_MISC_REG, TR_IREV_BIT, 0); + if (rc < 0) { + pr_err("Couldn't configure IREV threshold rc=%d\n", rc); + return rc; + } /* * If the slave charger has registered, configure Master SMB1390 for * triple-chg config, else configure for dual. Later, if the slave @@ -1622,6 +1797,12 @@ static enum power_supply_property smb1390_cp_slave_props[] = { POWER_SUPPLY_PROP_CURRENT_CAPABILITY, }; +static int smb1390_slave_prop_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + return 0; +} + static int smb1390_cp_slave_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -1680,7 +1861,7 @@ static const struct power_supply_desc cps_psy_desc = { .num_properties = ARRAY_SIZE(smb1390_cp_slave_props), .get_property = smb1390_cp_slave_get_prop, .set_property = smb1390_cp_slave_set_prop, - .property_is_writeable = smb1390_prop_is_writeable, + .property_is_writeable = smb1390_slave_prop_is_writeable, }; static int smb1390_init_cps_psy(struct smb1390 *chip) @@ -1715,6 +1896,15 @@ static int smb1390_slave_probe(struct smb1390 *chip) if (rc < 0) return rc; + /* Configure Slave CP Temp buffer O/P to High Impedance */ + rc = smb1390_masked_write(chip, CORE_FTRIM_CTRL_REG, + TEMP_BUFFER_OUTPUT_BIT, + TEMP_BUFFER_OUTPUT_BIT); + if (rc < 0) { + pr_err("Couldn't configure Slave temp Buffer rc=%d\n", rc); + return rc; + } + rc = smb1390_init_cps_psy(chip); if (rc < 0) pr_err("Couldn't initialize cps psy rc=%d\n", rc); @@ -1822,8 +2012,17 @@ static int smb1390_resume(struct device *dev) struct smb1390 *chip = dev_get_drvdata(dev); chip->suspended = false; - rerun_election(chip->ilim_votable); - rerun_election(chip->disable_votable); + + /* ILIM rerun is applicable for both master and slave */ + if (!chip->ilim_votable) + chip->ilim_votable = find_votable("CP_ILIM"); + + if (chip->ilim_votable) + rerun_election(chip->ilim_votable); + + /* Run disable votable for master only */ + if (chip->cp_role == CP_MASTER) + rerun_election(chip->disable_votable); return 0; } diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 2f995b62861b5e93c1de53e3ea46e8db79d515a2..aac6b220f21dc0e6c4253e48e37569dd6562d477 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -3675,6 +3675,54 @@ int smblib_get_pe_start(struct smb_charger *chg, return 0; } +int smblib_get_prop_smb_health(struct smb_charger *chg) +{ + int rc; + u8 stat; + int input_present; + + rc = smblib_is_input_present(chg, &input_present); + if (rc < 0) + return rc; + + if (input_present == INPUT_NOT_PRESENT) + return POWER_SUPPLY_HEALTH_UNKNOWN; + + if (chg->wa_flags & SW_THERM_REGULATION_WA) { + if (chg->smb_temp == -ENODATA) + return POWER_SUPPLY_HEALTH_UNKNOWN; + + if (chg->smb_temp > SMB_TEMP_RST_THRESH) + return POWER_SUPPLY_HEALTH_OVERHEAT; + + if (chg->smb_temp > SMB_TEMP_REG_H_THRESH) + return POWER_SUPPLY_HEALTH_HOT; + + if (chg->smb_temp > SMB_TEMP_REG_L_THRESH) + return POWER_SUPPLY_HEALTH_WARM; + + return POWER_SUPPLY_HEALTH_COOL; + } + + rc = smblib_read(chg, SMB_TEMP_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read SMB_TEMP_STATUS_REG, rc=%d\n", + rc); + return POWER_SUPPLY_HEALTH_UNKNOWN; + } + + if (stat & SMB_TEMP_RST_BIT) + return POWER_SUPPLY_HEALTH_OVERHEAT; + + if (stat & SMB_TEMP_UB_BIT) + return POWER_SUPPLY_HEALTH_HOT; + + if (stat & SMB_TEMP_LB_BIT) + return POWER_SUPPLY_HEALTH_WARM; + + return POWER_SUPPLY_HEALTH_COOL; +} + int smblib_get_prop_die_health(struct smb_charger *chg) { int rc; @@ -3763,11 +3811,14 @@ static int smblib_get_typec_connector_temp_status(struct smb_charger *chg) return POWER_SUPPLY_HEALTH_COOL; } -static int smblib_get_skin_temp_status(struct smb_charger *chg) +int smblib_get_skin_temp_status(struct smb_charger *chg) { int rc; u8 stat; + if (!chg->en_skin_therm_mitigation) + return POWER_SUPPLY_HEALTH_UNKNOWN; + rc = smblib_read(chg, SKIN_TEMP_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read SKIN_TEMP_STATUS_REG, rc=%d\n", @@ -5483,6 +5534,12 @@ static void typec_src_removal(struct smb_charger *chg) chg->voltage_max_uv = MICRO_5V; chg->usbin_forced_max_uv = 0; + /* Reset CC mode votes */ + vote(chg->fcc_main_votable, MAIN_FCC_VOTER, false, 0); + chg->adapter_cc_mode = 0; + vote_override(chg->fcc_votable, CC_MODE_VOTER, false, 0); + vote_override(chg->usb_icl_votable, CC_MODE_VOTER, false, 0); + /* write back the default FLOAT charger configuration */ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, (u8)FLOAT_OPTIONS_MASK, chg->float_cfg); @@ -6786,6 +6843,13 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + chg->fcc_main_votable = find_votable("FCC_MAIN"); + if (chg->fcc_main_votable == NULL) { + rc = -EINVAL; + smblib_err(chg, "Couldn't find FCC Main votable rc=%d\n", rc); + return rc; + } + chg->fv_votable = find_votable("FV"); if (chg->fv_votable == NULL) { rc = -EINVAL; diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index aa347f22b6be0b8860ca166063ceedc5414e5a3f..42ac6496592480f63d17107d624ad8b3f56e5285 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -80,6 +80,8 @@ enum print_reason { #define CHARGER_TYPE_VOTER "CHARGER_TYPE_VOTER" #define HDC_IRQ_VOTER "HDC_IRQ_VOTER" #define DETACH_DETECT_VOTER "DETACH_DETECT_VOTER" +#define CC_MODE_VOTER "CC_MODE_VOTER" +#define MAIN_FCC_VOTER "MAIN_FCC_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 @@ -229,6 +231,17 @@ enum chg_term_config_src { ITERM_SRC_ANALOG }; +enum comp_clamp_levels { + CLAMP_LEVEL_DEFAULT = 0, + CLAMP_LEVEL_1, + MAX_CLAMP_LEVEL, +}; + +struct clamp_config { + u16 reg[3]; + u16 val[3]; +}; + struct smb_irq_info { const char *name; const irq_handler_t handler; @@ -398,6 +411,9 @@ struct smb_charger { /* parallel charging */ struct parallel_params pl; + /* CC Mode */ + int adapter_cc_mode; + /* regulators */ struct smb_regulator *vbus_vreg; struct smb_regulator *vconn_vreg; @@ -406,6 +422,7 @@ struct smb_charger { /* votables */ struct votable *dc_suspend_votable; struct votable *fcc_votable; + struct votable *fcc_main_votable; struct votable *fv_votable; struct votable *usb_icl_votable; struct votable *awake_votable; @@ -514,7 +531,9 @@ struct smb_charger { bool hw_die_temp_mitigation; bool hw_connector_mitigation; bool hw_skin_temp_mitigation; + bool en_skin_therm_mitigation; int connector_pull_up; + int smb_pull_up; int aicl_5v_threshold_mv; int default_aicl_5v_threshold_mv; int aicl_cont_threshold_mv; @@ -526,6 +545,7 @@ struct smb_charger { int dr_mode; int usbin_forced_max_uv; int init_thermal_ua; + u32 comp_clamp_level; /* workaround flag */ u32 wa_flags; @@ -700,7 +720,9 @@ int smblib_get_pe_start(struct smb_charger *chg, int smblib_get_prop_charger_temp(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_die_health(struct smb_charger *chg); +int smblib_get_prop_smb_health(struct smb_charger *chg); int smblib_get_prop_connector_health(struct smb_charger *chg); +int smblib_get_skin_temp_status(struct smb_charger *chg); int smblib_get_prop_vph_voltage_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pd_current_max(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 0166a8824b77a0fc5c25be4eaa505e3f4bf89b9b..18e197ef46980771eebb04c7b6d7d5b81a675876 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -493,6 +493,12 @@ enum { #define CONNECTOR_TEMP_UB_BIT BIT(1) #define CONNECTOR_TEMP_LB_BIT BIT(0) +#define SMB_TEMP_STATUS_REG (MISC_BASE + 0x0A) +#define SMB_TEMP_SHDN_BIT BIT(3) +#define SMB_TEMP_RST_BIT BIT(2) +#define SMB_TEMP_UB_BIT BIT(1) +#define SMB_TEMP_LB_BIT BIT(0) + #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c index a37af0a407fe1183b441fdfbe7fb2e3318c8d120..ab8eeb897745d27a6176f2463e53a038ea75994a 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.c +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -158,7 +158,7 @@ static bool is_input_present(struct step_chg_info *chip) int read_range_data_from_node(struct device_node *node, const char *prop_str, struct range_data *ranges, - u32 max_threshold, u32 max_value) + int max_threshold, u32 max_value) { int rc = 0, i, length, per_tuple_length, tuples; diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h index 229f2980ab375b484de80ae96e07ec46236ad669..26e74ed484e9868f7b73008bf41d10f2e371b3b5 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.h +++ b/drivers/power/supply/qcom/step-chg-jeita.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,8 +23,8 @@ struct step_chg_jeita_param { }; struct range_data { - u32 low_threshold; - u32 high_threshold; + int low_threshold; + int high_threshold; u32 value; }; @@ -33,5 +33,5 @@ int qcom_step_chg_init(struct device *dev, void qcom_step_chg_deinit(void); int read_range_data_from_node(struct device_node *node, const char *prop_str, struct range_data *ranges, - u32 max_threshold, u32 max_value); + int max_threshold, u32 max_value); #endif /* __STEP_CHG_H__ */ diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dd881a9394c61c0f33340b16f23291fb4796dc34..c98b1f1fc0f2e09eb1e038a7634c52b1e4740b6d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1084,5 +1084,11 @@ config REGULATOR_STUB Clients can use the real regulator device names with proper constraint checking while the real driver is being developed. +config VIRTIO_REGULATOR + tristate "Virtio regulator driver" + depends on VIRTIO + ---help--- + This is the virtual regulator driver for virtio. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 63fe6cdf32f90bfc3761300efa8cd050ef774609..c06ffb3047812ce2b29961f9afa00f7cb2bed076 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -135,5 +135,6 @@ obj-$(CONFIG_REGULATOR_RPM_SMD) += rpm-smd-regulator.o obj-$(CONFIG_REGULATOR_SPM) += spm-regulator.o obj-$(CONFIG_REGULATOR_RPMH) += rpmh-regulator.o obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o +obj-$(CONFIG_VIRTIO_REGULATOR) += virtio_regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/virtio_regulator.c b/drivers/regulator/virtio_regulator.c new file mode 100644 index 0000000000000000000000000000000000000000..99c587026668db4ab1a4fd616a38459470827328 --- /dev/null +++ b/drivers/regulator/virtio_regulator.c @@ -0,0 +1,659 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIRTIO_REGULATOR_TIMEOUT 200 /* miliseconds */ +#define VIRTIO_REGULATOR_MAX_NAME 20 +#define VIRTIO_REGULATOR_VOLTAGE_UNKNOWN 1 + +struct reg_virtio; + +struct virtio_regulator { + struct virtio_device *vdev; + struct virtqueue *vq; + struct completion rsp_avail; + struct mutex lock; + struct reg_virtio *regs; + int regs_count; +}; + +struct reg_virtio { + struct device_node *of_node; + struct regulator_desc rdesc; + struct regulator_dev *rdev; + struct virtio_regulator *vreg; + char name[VIRTIO_REGULATOR_MAX_NAME]; + bool enabled; +}; + +static int virtio_regulator_enable(struct regulator_dev *rdev) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_ENABLE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vreg->vdev, rsp->result); + + if (!ret) + reg->enabled = true; +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static int virtio_regulator_disable(struct regulator_dev *rdev) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_DISABLE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vreg->vdev, rsp->result); + + if (!ret) + reg->enabled = false; +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static int virtio_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + + pr_debug("%s return %d\n", reg->rdesc.name, reg->enabled); + + return reg->enabled; +} + +static int virtio_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned int *selector) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_SET_VOLTAGE); + req->data[0] = cpu_to_virtio32(vreg->vdev, DIV_ROUND_UP(min_uV, 1000)); + req->data[1] = cpu_to_virtio32(vreg->vdev, max_uV / 1000); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vreg->vdev, rsp->result); + +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static int virtio_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_GET_VOLTAGE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + if (rsp->result) { + pr_debug("%s: error response (%d)\n", reg->rdesc.name, + virtio32_to_cpu(vreg->vdev, rsp->result)); + ret = VIRTIO_REGULATOR_VOLTAGE_UNKNOWN; + } else + ret = virtio32_to_cpu(vreg->vdev, rsp->data[0]) * 1000; + +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static int virtio_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_SET_MODE); + req->data[0] = cpu_to_virtio32(vreg->vdev, mode); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vreg->vdev, rsp->result); + +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static unsigned int virtio_regulator_get_mode(struct regulator_dev *rdev) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_GET_MODE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + if (rsp->result) { + pr_err("%s: error response (%d)\n", reg->rdesc.name, + virtio32_to_cpu(vreg->vdev, rsp->result)); + ret = 0; + } else + ret = virtio32_to_cpu(vreg->vdev, rsp->data[0]); + +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static int virtio_regulator_set_load(struct regulator_dev *rdev, int load_ua) +{ + struct reg_virtio *reg = rdev_get_drvdata(rdev); + struct virtio_regulator *vreg = reg->vreg; + struct virtio_regulator_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_regulator_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, reg->rdesc.name, sizeof(req->name)); + req->type = cpu_to_virtio32(vreg->vdev, VIRTIO_REGULATOR_T_SET_LOAD); + req->data[0] = cpu_to_virtio32(vreg->vdev, load_ua); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vreg->lock); + + ret = virtqueue_add_outbuf(vreg->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer\n", reg->rdesc.name); + goto out; + } + + virtqueue_kick(vreg->vq); + + ret = wait_for_completion_timeout(&vreg->rsp_avail, + msecs_to_jiffies(VIRTIO_REGULATOR_TIMEOUT)); + if (!ret) { + ret = -ETIMEDOUT; + goto out; + } + + rsp = virtqueue_get_buf(vreg->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", reg->rdesc.name); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vreg->vdev, rsp->result); + +out: + mutex_unlock(&vreg->lock); + kfree(req); + + pr_debug("%s return %d\n", reg->rdesc.name, ret); + + return ret; +} + +static struct regulator_ops virtio_regulator_ops = { + .enable = virtio_regulator_enable, + .disable = virtio_regulator_disable, + .is_enabled = virtio_regulator_is_enabled, + .set_voltage = virtio_regulator_set_voltage, + .get_voltage = virtio_regulator_get_voltage, + .set_mode = virtio_regulator_set_mode, + .get_mode = virtio_regulator_get_mode, + .set_load = virtio_regulator_set_load, +}; + +static void virtio_regulator_isr(struct virtqueue *vq) +{ + struct virtio_regulator *vregulator = vq->vdev->priv; + + complete(&vregulator->rsp_avail); +} + +static int virtio_regulator_init_vqs(struct virtio_regulator *vreg) +{ + struct virtqueue *vqs[1]; + vq_callback_t *cbs[] = { virtio_regulator_isr }; + static const char * const names[] = { "regulator" }; + int ret; + + ret = virtio_find_vqs(vreg->vdev, 1, vqs, cbs, names, NULL); + if (ret) + return ret; + + vreg->vq = vqs[0]; + + return 0; +} + +static int virtio_regulator_allocate_reg(struct virtio_regulator *vreg) +{ + struct device_node *parent_node, *node; + int i, ret; + + vreg->regs_count = 0; + parent_node = vreg->vdev->dev.parent->of_node; + + for_each_available_child_of_node(parent_node, node) { + /* Skip child nodes handled by other drivers. */ + if (of_find_property(node, "compatible", NULL)) + continue; + vreg->regs_count++; + } + + if (vreg->regs_count == 0) { + dev_err(&vreg->vdev->dev, + "could not find any regulator subnodes\n"); + return -ENODEV; + } + + vreg->regs = devm_kcalloc(&vreg->vdev->dev, vreg->regs_count, + sizeof(*vreg->regs), GFP_KERNEL); + if (!vreg->regs) + return -ENOMEM; + + i = 0; + for_each_available_child_of_node(parent_node, node) { + /* Skip child nodes handled by other drivers. */ + if (of_find_property(node, "compatible", NULL)) + continue; + + vreg->regs[i].of_node = node; + vreg->regs[i].vreg = vreg; + + ret = of_property_read_string(node, "regulator-name", + &vreg->regs[i].rdesc.name); + if (ret) { + dev_err(&vreg->vdev->dev, + "could not read regulator-name\n"); + return ret; + } + + i++; + } + + return 0; +} + +static int virtio_regulator_init_reg(struct reg_virtio *reg) +{ + struct device *dev = reg->vreg->vdev->dev.parent; + struct regulator_config reg_config = {}; + struct regulator_init_data *init_data; + int ret = 0; + + reg->rdesc.owner = THIS_MODULE; + reg->rdesc.type = REGULATOR_VOLTAGE; + reg->rdesc.ops = &virtio_regulator_ops; + + init_data = of_get_regulator_init_data(dev, reg->of_node, ®->rdesc); + if (init_data == NULL) + return -ENOMEM; + + init_data->constraints.input_uV = init_data->constraints.max_uV; + init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; + + reg_config.dev = dev; + reg_config.init_data = init_data; + reg_config.of_node = reg->of_node; + reg_config.driver_data = reg; + + reg->rdev = devm_regulator_register(dev, ®->rdesc, ®_config); + if (IS_ERR(reg->rdev)) { + ret = PTR_ERR(reg->rdev); + reg->rdev = NULL; + dev_err(®->vreg->vdev->dev, "fail to register regulator\n"); + return ret; + } + + return ret; +} + +static int virtio_regulator_probe(struct virtio_device *vdev) +{ + struct virtio_regulator *vreg; + unsigned int i; + int ret; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + vreg = devm_kzalloc(&vdev->dev, sizeof(struct virtio_regulator), + GFP_KERNEL); + if (!vreg) + return -ENOMEM; + + vdev->priv = vreg; + vreg->vdev = vdev; + mutex_init(&vreg->lock); + init_completion(&vreg->rsp_avail); + + ret = virtio_regulator_init_vqs(vreg); + if (ret) { + dev_err(&vdev->dev, "fail to initialize virtqueue\n"); + return ret; + } + + virtio_device_ready(vdev); + + ret = virtio_regulator_allocate_reg(vreg); + if (ret) { + dev_err(&vdev->dev, "fail to allocate regulators\n"); + goto err_allocate_reg; + } + + for (i = 0; i < vreg->regs_count; i++) { + ret = virtio_regulator_init_reg(&vreg->regs[i]); + if (ret) { + dev_err(&vdev->dev, "fail to initialize regulator %s\n", + vreg->regs[i].rdesc.name); + goto err_init_reg; + } + } + + dev_dbg(&vdev->dev, "virtio regulator probe successfully\n"); + + return 0; + +err_init_reg: +err_allocate_reg: + vdev->config->del_vqs(vdev); + return ret; +} + +static void virtio_regulator_remove(struct virtio_device *vdev) +{ + struct virtio_regulator *vreg = vdev->priv; + void *buf; + + vdev->config->reset(vdev); + while ((buf = virtqueue_detach_unused_buf(vreg->vq)) != NULL) + kfree(buf); + vdev->config->del_vqs(vdev); +} + +static const struct virtio_device_id id_table[] = { + { VIRTIO_ID_REGULATOR, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { +}; + +static struct virtio_driver virtio_regulator_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_regulator_probe, + .remove = virtio_regulator_remove, +}; + +static int __init virtio_regulator_init(void) +{ + return register_virtio_driver(&virtio_regulator_driver); +} + +static void __exit virtio_regulator_exit(void) +{ + unregister_virtio_driver(&virtio_regulator_driver); +} +subsys_initcall(virtio_regulator_init); +module_exit(virtio_regulator_exit); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f121bd9fbc132d354c6b51b441a8ea56c8083961..ee66de996d33d7cea53d480143bed7ad6bcd85e1 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1960,6 +1960,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (IS_ERR(glink->task)) { dev_err(dev, "failed to spawn intent kthread %ld\n", PTR_ERR(glink->task)); + mbox_free_channel(glink->mbox_chan); return ERR_CAST(glink->task); } @@ -2010,6 +2011,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, unregister: subsys_unregister_early_notifier(glink->name, XPORT_LAYER_NOTIF); + kthread_stop(glink->task); + mbox_free_channel(glink->mbox_chan); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 8b279dc2a713e2c7f1eea7ca7a94400c660fafe4..600c3619051cf16c3e675b983bdb5b48c50470c2 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -231,6 +231,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, ret = device_register(dev); if (ret) { pr_err("failed to register glink edge\n"); + kfree(dev); return ERR_PTR(ret); } @@ -238,21 +239,21 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, &remote_pid); if (ret) { dev_err(dev, "failed to parse qcom,remote-pid\n"); - goto err_put_dev; + goto unregister; } rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL); tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL); if (!rx_pipe || !tx_pipe) { ret = -ENOMEM; - goto err_put_dev; + goto unregister; } ret = qcom_smem_alloc(remote_pid, SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32); if (ret && ret != -EEXIST) { dev_err(dev, "failed to allocate glink descriptors\n"); - goto err_put_dev; + goto unregister; } descs = qcom_smem_get(remote_pid, @@ -260,13 +261,13 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, if (IS_ERR(descs)) { dev_err(dev, "failed to acquire xprt descriptor\n"); ret = PTR_ERR(descs); - goto err_put_dev; + goto unregister; } if (size != 32) { dev_err(dev, "glink descriptor of invalid size\n"); ret = -EINVAL; - goto err_put_dev; + goto unregister; } tx_pipe->tail = &descs[0]; @@ -278,7 +279,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, SZ_16K); if (ret && ret != -EEXIST) { dev_err(dev, "failed to allocate TX fifo\n"); - goto err_put_dev; + goto unregister; } tx_pipe->fifo = qcom_smem_get(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0, @@ -286,7 +287,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, if (IS_ERR(tx_pipe->fifo)) { dev_err(dev, "failed to acquire TX fifo\n"); ret = PTR_ERR(tx_pipe->fifo); - goto err_put_dev; + goto unregister; } rx_pipe->native.avail = glink_smem_rx_avail; @@ -307,13 +308,13 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, false); if (IS_ERR(glink)) { ret = PTR_ERR(glink); - goto err_put_dev; + goto unregister; } return glink; -err_put_dev: - put_device(dev); +unregister: + device_unregister(dev); return ERR_PTR(ret); } diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index f85cae240f123eafde246ba1c084c8b6943d171e..7e92e491c2e7f025f38759405fbc19b71780eb5c 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -480,6 +480,13 @@ static int da9063_rtc_probe(struct platform_device *pdev) da9063_data_to_tm(data, &rtc->alarm_time, rtc); rtc->rtc_sync = false; + /* + * TODO: some models have alarms on a minute boundary but still support + * real hardware interrupts. Add this once the core supports it. + */ + if (config->rtc_data_start != RTC_SEC) + rtc->rtc_dev->uie_unsupported = 1; + irq_alarm = platform_get_irq_byname(pdev, "ALARM"); ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, da9063_alarm_event, diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 6c2d3989f967baff96625ab39d0d19336b002def..9b6a927149a4e3d29df1f18217f9c7f084c3f2db 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -462,7 +462,7 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off) { unsigned int byte; - int value = 0xff; /* return 0xff for ignored values */ + int value = -1; /* return -1 for ignored values */ byte = readb(rtc->regbase + reg_off); if (byte & AR_ENB) { diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a19f2dc69e8aa1d4d543b733eac8b93a7cbf2c21..d9830c86d0c119c89cd766a454522e9ac0beb97b 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3022,12 +3022,14 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc; + hash_init(card->ip_htable); + if (gdev->dev.type == &qeth_generic_devtype) { rc = qeth_l3_create_device_attributes(&gdev->dev); if (rc) return rc; } - hash_init(card->ip_htable); + hash_init(card->ip_mc_htable); card->options.layer2 = 0; card->info.hwtrap = 0; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index ca218c82321f882228b11be13aed307aee208b60..0c5fd722a72dc503ba4a601c14561961eec78d0d 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -240,10 +240,6 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, list_for_each_entry(port, &adapter->port_list, list) { if ((port->d_id & range) == (ntoh24(page->rscn_fid) & range)) zfcp_fc_test_link(port); - if (!port->d_id) - zfcp_erp_port_reopen(port, - ZFCP_STATUS_COMMON_ERP_FAILED, - "fcrscn1"); } read_unlock_irqrestore(&adapter->port_list_lock, flags); } @@ -251,6 +247,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) { struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; + struct zfcp_adapter *adapter = fsf_req->adapter; struct fc_els_rscn *head; struct fc_els_rscn_page *page; u16 i; @@ -264,6 +261,22 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) no_entries = be16_to_cpu(head->rscn_plen) / sizeof(struct fc_els_rscn_page); + if (no_entries > 1) { + /* handle failed ports */ + unsigned long flags; + struct zfcp_port *port; + + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { + if (port->d_id) + continue; + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, + "fcrscn1"); + } + read_unlock_irqrestore(&adapter->port_list_lock, flags); + } + for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */ page++; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 89b1f1af2fd456c38e45e0a905af9a76385c1d89..31d31aad3de1d3fd0f2ff58d2141cabddec474bf 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -2164,7 +2164,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", fc_rport_state(rdata)); - rdata->flags &= ~FC_RP_STARTED; fc_rport_enter_delete(rdata, RPORT_EV_STOP); mutex_unlock(&rdata->rp_mutex); kref_put(&rdata->kref, fc_rport_destroy); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 22dc70a2138e2f7aa95cde2a34bcf3a75c54b7e6..630b7404843d0e2aec2128efea8d792b1624c24e 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -3207,6 +3207,8 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) return -EINVAL; ep = iscsi_lookup_endpoint(transport_fd); + if (!ep) + return -EINVAL; conn = cls_conn->dd_data; qla_conn = conn->dd_data; qla_conn->qla_ep = ep->dd_data; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 6b594bc7d94a0f8e7fdcb26c60c76a7cd0f8d4dc..022fcd2e47026de9430a0fb5d3d139d35851a21f 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -248,6 +248,7 @@ static struct { {"NETAPP", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"LSI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"ENGENIO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, + {"LENOVO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 375cede0c534bb364940a2f0aba077f923c247a4..c9bc6f05842457dd162125e20970cbb6c3e51408 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -75,6 +75,7 @@ static const struct scsi_dh_blist scsi_dh_blist[] = { {"NETAPP", "INF-01-00", "rdac", }, {"LSI", "INF-01-00", "rdac", }, {"ENGENIO", "INF-01-00", "rdac", }, + {"LENOVO", "DE_Series", "rdac", }, {NULL, NULL, NULL }, }; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 2fdd670011c4360dae59f99c5923501e3ccefbb3..e032a089ab857c8192f7392f8341481f442b1817 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2054,8 +2054,12 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, blk_mq_delay_run_hw_queue(hctx, SCSI_QUEUE_DELAY); break; default: + if (unlikely(!scsi_device_online(sdev))) + scsi_req(req)->result = DID_NO_CONNECT << 16; + else + scsi_req(req)->result = DID_ERROR << 16; /* - * Make sure to release all allocated ressources when + * Make sure to release all allocated resources when * we hit an error, as we will never see this command * again. */ diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index f6542c159ed637504ff3e5d2c157ebfed2dac196..b4d06bd9ed510ad5e6e416090bef691f09b12df9 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2185,6 +2185,8 @@ void iscsi_remove_session(struct iscsi_cls_session *session) scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE); /* flush running scans then delete devices */ flush_work(&session->scan_work); + /* flush running unbind operations */ + flush_work(&session->unbind_work); __iscsi_unbind_session(&session->unbind_work); /* hw iscsi may not have removed all connections from session */ diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index beb585ddc07dcd4594d5e290e32e1fe47980bace..5adeb1e4b1869105bff5585f81f195d1be698b44 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -658,13 +658,22 @@ static void handle_sc_creation(struct vmbus_channel *new_sc) static void handle_multichannel_storage(struct hv_device *device, int max_chns) { struct storvsc_device *stor_device; - int num_cpus = num_online_cpus(); int num_sc; struct storvsc_cmd_request *request; struct vstor_packet *vstor_packet; int ret, t; - num_sc = ((max_chns > num_cpus) ? num_cpus : max_chns); + /* + * If the number of CPUs is artificially restricted, such as + * with maxcpus=1 on the kernel boot line, Hyper-V could offer + * sub-channels >= the number of CPUs. These sub-channels + * should not be created. The primary channel is already created + * and assigned to one CPU, so check against # CPUs - 1. + */ + num_sc = min((int)(num_online_cpus() - 1), max_chns); + if (!num_sc) + return; + stor_device = get_out_stor_device(device); if (!stor_device) return; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 2f68809abacc9bb850b696631ecc3f7079c4d262..3587dbbd3a0a072171111af985a924201d3d8401 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -969,7 +969,9 @@ int ufs_qcom_crytpo_engine_cfg_start(struct ufs_hba *hba, unsigned int task_tag) int err = 0; if (!host->ice.pdev || - !lrbp->cmd || lrbp->command_type != UTP_CMD_TYPE_SCSI) + !lrbp->cmd || + (lrbp->command_type != UTP_CMD_TYPE_SCSI && + lrbp->command_type != UTP_CMD_TYPE_UFS_STORAGE)) goto out; err = ufs_qcom_ice_cfg_start(host, lrbp->cmd); @@ -984,7 +986,8 @@ int ufs_qcom_crytpo_engine_cfg_end(struct ufs_hba *hba, struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err = 0; - if (!host->ice.pdev || lrbp->command_type != UTP_CMD_TYPE_SCSI) + if (!host->ice.pdev || (lrbp->command_type != UTP_CMD_TYPE_SCSI && + lrbp->command_type != UTP_CMD_TYPE_UFS_STORAGE)) goto out; err = ufs_qcom_ice_cfg_end(host, req); diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 00df8861aeac04b7bc788e797a52043700811b89..5ff6531c0b7d0721e13e969cbe3947f183ec3f42 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -462,9 +462,9 @@ struct ufs_query_res { #define UFS_VREG_VCC_MAX_UV 3600000 /* uV */ #define UFS_VREG_VCC_1P8_MIN_UV 1700000 /* uV */ #define UFS_VREG_VCC_1P8_MAX_UV 1950000 /* uV */ -#define UFS_VREG_VCCQ_MIN_UV 1100000 /* uV */ +#define UFS_VREG_VCCQ_MIN_UV 1140000 /* uV */ #define UFS_VREG_VCCQ_MAX_UV 1300000 /* uV */ -#define UFS_VREG_VCCQ2_MIN_UV 1650000 /* uV */ +#define UFS_VREG_VCCQ2_MIN_UV 1700000 /* uV */ #define UFS_VREG_VCCQ2_MAX_UV 1950000 /* uV */ /* diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index b531892100279424b21c6d6ec97a55e45668ab2f..740dd5d6c3f3ffb5a8f3c576d0aeb1bafc22bea1 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -1758,6 +1758,7 @@ static int ngd_slim_probe(struct platform_device *pdev) bool rxreg_access = false; bool slim_mdm = false; const char *ext_modem_id = NULL; + char ipc_err_log_name[30]; if (of_device_is_compatible(pdev->dev.of_node, "qcom,iommu-slim-ctrl-cb")) @@ -1824,6 +1825,21 @@ static int ngd_slim_probe(struct platform_device *pdev) SLIM_INFO(dev, "start logging for slim dev %s\n", dev_name(dev->dev)); } + + /* Create Error IPC log context */ + memset(ipc_err_log_name, 0, sizeof(ipc_err_log_name)); + scnprintf(ipc_err_log_name, sizeof(ipc_err_log_name), "%s%s", + dev_name(dev->dev), "_err"); + dev->ipc_slimbus_log_err = + ipc_log_context_create(IPC_SLIMBUS_LOG_PAGES, + ipc_err_log_name, 0); + if (!dev->ipc_slimbus_log_err) + dev_err(&pdev->dev, + "error creating ipc_error_logging context\n"); + else + SLIM_INFO(dev, "start error logging for slim dev %s\n", + ipc_err_log_name); + ret = sysfs_create_file(&dev->dev->kobj, &dev_attr_debug_mask.attr); if (ret) { dev_err(&pdev->dev, "Failed to create dev. attr\n"); diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h index 44a6759ce4f3172592d162cd59f3761e256c0c42..adf2ba314461f0aa68dd7b1006d222cc8fa90c4a 100644 --- a/drivers/slimbus/slim-msm.h +++ b/drivers/slimbus/slim-msm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -321,6 +321,7 @@ struct msm_slim_ctrl { int ipc_log_mask; bool sysfs_created; void *ipc_slimbus_log; + void *ipc_slimbus_log_err; void (*rx_slim)(struct msm_slim_ctrl *dev, u8 *buf); u32 current_rx_buf[10]; int current_count; @@ -376,6 +377,9 @@ enum { if (dev->ipc_slimbus_log && dev->ipc_log_mask >= DBG_LEV) { \ ipc_log_string(dev->ipc_slimbus_log, x); \ } \ + if (dev->ipc_slimbus_log_err && dev->ipc_log_mask == FATAL_LEV) { \ + ipc_log_string(dev->ipc_slimbus_log_err, x); \ + } \ } while (0) #define SLIM_INFO(dev, x...) do { \ @@ -383,26 +387,36 @@ enum { if (dev->ipc_slimbus_log && dev->ipc_log_mask >= INFO_LEV) {\ ipc_log_string(dev->ipc_slimbus_log, x); \ } \ + if (dev->ipc_slimbus_log_err && dev->ipc_log_mask == FATAL_LEV) { \ + ipc_log_string(dev->ipc_slimbus_log_err, x); \ + } \ } while (0) /* warnings and errors show up on console always */ #define SLIM_WARN(dev, x...) do { \ - pr_warn(x); \ - if (dev->ipc_slimbus_log && dev->ipc_log_mask >= WARN_LEV) \ + if (dev->ipc_slimbus_log && dev->ipc_log_mask >= WARN_LEV) { \ + pr_warn(x); \ ipc_log_string(dev->ipc_slimbus_log, x); \ + } \ + if (dev->ipc_slimbus_log_err && dev->ipc_log_mask == FATAL_LEV) { \ + ipc_log_string(dev->ipc_slimbus_log_err, x); \ + } \ } while (0) /* ERROR condition in the driver sets the hs_serial_debug_mask * to ERR_FATAL level, so that this message can be seen - * in IPC logging. Further errors continue to log on the console + * in IPC logging. Further errors continue to log on the error IPC logging. */ #define SLIM_ERR(dev, x...) do { \ - pr_err(x); \ if (dev->ipc_slimbus_log && dev->ipc_log_mask >= ERR_LEV) { \ + pr_err(x); \ ipc_log_string(dev->ipc_slimbus_log, x); \ dev->default_ipc_log_mask = dev->ipc_log_mask; \ dev->ipc_log_mask = FATAL_LEV; \ } \ + if (dev->ipc_slimbus_log_err && dev->ipc_log_mask == FATAL_LEV) { \ + ipc_log_string(dev->ipc_slimbus_log_err, x); \ + } \ } while (0) #define SLIM_RST_LOGLVL(dev) { \ diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 91c0f66b44a31c44bb1e518b1e7a0ebc44fad6df..fb54ee455d0001ab0d92b4938deb8676fbb0e535 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -629,7 +629,7 @@ config MSM_SPCOM or server is allowed per logical channel. config MSM_TZ_SMMU - depends on ARCH_MSM8953 || ARCH_QCS405 + depends on ARCH_MSM8953 || ARCH_QCS405 || ARCH_QCS403 bool "Helper functions for SMMU configuration through TZ" help Say 'Y' here for targets that need to call into TZ to configure diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 30df5ddfca4a58fd3bb152373845c6a6ce6b5f4d..951f4e541e589e0bc05d5d6ee243f2c84142a11e 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -70,6 +70,7 @@ ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += subsystem_restart.o obj-y += ramdump.o obj-y += microdump_collector.o + obj-$(CONFIG_QTI_GVM_QUIN) += subsystem_notif_virt.o endif obj-$(CONFIG_QCOM_EUD) += eud.o obj-$(CONFIG_QSEE_IPC_IRQ) += qsee_ipc_irq.o diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c index a86cc47f831041effe7d2ec58377d94cfde1e58a..aa7715cf181528311025cf21c4a006836f350fff 100644 --- a/drivers/soc/qcom/dcc_v2.c +++ b/drivers/soc/qcom/dcc_v2.c @@ -612,6 +612,7 @@ static int dcc_enable(struct dcc_drvdata *drvdata) ram_cfg_base = drvdata->ram_cfg; ret = __dcc_ll_cfg(drvdata, list); if (ret) { + dcc_writel(drvdata, 0, DCC_LL_LOCK(list)); dev_info(drvdata->dev, "DCC ram programming failed\n"); goto err; } diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index 75c71590ce0ff7fd01b80850d2e2e26c18dd60c5..e269f7eaed7a84896be6994771f2cb1a8348a7e3 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -26,8 +26,6 @@ #define DFC_IS_TCP_BIDIR(r) (bool)((r) & DFC_MASK_TCP_BIDIR) #define DFC_IS_RAT_SWITCH(r) (bool)((r) & DFC_MASK_RAT_SWITCH) -#define DFC_IS_ANCILLARY(type) ((type) != AF_INET && (type) != AF_INET6) - #define DFC_MAX_QOS_ID_V01 2 #define DFC_ACK_TYPE_DISABLE 1 @@ -996,26 +994,23 @@ int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos) { - struct rmnet_flow_map *itm; int rc = 0, qlen; int enable; + int i; enable = bearer->grant_size ? 1 : 0; - list_for_each_entry(itm, &qos->flow_head, list) { - if (itm->bearer_id == bearer->bearer_id) { - /* - * Do not flow disable ancillary q if ancillary is true - */ - if (bearer->tcp_bidir && enable == 0 && - DFC_IS_ANCILLARY(itm->ip_type)) + for (i = 0; i < MAX_MQ_NUM; i++) { + if (qos->mq[i].bearer == bearer) { + /* Do not flow disable ancillary q in tcp bidir */ + if (qos->mq[i].ancillary && + bearer->tcp_bidir && !enable) continue; - qlen = qmi_rmnet_flow_control(dev, itm->tcm_handle, - enable); - trace_dfc_qmi_tc(dev->name, itm->bearer_id, - itm->flow_id, bearer->grant_size, - qlen, itm->tcm_handle, enable); + qlen = qmi_rmnet_flow_control(dev, i, enable); + trace_dfc_qmi_tc(dev->name, bearer->bearer_id, + bearer->grant_size, + qlen, i, enable); rc++; } } @@ -1033,9 +1028,9 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, struct dfc_flow_status_info_type_v01 *fc_info) { struct rmnet_bearer_map *bearer_itm; - struct rmnet_flow_map *flow_itm; int rc = 0, qlen; bool enable; + int i; enable = fc_info->num_bytes > 0 ? 1 : 0; @@ -1050,12 +1045,14 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, bearer_itm->last_seq = fc_info->seq_num; } - list_for_each_entry(flow_itm, &qos->flow_head, list) { - qlen = qmi_rmnet_flow_control(dev, flow_itm->tcm_handle, - enable); - trace_dfc_qmi_tc(dev->name, flow_itm->bearer_id, - flow_itm->flow_id, fc_info->num_bytes, - qlen, flow_itm->tcm_handle, enable); + for (i = 0; i < MAX_MQ_NUM; i++) { + bearer_itm = qos->mq[i].bearer; + if (!bearer_itm) + continue; + qlen = qmi_rmnet_flow_control(dev, i, enable); + trace_dfc_qmi_tc(dev->name, bearer_itm->bearer_id, + fc_info->num_bytes, + qlen, i, enable); rc++; } @@ -1519,22 +1516,28 @@ void dfc_qmi_client_exit(void *dfc_data) void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, int ip_type, u32 mark, unsigned int len) { - struct rmnet_bearer_map *bearer; + struct rmnet_bearer_map *bearer = NULL; struct rmnet_flow_map *itm; u32 start_grant; spin_lock_bh(&qos->qos_lock); - itm = qmi_rmnet_get_flow_map(qos, mark, ip_type); - if (unlikely(!itm)) - goto out; + if (dfc_mode == DFC_MODE_MQ_NUM) { + /* Mark is mq num */ + if (likely(mark < MAX_MQ_NUM)) + bearer = qos->mq[mark].bearer; + } else { + /* Mark is flow_id */ + itm = qmi_rmnet_get_flow_map(qos, mark, ip_type); + if (likely(itm)) + bearer = itm->bearer; + } - bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); if (unlikely(!bearer)) goto out; trace_dfc_flow_check(dev->name, bearer->bearer_id, - len, bearer->grant_size); + len, mark, bearer->grant_size); if (!bearer->grant_size) goto out; diff --git a/drivers/soc/qcom/hab/ghs_comm.c b/drivers/soc/qcom/hab/ghs_comm.c index 825f33a238587a8ac56dd24946c344bd47f825df..50b268c8ab7f23cfac6022496efa982d617f89f5 100644 --- a/drivers/soc/qcom/hab/ghs_comm.c +++ b/drivers/soc/qcom/hab/ghs_comm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,23 +39,24 @@ int physical_channel_send(struct physical_channel *pchan, struct hab_header *header, void *payload) { - int sizebytes = HAB_HEADER_GET_SIZE(*header); + size_t sizebytes = HAB_HEADER_GET_SIZE(*header); struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; GIPC_Result result; uint8_t *msg; + int irqs_disabled = irqs_disabled(); - spin_lock_bh(&dev->io_lock); + hab_spin_lock(&dev->io_lock, irqs_disabled); result = GIPC_PrepareMessage(dev->endpoint, sizebytes+sizeof(*header), (void **)&msg); if (result == GIPC_Full) { - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); /* need to wait for space! */ pr_err("failed to reserve send msg for %zd bytes\n", sizebytes+sizeof(*header)); return -EBUSY; } else if (result != GIPC_Success) { - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); pr_err("failed to send due to error %d\n", result); return -ENOMEM; } @@ -77,7 +78,7 @@ int physical_channel_send(struct physical_channel *pchan, result = GIPC_IssueMessage(dev->endpoint, sizebytes+sizeof(*header), header->id_type_size); - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); if (result != GIPC_Success) { pr_err("send error %d, sz %zd, prot %x\n", result, sizebytes+sizeof(*header), @@ -98,6 +99,7 @@ void physical_channel_rx_dispatch(unsigned long physical_channel) uint32_t events; unsigned long flags; + int irqs_disabled = irqs_disabled(); spin_lock_irqsave(&pchan->rxbuf_lock, flags); events = kgipc_dequeue_events(dev->endpoint); @@ -111,7 +113,7 @@ void physical_channel_rx_dispatch(unsigned long physical_channel) dev->name, pchan->vmid_remote); if (events & (GIPC_EVENT_RECEIVEREADY)) { - spin_lock_bh(&pchan->rxbuf_lock); + hab_spin_lock(&pchan->rxbuf_lock, irqs_disabled); while (1) { dev->read_size = 0; dev->read_offset = 0; @@ -133,7 +135,7 @@ void physical_channel_rx_dispatch(unsigned long physical_channel) result, dev->read_size); break; } - spin_unlock_bh(&pchan->rxbuf_lock); + hab_spin_unlock(&pchan->rxbuf_lock, irqs_disabled); } if (events & (GIPC_EVENT_SENDREADY)) diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h index ce7e83a2ba845c64d6ba358699671279d0454644..1ba38599532fb582ef58b11c42cbc1295b97c715 100644 --- a/drivers/soc/qcom/hab/hab.h +++ b/drivers/soc/qcom/hab/hab.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -577,6 +577,38 @@ int hab_stat_show_expimp(struct hab_driver *drv, int pid, char *buf, int sz); int hab_stat_init_sub(struct hab_driver *drv); int hab_stat_deinit_sub(struct hab_driver *drv); +static inline void hab_spin_lock(spinlock_t *lock, int irqs_disabled) +{ + if (irqs_disabled) + spin_lock(lock); + else + spin_lock_bh(lock); +} + +static inline void hab_spin_unlock(spinlock_t *lock, int irqs_disabled) +{ + if (irqs_disabled) + spin_unlock(lock); + else + spin_unlock_bh(lock); +} + +static inline void hab_write_lock(rwlock_t *lock, int irqs_disabled) +{ + if (irqs_disabled) + write_lock(lock); + else + write_lock_bh(lock); +} + +static inline void hab_write_unlock(rwlock_t *lock, int irqs_disabled) +{ + if (irqs_disabled) + write_unlock(lock); + else + write_unlock_bh(lock); +} + /* Global singleton HAB instance */ extern struct hab_driver hab_driver; diff --git a/drivers/soc/qcom/hab/hab_ghs.c b/drivers/soc/qcom/hab/hab_ghs.c index a445aa1a6707057a6c7ecc99552470ab32f621ef..575804c48abfe256ad8b95b3644e6d9d3382d03f 100644 --- a/drivers/soc/qcom/hab/hab_ghs.c +++ b/drivers/soc/qcom/hab/hab_ghs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -169,6 +169,7 @@ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, mmid_device->name, mmid_device->id, dt_name_idx); + of_node_put(gvh_dn); ret = -ENOENT; goto err; } @@ -176,9 +177,13 @@ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, ret = of_property_read_string(gvh_dn, ghs_vmm_plugin_info.dt_name[dt_name_idx], &ep_path); - if (ret) + if (ret) { pr_err("failed to read endpoint str ret %d\n", ret); + of_node_put(gvh_dn); + ret = -ENOENT; + goto err; + } of_node_put(gvh_dn); ep_dn = of_find_node_by_path(ep_path); diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c index 40ff1a9d6415dac167c7bb35514d10271d981393..f55628b299121a068e6b2248bc6631dd158b6802 100644 --- a/drivers/soc/qcom/hab/hab_msg.c +++ b/drivers/soc/qcom/hab/hab_msg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,10 +15,12 @@ static int hab_rx_queue_empty(struct virtual_channel *vchan) { int ret; + int irqs_disabled = irqs_disabled(); - spin_lock_bh(&vchan->rx_lock); + hab_spin_lock(&vchan->rx_lock, irqs_disabled); ret = list_empty(&vchan->rx_list); - spin_unlock_bh(&vchan->rx_lock); + hab_spin_unlock(&vchan->rx_lock, irqs_disabled); + return ret; } @@ -56,6 +58,7 @@ hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg, int ret = 0; int wait = !(flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING); int interruptible = !(flags & HABMM_SOCKET_RECV_FLAGS_UNINTERRUPTIBLE); + int irqs_disabled = irqs_disabled(); if (wait) { if (hab_rx_queue_empty(vchan)) { @@ -75,7 +78,7 @@ hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg, * and need empty check again in case the list is empty now due to * dequeue by other threads */ - spin_lock_bh(&vchan->rx_lock); + hab_spin_lock(&vchan->rx_lock, irqs_disabled); if ((!ret || (ret == -ERESTARTSYS)) && !list_empty(&vchan->rx_list)) { message = list_first_entry(&vchan->rx_list, @@ -99,7 +102,7 @@ hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg, /* no message received, retain the original status */ *rsize = 0; - spin_unlock_bh(&vchan->rx_lock); + hab_spin_unlock(&vchan->rx_lock, irqs_disabled); *msg = message; return ret; @@ -108,9 +111,11 @@ hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg, static void hab_msg_queue(struct virtual_channel *vchan, struct hab_message *message) { - spin_lock_bh(&vchan->rx_lock); + int irqs_disabled = irqs_disabled(); + + hab_spin_lock(&vchan->rx_lock, irqs_disabled); list_add_tail(&message->node, &vchan->rx_list); - spin_unlock_bh(&vchan->rx_lock); + hab_spin_unlock(&vchan->rx_lock, irqs_disabled); wake_up(&vchan->rx_queue); } @@ -119,11 +124,12 @@ static int hab_export_enqueue(struct virtual_channel *vchan, struct export_desc *exp) { struct uhab_context *ctx = vchan->ctx; + int irqs_disabled = irqs_disabled(); - spin_lock_bh(&ctx->imp_lock); + hab_spin_lock(&ctx->imp_lock, irqs_disabled); list_add_tail(&exp->node, &ctx->imp_whse); ctx->import_total++; - spin_unlock_bh(&ctx->imp_lock); + hab_spin_unlock(&ctx->imp_lock, irqs_disabled); return 0; } @@ -151,6 +157,7 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan, { struct hab_export_ack_recvd *ack_recvd = kzalloc(sizeof(*ack_recvd), GFP_ATOMIC); + int irqs_disabled = irqs_disabled(); if (!ack_recvd) return -ENOMEM; @@ -170,9 +177,9 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan, sizebytes) != sizebytes) return -EIO; - spin_lock_bh(&ctx->expq_lock); + hab_spin_lock(&ctx->expq_lock, irqs_disabled); list_add_tail(&ack_recvd->node, &ctx->exp_rxq); - spin_unlock_bh(&ctx->expq_lock); + hab_spin_unlock(&ctx->expq_lock, irqs_disabled); return 0; } diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c index bc2b774883f45c10cde93cad7a56bec381568493..a90460a1295ee83bb4049ff232334657b6ffdf7e 100644 --- a/drivers/soc/qcom/hab/hab_open.c +++ b/drivers/soc/qcom/hab/hab_open.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,7 @@ int hab_open_request_add(struct physical_channel *pchan, struct hab_device *dev = pchan->habdev; struct hab_open_request *request; struct timeval tv; + int irqs_disabled = irqs_disabled(); if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s request size too large %zd\n", @@ -70,10 +71,11 @@ int hab_open_request_add(struct physical_channel *pchan, tv.tv_usec/1000000; hab_pchan_get(pchan); - spin_lock_bh(&dev->openlock); + hab_spin_lock(&dev->openlock, irqs_disabled); list_add_tail(&node->node, &dev->openq_list); dev->openq_cnt++; - spin_unlock_bh(&dev->openlock); + hab_spin_unlock(&dev->openlock, irqs_disabled); + return 0; } @@ -192,6 +194,7 @@ int hab_open_receive_cancel(struct physical_channel *pchan, struct hab_open_node *node, *tmp; int bfound = 0; struct timeval tv; + int irqs_disabled = irqs_disabled(); if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s cancel size too large %zd\n", @@ -202,7 +205,7 @@ int hab_open_receive_cancel(struct physical_channel *pchan, if (physical_channel_read(pchan, &data, sizebytes) != sizebytes) return -EIO; - spin_lock_bh(&dev->openlock); + hab_spin_lock(&dev->openlock, irqs_disabled); list_for_each_entry_safe(node, tmp, &dev->openq_list, node) { request = &node->request; /* check if open request has been serviced or not */ @@ -221,7 +224,7 @@ int hab_open_receive_cancel(struct physical_channel *pchan, break; } } - spin_unlock_bh(&dev->openlock); + hab_spin_unlock(&dev->openlock, irqs_disabled); if (!bfound) { pr_info("init waiting is in-flight. vcid %x sub %d open %d\n", @@ -244,10 +247,10 @@ int hab_open_receive_cancel(struct physical_channel *pchan, /* put when this node is handled in open path */ hab_pchan_get(pchan); - spin_lock_bh(&dev->openlock); + hab_spin_lock(&dev->openlock, irqs_disabled); list_add_tail(&node->node, &dev->openq_list); dev->openq_cnt++; - spin_unlock_bh(&dev->openlock); + hab_spin_unlock(&dev->openlock, irqs_disabled); wake_up_interruptible(&dev->openq); } diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c index a95d6c7451c9ca726ab356cad62f3de55e49d91c..0ed957589ecc0b7403a3386b61ef8274d2c968ae 100644 --- a/drivers/soc/qcom/hab/hab_vchan.c +++ b/drivers/soc/qcom/hab/hab_vchan.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -77,16 +77,17 @@ hab_vchan_free(struct kref *ref) struct physical_channel *pchan = vchan->pchan; struct uhab_context *ctx = vchan->ctx; struct virtual_channel *vc, *vc_tmp; + int irqs_disabled = irqs_disabled(); - spin_lock_bh(&vchan->rx_lock); + hab_spin_lock(&vchan->rx_lock, irqs_disabled); list_for_each_entry_safe(message, msg_tmp, &vchan->rx_list, node) { list_del(&message->node); hab_msg_free(message); } - spin_unlock_bh(&vchan->rx_lock); + hab_spin_unlock(&vchan->rx_lock, irqs_disabled); /* release vchan from pchan. no more msg for this vchan */ - write_lock_bh(&pchan->vchans_lock); + hab_write_lock(&pchan->vchans_lock, irqs_disabled); list_for_each_entry_safe(vc, vc_tmp, &pchan->vchannels, pnode) { if (vchan == vc) { list_del(&vc->pnode); @@ -95,15 +96,15 @@ hab_vchan_free(struct kref *ref) break; } } - write_unlock_bh(&pchan->vchans_lock); + hab_write_unlock(&pchan->vchans_lock, irqs_disabled); /* the release vchan from ctx was done earlier in vchan close() */ hab_ctx_put(ctx); /* now ctx is not needed from this vchan's view */ /* release idr at the last so same idr will not be used early */ - spin_lock_bh(&pchan->vid_lock); + hab_spin_lock(&pchan->vid_lock, irqs_disabled); idr_remove(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan->id)); - spin_unlock_bh(&pchan->vid_lock); + hab_spin_unlock(&pchan->vid_lock, irqs_disabled); hab_pchan_put(pchan); /* no more need for pchan from this vchan */ @@ -122,8 +123,9 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) uint32_t session_id = HAB_HEADER_GET_SESSION_ID(*header); size_t sizebytes = HAB_HEADER_GET_SIZE(*header); uint32_t payload_type = HAB_HEADER_GET_TYPE(*header); + int irqs_disabled = irqs_disabled(); - spin_lock_bh(&pchan->vid_lock); + hab_spin_lock(&pchan->vid_lock, irqs_disabled); vchan = idr_find(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan_id)); if (vchan) { if (vchan->session_id != session_id) @@ -162,7 +164,7 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) vchan = NULL; } } - spin_unlock_bh(&pchan->vid_lock); + hab_spin_unlock(&pchan->vid_lock, irqs_disabled); return vchan; } diff --git a/drivers/soc/qcom/hab/qvm_comm.c b/drivers/soc/qcom/hab/qvm_comm.c index ab57f2758aedeb4668fc5d362fbcd8cb3160aeea..b743e8ddb60babcde28016b5c53dd0468ea164a4 100644 --- a/drivers/soc/qcom/hab/qvm_comm.c +++ b/drivers/soc/qcom/hab/qvm_comm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,19 +40,20 @@ int physical_channel_send(struct physical_channel *pchan, struct hab_header *header, void *payload) { - int sizebytes = HAB_HEADER_GET_SIZE(*header); + size_t sizebytes = HAB_HEADER_GET_SIZE(*header); struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data; - int total_size = sizeof(*header) + sizebytes; + size_t total_size = sizeof(*header) + sizebytes; + int irqs_disabled = irqs_disabled(); if (total_size > dev->pipe_ep->tx_info.sh_buf->size) return -EINVAL; /* too much data for ring */ - spin_lock_bh(&dev->io_lock); + hab_spin_lock(&dev->io_lock, irqs_disabled); if ((dev->pipe_ep->tx_info.sh_buf->size - (dev->pipe_ep->tx_info.wr_count - dev->pipe_ep->tx_info.sh_buf->rd_count)) < total_size) { - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); return -EAGAIN; /* not enough free space */ } @@ -62,7 +63,7 @@ int physical_channel_send(struct physical_channel *pchan, if (hab_pipe_write(dev->pipe_ep, (unsigned char *)header, sizeof(*header)) != sizeof(*header)) { - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); return -EIO; } @@ -76,7 +77,7 @@ int physical_channel_send(struct physical_channel *pchan, pstat->tx_sec = tv.tv_sec; pstat->tx_usec = tv.tv_usec; } else { - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); return -EINVAL; } } @@ -85,13 +86,14 @@ int physical_channel_send(struct physical_channel *pchan, if (hab_pipe_write(dev->pipe_ep, (unsigned char *)payload, sizebytes) != sizebytes) { - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); return -EIO; } } hab_pipe_write_commit(dev->pipe_ep); - spin_unlock_bh(&dev->io_lock); + hab_spin_unlock(&dev->io_lock, irqs_disabled); + habhyp_notify(dev); ++pchan->sequence_tx; return 0; @@ -102,8 +104,9 @@ void physical_channel_rx_dispatch(unsigned long data) struct hab_header header; struct physical_channel *pchan = (struct physical_channel *)data; struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data; + int irqs_disabled = irqs_disabled(); - spin_lock_bh(&pchan->rxbuf_lock); + hab_spin_lock(&pchan->rxbuf_lock, irqs_disabled); while (1) { if (hab_pipe_read(dev->pipe_ep, (unsigned char *)&header, @@ -122,5 +125,5 @@ void physical_channel_rx_dispatch(unsigned long data) hab_msg_recv(pchan, &header); } - spin_unlock_bh(&pchan->rxbuf_lock); + hab_spin_unlock(&pchan->rxbuf_lock, irqs_disabled); } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 2cb1599e29dc6958aae976d0e92b1f47864285e8..126a31435df9a78a7ff82f2dafd399d029b09edb 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -73,7 +73,7 @@ #define SUBSYS_INTERNAL_MODEM_NAME "modem" #define SUBSYS_EXTERNAL_MODEM_NAME "esoc0" -#define PROBE_TIMEOUT 5000 +#define PROBE_TIMEOUT 15000 #define FW_READY_TIMEOUT 50000 static struct icnss_priv *penv; @@ -302,6 +302,10 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type) return "PD_SERVICE_DOWN"; case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: return "FW_EARLY_CRASH_IND"; + case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN: + return "IDLE_SHUTDOWN"; + case ICNSS_DRIVER_EVENT_IDLE_RESTART: + return "IDLE_RESTART"; case ICNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } @@ -981,6 +985,10 @@ static int icnss_driver_event_server_arrive(void *data) ret = wlfw_ind_register_send_sync_msg(penv); if (ret < 0) { + if (ret == -EALREADY) { + ret = 0; + goto qmi_registered; + } ignore_assert = true; goto err_power_on; } @@ -1040,6 +1048,7 @@ static int icnss_driver_event_server_arrive(void *data) icnss_clear_server(penv); fail: ICNSS_ASSERT(ignore_assert); +qmi_registered: return ret; } @@ -1127,6 +1136,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_call_driver_shutdown(priv); clear_bit(ICNSS_PDR, &priv->state); + clear_bit(ICNSS_MODEM_CRASHED, &priv->state); clear_bit(ICNSS_REJUVENATE, &priv->state); clear_bit(ICNSS_PD_RESTART, &priv->state); priv->early_crash_ind = false; @@ -1405,6 +1415,51 @@ static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv, return ret; } +static int icnss_driver_event_idle_shutdown(void *data) +{ + int ret = 0; + + if (!penv->ops || !penv->ops->idle_shutdown) + return 0; + + if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) || + test_bit(ICNSS_PDR, &penv->state) || + test_bit(ICNSS_REJUVENATE, &penv->state)) { + icnss_pr_err("SSR/PDR is already in-progress during idle shutdown callback\n"); + ret = -EBUSY; + } else { + icnss_pr_dbg("Calling driver idle shutdown, state: 0x%lx\n", + penv->state); + icnss_block_shutdown(true); + ret = penv->ops->idle_shutdown(&penv->pdev->dev); + icnss_block_shutdown(false); + } + + return ret; +} + +static int icnss_driver_event_idle_restart(void *data) +{ + int ret = 0; + + if (!penv->ops || !penv->ops->idle_restart) + return 0; + + if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) || + test_bit(ICNSS_PDR, &penv->state) || + test_bit(ICNSS_REJUVENATE, &penv->state)) { + icnss_pr_err("SSR/PDR is already in-progress during idle restart callback\n"); + ret = -EBUSY; + } else { + icnss_pr_dbg("Calling driver idle restart, state: 0x%lx\n", + penv->state); + icnss_block_shutdown(true); + ret = penv->ops->idle_restart(&penv->pdev->dev); + icnss_block_shutdown(false); + } + + return ret; +} static void icnss_driver_event_work(struct work_struct *work) { @@ -1451,6 +1506,12 @@ static void icnss_driver_event_work(struct work_struct *work) ret = icnss_driver_event_early_crash_ind(penv, event->data); break; + case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN: + ret = icnss_driver_event_idle_shutdown(event->data); + break; + case ICNSS_DRIVER_EVENT_IDLE_RESTART: + ret = icnss_driver_event_idle_restart(event->data); + break; default: icnss_pr_err("Invalid Event type: %d", event->type); kfree(event); @@ -1525,17 +1586,23 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, priv->is_ssr = true; + if (notif->crashed) + set_bit(ICNSS_MODEM_CRASHED, &priv->state); + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && atomic_read(&priv->is_shutdown)) { atomic_set(&priv->is_shutdown, false); - icnss_call_driver_remove(priv); + if (!test_bit(ICNSS_PD_RESTART, &priv->state) && + !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state)) { + icnss_call_driver_remove(priv); + } } if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { if (!wait_for_completion_timeout(&priv->unblock_shutdown, - PROBE_TIMEOUT)) - icnss_pr_err("wlan driver probe timeout\n"); + msecs_to_jiffies(PROBE_TIMEOUT))) + icnss_pr_err("modem block shutdown timeout\n"); } if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed) { @@ -2514,6 +2581,48 @@ int icnss_trigger_recovery(struct device *dev) } EXPORT_SYMBOL(icnss_trigger_recovery); +int icnss_idle_shutdown(struct device *dev) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + + if (!priv) { + icnss_pr_err("Invalid drvdata: dev %pK", dev); + return -EINVAL; + } + + if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) || + test_bit(ICNSS_PDR, &priv->state) || + test_bit(ICNSS_REJUVENATE, &penv->state)) { + icnss_pr_err("SSR/PDR is already in-progress during idle shutdown\n"); + return -EBUSY; + } + + return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN, + ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); +} +EXPORT_SYMBOL(icnss_idle_shutdown); + +int icnss_idle_restart(struct device *dev) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + + if (!priv) { + icnss_pr_err("Invalid drvdata: dev %pK", dev); + return -EINVAL; + } + + if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) || + test_bit(ICNSS_PDR, &priv->state) || + test_bit(ICNSS_REJUVENATE, &penv->state)) { + icnss_pr_err("SSR/PDR is already in-progress during idle restart\n"); + return -EBUSY; + } + + return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_RESTART, + ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); +} +EXPORT_SYMBOL(icnss_idle_restart); + static int icnss_smmu_init(struct icnss_priv *priv) { @@ -2838,6 +2947,15 @@ static void icnss_allow_recursive_recovery(struct device *dev) icnss_pr_info("Recursive recovery allowed for WLAN\n"); } +static void icnss_disallow_recursive_recovery(struct device *dev) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + + priv->allow_recursive_recovery = false; + + icnss_pr_info("Recursive recovery disallowed for WLAN\n"); +} + static ssize_t icnss_fw_debug_write(struct file *fp, const char __user *user_buf, size_t count, loff_t *off) @@ -2889,6 +3007,9 @@ static ssize_t icnss_fw_debug_write(struct file *fp, case 4: icnss_allow_recursive_recovery(&priv->pdev->dev); break; + case 5: + icnss_disallow_recursive_recovery(&priv->pdev->dev); + break; default: return -EINVAL; } @@ -3018,6 +3139,8 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_ESOC_OFF: seq_puts(s, "ESOC_OFF"); continue; + case ICNSS_MODEM_CRASHED: + seq_puts(s, "MODEM CRASHED"); } seq_printf(s, "UNKNOWN-%d", i); @@ -3543,6 +3666,8 @@ static int icnss_probe(struct platform_device *pdev) priv->vreg_info = icnss_vreg_info; + icnss_allow_recursive_recovery(dev); + if (of_property_read_bool(pdev->dev.of_node, "qcom,icnss-adc_tm")) { ret = icnss_get_vbatt_info(priv); if (ret == -EPROBE_DEFER) diff --git a/drivers/soc/qcom/icnss_private.h b/drivers/soc/qcom/icnss_private.h index dc2c0812eea40fedada9de3db89b79dd976e0eb5..5edd8d7895549adad1f03a665b3a015ca1b2594a 100644 --- a/drivers/soc/qcom/icnss_private.h +++ b/drivers/soc/qcom/icnss_private.h @@ -120,6 +120,8 @@ enum icnss_driver_event_type { ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, + ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN, + ICNSS_DRIVER_EVENT_IDLE_RESTART, ICNSS_DRIVER_EVENT_MAX, }; @@ -165,6 +167,7 @@ enum icnss_driver_state { ICNSS_PDR, ICNSS_CLK_UP, ICNSS_ESOC_OFF, + ICNSS_MODEM_CRASHED, }; struct ce_irq_list { diff --git a/drivers/soc/qcom/icnss_qmi.c b/drivers/soc/qcom/icnss_qmi.c index c35149d4a2c112933c2c202b39d1010edf2383af..57a30421d9da0abf02ce69cee99373b071a7e797 100644 --- a/drivers/soc/qcom/icnss_qmi.c +++ b/drivers/soc/qcom/icnss_qmi.c @@ -315,14 +315,23 @@ int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv) priv->stats.ind_register_resp++; + if (resp->fw_status_valid && + (resp->fw_status & QMI_WLFW_ALREADY_REGISTERED_V01)) { + ret = -EALREADY; + icnss_pr_dbg("WLFW already registered\n"); + goto qmi_registered; + } + kfree(resp); kfree(req); + return 0; out: + priv->stats.ind_register_err++; +qmi_registered: kfree(resp); kfree(req); - priv->stats.ind_register_err++; return ret; } diff --git a/drivers/soc/qcom/llcc-atoll.c b/drivers/soc/qcom/llcc-atoll.c index b4be7589692c94a074174fa7f106ac5c430c9fc7..a57b70ea36310ca52cccf0a1c7277439bedf3a14 100644 --- a/drivers/soc/qcom/llcc-atoll.c +++ b/drivers/soc/qcom/llcc-atoll.c @@ -58,7 +58,7 @@ static struct llcc_slice_config atoll_data[] = { SCT_ENTRY("cpuss", 1, 1, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1), - SCT_ENTRY("modem", 8, 8, 256, 0, 0, 0xF, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("modem", 8, 8, 128, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0), SCT_ENTRY("gpuhtw", 11, 11, 128, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0), SCT_ENTRY("gpu", 12, 12, 128, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0), }; diff --git a/drivers/soc/qcom/mem-offline.c b/drivers/soc/qcom/mem-offline.c index 8c967a5919e04653ec64a35089146aae37874be3..0c154636d1274bbf105d7a6a5efa25986e5ee766 100644 --- a/drivers/soc/qcom/mem-offline.c +++ b/drivers/soc/qcom/mem-offline.c @@ -56,6 +56,8 @@ enum memory_states { MAX_STATE, }; +static enum memory_states *mem_hw_state; + static struct mem_offline_mailbox { struct mbox_client cl; struct mbox_chan *mbox; @@ -170,7 +172,7 @@ static int aop_send_msg(unsigned long addr, bool online) pkt.size = MAX_LEN; pkt.data = mbox_msg; - return mbox_send_message(mailbox.mbox, &pkt); + return (mbox_send_message(mailbox.mbox, &pkt) < 0); } static int send_msg(struct memory_notify *mn, bool online) @@ -184,6 +186,29 @@ static int send_msg(struct memory_notify *mn, bool online) return aop_send_msg(__pfn_to_phys(start), online); } +static int mem_change_refresh_state(struct memory_notify *mn, + enum memory_states state) +{ + int start = SECTION_ALIGN_DOWN(mn->start_pfn); + unsigned long sec_nr = pfn_to_section_nr(start); + bool online = (state == MEMORY_ONLINE) ? true : false; + unsigned long idx = (sec_nr - start_section_nr) / sections_per_block; + int ret; + + if (mem_hw_state[idx] == state) { + /* we shouldn't be getting this request */ + pr_warn("mem-offline: hardware state of mem%d block already in %s state. Ignoring refresh state change request\n", + sec_nr, online ? "online" : "offline"); + return 0; + } + ret = send_msg(mn, online); + if (ret) + return -EINVAL; + mem_hw_state[idx] = state; + + return 0; +} + static int mem_event_callback(struct notifier_block *self, unsigned long action, void *arg) { @@ -223,10 +248,12 @@ static int mem_event_callback(struct notifier_block *self, idx) / sections_per_block].fail_count; cur = ktime_get(); - if (send_msg(mn, true)) + if (mem_change_refresh_state(mn, MEMORY_ONLINE)) { pr_err("PASR: %s online request addr:0x%llx failed\n", is_rpm_controller ? "RPM" : "AOP", __pfn_to_phys(start)); + return NOTIFY_BAD; + } if (!debug_pagealloc_enabled()) { /* Create kernel page-tables */ create_pgtable_mapping(start_addr, end_addr); @@ -252,10 +279,15 @@ static int mem_event_callback(struct notifier_block *self, /* Clear kernel page-tables */ clear_pgtable_mapping(start_addr, end_addr); } - if (send_msg(mn, false)) + if (mem_change_refresh_state(mn, MEMORY_OFFLINE)) { pr_err("PASR: %s offline request addr:0x%llx failed\n", is_rpm_controller ? "RPM" : "AOP", __pfn_to_phys(start)); + /* + * Notifying that something went bad at this stage won't + * help since this is the last stage of memory hotplug. + */ + } delay = ktime_ms_delta(ktime_get(), cur); record_stat(sec_nr, delay, MEMORY_OFFLINE); @@ -266,7 +298,7 @@ static int mem_event_callback(struct notifier_block *self, case MEM_CANCEL_ONLINE: pr_info("mem-offline: MEM_CANCEL_ONLINE: start = 0x%lx end = 0x%lx", start_addr, end_addr); - if (send_msg(mn, false)) + if (mem_change_refresh_state(mn, MEMORY_OFFLINE)) pr_err("PASR: %s online request addr:0x%llx failed\n", is_rpm_controller ? "RPM" : "AOP", __pfn_to_phys(start)); @@ -401,9 +433,6 @@ static struct attribute_group mem_attr_group = { static int mem_sysfs_init(void) { - unsigned int total_blks = (end_section_nr - start_section_nr + 1) / - sections_per_block; - if (start_section_nr == end_section_nr) return -EINVAL; @@ -414,11 +443,6 @@ static int mem_sysfs_init(void) if (sysfs_create_group(kobj, &mem_attr_group)) kobject_put(kobj); - mem_info = kzalloc(sizeof(*mem_info) * total_blks * MAX_STATE, - GFP_KERNEL); - if (!mem_info) - return -ENOMEM; - return 0; } @@ -470,7 +494,8 @@ static struct notifier_block hotplug_memory_callback_nb = { static int mem_offline_driver_probe(struct platform_device *pdev) { - int ret; + unsigned int total_blks; + int ret, i; if (mem_parse_dt(pdev)) return -ENODEV; @@ -482,16 +507,46 @@ static int mem_offline_driver_probe(struct platform_device *pdev) if (ret > 0) pr_err("mem-offline: !!ERROR!! Auto onlining some memory blocks failed. System could run with less RAM\n"); - if (mem_sysfs_init()) - return -ENODEV; + total_blks = (end_section_nr - start_section_nr + 1) / + sections_per_block; + mem_info = kcalloc(total_blks * MAX_STATE, sizeof(*mem_info), + GFP_KERNEL); + if (!mem_info) + return -ENOMEM; + + mem_hw_state = kcalloc(total_blks, sizeof(*mem_hw_state), GFP_KERNEL); + if (!mem_hw_state) { + ret = -ENOMEM; + goto err_free_mem_info; + } + + /* we assume that hardware state of mem blocks are online after boot */ + for (i = 0; i < total_blks; i++) + mem_hw_state[i] = MEMORY_ONLINE; + + if (mem_sysfs_init()) { + ret = -ENODEV; + goto err_free_mem_hw_state; + } if (register_hotmemory_notifier(&hotplug_memory_callback_nb)) { pr_err("mem-offline: Registering memory hotplug notifier failed\n"); - return -ENODEV; + ret = -ENODEV; + goto err_sysfs_remove_group; } pr_info("mem-offline: Added memory blocks ranging from mem%lu - mem%lu\n", start_section_nr, end_section_nr); + return 0; + +err_sysfs_remove_group: + sysfs_remove_group(kobj, &mem_attr_group); + kobject_put(kobj); +err_free_mem_hw_state: + kfree(mem_hw_state); +err_free_mem_info: + kfree(mem_info); + return ret; } static const struct of_device_id mem_offline_match_table[] = { diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 7611b2540b0e09018fd6bb6035eeb3f4a00482b9..1d12fdf47a04c7003beee3b434cf5be4ec18d842 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -56,7 +56,7 @@ #define pil_memset_io(d, c, count) memset_io(d, c, count) #endif -#define PIL_NUM_DESC 10 +#define PIL_NUM_DESC 16 #define MAX_LEN 96 #define NUM_OF_ENCRYPTED_KEY 3 diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 84ec2e05ed74803232259f9db143d7aef4da614d..fdd20f3ca5ac8deed6b0e8189a56b1c730c9d6c9 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -117,6 +117,7 @@ struct qbt1000_drvdata { enum fd_indication_mode fd_ind_mode; bool ipc_is_stale; bool gestures_enabled; + atomic_t wakelock_acquired; }; /* @@ -311,6 +312,11 @@ static int qbt1000_release(struct inode *inode, struct file *file) } drvdata = file->private_data; atomic_inc(&drvdata->available); + if (atomic_read(&drvdata->wakelock_acquired) != 0) { + pr_debug("Releasing wakelock\n"); + pm_relax(drvdata->dev); + atomic_set(&drvdata->wakelock_acquired, 0); + } return 0; } @@ -589,6 +595,25 @@ static long qbt1000_ioctl( } break; } + case QBT1000_ACQUIRE_WAKELOCK: + { + if (atomic_read(&drvdata->wakelock_acquired) == 0) { + pr_debug("Acquiring wakelock\n"); + pm_stay_awake(drvdata->dev); + } + atomic_inc(&drvdata->wakelock_acquired); + break; + } + case QBT1000_RELEASE_WAKELOCK: + { + if (atomic_read(&drvdata->wakelock_acquired) == 0) + break; + if (atomic_dec_and_test(&drvdata->wakelock_acquired)) { + pr_debug("Releasing wakelock\n"); + pm_relax(drvdata->dev); + } + break; + } default: pr_err("invalid cmd %d\n", cmd); rc = -ENOIOCTLCMD; @@ -1234,6 +1259,7 @@ static int qbt1000_probe(struct platform_device *pdev) goto end; atomic_set(&drvdata->available, 1); + atomic_set(&drvdata->wakelock_acquired, 0); mutex_init(&drvdata->mutex); mutex_init(&drvdata->fw_events_mutex); diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c index 5f2575a313a15a14e3cd0c40df0305dc08b6caf0..1e5debbb598eaa1e393d9205707d818361ea02dc 100644 --- a/drivers/soc/qcom/qdss_bridge.c +++ b/drivers/soc/qcom/qdss_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,17 +31,6 @@ #define MODULE_NAME "qdss_bridge" -#define QDSS_BUF_SIZE (16*1024) -#define MHI_CLIENT_QDSS_IN 9 - -/* Max number of objects needed */ -static int poolsize = 32; -module_param(poolsize, int, 0644); - -/* Size of single buffer */ -static int itemsize = QDSS_BUF_SIZE; -module_param(itemsize, int, 0644); - static struct class *mhi_class; static const char * const str_mhi_transfer_mode[] = { @@ -106,8 +95,12 @@ static int qdss_create_buf_tbl(struct qdss_bridge_drvdata *drvdata) void *buf; struct qdss_request *usb_req; int i; + struct mhi_device *mhi_dev = drvdata->mhi_dev; + + drvdata->nr_trbs = mhi_get_no_free_descriptors(mhi_dev, + DMA_FROM_DEVICE); - for (i = 0; i < poolsize; i++) { + for (i = 0; i < drvdata->nr_trbs; i++) { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto err; @@ -455,7 +448,7 @@ static void usb_notifier(void *priv, unsigned int event, switch (event) { case USB_QDSS_CONNECT: - usb_qdss_alloc_req(ch, poolsize, 0); + usb_qdss_alloc_req(ch, drvdata->nr_trbs, 0); mhi_queue_read(drvdata); break; @@ -709,12 +702,11 @@ static ssize_t mhi_uci_read(struct file *file, 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++) { + for (i = 0; i < drvdata->nr_trbs; i++) { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto err; @@ -922,7 +914,7 @@ static int qdss_mhi_probe(struct mhi_device *mhi_dev, } static const struct mhi_device_id qdss_mhi_match_table[] = { - { .chan = "QDSS", .driver_data = 0x4000 }, + { .chan = "QDSS", .driver_data = 0x8000 }, {}, }; diff --git a/drivers/soc/qcom/qdss_bridge.h b/drivers/soc/qcom/qdss_bridge.h index f5e119b0ce844db2ea140afbcb9126517eea6a31..128e4bf0b82bc751b089df7651f4ca2ab22c7c0f 100644 --- a/drivers/soc/qcom/qdss_bridge.h +++ b/drivers/soc/qcom/qdss_bridge.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,6 +39,7 @@ enum open_status { struct qdss_bridge_drvdata { int alias; + int nr_trbs; enum open_status opened; struct completion completion; size_t mtu; diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 1508913df43649fc0a39b40671f61c4992da051d..f206c8442893f05320c848ebc5c411c9b79d432d 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -317,7 +317,6 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, memset(txn, 0, sizeof(*txn)); - mutex_init(&txn->lock); init_completion(&txn->completion); txn->qmi = qmi; txn->ei = ei; @@ -353,17 +352,12 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) ret = wait_for_completion_timeout(&txn->completion, timeout); - mutex_lock(&txn->lock); if (txn->result == -ENETRESET) { - mutex_unlock(&txn->lock); return txn->result; } - mutex_unlock(&txn->lock); mutex_lock(&qmi->txn_lock); - mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); - mutex_unlock(&txn->lock); mutex_unlock(&qmi->txn_lock); if (ret == 0) @@ -382,9 +376,7 @@ void qmi_txn_cancel(struct qmi_txn *txn) struct qmi_handle *qmi = txn->qmi; mutex_lock(&qmi->txn_lock); - mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); - mutex_unlock(&txn->lock); mutex_unlock(&qmi->txn_lock); } EXPORT_SYMBOL(qmi_txn_cancel); @@ -508,24 +500,22 @@ static void qmi_handle_message(struct qmi_handle *qmi, if (hdr->type == QMI_RESPONSE) { mutex_lock(&qmi->txn_lock); txn = idr_find(&qmi->txns, hdr->txn_id); - if (txn) - mutex_lock(&txn->lock); - mutex_unlock(&qmi->txn_lock); - } - - if (txn && txn->dest && txn->ei) { - ret = qmi_decode_message(buf, len, txn->ei, txn->dest); - if (ret < 0) - pr_err("failed to decode incoming message\n"); - - txn->result = ret; - complete(&txn->completion); - - mutex_unlock(&txn->lock); - } else if (txn) { - qmi_invoke_handler(qmi, sq, txn, buf, len); + /* Ignore unexpected responses */ + if (!txn) { + mutex_unlock(&qmi->txn_lock); + return; + } + if (txn->dest && txn->ei) { + ret = qmi_decode_message(buf, len, txn->ei, txn->dest); + if (ret < 0) + pr_err("failed to decode incoming message\n"); - mutex_unlock(&txn->lock); + txn->result = ret; + complete(&txn->completion); + } else { + qmi_invoke_handler(qmi, sq, txn, buf, len); + } + mutex_unlock(&qmi->txn_lock); } else { /* Create a txn based on the txn_id of the incoming message */ memset(&tmp_txn, 0, sizeof(tmp_txn)); @@ -736,11 +726,9 @@ void qmi_handle_release(struct qmi_handle *qmi) mutex_lock(&qmi->txn_lock); idr_for_each_entry(&qmi->txns, txn, txn_id) { - mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); txn->result = -ENETRESET; complete(&txn->completion); - mutex_unlock(&txn->lock); } mutex_unlock(&qmi->txn_lock); idr_destroy(&qmi->txns); diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 8317223984fd503d212ad111cf12fe5e2f8c3357..6d867048d25b07e6fb51acbf5d9bb84ae957dc04 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -31,7 +31,12 @@ #define FLAG_DFC_MASK 0x000F #define FLAG_POWERSAVE_MASK 0x0010 -#define DFC_MODE_MULTIQ 2 +#define FLAG_TO_MODE(f) ((f) & FLAG_DFC_MASK) +#define DFC_SUPPORTED_MODE(m) \ + ((m) == DFC_MODE_FLOW_ID || (m) == DFC_MODE_MQ_NUM) + +int dfc_mode; +#define IS_ANCILLARY(type) ((type) != AF_INET && (type) != AF_INET6) unsigned int rmnet_wq_frequency __read_mostly = 1000; module_param(rmnet_wq_frequency, uint, 0644); @@ -46,6 +51,10 @@ MODULE_PARM_DESC(rmnet_wq_frequency, "Frequency of PS check in ms"); static unsigned int qmi_rmnet_scale_factor = 5; #endif +static int +qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, + struct qmi_info *qmi); + struct qmi_elem_info data_ep_id_type_v01_ei[] = { { .data_type = QMI_SIGNED_4_BYTE_ENUM, @@ -83,7 +92,7 @@ void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) { int i; - if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ)) + if (!qmi || !DFC_SUPPORTED_MODE(FLAG_TO_MODE(qmi->flag))) return NULL; for (i = 0; i < MAX_CLIENT_NUM; i++) { @@ -138,6 +147,8 @@ qmi_rmnet_clean_flow_list(struct qmi_info *qmi, struct net_device *dev, list_del(&bearer->list); kfree(bearer); } + + memset(qos->mq, 0, sizeof(qos->mq)); } struct rmnet_flow_map * @@ -176,17 +187,17 @@ static void qmi_rmnet_update_flow_map(struct rmnet_flow_map *itm, itm->bearer_id = new_map->bearer_id; itm->flow_id = new_map->flow_id; itm->ip_type = new_map->ip_type; - itm->tcm_handle = new_map->tcm_handle; + itm->mq_idx = new_map->mq_idx; } -int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable) +int qmi_rmnet_flow_control(struct net_device *dev, u32 mq_idx, int enable) { struct netdev_queue *q; - if (unlikely(tcm_handle >= dev->num_tx_queues)) + if (unlikely(mq_idx >= dev->num_tx_queues)) return 0; - q = netdev_get_tx_queue(dev, tcm_handle); + q = netdev_get_tx_queue(dev, mq_idx); if (unlikely(!q)) return 0; @@ -198,74 +209,113 @@ int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable) return 0; } +static void qmi_rmnet_reset_txq(struct net_device *dev, unsigned int txq) +{ + struct Qdisc *qdisc; + + if (unlikely(txq >= dev->num_tx_queues)) + return; + + qdisc = rtnl_dereference(netdev_get_tx_queue(dev, txq)->qdisc); + if (qdisc) { + spin_lock_bh(qdisc_lock(qdisc)); + qdisc_reset(qdisc); + spin_unlock_bh(qdisc_lock(qdisc)); + } +} + static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, struct qmi_info *qmi) { struct qos_info *qos_info = (struct qos_info *)rmnet_get_qos_pt(dev); struct rmnet_flow_map new_map, *itm; struct rmnet_bearer_map *bearer; + struct tcmsg tmp_tcm; + struct mq_map *mq; + u32 mq_idx; - if (!qos_info) + if (!qos_info || !tcm || tcm->tcm_handle >= MAX_MQ_NUM) return -EINVAL; ASSERT_RTNL(); /* flow activate * tcm->tcm__pad1 - bearer_id, tcm->tcm_parent - flow_id, - * tcm->tcm_ifindex - ip_type, tcm->tcm_handle - tcm_handle + * tcm->tcm_ifindex - ip_type, tcm->tcm_handle - mq_idx */ new_map.bearer_id = tcm->tcm__pad1; new_map.flow_id = tcm->tcm_parent; new_map.ip_type = tcm->tcm_ifindex; - new_map.tcm_handle = tcm->tcm_handle; + new_map.mq_idx = tcm->tcm_handle; trace_dfc_flow_info(dev->name, new_map.bearer_id, new_map.flow_id, - new_map.ip_type, new_map.tcm_handle, 1); + new_map.ip_type, new_map.mq_idx, 1); +again: spin_lock_bh(&qos_info->qos_lock); itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id, new_map.ip_type); if (itm) { - qmi_rmnet_update_flow_map(itm, &new_map); + pr_debug("%s: stale flow found\n", __func__); + tmp_tcm.tcm__pad1 = itm->bearer_id; + tmp_tcm.tcm_parent = itm->flow_id; + tmp_tcm.tcm_ifindex = itm->ip_type; + tmp_tcm.tcm_handle = itm->mq_idx; + spin_unlock_bh(&qos_info->qos_lock); + qmi_rmnet_del_flow(dev, &tmp_tcm, qmi); + goto again; + } + + /* Create flow map */ + itm = kzalloc(sizeof(*itm), GFP_ATOMIC); + if (!itm) { + spin_unlock_bh(&qos_info->qos_lock); + return -ENOMEM; + } + + qmi_rmnet_update_flow_map(itm, &new_map); + list_add(&itm->list, &qos_info->flow_head); + + /* Create or update bearer map */ + bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); + if (bearer) { + bearer->flow_ref++; } else { - itm = kzalloc(sizeof(*itm), GFP_ATOMIC); - if (!itm) { + bearer = kzalloc(sizeof(*bearer), GFP_ATOMIC); + if (!bearer) { spin_unlock_bh(&qos_info->qos_lock); return -ENOMEM; } - 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_ATOMIC); - if (!bearer) { - spin_unlock_bh(&qos_info->qos_lock); - 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); - } - - qmi_rmnet_flow_control(dev, itm->tcm_handle, - bearer->grant_size > 0 ? 1 : 0); - - trace_dfc_qmi_tc(dev->name, itm->bearer_id, itm->flow_id, - bearer->grant_size, 0, itm->tcm_handle, 1); + 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); + } + itm->bearer = bearer; + + /* Update mq map */ + mq_idx = tcm->tcm_handle; + mq = &qos_info->mq[mq_idx]; + if (!mq->bearer) { + mq->bearer = bearer; + mq->ancillary = IS_ANCILLARY(new_map.ip_type); + + qmi_rmnet_flow_control(dev, mq_idx, + bearer->grant_size > 0 ? 1 : 0); + trace_dfc_qmi_tc(dev->name, itm->bearer_id, + bearer->grant_size, 0, mq_idx, + bearer->grant_size > 0 ? 1 : 0); + + } else if (mq->bearer->bearer_id != new_map.bearer_id) { + pr_debug("%s: un-managered bearer %u\n", + __func__, new_map.bearer_id); } spin_unlock_bh(&qos_info->qos_lock); - return 0; } @@ -276,6 +326,8 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, struct qos_info *qos_info = (struct qos_info *)rmnet_get_qos_pt(dev); struct rmnet_flow_map new_map, *itm; struct rmnet_bearer_map *bearer; + struct mq_map *mq; + u32 mq_idx; if (!qos_info) return -EINVAL; @@ -297,31 +349,38 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, if (itm) { trace_dfc_flow_info(dev->name, new_map.bearer_id, new_map.flow_id, new_map.ip_type, - itm->tcm_handle, 0); - list_del(&itm->list); - - /* Enable flow to allow new call setup */ - qmi_rmnet_flow_control(dev, itm->tcm_handle, 1); - trace_dfc_qmi_tc(dev->name, itm->bearer_id, itm->flow_id, - 0, 0, itm->tcm_handle, 1); + itm->mq_idx, 0); - /*clear bearer map*/ - bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); + bearer = itm->bearer; if (bearer && --bearer->flow_ref == 0) { + /* Remove the bearer from mq map */ + for (mq_idx = 0; mq_idx < MAX_MQ_NUM; mq_idx++) { + mq = &qos_info->mq[mq_idx]; + if (mq->bearer != bearer) + continue; + + mq->bearer = NULL; + mq->ancillary = false; + qmi_rmnet_reset_txq(dev, mq_idx); + qmi_rmnet_flow_control(dev, mq_idx, 1); + trace_dfc_qmi_tc(dev->name, + new_map.bearer_id, 0, 0, mq_idx, 1); + } + + /* Remove from bearer map */ list_del(&bearer->list); kfree(bearer); } + /* Remove from flow map */ + list_del(&itm->list); kfree(itm); } - if (list_empty(&qos_info->flow_head)) { + if (list_empty(&qos_info->flow_head)) netif_tx_wake_all_queues(dev); - trace_dfc_qmi_tc(dev->name, 0xFF, 0, DEFAULT_GRANT, 0, 0, 1); - } spin_unlock_bh(&qos_info->qos_lock); - return 0; } @@ -418,7 +477,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) svc.ep_type = tcm->tcm_info; svc.iface_id = tcm->tcm_parent; - if (((tcm->tcm_ifindex & FLAG_DFC_MASK) == DFC_MODE_MULTIQ) && + if (DFC_SUPPORTED_MODE(FLAG_TO_MODE(tcm->tcm_ifindex)) && !qmi->dfc_clients[idx] && !qmi->dfc_pending[idx]) { rc = dfc_qmi_client_init(port, idx, &svc, qmi); if (rc < 0) @@ -495,20 +554,21 @@ void qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt) switch (tcm->tcm_family) { case NLMSG_FLOW_ACTIVATE: - if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ) || + if (!qmi || !DFC_SUPPORTED_MODE(FLAG_TO_MODE(qmi->flag)) || !qmi_rmnet_has_dfc_client(qmi)) return; qmi_rmnet_add_flow(dev, tcm, qmi); break; case NLMSG_FLOW_DEACTIVATE: - if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ)) + if (!qmi || !DFC_SUPPORTED_MODE(FLAG_TO_MODE(qmi->flag))) return; qmi_rmnet_del_flow(dev, tcm, qmi); break; case NLMSG_CLIENT_SETUP: - if (((tcm->tcm_ifindex & FLAG_DFC_MASK) != DFC_MODE_MULTIQ) && + dfc_mode = FLAG_TO_MODE(tcm->tcm_ifindex); + if (!DFC_SUPPORTED_MODE(dfc_mode) && !(tcm->tcm_ifindex & FLAG_POWERSAVE_MASK)) return; @@ -653,6 +713,10 @@ int qmi_rmnet_get_queue(struct net_device *dev, struct sk_buff *skb) if (!qos) return 0; + /* If mark is mq num return it */ + if (dfc_mode == DFC_MODE_MQ_NUM) + return mark; + switch (skb->protocol) { /* TCPv4 ACKs */ case htons(ETH_P_IP): @@ -687,7 +751,7 @@ int qmi_rmnet_get_queue(struct net_device *dev, struct sk_buff *skb) if (unlikely(!itm)) goto done; - txq = itm->tcm_handle; + txq = itm->mq_idx; done: spin_unlock_bh(&qos->qos_lock); @@ -705,7 +769,7 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) { struct qos_info *qos; - qos = kmalloc(sizeof(*qos), GFP_KERNEL); + qos = kzalloc(sizeof(*qos), GFP_KERNEL); if (!qos) return NULL; @@ -739,6 +803,7 @@ EXPORT_SYMBOL(qmi_rmnet_qos_exit); #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE static struct workqueue_struct *rmnet_ps_wq; static struct rmnet_powersave_work *rmnet_work; +static bool rmnet_work_quit; static LIST_HEAD(ps_list); struct rmnet_powersave_work { @@ -821,9 +886,10 @@ EXPORT_SYMBOL(qmi_rmnet_set_powersave_mode); static void qmi_rmnet_work_restart(void *port) { - if (!rmnet_ps_wq || !rmnet_work) - return; - queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, NO_DELAY); + rcu_read_lock(); + if (!rmnet_work_quit) + queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, NO_DELAY); + rcu_read_unlock(); } static void qmi_rmnet_check_stats(struct work_struct *work) @@ -850,13 +916,9 @@ static void qmi_rmnet_check_stats(struct work_struct *work) qmi->ps_ignore_grant = false; /* Register to get QMI DFC and DL marker */ - if (qmi_rmnet_set_powersave_mode(real_work->port, 0) < 0) { - /* If this failed need to retry quickly */ - queue_delayed_work(rmnet_ps_wq, - &real_work->work, HZ / 50); - return; + if (qmi_rmnet_set_powersave_mode(real_work->port, 0) < 0) + goto end; - } qmi->ps_enabled = false; /* Do a query when coming out of powersave */ @@ -886,11 +948,9 @@ static void qmi_rmnet_check_stats(struct work_struct *work) goto end; /* Deregister to suppress QMI DFC and DL marker */ - if (qmi_rmnet_set_powersave_mode(real_work->port, 1) < 0) { - queue_delayed_work(rmnet_ps_wq, - &real_work->work, PS_INTERVAL); - return; - } + if (qmi_rmnet_set_powersave_mode(real_work->port, 1) < 0) + goto end; + qmi->ps_enabled = true; /* Ignore grant after going into powersave */ @@ -908,7 +968,10 @@ static void qmi_rmnet_check_stats(struct work_struct *work) return; } end: - queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL); + rcu_read_lock(); + if (!rmnet_work_quit) + queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL); + rcu_read_unlock(); } static void qmi_rmnet_work_set_active(void *port, int status) @@ -933,7 +996,7 @@ void qmi_rmnet_work_init(void *port) rmnet_ps_wq = alloc_workqueue("rmnet_powersave_work", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1); - rmnet_work = kmalloc(sizeof(*rmnet_work), GFP_ATOMIC); + rmnet_work = kzalloc(sizeof(*rmnet_work), GFP_ATOMIC); if (!rmnet_work) { destroy_workqueue(rmnet_ps_wq); rmnet_ps_wq = NULL; @@ -944,6 +1007,7 @@ void qmi_rmnet_work_init(void *port) rmnet_get_packets(rmnet_work->port, &rmnet_work->old_rx_pkts, &rmnet_work->old_tx_pkts); + rmnet_work_quit = false; qmi_rmnet_work_set_active(rmnet_work->port, 1); queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, PS_INTERVAL); } @@ -966,6 +1030,10 @@ void qmi_rmnet_work_exit(void *port) { if (!rmnet_ps_wq || !rmnet_work) return; + + rmnet_work_quit = true; + synchronize_rcu(); + cancel_delayed_work_sync(&rmnet_work->work); destroy_workqueue(rmnet_ps_wq); qmi_rmnet_work_set_active(port, 0); diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index b24a6aa37c5c761088409ffb306f52f480a830b9..b95c8a0ebd8f4f3b6c59e81cb9c6f050bcb69cfb 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -20,18 +20,15 @@ #define IP_VER_4 4 #define IP_VER_6 6 +#define MAX_MQ_NUM 10 #define MAX_CLIENT_NUM 2 #define MAX_FLOW_NUM 32 #define DEFAULT_GRANT 1 #define DFC_MAX_BEARERS_V01 16 -struct rmnet_flow_map { - struct list_head list; - u8 bearer_id; - u32 flow_id; - int ip_type; - u32 tcm_handle; -}; +#define DFC_MODE_FLOW_ID 2 +#define DFC_MODE_MQ_NUM 3 +extern int dfc_mode; struct rmnet_bearer_map { struct list_head list; @@ -48,27 +45,37 @@ struct rmnet_bearer_map { bool tx_off; }; +struct rmnet_flow_map { + struct list_head list; + u8 bearer_id; + u32 flow_id; + int ip_type; + u32 mq_idx; + struct rmnet_bearer_map *bearer; +}; + struct svc_info { u32 instance; u32 ep_type; u32 iface_id; }; +struct mq_map { + struct rmnet_bearer_map *bearer; + bool ancillary; +}; + struct qos_info { u8 mux_id; struct net_device *real_dev; struct list_head flow_head; struct list_head bearer_head; + struct mq_map mq[MAX_MQ_NUM]; u32 default_grant; u32 tran_num; spinlock_t qos_lock; }; -struct flow_info { - struct net_device *dev; - struct rmnet_flow_map *itm; -}; - struct qmi_info { int flag; void *wda_client; @@ -119,7 +126,7 @@ void dfc_qmi_client_exit(void *dfc_data); void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, int ip_type, u32 mark, unsigned int len); -int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable); +int qmi_rmnet_flow_control(struct net_device *dev, u32 mq_idx, int enable); void dfc_qmi_query_flow(void *dfc_data); diff --git a/drivers/soc/qcom/scm_qcpe.c b/drivers/soc/qcom/scm_qcpe.c index 4ae30c0559eb444b9b9700f2aa7039961b55d27c..fef882816b10e20a2fc25edd17f6dc9a5fbbf0cf 100644 --- a/drivers/soc/qcom/scm_qcpe.c +++ b/drivers/soc/qcom/scm_qcpe.c @@ -239,6 +239,18 @@ static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc, bool atomic) fn_id, desc->arginfo, desc->args[0], desc->args[1], desc->args[2], desc->args[3], desc->x5); + if (!opened) { + if (!atomic) { + if (scm_qcpe_hab_open()) { + pr_err("HAB channel re-open failed\n"); + return -ENODEV; + } + } else { + pr_err("HAB channel is not opened\n"); + return -ENODEV; + } + } + smc_params.fn_id = fn_id | scm_version_mask; smc_params.arginfo = desc->arginfo; smc_params.args[0] = desc->args[0]; @@ -324,6 +336,8 @@ bool is_scm_armv8(void) { int ret; u64 ret1, x0; + bool ret_scm_version; + bool save_scm_version; struct scm_desc desc = {0}; @@ -346,6 +360,7 @@ bool is_scm_armv8(void) desc.args[0] = x0; ret = scm_call_qcpe(x0 | SMC64_MASK, &desc, true); + save_scm_version = (ret == -ENODEV) ? false : true; ret1 = desc.ret[0]; @@ -357,6 +372,7 @@ bool is_scm_armv8(void) desc.args[0] = x0; ret = scm_call_qcpe(x0, &desc, true); + save_scm_version = (ret == -ENODEV) ? false : true; if (ret || !ret1) scm_version = SCM_LEGACY; @@ -368,8 +384,15 @@ bool is_scm_armv8(void) pr_debug("scm_call: scm version is %x, mask is %x\n", scm_version, scm_version_mask); - return (scm_version == SCM_ARMV8_32) || + ret_scm_version = (scm_version == SCM_ARMV8_32) || (scm_version == SCM_ARMV8_64); + + /* Don't cache the scm_version in case error is due to hab issues. */ + /* In this case, allow a later retry. */ + if (!save_scm_version) + scm_version = SCM_UNKNOWN; + + return ret_scm_version; } /* diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index 7f95bb279de376f7956ca10ce403c64757a7dfeb..ef899cd55526043758d7ae12262a36e58683f404 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -209,6 +209,7 @@ struct smcinvoke_cb_txn { size_t cb_req_bytes; struct file **filp_to_release; struct hlist_node hash; + struct kref ref_cnt; }; struct smcinvoke_server_info { @@ -456,6 +457,15 @@ static void release_tzhandles(const int32_t *tzhandles, size_t len) mutex_unlock(&g_smcinvoke_lock); } +static void delete_cb_txn(struct kref *kref) +{ + struct smcinvoke_cb_txn *cb_txn = container_of(kref, + struct smcinvoke_cb_txn, ref_cnt); + + kfree(cb_txn->cb_req); + kfree(cb_txn); +} + static struct smcinvoke_cb_txn *find_cbtxn_locked( struct smcinvoke_server_info *server, uint32_t txn_id, int32_t state) @@ -470,6 +480,7 @@ static struct smcinvoke_cb_txn *find_cbtxn_locked( if (state == SMCINVOKE_REQ_PLACED) { /* pick up 1st req */ hash_for_each(server->reqs_table, i, cb_txn, hash) { + kref_get(&cb_txn->ref_cnt); hash_del(&cb_txn->hash); return cb_txn; } @@ -477,6 +488,7 @@ static struct smcinvoke_cb_txn *find_cbtxn_locked( hash_for_each_possible( server->responses_table, cb_txn, hash, txn_id) { if (cb_txn->txn_id == txn_id) { + kref_get(&cb_txn->ref_cnt); hash_del(&cb_txn->hash); return cb_txn; } @@ -833,7 +845,13 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) if (buf_len < sizeof(struct smcinvoke_tzcb_req)) return; - cb_req = buf; + cb_req = kzalloc(buf_len, GFP_KERNEL); + if (!cb_req) { + ret = OBJECT_ERROR_KMEM; + goto out; + } + memcpy(cb_req, buf, buf_len); + /* check whether it is to be served by kernel or userspace */ if (TZHANDLE_IS_KERNEL_OBJ(cb_req->hdr.tzhandle)) { return process_kernel_obj(buf, buf_len); @@ -854,6 +872,7 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) cb_txn->cb_req = cb_req; cb_txn->cb_req_bytes = buf_len; cb_txn->filp_to_release = arr_filp; + kref_init(&cb_txn->ref_cnt); mutex_lock(&g_smcinvoke_lock); srvr_info = find_cb_server_locked( @@ -867,9 +886,11 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) hash_add(srvr_info->reqs_table, &cb_txn->hash, cb_txn->txn_id); mutex_unlock(&g_smcinvoke_lock); wake_up_interruptible(&srvr_info->req_wait_q); - wait_event(srvr_info->rsp_wait_q, + ret = wait_event_interruptible(srvr_info->rsp_wait_q, (cb_txn->state == SMCINVOKE_REQ_PROCESSED) || (srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT)); + if (ret) + pr_err("%s wait_event interrupted: ret = %d\n", __func__, ret); out: /* * If we are here, either req is processed or not @@ -877,17 +898,19 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) * if not processed, we should set result with ret which should have * correct value that TZ/TA can understand */ + mutex_lock(&g_smcinvoke_lock); if (!cb_txn || (cb_txn->state != SMCINVOKE_REQ_PROCESSED)) { cb_req->result = ret; if (srvr_info && srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT && OBJECT_OP_METHODID(cb_req->hdr.op) == OBJECT_OP_RELEASE) { - mutex_lock(&g_smcinvoke_lock); release_tzhandle_locked(cb_req->hdr.tzhandle); - mutex_unlock(&g_smcinvoke_lock); } } - kfree(cb_txn); + hash_del(&cb_txn->hash); + memcpy(buf, cb_req, buf_len); + kref_put(&cb_txn->ref_cnt, delete_cb_txn); + mutex_unlock(&g_smcinvoke_lock); } static int marshal_out_invoke_req(const uint8_t *buf, uint32_t buf_size, @@ -1431,6 +1454,7 @@ static long process_accept_req(struct file *filp, unsigned int cmd, release_tzhandles(&cb_txn->cb_req->hdr.tzhandle, 1); cb_txn->state = SMCINVOKE_REQ_PROCESSED; + kref_put(&cb_txn->ref_cnt, delete_cb_txn); wake_up(&server_info->rsp_wait_q); /* * if marshal_out fails, we should let userspace release @@ -1447,7 +1471,8 @@ static long process_accept_req(struct file *filp, unsigned int cmd, ret = wait_event_interruptible(server_info->req_wait_q, !hash_empty(server_info->reqs_table)); if (ret) { - destroy_cb_server(server_obj->server_id); + pr_err("%s wait_event interrupted: ret = %d\n", + __func__, ret); goto out; } @@ -1463,12 +1488,14 @@ static long process_accept_req(struct file *filp, unsigned int cmd, if (ret) { cb_txn->cb_req->result = OBJECT_ERROR_UNAVAIL; cb_txn->state = SMCINVOKE_REQ_PROCESSED; + kref_put(&cb_txn->ref_cnt, delete_cb_txn); wake_up_interruptible(&server_info->rsp_wait_q); continue; } mutex_lock(&g_smcinvoke_lock); hash_add(server_info->responses_table, &cb_txn->hash, cb_txn->txn_id); + kref_put(&cb_txn->ref_cnt, delete_cb_txn); mutex_unlock(&g_smcinvoke_lock); ret = copy_to_user((void __user *)arg, &user_args, sizeof(struct smcinvoke_accept)); diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 788d16f59a6359038c266405241317293ea1406d..bfc4aad91f44011898632479ba4369fedf9264b0 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Sony Mobile Communications AB. - * Copyright (c) 2012-2013, 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2018-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -558,10 +558,80 @@ static int smp2p_parse_ipc(struct qcom_smp2p *smp2p) return 0; } -static int qcom_smp2p_probe(struct platform_device *pdev) +static int qcom_smp2p_alloc_item(struct platform_device *pdev, + struct qcom_smp2p *smp2p) { + int ret = 0; struct smp2p_entry *entry; struct device_node *node; + + ret = qcom_smp2p_alloc_outbound_item(smp2p); + if (ret < 0) + return ret; + + for_each_available_child_of_node(pdev->dev.of_node, node) { + entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->smp2p = smp2p; + spin_lock_init(&entry->lock); + + ret = of_property_read_string(node, "qcom,entry-name", + &entry->name); + if (ret < 0) + return ret; + + if (of_property_read_bool(node, "interrupt-controller")) { + ret = qcom_smp2p_inbound_entry(smp2p, entry, node); + if (ret < 0) + return ret; + + list_add(&entry->node, &smp2p->inbound); + } else { + ret = qcom_smp2p_outbound_entry(smp2p, entry, node); + if (ret < 0) + return ret; + + list_add(&entry->node, &smp2p->outbound); + } + } + wakeup_source_init(&smp2p->ws, "smp2p"); + + /* Kick the outgoing edge after allocating entries */ + qcom_smp2p_kick(smp2p); + + return ret; +} + +static void qcom_smp2p_release_item(struct device *dev, + struct qcom_smp2p *smp2p) +{ + struct smp2p_entry *entry; + struct smp2p_entry *next_entry; + + /* Walk through the out bound list and release state and entry */ + list_for_each_entry_safe(entry, next_entry, &smp2p->outbound, node) { + qcom_smem_state_unregister(entry->state); + list_del(&entry->node); + devm_kfree(smp2p->dev, entry); + } + INIT_LIST_HEAD(&smp2p->outbound); + + /* Walk through the inbound list and release domain and entry */ + list_for_each_entry_safe(entry, next_entry, &smp2p->inbound, node) { + irq_domain_remove(entry->domain); + list_del(&entry->node); + devm_kfree(smp2p->dev, entry); + } + INIT_LIST_HEAD(&smp2p->inbound); + /* remove wakeup source */ + wakeup_source_trash(&smp2p->ws); +} + +static int qcom_smp2p_probe(struct platform_device *pdev) +{ + struct smp2p_entry *entry; struct qcom_smp2p *smp2p; const char *key; int ret; @@ -619,42 +689,16 @@ static int qcom_smp2p_probe(struct platform_device *pdev) return ret; } - ret = qcom_smp2p_alloc_outbound_item(smp2p); - if (ret < 0) - goto release_mbox; - - for_each_available_child_of_node(pdev->dev.of_node, node) { - entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); - if (!entry) { - ret = -ENOMEM; - goto unwind_interfaces; - } - - entry->smp2p = smp2p; - spin_lock_init(&entry->lock); - - ret = of_property_read_string(node, "qcom,entry-name", &entry->name); - if (ret < 0) - goto unwind_interfaces; - - if (of_property_read_bool(node, "interrupt-controller")) { - ret = qcom_smp2p_inbound_entry(smp2p, entry, node); - if (ret < 0) - goto unwind_interfaces; - - list_add(&entry->node, &smp2p->inbound); - } else { - ret = qcom_smp2p_outbound_entry(smp2p, entry, node); - if (ret < 0) - goto unwind_interfaces; - - list_add(&entry->node, &smp2p->outbound); + ret = qcom_smp2p_alloc_item(pdev, smp2p); + if (ret < 0 && ret != -EEXIST) { + if (ret != -EPROBE_DEFER) { + dev_err(&pdev->dev, "failed to alloc outbound items\n"); + goto release_mbox; } + } else if (ret) { + dev_err(&pdev->dev, "failed to get smp2p entries\n"); + goto unwind_interfaces; } - wakeup_source_init(&smp2p->ws, "smp2p"); - - /* Kick the outgoing edge after allocating entries */ - qcom_smp2p_kick(smp2p); ret = devm_request_threaded_irq(&pdev->dev, smp2p->irq, qcom_smp2p_isr, qcom_smp2p_intr, @@ -701,6 +745,33 @@ static int qcom_smp2p_remove(struct platform_device *pdev) return 0; } +static int qcom_smp2p_resume(struct device *dev) +{ + int ret = 0; + struct qcom_smp2p *smp2p = dev_get_drvdata(dev); + struct platform_device *pdev = container_of(dev, struct + platform_device, dev); + + ret = qcom_smp2p_alloc_item(pdev, smp2p); + if (ret < 0 && ret != -EEXIST) + dev_err(dev, "failed to alloc items ret = %d\n", ret); + + return ret; +} + +static int qcom_smp2p_suspend(struct device *dev) +{ + struct qcom_smp2p *smp2p = dev_get_drvdata(dev); + + qcom_smp2p_release_item(dev, smp2p); + return 0; +} + +static const struct dev_pm_ops qcom_smp2p_pm_ops = { + .freeze = qcom_smp2p_suspend, + .restore = qcom_smp2p_resume, +}; + static const struct of_device_id qcom_smp2p_of_match[] = { { .compatible = "qcom,smp2p" }, {} @@ -713,6 +784,7 @@ static struct platform_driver qcom_smp2p_driver = { .driver = { .name = "qcom_smp2p", .of_match_table = qcom_smp2p_of_match, + .pm = &qcom_smp2p_pm_ops, }, }; module_platform_driver(qcom_smp2p_driver); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index f52fc070d56ca1de246622b6474efbd3c6cc5401..5c46e39510e43b945efb1517628a9ed8fed501ce 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -381,6 +381,12 @@ static struct msm_soc_info cpu_of_id[] = { /* qcs405 ID */ [352] = {MSM_CPU_QCS405, "QCS405"}, + /* qcs404 ID */ + [410] = {MSM_CPU_QCS404, "QCS404"}, + + /* qcs407 ID */ + [411] = {MSM_CPU_QCS407, "QCS407"}, + /* qcs403 ID */ [373] = {MSM_CPU_QCS403, "QCS403"}, @@ -1355,6 +1361,14 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 372; strlcpy(dummy_socinfo.build_id, "qcs401 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_qcs404()) { + dummy_socinfo.id = 410; + strlcpy(dummy_socinfo.build_id, "qcs404 - ", + sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_qcs407()) { + dummy_socinfo.id = 411; + strlcpy(dummy_socinfo.build_id, "qcs407 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_sdxprairie()) { dummy_socinfo.id = 357; strlcpy(dummy_socinfo.build_id, "sdxprairie - ", diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 723ca904ae9ad2c836ac082806a14e87063ac85c..3306cc12f7a4ed049f23addcfce7ce4c0aa2f78d 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -1684,7 +1684,7 @@ static int spcom_create_channel_chardev(const char *name) ch = spcom_find_channel_by_name(name); if (ch) { pr_err("channel [%s] already exist.\n", name); - return -EINVAL; + return -EBUSY; } ch = spcom_find_channel_by_name(""); /* find reserved channel */ diff --git a/drivers/soc/qcom/subsystem_notif_virt.c b/drivers/soc/qcom/subsystem_notif_virt.c new file mode 100644 index 0000000000000000000000000000000000000000..99ad947446532473846bdf40be784e3fdaa4270d --- /dev/null +++ b/drivers/soc/qcom/subsystem_notif_virt.c @@ -0,0 +1,251 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include + +#define CLIENT_STATE_OFFSET 4 +#define SUBSYS_STATE_OFFSET 8 + +static void __iomem *base_reg; + +enum subsystem_type { + VIRTUAL, + NATIVE, +}; + +struct subsystem_descriptor { + const char *name; + u32 offset; + enum subsystem_type type; + struct notifier_block nb; + void *handle; + int ssr_irq; + struct list_head subsystem_list; + struct work_struct work; +}; + +static LIST_HEAD(subsystem_descriptor_list); +static struct workqueue_struct *ssr_wq; + +static void subsystem_notif_wq_func(struct work_struct *work) +{ + struct subsystem_descriptor *subsystem = + container_of(work, struct subsystem_descriptor, work); + void *subsystem_handle; + int state, ret; + + state = readl_relaxed(base_reg + subsystem->offset); + subsystem_handle = subsys_notif_add_subsys(subsystem->name); + ret = subsys_notif_queue_notification(subsystem_handle, state, NULL); + writel_relaxed(ret, base_reg + subsystem->offset + CLIENT_STATE_OFFSET); +} + +static int subsystem_state_callback(struct notifier_block *this, + unsigned long value, void *priv) +{ + struct subsystem_descriptor *subsystem = + container_of(this, struct subsystem_descriptor, nb); + + writel_relaxed(value, base_reg + subsystem->offset + + SUBSYS_STATE_OFFSET); + + return NOTIFY_OK; +} + +static irqreturn_t subsystem_restart_irq_handler(int irq, void *dev_id) +{ + struct subsystem_descriptor *subsystem = dev_id; + + queue_work(ssr_wq, &subsystem->work); + + return IRQ_HANDLED; +} + +static int get_resources(struct platform_device *pdev) +{ + struct device_node *node; + struct device_node *child = NULL; + const char *ss_type; + struct resource *res; + struct subsystem_descriptor *subsystem = NULL; + int ret = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vdev_base"); + base_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR_OR_NULL(base_reg)) { + dev_err(&pdev->dev, "Memory mapping failed\n"); + return -ENOMEM; + } + + node = pdev->dev.of_node; + for_each_child_of_node(node, child) { + + subsystem = devm_kmalloc(&pdev->dev, + sizeof(struct subsystem_descriptor), + GFP_KERNEL); + if (!subsystem) + return -ENOMEM; + + subsystem->name = + of_get_property(child, "subsys-name", NULL); + if (IS_ERR_OR_NULL(subsystem->name)) { + dev_err(&pdev->dev, "Could not find subsystem name\n"); + return -EINVAL; + } + + ret = of_property_read_u32(child, "offset", + &subsystem->offset); + if (ret) { + dev_err(&pdev->dev, "offset reading for %s failed\n", + subsystem->name); + return -EINVAL; + } + + ret = of_property_read_string(child, "type", + &ss_type); + if (ret) { + dev_err(&pdev->dev, "type reading for %s failed\n", + subsystem->name); + return -EINVAL; + } + + if (!strcmp(ss_type, "virtual")) + subsystem->type = VIRTUAL; + + if (!strcmp(ss_type, "native")) + subsystem->type = NATIVE; + + switch (subsystem->type) { + case NATIVE: + subsystem->nb.notifier_call = + subsystem_state_callback; + + subsystem->handle = + subsys_notif_register_notifier( + subsystem->name, &subsystem->nb); + if (IS_ERR_OR_NULL(subsystem->handle)) { + dev_err(&pdev->dev, + "Could not register SSR notifier cb\n"); + return -EINVAL; + } + list_add_tail(&subsystem->subsystem_list, + &subsystem_descriptor_list); + break; + case VIRTUAL: + subsystem->ssr_irq = + of_irq_get_byname(child, "state-irq"); + if (subsystem->ssr_irq < 0) { + dev_err(&pdev->dev, "Could not find IRQ\n"); + return -EINVAL; + } + ret = devm_request_threaded_irq(&pdev->dev, + subsystem->ssr_irq, NULL, + subsystem_restart_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + subsystem->name, subsystem); + INIT_WORK(&subsystem->work, subsystem_notif_wq_func); + break; + default: + dev_err(&pdev->dev, "Unsupported type %d\n", + subsystem->type); + } + } + + return 0; +} + +static void release_resources(void) +{ + struct subsystem_descriptor *subsystem, *node; + + list_for_each_entry_safe(subsystem, node, &subsystem_descriptor_list, + subsystem_list) { + subsys_notif_unregister_notifier(subsystem->handle, + &subsystem->nb); + list_del(&subsystem->subsystem_list); + } +} + +static int subsys_notif_virt_probe(struct platform_device *pdev) +{ + int ret = 0; + + if (!pdev) { + dev_err(&pdev->dev, "pdev is NULL\n"); + return -EINVAL; + } + + ssr_wq = create_singlethread_workqueue("ssr_wq"); + if (!ssr_wq) { + dev_err(&pdev->dev, "Workqueue creation failed\n"); + return -ENOMEM; + } + + ret = get_resources(pdev); + if (ret) + destroy_workqueue(ssr_wq); + + return ret; +} + +static int subsys_notif_virt_remove(struct platform_device *pdev) +{ + destroy_workqueue(ssr_wq); + release_resources(); + + return 0; +} + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,subsys-notif-virt" }, + {}, +}; + +static struct platform_driver subsys_notif_virt_driver = { + .probe = subsys_notif_virt_probe, + .remove = subsys_notif_virt_remove, + .driver = { + .name = "subsys_notif_virt", + .owner = THIS_MODULE, + .of_match_table = match_table, + }, +}; + +static int __init subsys_notif_virt_init(void) +{ + return platform_driver_register(&subsys_notif_virt_driver); +} +module_init(subsys_notif_virt_init); + +static void __exit subsys_notif_virt_exit(void) +{ + platform_driver_unregister(&subsys_notif_virt_driver); +} +module_exit(subsys_notif_virt_exit); + +MODULE_DESCRIPTION("Subsystem Notification Virtual Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index 7a48f8386f0d387c5cefab2b5afb7850324da77a..e0f768cf14b240ac0d2fd8fc430ad0c4a9062bad 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -922,8 +922,7 @@ static int msm_watchdog_probe(struct platform_device *pdev) } static const struct dev_pm_ops msm_watchdog_dev_pm_ops = { - .suspend_noirq = msm_watchdog_suspend, - .resume_noirq = msm_watchdog_resume, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(msm_watchdog_suspend, msm_watchdog_resume) }; static struct platform_driver msm_watchdog_driver = { diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 7e9ef3431bea4adc6487f4982dd15f93a85025f1..2422ed56895afca583a82e94b92be38a4f5d15c5 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -521,16 +521,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off); */ int tegra_powergate_is_powered(unsigned int id) { - int status; - if (!tegra_powergate_is_valid(id)) return -EINVAL; - mutex_lock(&pmc->powergates_lock); - status = tegra_powergate_state(id); - mutex_unlock(&pmc->powergates_lock); - - return status; + return tegra_powergate_state(id); } /** diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index 711d5f6067b2475436ad32c117fb01acb06a5e8d..a7e909ca2b7d244d0de6a2d95ff2bc5d580b2efc 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -34,6 +34,16 @@ config SPMI_MSM_PMIC_ARB_DEBUG Inc. (QTI) MSM family processors. This feature is available on chips with PMIC arbiter version 5 and above. +config VIOSPMI_MSM_PMIC_ARB + tristate "QTI Virtio SPMI Controller (Virtio PMIC Arbiter)" + select IRQ_DOMAIN + depends on ARCH_QCOM || COMPILE_TEST + depends on HAS_IOMEM + depends on VIRTIO + default ARCH_QCOM + help + This is virtio SPMI frontend driver for QTI MSM virtual platform. + source "drivers/spmi/simulator/Kconfig" endif diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile index cd050b7cc64357d0d0224cd7977d96918809dd11..d2e979dcfb7fb3b4bd63932b479ae9dd50dda6a2 100644 --- a/drivers/spmi/Makefile +++ b/drivers/spmi/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_SPMI) += spmi.o obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o obj-$(CONFIG_SPMI_MSM_PMIC_ARB_DEBUG) += spmi-pmic-arb-debug.o +obj-$(CONFIG_VIOSPMI_MSM_PMIC_ARB) += viospmi-pmic-arb.o obj-y += simulator/ diff --git a/drivers/spmi/viospmi-pmic-arb.c b/drivers/spmi/viospmi-pmic-arb.c new file mode 100644 index 0000000000000000000000000000000000000000..de5230728f30733a29af59be650ddfa2c07f1ef0 --- /dev/null +++ b/drivers/spmi/viospmi-pmic-arb.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Mapping Table */ +#define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ +#define PMIC_ARB_APID_VALID BIT(15) +#define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(24)) +#define INVALID_EE 0xFF + +/* Command Opcodes */ +enum pmic_arb_cmd_op_code { + PMIC_ARB_OP_EXT_WRITEL = 0, + PMIC_ARB_OP_EXT_READL = 1, + PMIC_ARB_OP_EXT_WRITE = 2, + PMIC_ARB_OP_RESET = 3, + PMIC_ARB_OP_SLEEP = 4, + PMIC_ARB_OP_SHUTDOWN = 5, + PMIC_ARB_OP_WAKEUP = 6, + PMIC_ARB_OP_AUTHENTICATE = 7, + PMIC_ARB_OP_MSTR_READ = 8, + PMIC_ARB_OP_MSTR_WRITE = 9, + PMIC_ARB_OP_EXT_READ = 13, + PMIC_ARB_OP_WRITE = 14, + PMIC_ARB_OP_READ = 15, + PMIC_ARB_OP_ZERO_WRITE = 16, +}; + +/* Maximum number of support PMIC peripherals */ +#define PMIC_ARB_MAX_PERIPHS 512 +#define PMIC_ARB_MAX_TRANS_BYTES (8) + +#define PMIC_ARB_APID_MASK 0xFF +#define PMIC_ARB_PPID_MASK 0xFFF + +/* interrupt enable bit */ +#define SPMI_PIC_ACC_ENABLE_BIT BIT(0) + +#define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ + ((((slave_id) & 0xF) << 28) | \ + (((periph_id) & 0xFF) << 20) | \ + (((irq_id) & 0x7) << 16) | \ + (((apid) & 0x1FF) << 0)) + +#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) +#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) +#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) +#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF) + +struct pmic_arb_ver_ops; + +struct apid_data { + u16 ppid; + u8 write_ee; + u8 irq_ee; +}; + +struct virtio_spmi { + struct virtio_device *vdev; + struct virtqueue *vq; + spinlock_t lock; + struct virtio_spmi_config config; + struct spmi_pmic_arb *pa; +}; +static struct virtio_spmi *g_vspmi; + +/** + * spmi_pmic_arb - SPMI PMIC Arbiter object + * + * @irq: PMIC ARB interrupt. + * @ee: the current Execution Environment + * @min_apid: minimum APID (used for bounding IRQ search) + * @max_apid: maximum APID + * @domain: irq domain object for PMIC IRQ domain + * @spmic: SPMI controller object + * @ver_ops: version dependent operations. + * @ppid_to_apid in-memory copy of PPID -> APID mapping table. + */ +struct spmi_pmic_arb { + int irq; + u8 ee; + u16 min_apid; + u16 max_apid; + struct irq_domain *domain; + struct spmi_controller *spmic; + const struct pmic_arb_ver_ops *ver_ops; + u16 *ppid_to_apid; + struct apid_data apid_data[PMIC_ARB_MAX_PERIPHS]; +}; + +/** + * pmic_arb_ver: version dependent functionality. + * + * @ver_str: version string. + * @ppid_to_apid: finds the apid for a given ppid. + * @fmt_cmd: formats a GENI/SPMI command. + */ +struct pmic_arb_ver_ops { + const char *ver_str; + int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u16 ppid); + u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); +}; + +static int +vspmi_pmic_arb_xfer(struct spmi_pmic_arb *pa, struct virtio_spmi_msg *req) +{ + struct scatterlist sg[1]; + struct virtio_spmi_msg *rsp; + unsigned int vqlen; + int rc = 0; + unsigned long flags; + + sg_init_one(sg, req, virtio32_to_cpu(g_vspmi->vdev, req->len)); + + spin_lock_irqsave(&g_vspmi->lock, flags); + rc = virtqueue_add_outbuf(g_vspmi->vq, sg, 1, req, GFP_ATOMIC); + if (rc) { + dev_err(&g_vspmi->vdev->dev, "fail to add output buffer\n"); + goto out; + } + + virtqueue_kick(g_vspmi->vq); + + do { + rsp = virtqueue_get_buf(g_vspmi->vq, &vqlen); + } while (!rsp); + rc = virtio32_to_cpu(g_vspmi->vdev, rsp->res); + +out: + spin_unlock_irqrestore(&g_vspmi->lock, flags); + return rc; +} + +static struct virtio_spmi_msg *vspmi_init_msg(u32 len, u32 type, u32 u) +{ + struct virtio_spmi_msg *req = NULL; + + req = kzalloc(len, GFP_ATOMIC); + if (req) { + req->len = cpu_to_virtio32(g_vspmi->vdev, len); + req->type = cpu_to_virtio32(g_vspmi->vdev, type); + req->u.cnt = req->u.cmd = cpu_to_virtio32(g_vspmi->vdev, u); + } else { + dev_err(&g_vspmi->vdev->dev, "no atomic mem\n"); + } + + dev_dbg(&g_vspmi->vdev->dev, "len:%u type:%u u:%x\n", len, type, u); + return req; +} + +static void +vspmi_fill_one(struct virtio_spmi_msg *req, u32 ppid, u32 val) +{ + u32 idx = virtio32_to_cpu(g_vspmi->vdev, req->u.cnt); + u32 type = virtio32_to_cpu(g_vspmi->vdev, req->type); + + req->payload[idx].irqd.ppid = + cpu_to_virtio32(g_vspmi->vdev, ppid); + if ((type == VIO_IRQ_CLEAR) || (type == VIO_ACC_ENABLE_WR)) + req->payload[idx].irqd.val = + cpu_to_virtio32(g_vspmi->vdev, val); + + dev_dbg(&g_vspmi->vdev->dev, "spmi: cnt:%u ppid:%u val:%u\n", idx, + virtio32_to_cpu(g_vspmi->vdev, req->payload[idx].irqd.ppid), + virtio32_to_cpu(g_vspmi->vdev, req->payload[idx].irqd.val)); + + req->u.cnt = cpu_to_virtio32(g_vspmi->vdev, (idx + 1)); +} + +static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, + u16 addr, u8 *buf, size_t len) +{ + struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); + struct virtio_spmi_msg *req; + u8 bc = len - 1; + u32 data, cmd; + int rc; + + if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { + dev_err(&ctrl->dev, + "pmic-arb supports 1..%d bytes per trans, but:%zu requested", + PMIC_ARB_MAX_TRANS_BYTES, len); + return -EINVAL; + } + + /* Check the opcode */ + if (opc >= 0x60 && opc <= 0x7F) + opc = PMIC_ARB_OP_READ; + else if (opc >= 0x20 && opc <= 0x2F) + opc = PMIC_ARB_OP_EXT_READ; + else if (opc >= 0x38 && opc <= 0x3F) + opc = PMIC_ARB_OP_EXT_READL; + else + return -EINVAL; + + cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc); + + req = vspmi_init_msg(MSG_SZ(1), VIO_SPMI_BUS_READ, cmd); + if (!req) + return -ENOMEM; + + rc = vspmi_pmic_arb_xfer(pa, req); + if (rc) + goto out; + + data = virtio32_to_cpu(g_vspmi->vdev, + req->payload[0].cmdd.data[0]); + memcpy(buf, &data, (bc & 3) + 1); + + if (bc > 3) { + data = virtio32_to_cpu(g_vspmi->vdev, + req->payload[0].cmdd.data[1]); + memcpy((buf + 4), &data, ((bc - 4) & 3) + 1); + } + +out: + kfree(req); + return rc; +} + +static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, + u8 sid, u16 addr, const u8 *buf, size_t len) +{ + struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); + struct virtio_spmi_msg *req; + u8 bc = len - 1; + u32 data, cmd; + int rc; + + if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { + dev_err(&ctrl->dev, + "pmic-arb supports 1..%d bytes per trans, but:%zu requested", + PMIC_ARB_MAX_TRANS_BYTES, len); + return -EINVAL; + } + + /* Check the opcode */ + if (opc >= 0x40 && opc <= 0x5F) + opc = PMIC_ARB_OP_WRITE; + else if (opc <= 0x0F) + opc = PMIC_ARB_OP_EXT_WRITE; + else if (opc >= 0x30 && opc <= 0x37) + opc = PMIC_ARB_OP_EXT_WRITEL; + else if (opc >= 0x80) + opc = PMIC_ARB_OP_ZERO_WRITE; + else + return -EINVAL; + + cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc); + + req = vspmi_init_msg(MSG_SZ(1), VIO_SPMI_BUS_WRITE, cmd); + if (!req) + return -ENOMEM; + + memcpy(&data, buf, (bc & 3) + 1); + req->payload[0].cmdd.data[0] = cpu_to_virtio32(g_vspmi->vdev, data); + if (bc > 3) { + memcpy(&data, (buf + 4), ((bc - 4) & 3) + 1); + req->payload[0].cmdd.data[1] = + cpu_to_virtio32(g_vspmi->vdev, data); + } + + rc = vspmi_pmic_arb_xfer(pa, req); + + kfree(req); + return rc; +} + +enum qpnpint_regs { + QPNPINT_REG_RT_STS = 0x10, + QPNPINT_REG_SET_TYPE = 0x11, + QPNPINT_REG_POLARITY_HIGH = 0x12, + QPNPINT_REG_POLARITY_LOW = 0x13, + QPNPINT_REG_LATCHED_CLR = 0x14, + QPNPINT_REG_EN_SET = 0x15, + QPNPINT_REG_EN_CLR = 0x16, + QPNPINT_REG_LATCHED_STS = 0x18, +}; + +struct spmi_pmic_arb_qpnpint_type { + u8 type; /* 1 -> edge */ + u8 polarity_high; + u8 polarity_low; +} __packed; + +/* Simplified accessor functions for irqchip callbacks */ +static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf, + size_t len) +{ + struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); + u8 sid = hwirq_to_sid(d->hwirq); + u8 per = hwirq_to_per(d->hwirq); + + if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid, + (per << 8) + reg, buf, len)) + dev_err_ratelimited(&pa->spmic->dev, + "failed irqchip transaction on %x\n", d->irq); +} + +static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len) +{ + struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); + u8 sid = hwirq_to_sid(d->hwirq); + u8 per = hwirq_to_per(d->hwirq); + + if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid, + (per << 8) + reg, buf, len)) + dev_err_ratelimited(&pa->spmic->dev, + "failed irqchip transaction on %x\n", d->irq); +} + +static void cleanup_irq(struct spmi_pmic_arb *pa, u16 apid, int id) +{ + u16 ppid = pa->apid_data[apid].ppid; + u8 sid = ppid >> 8; + u8 per = ppid & 0xFF; + u8 irq_mask = BIT(id); + + struct virtio_spmi_msg *req; + + req = vspmi_init_msg(MSG_SZ(1), VIO_IRQ_CLEAR, 0); + if (req) { + dev_err_ratelimited(&pa->spmic->dev, + "%s apid=%d sid=0x%x per=0x%x irq=%d\n", + __func__, apid, sid, per, id); + + vspmi_fill_one(req, ppid, irq_mask); + vspmi_pmic_arb_xfer(pa, req); + kfree(req); + } +} + +static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid) +{ + unsigned int irq; + u32 status, id; + u8 sid = (pa->apid_data[apid].ppid >> 8) & 0xF; + u8 per = pa->apid_data[apid].ppid & 0xFF; + + struct virtio_spmi_msg *req; + + req = vspmi_init_msg(MSG_SZ(1), VIO_IRQ_STATUS, 0); + if (!req) + return; + + vspmi_fill_one(req, pa->apid_data[apid].ppid, 0); + if (vspmi_pmic_arb_xfer(pa, req)) { + kfree(req); + return; + } + + status = virtio32_to_cpu(g_vspmi->vdev, + req->payload[0].irqd.val); + kfree(req); + + while (status) { + id = ffs(status) - 1; + status &= ~BIT(id); + irq = irq_find_mapping(pa->domain, + spec_to_hwirq(sid, per, id, apid)); + if (irq == 0) { + cleanup_irq(pa, apid, id); + continue; + } + generic_handle_irq(irq); + } +} + +static void pmic_arb_chained_irq(struct irq_desc *desc) +{ + struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + + u32 enable; + int i; + u16 ppid; + + struct virtio_spmi_msg *req; + u32 *irq_status; + + irq_status = kzalloc((pa->max_apid + 1) * sizeof(u32), GFP_ATOMIC); + if (!irq_status) + return; + + chained_irq_enter(chip, desc); + + /* get all irq_status */ + req = vspmi_init_msg(MSG_SZ(pa->max_apid + 1), VIO_IRQ_STATUS, 0); + if (req) { + for (i = pa->min_apid; i <= pa->max_apid; i++) { + ppid = pa->apid_data[i].ppid; + vspmi_fill_one(req, ppid, 0); + } + } else + goto out; + + if (vspmi_pmic_arb_xfer(pa, req)) { + kfree(req); + goto out; + } + + for (i = pa->min_apid; i <= pa->max_apid; i++) + irq_status[i] = virtio32_to_cpu(g_vspmi->vdev, + req->payload[i].irqd.val); + kfree(req); + + /* ACC_STATUS is empty but IRQ fired check IRQ_STATUS */ + for (i = pa->min_apid; i <= pa->max_apid; i++) { + ppid = pa->apid_data[i].ppid; + + if (irq_status[i]) { + req = vspmi_init_msg(MSG_SZ(1), VIO_ACC_ENABLE_RD, 0); + if (!req) + goto out; + + vspmi_fill_one(req, ppid, 0); + if (vspmi_pmic_arb_xfer(pa, req)) + goto out; + + enable = virtio32_to_cpu(g_vspmi->vdev, + req->payload[0].irqd.val); + kfree(req); + + if (enable & SPMI_PIC_ACC_ENABLE_BIT) { + dev_dbg(&pa->spmic->dev, + "Dispatching IRQ for apid=%d status=%x\n", + i, irq_status[i]); + periph_interrupt(pa, i); + } + } + } + +out: + chained_irq_exit(chip, desc); + kfree(irq_status); +} + +static void qpnpint_irq_ack(struct irq_data *d) +{ + struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); + u8 irq = hwirq_to_irq(d->hwirq); + u16 apid = hwirq_to_apid(d->hwirq); + u16 ppid = pa->apid_data[apid].ppid; + u8 data; + + struct virtio_spmi_msg *req; + + req = vspmi_init_msg(MSG_SZ(1), VIO_IRQ_CLEAR, 0); + if (req) { + vspmi_fill_one(req, ppid, BIT(irq)); + vspmi_pmic_arb_xfer(pa, req); + kfree(req); + } else + return; + + data = BIT(irq); + qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1); +} + +static void qpnpint_irq_mask(struct irq_data *d) +{ + u8 irq = hwirq_to_irq(d->hwirq); + u8 data = BIT(irq); + + qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1); +} + +static void qpnpint_irq_unmask(struct irq_data *d) +{ + struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); + u8 irq = hwirq_to_irq(d->hwirq); + u16 apid = hwirq_to_apid(d->hwirq); + u16 ppid = pa->apid_data[apid].ppid; + u8 buf[2]; + + struct virtio_spmi_msg *req; + + req = vspmi_init_msg(MSG_SZ(1), VIO_ACC_ENABLE_WR, 0); + if (req) { + vspmi_fill_one(req, ppid, SPMI_PIC_ACC_ENABLE_BIT); + vspmi_pmic_arb_xfer(pa, req); + kfree(req); + } else + return; + + qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1); + if (!(buf[0] & BIT(irq))) { + /* + * Since the interrupt is currently disabled, write to both the + * LATCHED_CLR and EN_SET registers so that a spurious interrupt + * cannot be triggered when the interrupt is enabled + */ + buf[0] = BIT(irq); + buf[1] = BIT(irq); + qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 2); + } +} + +static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) +{ + struct spmi_pmic_arb_qpnpint_type type; + irq_flow_handler_t flow_handler; + u8 irq = hwirq_to_irq(d->hwirq); + + qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); + + if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + type.type |= BIT(irq); + if (flow_type & IRQF_TRIGGER_RISING) + type.polarity_high |= BIT(irq); + else + type.polarity_high &= ~BIT(irq); + if (flow_type & IRQF_TRIGGER_FALLING) + type.polarity_low |= BIT(irq); + else + type.polarity_low &= ~BIT(irq); + + flow_handler = handle_edge_irq; + } else { + if ((flow_type & (IRQF_TRIGGER_HIGH)) && + (flow_type & (IRQF_TRIGGER_LOW))) + return -EINVAL; + + type.type &= ~BIT(irq); /* level trig */ + if (flow_type & IRQF_TRIGGER_HIGH) { + type.polarity_high |= BIT(irq); + type.polarity_low &= ~BIT(irq); + } else { + type.polarity_low |= BIT(irq); + type.polarity_high &= ~BIT(irq); + } + + flow_handler = handle_level_irq; + } + + qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); + irq_set_handler_locked(d, flow_handler); + + return 0; +} + +static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); + + return irq_set_irq_wake(pa->irq, on); +} + +static int qpnpint_get_irqchip_state(struct irq_data *d, + enum irqchip_irq_state which, + bool *state) +{ + u8 irq = hwirq_to_irq(d->hwirq); + u8 status = 0; + + if (which != IRQCHIP_STATE_LINE_LEVEL) + return -EINVAL; + + qpnpint_spmi_read(d, QPNPINT_REG_RT_STS, &status, 1); + *state = !!(status & BIT(irq)); + + return 0; +} + +static int qpnpint_irq_request_resources(struct irq_data *d) +{ + struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); + u16 periph = hwirq_to_per(d->hwirq); + u16 apid = hwirq_to_apid(d->hwirq); + u16 sid = hwirq_to_sid(d->hwirq); + u16 irq = hwirq_to_irq(d->hwirq); + + if (pa->apid_data[apid].irq_ee != pa->ee) { + dev_err(&pa->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", + sid, periph, irq, pa->ee, + pa->apid_data[apid].irq_ee); + return -ENODEV; + } + + return 0; +} + +static struct irq_chip pmic_arb_irqchip = { + .name = "pmic_arb", + .irq_ack = qpnpint_irq_ack, + .irq_mask = qpnpint_irq_mask, + .irq_unmask = qpnpint_irq_unmask, + .irq_set_type = qpnpint_irq_set_type, + .irq_set_wake = qpnpint_irq_set_wake, + .irq_get_irqchip_state = qpnpint_get_irqchip_state, + .irq_request_resources = qpnpint_irq_request_resources, + .flags = IRQCHIP_MASK_ON_SUSPEND, +}; + +static void qpnpint_irq_domain_activate(struct irq_domain *domain, + struct irq_data *d) +{ + u8 irq = hwirq_to_irq(d->hwirq); + u8 buf; + + buf = BIT(irq); + qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &buf, 1); + qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 1); +} + +static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct spmi_pmic_arb *pa = d->host_data; + u16 apid, ppid; + int rc; + + dev_dbg(&pa->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", + intspec[0], intspec[1], intspec[2]); + + if (irq_domain_get_of_node(d) != controller) + return -EINVAL; + if (intsize != 4) + return -EINVAL; + if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) + return -EINVAL; + + ppid = intspec[0] << 8 | intspec[1]; + rc = pa->ver_ops->ppid_to_apid(pa, ppid); + if (rc < 0) { + dev_err(&pa->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n", + intspec[0], intspec[1], intspec[2], rc); + return rc; + } + + apid = rc; + /* Keep track of {max,min}_apid for bounding search during interrupt */ + if (apid > pa->max_apid) + pa->max_apid = apid; + if (apid < pa->min_apid) + pa->min_apid = apid; + + *out_hwirq = spec_to_hwirq(intspec[0], intspec[1], intspec[2], apid); + *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; + + dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq); + + return 0; +} + +static int qpnpint_irq_domain_map(struct irq_domain *d, + unsigned int virq, + irq_hw_number_t hwirq) +{ + struct spmi_pmic_arb *pa = d->host_data; + + dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq); + + irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq); + irq_set_chip_data(virq, d->host_data); + irq_set_noprobe(virq); + return 0; +} + +static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pa) +{ + struct apid_data *apidd = pa->apid_data; + u16 apid, ppid; + u16 i; + + for (i = 0; i < VM_MAX_PERIPHS; i++) { + ppid = g_vspmi->config.ppid_allowed[i]; + if (!ppid) + break; + + apid = i; + pa->ppid_to_apid[ppid] = apid | PMIC_ARB_APID_VALID; + pa->apid_data[apid].ppid = ppid; + pa->apid_data[apid].irq_ee = 0; + pa->apid_data[apid].write_ee = 0; + } + + /* Dump the mapping table for debug purposes. */ + dev_dbg(&pa->spmic->dev, "PPID APID Write-EE IRQ-EE\n"); + for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { + apid = pa->ppid_to_apid[ppid]; + if (apid & PMIC_ARB_APID_VALID) { + apid &= ~PMIC_ARB_APID_VALID; + apidd = &pa->apid_data[apid]; + dev_dbg(&pa->spmic->dev, "%#03X %3u %2u %2u\n", + ppid, apid, apidd->write_ee, apidd->irq_ee); + } + } + + return 0; +} + +static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pa, u16 ppid) +{ + if (!(pa->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID)) + return -ENODEV; + + return pa->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; +} + +static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) +{ + return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); +} + +static const struct pmic_arb_ver_ops pmic_arb_v5 = { + .ver_str = "v5", + .ppid_to_apid = pmic_arb_ppid_to_apid_v5, + .fmt_cmd = pmic_arb_fmt_cmd_v1, +}; + +static const struct irq_domain_ops pmic_arb_irq_domain_ops = { + .map = qpnpint_irq_domain_map, + .xlate = qpnpint_irq_domain_dt_translate, + .activate = qpnpint_irq_domain_activate, +}; + +static int spmi_pmic_arb_probe(struct platform_device *pdev) +{ + struct spmi_pmic_arb *pa; + struct spmi_controller *ctrl; + int err; + u32 ee; + + if (!g_vspmi) + return -EINVAL; + + ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa)); + if (!ctrl) + return -ENOMEM; + + pa = spmi_controller_get_drvdata(ctrl); + pa->spmic = ctrl; + g_vspmi->pa = pa; + + pa->ver_ops = &pmic_arb_v5; + dev_info(&ctrl->dev, "Virtio PMIC arbiter\n"); + + pa->irq = platform_get_irq_byname(pdev, "periph_irq"); + if (pa->irq < 0) { + err = pa->irq; + goto err_put_ctrl; + } + + err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee); + if (err) { + dev_err(&pdev->dev, "EE unspecified.\n"); + goto err_put_ctrl; + } + pa->ee = ee; + + pa->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, + sizeof(*pa->ppid_to_apid), + GFP_KERNEL); + if (!pa->ppid_to_apid) { + err = -ENOMEM; + goto err_put_ctrl; + } + + /* Initialize max_apid/min_apid to the opposite bounds, during + * the irq domain translation, we are sure to update these + */ + pa->max_apid = 0; + pa->min_apid = PMIC_ARB_MAX_PERIPHS - 1; + + platform_set_drvdata(pdev, ctrl); + + ctrl->read_cmd = pmic_arb_read_cmd; + ctrl->write_cmd = pmic_arb_write_cmd; + + err = pmic_arb_read_apid_map_v5(pa); + if (err) { + dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n", + err); + goto err_put_ctrl; + } + + dev_dbg(&pdev->dev, "adding irq domain\n"); + pa->domain = irq_domain_add_tree(pdev->dev.of_node, + &pmic_arb_irq_domain_ops, pa); + if (!pa->domain) { + dev_err(&pdev->dev, "unable to create irq_domain\n"); + err = -ENOMEM; + goto err_put_ctrl; + } + + irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa); + err = spmi_controller_add(ctrl); + if (err) + goto err_domain_remove; + + return 0; + +err_domain_remove: + irq_set_chained_handler_and_data(pa->irq, NULL, NULL); + irq_domain_remove(pa->domain); +err_put_ctrl: + spmi_controller_put(ctrl); + return err; +} + +static int spmi_pmic_arb_remove(struct platform_device *pdev) +{ + struct spmi_controller *ctrl = platform_get_drvdata(pdev); + struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); + + spmi_controller_remove(ctrl); + irq_set_chained_handler_and_data(pa->irq, NULL, NULL); + irq_domain_remove(pa->domain); + spmi_controller_put(ctrl); + return 0; +} + +static const struct of_device_id spmi_pmic_arb_match_table[] = { + { .compatible = "qcom,viospmi-pmic-arb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); + +static struct platform_driver spmi_pmic_arb_driver = { + .probe = spmi_pmic_arb_probe, + .remove = spmi_pmic_arb_remove, + .driver = { + .name = "viospmi_pmic_arb", + .of_match_table = spmi_pmic_arb_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +static void virtio_spmi_isr(struct virtqueue *vq) { } + +static int virtio_spmi_init_vqs(struct virtio_spmi *vspmi) +{ + struct virtqueue *vqs[1]; + vq_callback_t *cbs[] = { virtio_spmi_isr }; + static const char * const names[] = { "virtio_spmi_isr" }; + int rc; + + rc = virtio_find_vqs(vspmi->vdev, 1, vqs, cbs, names, NULL); + if (rc) + return rc; + + vspmi->vq = vqs[0]; + + return 0; +} + +static void virtio_spmi_del_vqs(struct virtio_spmi *vspmi) +{ + vspmi->vdev->config->del_vqs(vspmi->vdev); +} + +static int virtio_spmi_probe(struct virtio_device *vdev) +{ + struct virtio_spmi *vspmi; + int i; + int ret = 0; + u32 val; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + vspmi = devm_kzalloc(&vdev->dev, sizeof(*vspmi), GFP_KERNEL); + if (!vspmi) + return -ENOMEM; + + vdev->priv = vspmi; + vspmi->vdev = vdev; + spin_lock_init(&vspmi->lock); + + ret = virtio_spmi_init_vqs(vspmi); + if (ret) + goto err_init_vq; + + virtio_device_ready(vdev); + + memset(&vspmi->config, 0x0, sizeof(vspmi->config)); + + for (i = 0; i < VM_MAX_PERIPHS; i += 2) { + val = virtio_cread32(vdev, + offsetof(struct virtio_spmi_config, ppid_allowed[i])); + vspmi->config.ppid_allowed[i] = val & PMIC_ARB_PPID_MASK; + vspmi->config.ppid_allowed[i + 1] = + (val >> 16) & PMIC_ARB_PPID_MASK; + if ((!vspmi->config.ppid_allowed[i]) || + !(vspmi->config.ppid_allowed[i + 1])) + break; + } + + g_vspmi = vspmi; + + return platform_driver_register(&spmi_pmic_arb_driver); + +err_init_vq: + virtio_spmi_del_vqs(vspmi); + devm_kfree(&vdev->dev, vspmi); + return ret; +} + +static void virtio_spmi_remove(struct virtio_device *vdev) +{ + struct virtio_spmi *vspmi = vdev->priv; + + vdev->config->reset(vdev); + vdev->config->del_vqs(vdev); + devm_kfree(&vdev->dev, vspmi); + g_vspmi = NULL; +} + +static unsigned int features[] = { + VIRTIO_SPMI_F_INT, +}; + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_SPMI, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtio_spmi_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_spmi_probe, + .remove = virtio_spmi_remove, +}; + +static int __init virtio_spmi_init(void) +{ + return register_virtio_driver(&virtio_spmi_driver); +} + +static void __exit virtio_spmi_exit(void) +{ + unregister_virtio_driver(&virtio_spmi_driver); +} + +subsys_initcall(virtio_spmi_init); +module_exit(virtio_spmi_exit); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("virtio spmi_pmic_arb frontend driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index e196bdba0dc6643e9d6e730d903d043575364647..5c7fb1b802ccc29bf74165678f9bfee24dd3085f 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -49,6 +49,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -111,8 +112,14 @@ static atomic_t shift_adj = ATOMIC_INIT(0); static short adj_max_shift = 353; module_param_named(adj_max_shift, adj_max_shift, short, 0644); +enum { + ADAPTIVE_LMK_DISABLED = 0, + ADAPTIVE_LMK_ENABLED, + ADAPTIVE_LMK_WAS_ENABLED, +}; + /* User knob to enable/disable adaptive lmk feature */ -static int enable_adaptive_lmk; +static int enable_adaptive_lmk = ADAPTIVE_LMK_DISABLED; module_param_named(enable_adaptive_lmk, enable_adaptive_lmk, int, 0644); /* @@ -153,7 +160,7 @@ static int adjust_minadj(short *min_score_adj) { int ret = VMPRESSURE_NO_ADJUST; - if (!enable_adaptive_lmk) + if (enable_adaptive_lmk != ADAPTIVE_LMK_ENABLED) return 0; if (atomic_read(&shift_adj) && @@ -176,7 +183,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, unsigned long pressure = action; int array_size = ARRAY_SIZE(lowmem_adj); - if (!enable_adaptive_lmk) + if (enable_adaptive_lmk != ADAPTIVE_LMK_ENABLED) return 0; if (pressure >= 95) { @@ -678,16 +685,41 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) return rem; } +static int lmk_hotplug_callback(struct notifier_block *self, + unsigned long action, void *arg) +{ + switch (action) { + case MEM_GOING_OFFLINE: + if (enable_adaptive_lmk == ADAPTIVE_LMK_ENABLED) + enable_adaptive_lmk = ADAPTIVE_LMK_WAS_ENABLED; + break; + case MEM_OFFLINE: + if (enable_adaptive_lmk == ADAPTIVE_LMK_WAS_ENABLED) + enable_adaptive_lmk = ADAPTIVE_LMK_ENABLED; + break; + default: + break; + } + return NOTIFY_OK; +} + static struct shrinker lowmem_shrinker = { .scan_objects = lowmem_scan, .count_objects = lowmem_count, .seeks = DEFAULT_SEEKS * 16 }; +static struct notifier_block lmk_memory_callback_nb = { + .notifier_call = lmk_hotplug_callback, + .priority = 0, +}; + static int __init lowmem_init(void) { register_shrinker(&lowmem_shrinker); vmpressure_notifier_register(&lmk_vmpr_nb); + if (register_hotmemory_notifier(&lmk_memory_callback_nb)) + lowmem_print(1, "Registering memory hotplug notifier failed\n"); return 0; } device_initcall(lowmem_init); diff --git a/drivers/staging/ccree/ssi_hash.c b/drivers/staging/ccree/ssi_hash.c index e266a70a1b32e557b51ac4be4318aab40f1c3339..13291aeaf350ba20e26236f4a20eb025f45a5c7e 100644 --- a/drivers/staging/ccree/ssi_hash.c +++ b/drivers/staging/ccree/ssi_hash.c @@ -1781,7 +1781,7 @@ static int ssi_ahash_import(struct ahash_request *req, const void *in) struct device *dev = &ctx->drvdata->plat_dev->dev; struct ahash_req_ctx *state = ahash_request_ctx(req); u32 tmp; - int rc = 0; + int rc; memcpy(&tmp, in, sizeof(u32)); if (tmp != CC_EXPORT_MAGIC) { @@ -1790,12 +1790,9 @@ static int ssi_ahash_import(struct ahash_request *req, const void *in) } in += sizeof(u32); - /* call init() to allocate bufs if the user hasn't */ - if (!state->digest_buff) { - rc = ssi_hash_init(state, ctx); - if (rc) - goto out; - } + rc = ssi_hash_init(state, ctx); + if (rc) + goto out; dma_sync_single_for_cpu(dev, state->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL); diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c index 9a0a96329a55083f158b59110fb2244272400dd3..009c5277387b64620d93d4f8f96db7b67a1df950 100644 --- a/drivers/staging/comedi/drivers/ni_usb6501.c +++ b/drivers/staging/comedi/drivers/ni_usb6501.c @@ -472,10 +472,8 @@ static int ni6501_alloc_usb_buffers(struct comedi_device *dev) size = usb_endpoint_maxp(devpriv->ep_tx); devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL); - if (!devpriv->usb_tx_buf) { - kfree(devpriv->usb_rx_buf); + if (!devpriv->usb_tx_buf) return -ENOMEM; - } return 0; } @@ -527,6 +525,9 @@ static int ni6501_auto_attach(struct comedi_device *dev, if (!devpriv) return -ENOMEM; + mutex_init(&devpriv->mut); + usb_set_intfdata(intf, devpriv); + ret = ni6501_find_endpoints(dev); if (ret) return ret; @@ -535,9 +536,6 @@ static int ni6501_auto_attach(struct comedi_device *dev, if (ret) return ret; - mutex_init(&devpriv->mut); - usb_set_intfdata(intf, devpriv); - ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index a004aed0147a526fa3732d1d8718be3e2957ef10..1800eb3ae0176c3bd27d37431c00509fb917ce86 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -691,10 +691,8 @@ static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev) size = usb_endpoint_maxp(devpriv->ep_tx); devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL); - if (!devpriv->usb_tx_buf) { - kfree(devpriv->usb_rx_buf); + if (!devpriv->usb_tx_buf) return -ENOMEM; - } return 0; } @@ -809,6 +807,8 @@ static int vmk80xx_auto_attach(struct comedi_device *dev, devpriv->model = board->model; + sema_init(&devpriv->limit_sem, 8); + ret = vmk80xx_find_usb_endpoints(dev); if (ret) return ret; @@ -817,8 +817,6 @@ static int vmk80xx_auto_attach(struct comedi_device *dev, if (ret) return ret; - sema_init(&devpriv->limit_sem, 8); - usb_set_intfdata(intf, devpriv); if (devpriv->model == VMK8055_MODEL) diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 31a195d1bf0572594d312a4bb8494887d16ed886..f58c80327ba546ec4414abe4ae14954a6ba30dce 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -109,10 +109,10 @@ #define AD7192_CH_AIN3 BIT(6) /* AIN3 - AINCOM */ #define AD7192_CH_AIN4 BIT(7) /* AIN4 - AINCOM */ -#define AD7193_CH_AIN1P_AIN2M 0x000 /* AIN1(+) - AIN2(-) */ -#define AD7193_CH_AIN3P_AIN4M 0x001 /* AIN3(+) - AIN4(-) */ -#define AD7193_CH_AIN5P_AIN6M 0x002 /* AIN5(+) - AIN6(-) */ -#define AD7193_CH_AIN7P_AIN8M 0x004 /* AIN7(+) - AIN8(-) */ +#define AD7193_CH_AIN1P_AIN2M 0x001 /* AIN1(+) - AIN2(-) */ +#define AD7193_CH_AIN3P_AIN4M 0x002 /* AIN3(+) - AIN4(-) */ +#define AD7193_CH_AIN5P_AIN6M 0x004 /* AIN5(+) - AIN6(-) */ +#define AD7193_CH_AIN7P_AIN8M 0x008 /* AIN7(+) - AIN8(-) */ #define AD7193_CH_TEMP 0x100 /* Temp senseor */ #define AD7193_CH_AIN2P_AIN2M 0x200 /* AIN2(+) - AIN2(-) */ #define AD7193_CH_AIN1 0x401 /* AIN1 - AINCOM */ diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index b2bce26499f53d8c853c55438553cfc29f4d90dd..7378aa7730ef36734ce4297e7ac5efc1f4805bab 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -47,6 +47,8 @@ #define ADT7516_MSB_AIN3 0xA #define ADT7516_MSB_AIN4 0xB #define ADT7316_DA_DATA_BASE 0x10 +#define ADT7316_DA_10_BIT_LSB_SHIFT 6 +#define ADT7316_DA_12_BIT_LSB_SHIFT 4 #define ADT7316_DA_MSB_DATA_REGS 4 #define ADT7316_LSB_DAC_A 0x10 #define ADT7316_MSB_DAC_A 0x11 @@ -1086,7 +1088,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK); if (data & 0x1) ldac_config |= ADT7516_DAC_AB_IN_VREF; - else if (data & 0x2) + if (data & 0x2) ldac_config |= ADT7516_DAC_CD_IN_VREF; } else { ret = kstrtou8(buf, 16, &data); @@ -1408,7 +1410,7 @@ static IIO_DEVICE_ATTR(ex_analog_temp_offset, 0644, static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, int channel, char *buf) { - u16 data; + u16 data = 0; u8 msb, lsb, offset; int ret; @@ -1433,7 +1435,11 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, if (ret) return -EIO; - data = (msb << offset) + (lsb & ((1 << offset) - 1)); + if (chip->dac_bits == 12) + data = lsb >> ADT7316_DA_12_BIT_LSB_SHIFT; + else if (chip->dac_bits == 10) + data = lsb >> ADT7316_DA_10_BIT_LSB_SHIFT; + data |= msb << offset; return sprintf(buf, "%d\n", data); } @@ -1441,7 +1447,7 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, int channel, const char *buf, size_t len) { - u8 msb, lsb, offset; + u8 msb, lsb, lsb_reg, offset; u16 data; int ret; @@ -1459,9 +1465,13 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, return -EINVAL; if (chip->dac_bits > 8) { - lsb = data & (1 << offset); + lsb = data & ((1 << offset) - 1); + if (chip->dac_bits == 12) + lsb_reg = lsb << ADT7316_DA_12_BIT_LSB_SHIFT; + else + lsb_reg = lsb << ADT7316_DA_10_BIT_LSB_SHIFT; ret = chip->bus.write(chip->bus.client, - ADT7316_DA_DATA_BASE + channel * 2, lsb); + ADT7316_DA_DATA_BASE + channel * 2, lsb_reg); if (ret) return -EIO; } diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c index 70612da64a8baee961853f7b849be67258b8c561..7ae774ef9da3d7164bfd451d15b8500175413f99 100644 --- a/drivers/staging/iio/meter/ade7854.c +++ b/drivers/staging/iio/meter/ade7854.c @@ -269,7 +269,7 @@ static IIO_DEV_ATTR_VPEAK(0644, static IIO_DEV_ATTR_IPEAK(0644, ade7854_read_32bit, ade7854_write_32bit, - ADE7854_VPEAK); + ADE7854_IPEAK); static IIO_DEV_ATTR_APHCAL(0644, ade7854_read_16bit, ade7854_write_16bit, diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index be2f46eb9f78cbfdfab9f0c7eb07ea3b473493b4..904b988ecc4eee3713e0dacb568c27d9370b7010 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -188,7 +188,9 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; - rtw_alloc_hwxmits(padapter); + res = rtw_alloc_hwxmits(padapter); + if (res == _FAIL) + goto exit; rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); for (i = 0; i < 4; i++) @@ -1573,7 +1575,7 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) return res; } -void rtw_alloc_hwxmits(struct adapter *padapter) +s32 rtw_alloc_hwxmits(struct adapter *padapter) { struct hw_xmit *hwxmits; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -1582,6 +1584,8 @@ void rtw_alloc_hwxmits(struct adapter *padapter) pxmitpriv->hwxmits = kcalloc(pxmitpriv->hwxmit_entry, sizeof(struct hw_xmit), GFP_KERNEL); + if (!pxmitpriv->hwxmits) + return _FAIL; hwxmits = pxmitpriv->hwxmits; @@ -1589,6 +1593,7 @@ void rtw_alloc_hwxmits(struct adapter *padapter) hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; hwxmits[2] .sta_queue = &pxmitpriv->be_pending; hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + return _SUCCESS; } void rtw_free_hwxmits(struct adapter *padapter) diff --git a/drivers/staging/rtl8188eu/include/rtw_xmit.h b/drivers/staging/rtl8188eu/include/rtw_xmit.h index dd6b7a9a8d4aaba395c9c491a1fdc2dad507e3c7..1be4b478475add742d86f0ecf3f55ace242cc003 100644 --- a/drivers/staging/rtl8188eu/include/rtw_xmit.h +++ b/drivers/staging/rtl8188eu/include/rtw_xmit.h @@ -342,7 +342,7 @@ s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry); s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter); void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv); -void rtw_alloc_hwxmits(struct adapter *padapter); +s32 rtw_alloc_hwxmits(struct adapter *padapter); void rtw_free_hwxmits(struct adapter *padapter); s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt); diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c index 0104aced113e4e284900b291663ac2e8137ca4ce..ccda04e916c546b3e6f8cd923265c7eaf5e8c288 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.c +++ b/drivers/staging/rtl8712/rtl8712_cmd.c @@ -159,17 +159,9 @@ static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf) static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) { - u32 val; - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - if (pcmd->rsp && pcmd->rspsz > 0) - memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz); - pcmd_callback = cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) - r8712_free_cmd_obj(pcmd); - else - pcmd_callback(padapter, pcmd); + r8712_free_cmd_obj(pcmd); return H2C_SUCCESS; } diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h index 67e9e910aef987f53d69c5111303b2c9f4a79e43..d10a59d4a5503159181346beeb2049d72a197f76 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.h +++ b/drivers/staging/rtl8712/rtl8712_cmd.h @@ -152,7 +152,7 @@ enum rtl8712_h2c_cmd { static struct _cmd_callback cmd_callback[] = { {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ {GEN_CMD_CODE(_Write_MACREG), NULL}, - {GEN_CMD_CODE(_Read_BBREG), &r8712_getbbrfreg_cmdrsp_callback}, + {GEN_CMD_CODE(_Read_BBREG), NULL}, {GEN_CMD_CODE(_Write_BBREG), NULL}, {GEN_CMD_CODE(_Read_RFREG), &r8712_getbbrfreg_cmdrsp_callback}, {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 022f654419e4dcd0724f86444fb37de77ef40641..91dab7f8a7399d1361b023bb66f8f2cc2df94961 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -271,7 +271,9 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) } } - rtw_alloc_hwxmits(padapter); + res = rtw_alloc_hwxmits(padapter); + if (res == _FAIL) + goto exit; rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); for (i = 0; i < 4; i++) { @@ -2157,7 +2159,7 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) return res; } -void rtw_alloc_hwxmits(struct adapter *padapter) +s32 rtw_alloc_hwxmits(struct adapter *padapter) { struct hw_xmit *hwxmits; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -2168,10 +2170,8 @@ void rtw_alloc_hwxmits(struct adapter *padapter) pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry); - if (pxmitpriv->hwxmits == NULL) { - DBG_871X("alloc hwxmits fail!...\n"); - return; - } + if (!pxmitpriv->hwxmits) + return _FAIL; hwxmits = pxmitpriv->hwxmits; @@ -2217,7 +2217,7 @@ void rtw_alloc_hwxmits(struct adapter *padapter) } - + return _SUCCESS; } void rtw_free_hwxmits(struct adapter *padapter) diff --git a/drivers/staging/rtl8723bs/include/rtw_xmit.h b/drivers/staging/rtl8723bs/include/rtw_xmit.h index 11571649cd2c3b935470285de914bd3667507ee6..92236ca8a1efea584db9980dad143b7a157f3845 100644 --- a/drivers/staging/rtl8723bs/include/rtw_xmit.h +++ b/drivers/staging/rtl8723bs/include/rtw_xmit.h @@ -494,7 +494,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter); void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv); -void rtw_alloc_hwxmits(struct adapter *padapter); +s32 rtw_alloc_hwxmits(struct adapter *padapter); void rtw_free_hwxmits(struct adapter *padapter); diff --git a/drivers/staging/rtlwifi/phydm/rtl_phydm.c b/drivers/staging/rtlwifi/phydm/rtl_phydm.c index 85e490d3601f2cf49305c8e6f118b6403bf74b28..cab563fefc34ed87a1e9bcaf944c386ccac7ac3a 100644 --- a/drivers/staging/rtlwifi/phydm/rtl_phydm.c +++ b/drivers/staging/rtlwifi/phydm/rtl_phydm.c @@ -191,6 +191,8 @@ static int rtl_phydm_init_priv(struct rtl_priv *rtlpriv, rtlpriv->phydm.internal = kzalloc(sizeof(struct phy_dm_struct), GFP_KERNEL); + if (!rtlpriv->phydm.internal) + return 0; _rtl_phydm_init_com_info(rtlpriv, ic, params); diff --git a/drivers/staging/rtlwifi/rtl8822be/fw.c b/drivers/staging/rtlwifi/rtl8822be/fw.c index acabb2470d55e074633167aaf0d81a3aceff77a0..02ca3157c5a578ed2a7a37fff065e519f7c98943 100644 --- a/drivers/staging/rtlwifi/rtl8822be/fw.c +++ b/drivers/staging/rtlwifi/rtl8822be/fw.c @@ -752,6 +752,8 @@ void rtl8822be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1_rsvd_page_loc, 3); skb = dev_alloc_skb(totalpacketlen); + if (!skb) + return; memcpy((u8 *)skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c index 24b006a9514217dc10984be657b376f186c54fbd..8646fb7425f2f5ef709eca32b24116d9c8ba8273 100644 --- a/drivers/thermal/broadcom/bcm2835_thermal.c +++ b/drivers/thermal/broadcom/bcm2835_thermal.c @@ -128,8 +128,7 @@ static const struct debugfs_reg32 bcm2835_thermal_regs[] = { static void bcm2835_thermal_debugfs(struct platform_device *pdev) { - struct thermal_zone_device *tz = platform_get_drvdata(pdev); - struct bcm2835_thermal_data *data = tz->devdata; + struct bcm2835_thermal_data *data = platform_get_drvdata(pdev); struct debugfs_regset32 *regset; data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL); @@ -275,7 +274,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) data->tz = tz; - platform_set_drvdata(pdev, tz); + platform_set_drvdata(pdev, data); /* * Thermal_zone doesn't enable hwmon as default, @@ -299,8 +298,8 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) static int bcm2835_thermal_remove(struct platform_device *pdev) { - struct thermal_zone_device *tz = platform_get_drvdata(pdev); - struct bcm2835_thermal_data *data = tz->devdata; + struct bcm2835_thermal_data *data = platform_get_drvdata(pdev); + struct thermal_zone_device *tz = data->tz; debugfs_remove_recursive(data->debugfsdir); thermal_zone_of_sensor_unregister(&pdev->dev, tz); diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index 43b90fd577e49d86852760b0b917e0660a473c88..4a20f4d47b1de299e827dfb658be53b4ab69c214 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c @@ -22,6 +22,13 @@ enum int3400_thermal_uuid { INT3400_THERMAL_PASSIVE_1, INT3400_THERMAL_ACTIVE, INT3400_THERMAL_CRITICAL, + INT3400_THERMAL_ADAPTIVE_PERFORMANCE, + INT3400_THERMAL_EMERGENCY_CALL_MODE, + INT3400_THERMAL_PASSIVE_2, + INT3400_THERMAL_POWER_BOSS, + INT3400_THERMAL_VIRTUAL_SENSOR, + INT3400_THERMAL_COOLING_MODE, + INT3400_THERMAL_HARDWARE_DUTY_CYCLING, INT3400_THERMAL_MAXIMUM_UUID, }; @@ -29,6 +36,13 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { "42A441D6-AE6A-462b-A84B-4A8CE79027D3", "3A95C389-E4B8-4629-A526-C52C88626BAE", "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", + "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D", + "5349962F-71E6-431D-9AE8-0A635B710AEE", + "9E04115A-AE87-4D1C-9500-0F3E340BFE75", + "F5A35014-C209-46A4-993A-EB56DE7530A1", + "6ED722A7-9240-48A5-B479-31EEF723D7CF", + "16CAF1B7-DD38-40ED-B1C1-1B8A1913D531", + "BE84BABF-C4D4-403D-B495-3128FD44dAC1", }; struct int3400_thermal_priv { @@ -302,10 +316,9 @@ static int int3400_thermal_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) { - int3400_thermal_ops.get_mode = int3400_thermal_get_mode; - int3400_thermal_ops.set_mode = int3400_thermal_set_mode; - } + int3400_thermal_ops.get_mode = int3400_thermal_get_mode; + int3400_thermal_ops.set_mode = int3400_thermal_set_mode; + priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, priv, &int3400_thermal_ops, &int3400_thermal_params, 0, 0); diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index d718cd179ddbb29277d05bf3cb308ebd17abc901..c3293fa2bb1b386dc647e98761083c4135d1d541 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -101,7 +101,7 @@ struct powerclamp_worker_data { bool clamping; }; -static struct powerclamp_worker_data * __percpu worker_data; +static struct powerclamp_worker_data __percpu *worker_data; static struct thermal_cooling_device *cooling_dev; static unsigned long *cpu_clamping_mask; /* bit map for tracking per cpu * clamping kthread worker @@ -494,7 +494,7 @@ static void start_power_clamp_worker(unsigned long cpu) struct powerclamp_worker_data *w_data = per_cpu_ptr(worker_data, cpu); struct kthread_worker *worker; - worker = kthread_create_worker_on_cpu(cpu, 0, "kidle_inject/%ld", cpu); + worker = kthread_create_worker_on_cpu(cpu, 0, "kidle_inj/%ld", cpu); if (IS_ERR(worker)) return; diff --git a/drivers/thermal/qcom/adc-tm.c b/drivers/thermal/qcom/adc-tm.c index 730f7122ac5659576b2ffac368a24d26447a2e34..d7bfc038c69678e85872b5db0abf55154982a8a3 100644 --- a/drivers/thermal/qcom/adc-tm.c +++ b/drivers/thermal/qcom/adc-tm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -359,6 +359,8 @@ static int adc_tm_probe(struct platform_device *pdev) adc_tm->base = reg; adc_tm->dt_channels = dt_chan_num; + platform_set_drvdata(pdev, adc_tm); + revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0); if (revid_dev_node) { adc_tm->pmic_rev_id = get_revid_data(revid_dev_node); @@ -402,7 +404,6 @@ static int adc_tm_probe(struct platform_device *pdev) } list_add_tail(&adc_tm->list, &adc_tm_device_list); - platform_set_drvdata(pdev, adc_tm); return 0; fail: i = 0; @@ -424,10 +425,30 @@ static int adc_tm_remove(struct platform_device *pdev) return 0; } +static int adc_tm_suspend_noirq(struct device *dev) +{ + struct adc_tm_chip *adc_tm = dev_get_drvdata(dev); + int i = 0; + + while (i < adc_tm->dt_channels) { + if (adc_tm->sensor[i].req_wq) { + pr_debug("flushing queue for sensor %d\n", i); + flush_workqueue(adc_tm->sensor[i].req_wq); + } + i++; + } + return 0; +} + +static const struct dev_pm_ops adc_tm_pm_ops = { + .suspend_noirq = adc_tm_suspend_noirq, +}; + static struct platform_driver adc_tm_driver = { .driver = { .name = "qcom,adc-tm", .of_match_table = adc_tm_match_table, + .pm = &adc_tm_pm_ops, }, .probe = adc_tm_probe, .remove = adc_tm_remove, diff --git a/drivers/thermal/qcom/bcl_pmic5.c b/drivers/thermal/qcom/bcl_pmic5.c index a8118cc74839b8c1d3850cef496267b3a6625082..8ba988cd35b3b3e42dc8eebd32427067fd17356e 100644 --- a/drivers/thermal/qcom/bcl_pmic5.c +++ b/drivers/thermal/qcom/bcl_pmic5.c @@ -31,7 +31,7 @@ #define BCL_DRIVER_NAME "bcl_pmic5" #define BCL_MONITOR_EN 0x46 -#define BCL_IRQ_STATUS 0x09 +#define BCL_IRQ_STATUS 0x08 #define BCL_IBAT_HIGH 0x4B #define BCL_IBAT_TOO_HIGH 0x4C @@ -43,12 +43,9 @@ #define BCL_VBAT_COMP_LOW 0x49 #define BCL_VBAT_COMP_TLOW 0x4A -#define BCL_IRQ_VCMP_L0 0x1 -#define BCL_IRQ_VCMP_L1 0x2 -#define BCL_IRQ_VCMP_L2 0x4 -#define BCL_IRQ_IBAT_L0 0x10 -#define BCL_IRQ_IBAT_L1 0x20 -#define BCL_IRQ_IBAT_L2 0x40 +#define BCL_IRQ_L0 0x1 +#define BCL_IRQ_L1 0x2 +#define BCL_IRQ_L2 0x4 #define BCL_VBAT_SCALING_UV 49827 #define BCL_VBAT_NO_READING 127 @@ -64,6 +61,9 @@ enum bcl_dev_type { BCL_VBAT_LVL0, BCL_VBAT_LVL1, BCL_VBAT_LVL2, + BCL_LVL0, + BCL_LVL1, + BCL_LVL2, BCL_TYPE_MAX, }; @@ -73,6 +73,9 @@ static char bcl_int_names[BCL_TYPE_MAX][25] = { "bcl-vbat-lvl0", "bcl-vbat-lvl1", "bcl-vbat-lvl2", + "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2", }; struct bcl_device; @@ -361,117 +364,83 @@ static int bcl_read_vbat(void *data, int *adc_value) return ret; } -static irqreturn_t bcl_handle_irq(int irq, void *data) +static int bcl_set_lbat(void *data, int low, int high) { - struct bcl_peripheral_data *perph_data = + struct bcl_peripheral_data *bat_data = (struct bcl_peripheral_data *)data; - unsigned int irq_status = 0; - int ret; - bool notify = false; - struct bcl_device *bcl_perph; - mutex_lock(&perph_data->state_trans_lock); - if (!perph_data->irq_enabled) { - pr_err("irq:%d not in expected state\n", irq); - disable_irq_nosync(irq); - perph_data->irq_enabled = false; - goto exit_intr; - } - mutex_unlock(&perph_data->state_trans_lock); + mutex_lock(&bat_data->state_trans_lock); - bcl_perph = perph_data->dev; - ret = bcl_read_register(bcl_perph, BCL_IRQ_STATUS, &irq_status); - if (ret) { - disable_irq_nosync(irq); - perph_data->irq_enabled = false; - return IRQ_HANDLED; + if (high == INT_MAX && + bat_data->irq_num && bat_data->irq_enabled) { + disable_irq_nosync(bat_data->irq_num); + bat_data->irq_enabled = false; + pr_debug("lbat[%d]: disable irq:%d\n", + bat_data->type, + bat_data->irq_num); + } else if (high != INT_MAX && + bat_data->irq_num && !bat_data->irq_enabled) { + enable_irq(bat_data->irq_num); + bat_data->irq_enabled = true; + pr_debug("lbat[%d]: enable irq:%d\n", + bat_data->type, + bat_data->irq_num); } - pr_debug("Irq:%d triggered for bcl type:%d. status:%u\n", - irq, perph_data->type, irq_status); - switch (perph_data->type) { - case BCL_VBAT_LVL0: /* BCL L0 interrupt */ - if ((irq_status & BCL_IRQ_VCMP_L0) && - (bcl_perph->param[BCL_VBAT_LVL0].tz_dev)) { - of_thermal_handle_trip( - bcl_perph->param[BCL_VBAT_LVL0].tz_dev); - notify = true; - } - if ((irq_status & BCL_IRQ_IBAT_L0) && - (bcl_perph->param[BCL_IBAT_LVL0].tz_dev)) { - of_thermal_handle_trip( - bcl_perph->param[BCL_IBAT_LVL0].tz_dev); - notify = true; - } + + mutex_unlock(&bat_data->state_trans_lock); + + return 0; +} + +static int bcl_read_lbat(void *data, int *adc_value) +{ + int ret = 0; + unsigned int val = 0; + struct bcl_peripheral_data *bat_data = + (struct bcl_peripheral_data *)data; + struct bcl_device *bcl_perph = bat_data->dev; + + *adc_value = val; + ret = bcl_read_register(bcl_perph, BCL_IRQ_STATUS, &val); + if (ret) + goto bcl_read_exit; + switch (bat_data->type) { + case BCL_LVL0: + *adc_value = val & BCL_IRQ_L0; break; - case BCL_VBAT_LVL1: /* BCL L1 interrupt */ - if ((irq_status & BCL_IRQ_VCMP_L1) && - (bcl_perph->param[BCL_VBAT_LVL1].tz_dev)) { - of_thermal_handle_trip( - bcl_perph->param[BCL_VBAT_LVL1].tz_dev); - - /* - * There is a possibility that just vbat_l1 be the - * source of bcl event. So trigger Vbat_l0 in - * those case. - */ - if (!(irq_status & BCL_IRQ_VCMP_L0) && - (bcl_perph->param[BCL_VBAT_LVL0].tz_dev)) - of_thermal_handle_trip( - bcl_perph->param[BCL_VBAT_LVL0].tz_dev); - notify = true; - } - if ((irq_status & BCL_IRQ_IBAT_L1) && - (bcl_perph->param[BCL_IBAT_LVL1].tz_dev)) { - of_thermal_handle_trip( - bcl_perph->param[BCL_IBAT_LVL1].tz_dev); - - /* - * There is a possibility that just ibat_l1 be the - * source of bcl event. So trigger ibat_l0 in - * those case. - */ - if (!(irq_status & BCL_IRQ_IBAT_L0) && - (bcl_perph->param[BCL_IBAT_LVL0].tz_dev)) - of_thermal_handle_trip( - bcl_perph->param[BCL_IBAT_LVL0].tz_dev); - notify = true; - } + case BCL_LVL1: + *adc_value = val & BCL_IRQ_L1; break; - case BCL_VBAT_LVL2: /* BCL L2 interrupt */ - if ((irq_status & BCL_IRQ_VCMP_L2) && - (bcl_perph->param[BCL_VBAT_LVL2].tz_dev)) { - of_thermal_handle_trip( - bcl_perph->param[BCL_VBAT_LVL2].tz_dev); - - /* - * There is a possibility that just vbat_l2 be the - * source of bcl event. So trigger Vbat_l0 and vbat_l1 - * in those case. - */ - if (!(irq_status & BCL_IRQ_VCMP_L1) && - (bcl_perph->param[BCL_VBAT_LVL1].tz_dev)) - of_thermal_handle_trip( - bcl_perph->param[BCL_VBAT_LVL1].tz_dev); - if (!(irq_status & BCL_IRQ_VCMP_L0) && - (bcl_perph->param[BCL_VBAT_LVL0].tz_dev)) - of_thermal_handle_trip( - bcl_perph->param[BCL_VBAT_LVL0].tz_dev); - notify = true; - } + case BCL_LVL2: + *adc_value = val & BCL_IRQ_L2; break; default: - pr_err("Invalid type%d for interrupt:%d\n", - perph_data->type, irq); - break; + pr_err("Invalid sensor type:%d\n", bat_data->type); + ret = -ENODEV; + goto bcl_read_exit; } - if (!notify) - pr_err_ratelimited("Irq:%d triggered. status:%u\n", - irq, irq_status); + bat_data->last_val = *adc_value; + pr_debug("lbat:%d val:%d\n", bat_data->type, + bat_data->last_val); - return IRQ_HANDLED; +bcl_read_exit: + return ret; +} + +static irqreturn_t bcl_handle_irq(int irq, void *data) +{ + struct bcl_peripheral_data *perph_data = + (struct bcl_peripheral_data *)data; + unsigned int irq_status = 0; + struct bcl_device *bcl_perph; + + bcl_perph = perph_data->dev; + bcl_read_register(bcl_perph, BCL_IRQ_STATUS, &irq_status); + pr_debug("Irq:%d triggered for bcl type:%s. status:%u\n", + irq, bcl_int_names[perph_data->type], + irq_status); + of_thermal_handle_trip(perph_data->tz_dev); -exit_intr: - mutex_unlock(&perph_data->state_trans_lock); return IRQ_HANDLED; } @@ -533,15 +502,15 @@ static void bcl_vbat_init(struct platform_device *pdev, enum bcl_dev_type type, struct bcl_device *bcl_perph) { struct bcl_peripheral_data *vbat = &bcl_perph->param[type]; - irqreturn_t (*handle)(int, void *) = bcl_handle_irq; mutex_init(&vbat->state_trans_lock); vbat->type = type; vbat->dev = bcl_perph; - bcl_fetch_trip(pdev, type, vbat, handle); vbat->ops.get_temp = bcl_read_vbat; vbat->ops.set_trips = bcl_set_vbat; vbat->ops.get_trip_temp = bcl_get_vbat_trip; + vbat->irq_num = 0; + vbat->irq_enabled = false; vbat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, type, vbat, &vbat->ops); if (IS_ERR(vbat->tz_dev)) { @@ -570,35 +539,10 @@ static void bcl_ibat_init(struct platform_device *pdev, mutex_init(&ibat->state_trans_lock); ibat->type = type; ibat->dev = bcl_perph; - bcl_fetch_trip(pdev, type, ibat, NULL); - if (ibat->irq_num <= 0) - return; - + ibat->irq_num = 0; + ibat->irq_enabled = false; ibat->ops.get_temp = bcl_read_ibat; ibat->ops.set_trips = bcl_set_ibat; - - switch (type) { - case BCL_IBAT_LVL0: - if (!bcl_perph->param[BCL_VBAT_LVL0].irq_num || - ibat->irq_num != - bcl_perph->param[BCL_VBAT_LVL0].irq_num) { - pr_err("ibat[%d]: irq %d mismatch\n", - type, ibat->irq_num); - return; - } - break; - case BCL_IBAT_LVL1: - if (!bcl_perph->param[BCL_VBAT_LVL1].irq_num || - ibat->irq_num != - bcl_perph->param[BCL_VBAT_LVL1].irq_num) { - pr_err("ibat[%d]: irq %d mismatch\n", - type, ibat->irq_num); - return; - } - break; - default: - return; - } ibat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, type, ibat, &ibat->ops); if (IS_ERR(ibat->tz_dev)) { @@ -618,6 +562,41 @@ static void bcl_probe_ibat(struct platform_device *pdev, bcl_ibat_init(pdev, BCL_IBAT_LVL1, bcl_perph); } +static void bcl_lvl_init(struct platform_device *pdev, + enum bcl_dev_type type, struct bcl_device *bcl_perph) +{ + struct bcl_peripheral_data *lbat = &bcl_perph->param[type]; + + mutex_init(&lbat->state_trans_lock); + lbat->type = type; + lbat->dev = bcl_perph; + bcl_fetch_trip(pdev, type, lbat, bcl_handle_irq); + if (lbat->irq_num <= 0) + return; + + lbat->ops.get_temp = bcl_read_lbat; + lbat->ops.set_trips = bcl_set_lbat; + + lbat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, + type, lbat, &lbat->ops); + if (IS_ERR(lbat->tz_dev)) { + pr_debug("lbat:[%s] register failed. err:%ld\n", + bcl_int_names[type], + PTR_ERR(lbat->tz_dev)); + lbat->tz_dev = NULL; + return; + } + thermal_zone_device_update(lbat->tz_dev, THERMAL_DEVICE_UP); +} + +static void bcl_probe_lvls(struct platform_device *pdev, + struct bcl_device *bcl_perph) +{ + bcl_lvl_init(pdev, BCL_LVL0, bcl_perph); + bcl_lvl_init(pdev, BCL_LVL1, bcl_perph); + bcl_lvl_init(pdev, BCL_LVL2, bcl_perph); +} + static void bcl_configure_bcl_peripheral(struct bcl_device *bcl_perph) { bcl_write_register(bcl_perph, BCL_MONITOR_EN, BIT(7)); @@ -663,6 +642,7 @@ static int bcl_probe(struct platform_device *pdev) bcl_get_devicetree_data(pdev, bcl_perph); bcl_probe_vbat(pdev, bcl_perph); bcl_probe_ibat(pdev, bcl_perph); + bcl_probe_lvls(pdev, bcl_perph); bcl_configure_bcl_peripheral(bcl_perph); dev_set_drvdata(&pdev->dev, bcl_perph); diff --git a/drivers/thermal/qcom/qmi_sensors.c b/drivers/thermal/qcom/qmi_sensors.c index dbd2eb4bfd69181ce9088500a18262c6fcb96886..7bca52588f51e14c7ffa5a9b49189c9036a62815 100644 --- a/drivers/thermal/qcom/qmi_sensors.c +++ b/drivers/thermal/qcom/qmi_sensors.c @@ -51,6 +51,19 @@ enum qmi_ts_sensor { QMI_TS_MODEM_SKIN, QMI_TS_QFE_PA_MDM, QMI_TS_QFE_PA_WTR, + QMI_TS_STREAMER_0, + QMI_TS_MOD_MMW_0, + QMI_TS_MOD_MMW_1, + QMI_TS_MOD_MMW_2, + QMI_TS_MOD_MMW_3, + QMI_TS_RET_PA_0, + QMI_TS_WTR_PA_0, + QMI_TS_WTR_PA_1, + QMI_TS_WTR_PA_2, + QMI_TS_WTR_PA_3, + QMI_SYS_THERM1, + QMI_SYS_THERM2, + QMI_TS_TSENS_1, QMI_TS_MAX_NR }; @@ -95,6 +108,19 @@ static char sensor_clients[QMI_TS_MAX_NR][QMI_CLIENT_NAME_LENGTH] = { {"xo_therm"}, {"qfe_pa_mdm"}, {"qfe_pa_wtr"}, + {"qfe_mmw_streamer0"}, + {"qfe_mmw0_mod"}, + {"qfe_mmw1_mod"}, + {"qfe_mmw2_mod"}, + {"qfe_mmw3_mod"}, + {"qfe_ret_pa0"}, + {"qfe_wtr_pa0"}, + {"qfe_wtr_pa1"}, + {"qfe_wtr_pa2"}, + {"qfe_wtr_pa3"}, + {"sys_therm1"}, + {"sys_therm2"}, + {"modem_tsens1"}, }; static int32_t encode_qmi(int32_t val) diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 22c825928b7a7350713e52c615216b9456a0e2e2..82af120a80d3307e7ce71c0dce0a38042f9e5074 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -487,4 +487,28 @@ config OKL4_VTTY_CONSOLE default y help Console support for OKL4 Microvisor virtual ttys. + +config LDISC_AUTOLOAD + bool "Automatically load TTY Line Disciplines" + default y + help + Historically the kernel has always automatically loaded any + line discipline that is in a kernel module when a user asks + for it to be loaded with the TIOCSETD ioctl, or through other + means. This is not always the best thing to do on systems + where you know you will not be using some of the more + "ancient" line disciplines, so prevent the kernel from doing + this unless the request is coming from a process with the + CAP_SYS_MODULE permissions. + + Say 'Y' here if you trust your userspace users to do the right + thing, or if you have only provided the line disciplines that + you know you will be using, or if you wish to continue to use + the traditional method of on-demand loading of these modules + by any user. + + This functionality can be changed at runtime with the + dev.tty.ldisc_autoload sysctl, this configuration option will + only set the default value of this functionality. + endif # TTY diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 9323f7b5115e9420f28782abd78f5a6691c4477b..bd0cf13acd591544c6edb43bd5704be85b055674 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1135,6 +1135,15 @@ config SERIAL_MSM_HS Choose M here to compile it as a module. The module will be called msm_serial_hs. +config SERIAL_MSM_WITH_HALF_SAMPLING + bool "Changes clock divider which impacts sampling rate for QUP HW ver greater than 2.5.0" + depends on SERIAL_MSM_GENI + help + Clock divider value should get double for QUP Hardware version + greater than 2.5.0. + As earlycon can't have HW version awareness,decision is taken + based on the configuration. + config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" depends on ARCH_VT8500 diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index decc7f3c1ab2053bebe85b5653caf2fa356e40b6..ed545a61413c045df92a11c0cbc188e03cdb2926 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -52,11 +52,6 @@ struct ar933x_uart_port { struct clk *clk; }; -static inline bool ar933x_uart_console_enabled(void) -{ - return IS_ENABLED(CONFIG_SERIAL_AR933X_CONSOLE); -} - static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, int offset) { @@ -511,6 +506,7 @@ static const struct uart_ops ar933x_uart_ops = { .verify_port = ar933x_uart_verify_port, }; +#ifdef CONFIG_SERIAL_AR933X_CONSOLE static struct ar933x_uart_port * ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; @@ -607,14 +603,7 @@ static struct console ar933x_uart_console = { .index = -1, .data = &ar933x_uart_driver, }; - -static void ar933x_uart_add_console_port(struct ar933x_uart_port *up) -{ - if (!ar933x_uart_console_enabled()) - return; - - ar933x_console_ports[up->port.line] = up; -} +#endif /* CONFIG_SERIAL_AR933X_CONSOLE */ static struct uart_driver ar933x_uart_driver = { .owner = THIS_MODULE, @@ -703,7 +692,9 @@ static int ar933x_uart_probe(struct platform_device *pdev) baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); - ar933x_uart_add_console_port(up); +#ifdef CONFIG_SERIAL_AR933X_CONSOLE + ar933x_console_ports[up->port.line] = up; +#endif ret = uart_add_one_port(&ar933x_uart_driver, &up->port); if (ret) @@ -752,8 +743,9 @@ static int __init ar933x_uart_init(void) { int ret; - if (ar933x_uart_console_enabled()) - ar933x_uart_driver.cons = &ar933x_uart_console; +#ifdef CONFIG_SERIAL_AR933X_CONSOLE + ar933x_uart_driver.cons = &ar933x_uart_console; +#endif ret = uart_register_driver(&ar933x_uart_driver); if (ret) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index a47f873c2659f74d8def03982f1de27efe963f6f..a3c4db7e5ebce37bf43f1587d4c7d6f530f386ba 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -131,6 +131,15 @@ #define DMA_RX_BUF_SIZE (2048) #define UART_CONSOLE_RX_WM (2) + +struct msm_geni_serial_ver_info { + int hw_major_ver; + int hw_minor_ver; + int hw_step_ver; + int m_fw_ver; + int s_fw_ver; +}; + struct msm_geni_serial_port { struct uart_port uport; char name[20]; @@ -167,6 +176,7 @@ struct msm_geni_serial_port { int ioctl_count; int edge_count; bool manual_flow; + struct msm_geni_serial_ver_info ver_info; }; static const struct uart_ops msm_geni_serial_pops; @@ -190,8 +200,8 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport, static void msm_geni_serial_stop_rx(struct uart_port *uport); static int msm_geni_serial_runtime_resume(struct device *dev); static int msm_geni_serial_runtime_suspend(struct device *dev); - -static atomic_t uart_line_id = ATOMIC_INIT(0); +static int uart_line_id; +static int msm_geni_serial_get_ver_info(struct uart_port *uport); #define GET_DEV_PORT(uport) \ container_of(uport, struct msm_geni_serial_port, uport) @@ -320,7 +330,7 @@ static void wait_for_transfers_inflight(struct uart_port *uport) static int vote_clock_on(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - int usage_count = atomic_read(&uport->dev->power.usage_count); + int usage_count; int ret = 0; ret = msm_geni_serial_power_on(uport); @@ -329,15 +339,18 @@ static int vote_clock_on(struct uart_port *uport) return ret; } port->ioctl_count++; - IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d usage_count %d\n", - __func__, current->comm, port->ioctl_count, usage_count); + usage_count = atomic_read(&uport->dev->power.usage_count); + IPC_LOG_MSG(port->ipc_log_pwr, + "%s :%s ioctl:%d usage_count:%d edge-Count:%d\n", + __func__, current->comm, port->ioctl_count, + usage_count, port->edge_count); return 0; } static int vote_clock_off(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - int usage_count = atomic_read(&uport->dev->power.usage_count); + int usage_count; if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); @@ -354,7 +367,8 @@ static int vote_clock_off(struct uart_port *uport) wait_for_transfers_inflight(uport); port->ioctl_count--; msm_geni_serial_power_off(uport); - IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d usage_count %d\n", + usage_count = atomic_read(&uport->dev->power.usage_count); + IPC_LOG_MSG(port->ipc_log_pwr, "%s:%s ioctl:%d usage_count:%d\n", __func__, current->comm, port->ioctl_count, usage_count); return 0; }; @@ -389,7 +403,8 @@ static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl) if (!uart_console(uport) && device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, - "%s.Device is suspended.\n", __func__); + "%s.Device is suspended, %s\n", + __func__, current->comm); return; } @@ -412,9 +427,14 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) { u32 geni_ios = 0; unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; + struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - if (device_pending_suspend(uport)) + if (!uart_console(uport) && device_pending_suspend(uport)) { + IPC_LOG_MSG(port->ipc_log_misc, + "%s.Device is suspended, %s\n", + __func__, current->comm); return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; + } geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) @@ -436,7 +456,8 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, if (device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, - "%s.Device is suspended.\n", __func__); + "%s.Device is suspended, %s: mctrl=0x%x\n", + __func__, current->comm, mctrl); return; } if (!(mctrl & TIOCM_RTS)) { @@ -449,6 +470,10 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, SE_UART_MANUAL_RFR); /* Write to flow control must complete before return to client*/ mb(); + IPC_LOG_MSG(port->ipc_log_misc, + "%s:%s, mctrl=0x%x, manual_rfr=0x%x, flow=%s\n", + __func__, current->comm, mctrl, uart_manual_rfr, + (port->manual_flow ? "OFF" : "ON")); } static const char *msm_geni_serial_get_type(struct uart_port *uport) @@ -878,6 +903,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned int geni_status; unsigned int geni_ios; + static unsigned int ios_log_limit; if (!uart_console(uport) && !pm_runtime_active(uport->dev)) { IPC_LOG_MSG(msm_port->ipc_log_misc, @@ -920,9 +946,11 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) return; check_flow_ctrl: geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); - if (!(geni_ios & IO2_DATA_IN)) + if (++ios_log_limit % 5 == 0) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: ios: 0x%08x\n", - __func__, geni_ios); + __func__, geni_ios); + ios_log_limit = 0; + } exit_start_tx: if (!uart_console(uport)) msm_geni_serial_power_off(uport); @@ -1023,8 +1051,21 @@ static void start_rx_sequencer(struct uart_port *uport) u32 geni_se_param = UART_PARAM_RFR_OPEN; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - if (geni_status & S_GENI_CMD_ACTIVE) + if (geni_status & S_GENI_CMD_ACTIVE) { + if (port->xfer_mode == SE_DMA && !port->rx_dma) { + IPC_LOG_MSG(port->ipc_log_misc, + "%s: GENI: 0x%x\n", __func__, geni_status); + ret = geni_se_rx_dma_prep(port->wrapper_dev, + uport->membase, port->rx_buf, DMA_RX_BUF_SIZE, + &port->rx_dma); + if (ret) { + IPC_LOG_MSG(port->ipc_log_misc, + "%s: RX buff Fail %d\n", __func__, ret); + goto exit_start_rx_sequencer; + } + } msm_geni_serial_stop_rx(uport); + } /* Start RX with the RFR_OPEN to keep RFR in always ready state */ geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); @@ -1057,9 +1098,10 @@ static void start_rx_sequencer(struct uart_port *uport) * go through. */ mb(); - geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); exit_start_rx_sequencer: - IPC_LOG_MSG(port->ipc_log_misc, "%s 0x%x\n", __func__, geni_status); + geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); + IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__, + geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0)); } static void msm_geni_serial_start_rx(struct uart_port *uport) @@ -1157,6 +1199,8 @@ static void stop_rx_sequencer(struct uart_port *uport) DMA_RX_BUF_SIZE); port->rx_dma = (dma_addr_t)NULL; } + geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); + IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x\n", __func__, geni_status); } static void msm_geni_serial_stop_rx(struct uart_port *uport) @@ -1693,16 +1737,6 @@ static int msm_geni_serial_startup(struct uart_port *uport) } } - if (unlikely(get_se_proto(uport->membase) != UART)) { - dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", - __func__, get_se_proto(uport->membase)); - ret = -ENXIO; - goto exit_startup; - } - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", - __func__, - get_se_m_fw(uport->membase), get_se_s_fw(uport->membase)); - get_tx_fifo_size(msm_port); if (!msm_port->port_setup) { if (msm_geni_serial_port_setup(uport)) @@ -1792,6 +1826,7 @@ static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback, SE_UART_TX_STOP_BIT_LEN); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG); + geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG); } static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate) @@ -1855,6 +1890,9 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (clk_div <= 0) goto exit_set_termios; + if (IS_ENABLED(CONFIG_SERIAL_MSM_WITH_HALF_SAMPLING)) + clk_div *= 2; + uport->uartclk = clk_rate; clk_set_rate(port->serial_rsc.se_clk, clk_rate); ser_clk_cfg |= SER_CLK_EN; @@ -2028,6 +2066,23 @@ static ssize_t msm_geni_serial_xfer_mode_store(struct device *dev, static DEVICE_ATTR(xfer_mode, 0644, msm_geni_serial_xfer_mode_show, msm_geni_serial_xfer_mode_store); +static ssize_t ver_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct msm_geni_serial_port *port = platform_get_drvdata(pdev); + ssize_t ret = 0; + int len = (sizeof(struct msm_geni_serial_ver_info) * 2); + + ret = snprintf(buf, len, "FW ver=0x%x%x, HW ver=%d.%d.%d\n", + port->ver_info.m_fw_ver, port->ver_info.m_fw_ver, + port->ver_info.hw_major_ver, port->ver_info.hw_minor_ver, + port->ver_info.hw_step_ver); + + return ret; +} +static DEVICE_ATTR_RO(ver_info); + #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) static int __init msm_geni_console_setup(struct console *co, char *options) { @@ -2133,6 +2188,9 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, goto exit_geni_serial_earlyconsetup; } + if (IS_ENABLED(CONFIG_SERIAL_MSM_WITH_HALF_SAMPLING)) + clk_div *= 2; + s_clk_cfg |= SER_CLK_EN; s_clk_cfg |= (clk_div << CLK_DIV_SHFT); @@ -2325,6 +2383,43 @@ static const struct of_device_id msm_geni_device_tbl[] = { {}, }; +static int msm_geni_serial_get_ver_info(struct uart_port *uport) +{ + int hw_ver, ret = 0; + struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); + + se_geni_clks_on(&msm_port->serial_rsc); + /* Basic HW and FW info */ + if (unlikely(get_se_proto(uport->membase) != UART)) { + dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", + __func__, get_se_proto(uport->membase)); + ret = -ENXIO; + goto exit_ver_info; + } + + msm_port->ver_info.m_fw_ver = get_se_m_fw(uport->membase); + msm_port->ver_info.s_fw_ver = get_se_s_fw(uport->membase); + IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", + __func__, + msm_port->ver_info.m_fw_ver, msm_port->ver_info.s_fw_ver); + + hw_ver = geni_se_qupv3_hw_version(msm_port->wrapper_dev, + &msm_port->ver_info.hw_major_ver, + &msm_port->ver_info.hw_minor_ver, + &msm_port->ver_info.hw_step_ver); + if (hw_ver) + dev_err(uport->dev, "%s:Err getting HW version %d\n", + __func__, hw_ver); + else + IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: HW Ver:%x.%x.%x\n", + __func__, msm_port->ver_info.hw_major_ver, + msm_port->ver_info.hw_minor_ver, + msm_port->ver_info.hw_step_ver); +exit_ver_info: + se_geni_clks_off(&msm_port->serial_rsc); + return ret; +} + static int msm_geni_serial_probe(struct platform_device *pdev) { int ret = 0; @@ -2350,20 +2445,21 @@ static int msm_geni_serial_probe(struct platform_device *pdev) } if (pdev->dev.of_node) { - if (drv->cons) + if (drv->cons) { line = of_alias_get_id(pdev->dev.of_node, "serial"); - else + if (line < 0) + line = 0; + } else { line = of_alias_get_id(pdev->dev.of_node, "hsuart"); + if (line < 0) + line = uart_line_id++; + else + uart_line_id++; + } } else { line = pdev->id; } - if (line < 0) - line = atomic_inc_return(&uart_line_id) - 1; - - if ((line < 0) || (line >= GENI_UART_NR_PORTS)) - return -ENXIO; - if (strcmp(id->compatible, "qcom,msm-geni-console") == 0) snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_UART_%d Init", line); @@ -2546,8 +2642,13 @@ static int msm_geni_serial_probe(struct platform_device *pdev) line, uport->fifosize, is_console); device_create_file(uport->dev, &dev_attr_loopback); device_create_file(uport->dev, &dev_attr_xfer_mode); + device_create_file(uport->dev, &dev_attr_ver_info); msm_geni_serial_debug_init(uport, is_console); dev_port->port_setup = false; + ret = msm_geni_serial_get_ver_info(uport); + if (ret) + goto exit_geni_serial_probe; + ret = uart_add_one_port(drv, uport); if (!ret) { if (strcmp(id->compatible, "qcom,msm-geni-console") == 0) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index a79f18edf2bd490f47d08f1af2283a19e66ca068..e48523da47ac96de1771f5a694e57bee6fc5beb8 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1483,7 +1483,7 @@ static int __init sc16is7xx_init(void) ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); if (ret < 0) { pr_err("failed to init sc16is7xx i2c --> %d\n", ret); - return ret; + goto err_i2c; } #endif @@ -1491,10 +1491,18 @@ static int __init sc16is7xx_init(void) ret = spi_register_driver(&sc16is7xx_spi_uart_driver); if (ret < 0) { pr_err("failed to init sc16is7xx spi --> %d\n", ret); - return ret; + goto err_spi; } #endif return ret; + +err_spi: +#ifdef CONFIG_SERIAL_SC16IS7XX_I2C + i2c_del_driver(&sc16is7xx_i2c_uart_driver); +#endif +err_i2c: + uart_unregister_driver(&sc16is7xx_uart); + return ret; } module_init(sc16is7xx_init); diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index f438a2158006d9ad6c6c46e564a021f62424bf67..b0da63737aa1923863ed1445847bd0d0aaf37e23 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1270,7 +1270,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, * * Return: 0 on success, negative errno otherwise. */ -static int __init cdns_uart_console_setup(struct console *co, char *options) +static int cdns_uart_console_setup(struct console *co, char *options) { struct uart_port *port = &cdns_uart_port[co->index]; int baud = 9600; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7e351d20539382e32fd19636590f22f48ec6e2bf..dba4f53a7fff90f47c0b5176acc3347063b45a5a 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -511,6 +511,8 @@ static const struct file_operations hung_up_tty_fops = { static DEFINE_SPINLOCK(redirect_lock); static struct file *redirect; +extern void tty_sysctl_init(void); + /** * tty_wakeup - request more data * @tty: terminal @@ -3332,6 +3334,7 @@ void console_sysfs_notify(void) */ int __init tty_init(void) { + tty_sysctl_init(); cdev_init(&tty_cdev, &tty_fops); if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index ca656ef8de648c7fcca3757ba981f04528f6966c..01fcdc7ff07716f3f27e64d14c8dd5dae187c603 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -155,6 +155,13 @@ static void put_ldops(struct tty_ldisc_ops *ldops) * takes tty_ldiscs_lock to guard against ldisc races */ +#if defined(CONFIG_LDISC_AUTOLOAD) + #define INITIAL_AUTOLOAD_STATE 1 +#else + #define INITIAL_AUTOLOAD_STATE 0 +#endif +static int tty_ldisc_autoload = INITIAL_AUTOLOAD_STATE; + static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) { struct tty_ldisc *ld; @@ -169,6 +176,8 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) */ ldops = get_ldops(disc); if (IS_ERR(ldops)) { + if (!capable(CAP_SYS_MODULE) && !tty_ldisc_autoload) + return ERR_PTR(-EPERM); request_module("tty-ldisc-%d", disc); ldops = get_ldops(disc); if (IS_ERR(ldops)) @@ -841,3 +850,41 @@ void tty_ldisc_deinit(struct tty_struct *tty) tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; } + +static int zero; +static int one = 1; +static struct ctl_table tty_table[] = { + { + .procname = "ldisc_autoload", + .data = &tty_ldisc_autoload, + .maxlen = sizeof(tty_ldisc_autoload), + .mode = 0644, + .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &one, + }, + { } +}; + +static struct ctl_table tty_dir_table[] = { + { + .procname = "tty", + .mode = 0555, + .child = tty_table, + }, + { } +}; + +static struct ctl_table tty_root_table[] = { + { + .procname = "dev", + .mode = 0555, + .child = tty_dir_table, + }, + { } +}; + +void tty_sysctl_init(void) +{ + register_sysctl_table(tty_root_table); +} diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index cf85ca863385fcdd8734d7fd69711adbb7c299f1..69352c50eab01b42f8f743f1c594e1ddab4a6ae7 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -473,11 +473,6 @@ static int usb_unbind_interface(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - /* Undo any residual pm_autopm_get_interface_* calls */ - for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r) - usb_autopm_put_interface_no_suspend(intf); - atomic_set(&intf->pm_usage_cnt, 0); - if (!error) usb_autosuspend_device(udev); @@ -1640,7 +1635,6 @@ void usb_autopm_put_interface(struct usb_interface *intf) int status; usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); status = pm_runtime_put_sync(&intf->dev); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), @@ -1669,7 +1663,6 @@ void usb_autopm_put_interface_async(struct usb_interface *intf) int status; usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); status = pm_runtime_put(&intf->dev); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), @@ -1691,7 +1684,6 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); pm_runtime_put_noidle(&intf->dev); } EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); @@ -1722,8 +1714,6 @@ int usb_autopm_get_interface(struct usb_interface *intf) status = pm_runtime_get_sync(&intf->dev); if (status < 0) pm_runtime_put_sync(&intf->dev); - else - atomic_inc(&intf->pm_usage_cnt); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), status); @@ -1757,8 +1747,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) status = pm_runtime_get(&intf->dev); if (status < 0 && status != -EINPROGRESS) pm_runtime_put_noidle(&intf->dev); - else - atomic_inc(&intf->pm_usage_cnt); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), status); @@ -1782,7 +1770,6 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); usb_mark_last_busy(udev); - atomic_inc(&intf->pm_usage_cnt); pm_runtime_get_noresume(&intf->dev); } EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); @@ -1903,14 +1890,11 @@ int usb_runtime_idle(struct device *dev) return -EBUSY; } -int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; - if (enable && !udev->usb2_hw_lpm_allowed) - return 0; - if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) @@ -1920,6 +1904,24 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } +int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_capable || + !udev->usb2_hw_lpm_allowed || + udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 1); +} + +int usb_disable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 0); +} + #endif /* CONFIG_PM */ struct bus_type usb_bus_type = { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8ce80fa255a6ae88dac0967d461ed5767e806808..cbe1539d06b2d16d35ecaffb24346042c8ad08ce 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3185,8 +3185,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } /* disable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); if (usb_disable_ltm(udev)) { dev_err(&udev->dev, "Failed to disable LTM before suspend\n."); @@ -3224,8 +3223,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_enable_ltm(udev); err_ltm: /* Try to enable USB2 hardware LPM again */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); if (udev->do_remote_wakeup) (void) usb_disable_remote_wakeup(udev); @@ -3511,8 +3509,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) hub_port_logical_disconnect(hub, port1); } else { /* Try to enable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); /* Try to enable USB3 LTM */ usb_enable_ltm(udev); @@ -3600,6 +3597,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); unsigned port1; int status; @@ -3633,6 +3631,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) } if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) { + if (!hdev->parent && hcd->primary_hcd) + usb_phy_powerup(hcd->primary_hcd->usb3_phy); + /* Enable hub to send remote wakeup for all ports. */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { status = set_port_feature(hdev, @@ -3642,6 +3643,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT, USB_PORT_FEAT_REMOTE_WAKE_MASK); } + + if (!hdev->parent && hcd->primary_hcd) + usb_phy_powerdown(hcd->primary_hcd->usb3_phy); } dev_dbg(&intf->dev, "%s\n", __func__); @@ -4348,7 +4352,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { udev->usb2_hw_lpm_allowed = 1; - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); } } @@ -5511,8 +5515,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) /* Disable USB2 hardware LPM. * It will be re-enabled by the enumeration process. */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); /* Disable LPM and LTM while we reset the device and reinstall the alt * settings. Device-initiated LPM settings, and system exit latency @@ -5622,7 +5625,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 833ddd228e3a80cc150a484cc683a567df48a62e..c3f3f6370f64c377c2318f15021cacc9774d8a24 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -818,9 +818,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - if (size <= 0 || !buf || !index) + if (size <= 0 || !buf) return -EINVAL; buf[0] = 0; + if (index <= 0 || index >= 256) + return -EINVAL; tbuf = kmalloc(256, GFP_NOIO); if (!tbuf) return -ENOMEM; @@ -1182,8 +1184,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev->actconfig->interface[i] = NULL; } - if (dev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(dev, 0); + usb_disable_usb2_hardware_lpm(dev); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 733479ddf8a7924f4b817c269ed96d1969ecbb2b..7104cc76d216acd1d055b786fb7f8628f158baa7 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -282,6 +282,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* DJI CineSSD */ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + /* Kingston DataTraveler 3.0 */ + { USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM }, + /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d930bfda40101457dad980ec432c0b73d7193981..15c19863f7b34a49a6c3118347322ea5b5309348 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -508,7 +508,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, if (!ret) { udev->usb2_hw_lpm_allowed = value; - ret = usb_set_usb2_hardware_lpm(udev, value); + if (value) + ret = usb_enable_usb2_hardware_lpm(udev); + else + ret = usb_disable_usb2_hardware_lpm(udev); } usb_unlock_device(udev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 4c73d8e93c3184cf58ff1b6404378df5249ea6a4..79239342c95ba970a17bd09be92ff864ceee3835 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -89,7 +89,8 @@ extern int usb_remote_wakeup(struct usb_device *dev); extern int usb_runtime_suspend(struct device *dev); extern int usb_runtime_resume(struct device *dev); extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); +extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev); +extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev); #else @@ -109,7 +110,12 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + return 0; +} + +static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { return 0; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index da67caf2d47f09a35b5860017104167a735235e2..8d1a8d9d3132afd0f2bb6b3fa89fca4ef8e4c203 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -45,6 +45,7 @@ #define DWC3_EP0_SETUP_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 +#define MAX_ERROR_RECOVERY_TRIES 3 #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_BUFFERS_SIZE 4096 @@ -1204,6 +1205,7 @@ struct dwc3 { * connected devices on PM resume. */ bool host_poweroff_in_pm_suspend; + int retries_on_error; }; #define work_to_dwc(w) (container_of((w), struct dwc3, drd_work)) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 0f7f7ec2c1e6663716599aee7dc8d277a8a3bcde..29d056d5a63a37b7f0cf260d3dc3a85b6ca3e9c2 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -281,6 +281,7 @@ struct dwc3_msm { unsigned int max_power; bool charging_disabled; enum dwc3_drd_state drd_state; + enum bus_vote default_bus_vote; enum bus_vote override_bus_vote; u32 bus_perf_client; struct msm_bus_scale_pdata *bus_scale_table; @@ -322,10 +323,13 @@ struct dwc3_msm { enum usb_device_speed override_usb_speed; u32 *gsi_reg; int gsi_reg_offset_cnt; + bool gsi_io_coherency_disabled; struct notifier_block dpdm_nb; struct regulator *dpdm_reg; + u64 dummy_gsi_db; + dma_addr_t dummy_gsi_db_dma; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -1003,6 +1007,14 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, ep->name, request->db_reg_phs_addr_lsb, (unsigned long long)request->mapped_db_reg_phs_addr_lsb); + /* + * Replace dummy doorbell address with real one as IPA connection + * is setup now and GSI must be ready to handle doorbell updates. + */ + dwc3_msm_write_reg_field(mdwc->base, + GSI_DBL_ADDR_H(mdwc->gsi_reg[DBL_ADDR_H], (n)), + ~0x0, 0x0); + dwc3_msm_write_reg(mdwc->base, GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)), (u32)request->mapped_db_reg_phs_addr_lsb); @@ -1110,7 +1122,7 @@ static void gsi_endxfer_for_ep(struct usb_ep *ep) } /** - * Allocates and configures TRBs for GSI EPs. + * Allocates Buffers and TRBs. Configures TRBs for GSI EPs. * * @usb_ep - pointer to usb_ep instance. * @request - pointer to GSI request. @@ -1120,9 +1132,12 @@ static void gsi_endxfer_for_ep(struct usb_ep *ep) static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req) { int i = 0; - dma_addr_t buffer_addr = req->dma; + size_t len; + unsigned long dma_attr; + dma_addr_t buffer_addr; struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; + struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct dwc3_trb *trb; int num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2) : (req->num_bufs + 2); @@ -1134,14 +1149,37 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req) return -ESHUTDOWN; } - dep->trb_pool = dma_zalloc_coherent(dwc->sysdev, + if (mdwc->gsi_io_coherency_disabled) + dma_attr = DMA_ATTR_FORCE_NON_COHERENT; + else + dma_attr = DMA_ATTR_FORCE_COHERENT; + + /* Allocate TRB buffers */ + + len = req->buf_len * req->num_bufs; + req->buf_base_addr = dma_alloc_attrs(dwc->sysdev, len, &req->dma, + GFP_KERNEL, dma_attr); + if (!req->buf_base_addr) { + dev_err(dwc->dev, "%s: buf_base_addr allocate failed %s\n", + dep->name); + return -ENOMEM; + } + + dma_get_sgtable(dwc->sysdev, &req->sgt_data_buff, req->buf_base_addr, + req->dma, len); + + buffer_addr = req->dma; + + /* Allocate and configgure TRBs */ + + dep->trb_pool = dma_alloc_attrs(dwc->sysdev, num_trbs * sizeof(struct dwc3_trb), - &dep->trb_pool_dma, GFP_KERNEL); + &dep->trb_pool_dma, GFP_KERNEL, dma_attr); if (!dep->trb_pool) { dev_err(dep->dwc->dev, "failed to alloc trb dma pool for %s\n", dep->name); - return -ENOMEM; + goto free_trb_buffer; } dep->num_trbs = num_trbs; @@ -1238,10 +1276,17 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req) } return 0; + +free_trb_buffer: + dma_free_attrs(dwc->sysdev, len, req->buf_base_addr, req->dma, + dma_attr); + req->buf_base_addr = NULL; + sg_free_table(&req->sgt_data_buff); + return -ENOMEM; } /** - * Frees TRBs for GSI EPs. + * Frees TRBs and buffers for GSI EPs. * * @usb_ep - pointer to usb_ep instance. * @@ -1250,20 +1295,32 @@ static void gsi_free_trbs(struct usb_ep *ep, struct usb_gsi_request *req) { struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; + struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); + unsigned long dma_attr; if (dep->endpoint.ep_type == EP_TYPE_NORMAL) return; + if (mdwc->gsi_io_coherency_disabled) + dma_attr = DMA_ATTR_FORCE_NON_COHERENT; + else + dma_attr = DMA_ATTR_FORCE_COHERENT; + /* Free TRBs and TRB pool for EP */ if (dep->trb_pool_dma) { - dma_free_coherent(dwc->sysdev, + dma_free_attrs(dwc->sysdev, dep->num_trbs * sizeof(struct dwc3_trb), - dep->trb_pool, - dep->trb_pool_dma); + dep->trb_pool, dep->trb_pool_dma, dma_attr); dep->trb_pool = NULL; dep->trb_pool_dma = 0; } sg_free_table(&req->sgt_trb_xfer_ring); + + /* free TRB buffers */ + dma_free_attrs(dwc->sysdev, req->buf_len * req->num_bufs, + req->buf_base_addr, req->dma, dma_attr); + req->buf_base_addr = NULL; + sg_free_table(&req->sgt_data_buff); } /** * Configures GSI EPs. For GSI EPs we need to set interrupter numbers. @@ -1279,9 +1336,22 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request) struct dwc3_gadget_ep_cmd_params params; const struct usb_endpoint_descriptor *desc = ep->desc; const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc; + int n = ep->ep_intr_num - 1; u32 reg; int ret; + /* setup dummy doorbell as IPA connection isn't setup yet */ + dwc3_msm_write_reg_field(mdwc->base, + GSI_DBL_ADDR_H(mdwc->gsi_reg[DBL_ADDR_H], (n)), + ~0x0, (u32)((u64)mdwc->dummy_gsi_db_dma >> 32)); + + dwc3_msm_write_reg_field(mdwc->base, + GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)), + ~0x0, (u32)mdwc->dummy_gsi_db_dma); + dev_dbg(mdwc->dev, "Dummy DB Addr %pK: %llx %llx (LSB)\n", + &mdwc->dummy_gsi_db, mdwc->dummy_gsi_db_dma, + (u32)mdwc->dummy_gsi_db_dma); + memset(¶ms, 0x00, sizeof(params)); /* Configure GSI EP */ @@ -1861,8 +1931,13 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, reg |= DWC3_GCTL_CORESOFTRESET; dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg); - /* restart USB which performs full reset and reconnect */ - schedule_work(&mdwc->restart_usb_work); + /* + * If core could not recover after MAX_ERROR_RECOVERY_TRIES + * skip the restart USB work and keep the core in softreset + * state + */ + if (dwc->retries_on_error < MAX_ERROR_RECOVERY_TRIES) + schedule_work(&mdwc->restart_usb_work); break; case DWC3_CONTROLLER_RESET_EVENT: dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n"); @@ -1972,6 +2047,19 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, } mdwc->gsi_ev_buff[i] = evt; } + /* + * Set-up dummy buffer to use as doorbell while IPA GSI + * connection is in progress. + */ + mdwc->dummy_gsi_db_dma = dma_map_single(dwc->sysdev, + &mdwc->dummy_gsi_db, + sizeof(mdwc->dummy_gsi_db), + DMA_FROM_DEVICE); + + if (dma_mapping_error(dwc->sysdev, mdwc->dummy_gsi_db_dma)) { + dev_err(dwc->dev, "failed to map dummy doorbell buffer\n"); + mdwc->dummy_gsi_db_dma = (dma_addr_t)NULL; + } break; case DWC3_GSI_EVT_BUF_SETUP: dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_SETUP\n"); @@ -2045,6 +2133,12 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma); } + if (mdwc->dummy_gsi_db_dma) { + dma_unmap_single(dwc->sysdev, mdwc->dummy_gsi_db_dma, + sizeof(mdwc->dummy_gsi_db), + DMA_FROM_DEVICE); + mdwc->dummy_gsi_db_dma = (dma_addr_t)NULL; + } break; case DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER: dwc3_msm_dbm_disable_updxfer(dwc, value); @@ -2327,7 +2421,7 @@ static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) * from userspace. */ if (bv >= mdwc->bus_scale_table->num_usecases) - bv_index = BUS_VOTE_NOMINAL; + bv_index = mdwc->default_bus_vote; else if (bv == BUS_VOTE_NONE) bv_index = BUS_VOTE_NONE; @@ -2569,7 +2663,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) if (mdwc->in_host_mode && mdwc->max_rh_port_speed == USB_SPEED_HIGH) dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_SVS); else - dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_NOMINAL); + dwc3_msm_update_bus_bw(mdwc, mdwc->default_bus_vote); /* Vote for TCXO while waking up USB HSPHY */ ret = clk_prepare_enable(mdwc->xo_clk); @@ -2785,7 +2879,7 @@ static void dwc3_resume_work(struct work_struct *w) dwc->maximum_speed = USB_SPEED_HIGH; if (mdwc->override_usb_speed && - mdwc->override_usb_speed < dwc->maximum_speed) { + mdwc->override_usb_speed <= dwc->maximum_speed) { dwc->maximum_speed = mdwc->override_usb_speed; dwc->gadget.max_speed = dwc->maximum_speed; dbg_event(0xFF, "override_speed", @@ -3429,7 +3523,7 @@ static ssize_t bus_vote_store(struct device *dev, && (mdwc->max_rh_port_speed == USB_SPEED_HIGH)) bv = BUS_VOTE_SVS; else - bv = BUS_VOTE_NOMINAL; + bv = mdwc->default_bus_vote; dwc3_msm_update_bus_bw(mdwc, bv); } @@ -3658,6 +3752,10 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->use_pdc_interrupts = of_property_read_bool(node, "qcom,use-pdc-interrupts"); + + mdwc->gsi_io_coherency_disabled = of_property_read_bool(node, + "qcom,gsi-disable-io-coherency"); + dwc3_set_notifier(&dwc3_msm_notify_event); ret = dwc3_msm_init_iommu(mdwc); @@ -3711,10 +3809,20 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } + /* use default as nominal bus voting */ + mdwc->default_bus_vote = BUS_VOTE_NOMINAL; + ret = of_property_read_u32(node, "qcom,default-bus-vote", + &mdwc->default_bus_vote); + mdwc->bus_scale_table = msm_bus_cl_get_pdata(pdev); if (mdwc->bus_scale_table) { mdwc->bus_perf_client = msm_bus_scale_register_client(mdwc->bus_scale_table); + + /* default_bus_vote is out of range, use nominal bus voting */ + if (mdwc->default_bus_vote >= + mdwc->bus_scale_table->num_usecases) + mdwc->default_bus_vote = BUS_VOTE_NOMINAL; } dwc = platform_get_drvdata(mdwc->dwc3); @@ -3990,7 +4098,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, dev_dbg(mdwc->dev, "set core clk rate %ld\n", mdwc->core_clk_rate); mdwc->max_rh_port_speed = USB_SPEED_UNKNOWN; - dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_NOMINAL); + dwc3_msm_update_bus_bw(mdwc, mdwc->default_bus_vote); } } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 62d06d002de008a6fe41c5bf88ef50fbe1019035..ca9511afa3d3bdf24f1333455a898c1f679846a2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -845,6 +845,21 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } + + if (dep->number == 1 && dwc->ep0state != EP0_SETUP_PHASE) { + unsigned int dir; + + dbg_log_string("CTRLPEND", dwc->ep0state); + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + + dwc->eps[0]->trb_enqueue = 0; + dwc->eps[1]->trb_enqueue = 0; + } + dbg_log_string("DONE for %s(%d)", dep->name, dep->number); } @@ -2091,6 +2106,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) reg1 |= DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg1); + dwc->err_evt_seen = false; dwc->pullups_connected = false; __dwc3_gadget_ep_disable(dwc->eps[0]); @@ -2195,6 +2211,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) } disable_irq(dwc->irq); + + /* prevent pending bh to run later */ + flush_work(&dwc->bh_work); + spin_lock_irqsave(&dwc->lock, flags); if (dwc->ep0state != EP0_SETUP_PHASE) dbg_event(0xFF, "EP0 is not in SETUP phase\n", 0); @@ -3261,6 +3281,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } + /* Reset the retry on erratic error event count */ + dwc->retries_on_error = 0; + /* * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed * each time on Connect Done. @@ -3624,7 +3647,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc->dbg_gadget_events.sof++; break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - dbg_event(0xFF, "ERROR", 0); + dbg_event(0xFF, "ERROR", dwc->retries_on_error); dwc->dbg_gadget_events.erratic_error++; dwc->err_evt_seen = true; break; @@ -3682,6 +3705,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) if (dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT, 0)) dwc->err_evt_seen = 0; + dwc->retries_on_error++; break; } diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 1c51407ae16e368e16fb72f4e21453e5b82d32c9..457e2b181f1cb35bdc1bf037d819df48ca7caeb7 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -329,6 +329,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item, gi->composite.gadget_driver.udc_name = NULL; goto err; } + schedule_work(&gi->work); } mutex_unlock(&gi->lock); return len; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 5e222e30b22df9255febe51435f82ea2e9b9f833..9f83c2d821935df877092de6aa1f9a3c4739fb98 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -74,8 +74,6 @@ static DEFINE_IDA(gsi_ida); static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi); -static int gsi_alloc_trb_buffer(struct f_gsi *gsi); -static void gsi_free_trb_buffer(struct f_gsi *gsi); static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned int len, gfp_t flags); static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt); @@ -551,7 +549,8 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) struct ipa_req_chan_out_params ipa_in_channel_out_params; struct ipa_req_chan_out_params ipa_out_channel_out_params; - log_event_dbg("%s: USB GSI IN OPS", __func__); + log_event_dbg("IN: num_bufs:=%zu, buf_len=%zu\n", + d_port->in_request.num_bufs, d_port->in_request.buf_len); ret = usb_gsi_ep_op(d_port->in_ep, &d_port->in_request, GSI_EP_OP_PREPARE_TRBS); if (ret) { @@ -565,7 +564,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_STARTXFER failed: %d\n", __func__, ret); - return ret; + goto free_trb_ep_in; } d_port->in_xfer_rsc_index = usb_gsi_ep_op(d_port->in_ep, NULL, @@ -607,13 +606,15 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) gsi_channel_info.depcmd_hi_addr; if (d_port->out_ep) { - log_event_dbg("%s: USB GSI OUT OPS", __func__); + log_event_dbg("OUT: num_bufs:=%zu, buf_len=%zu\n", + d_port->out_request.num_bufs, + d_port->out_request.buf_len); ret = usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, GSI_EP_OP_PREPARE_TRBS); if (ret) { log_event_err("%s: GSI_EP_OP_PREPARE_TRBS failed: %d\n", __func__, ret); - return ret; + goto end_xfer_ep_in; } ret = usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, @@ -621,7 +622,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_STARTXFER failed: %d\n", __func__, ret); - return ret; + goto free_trb_ep_out; } d_port->out_xfer_rsc_index = @@ -705,7 +706,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) conn_params); if (ret) { log_event_err("%s: IPA connect failed %d", __func__, ret); - return ret; + goto end_xfer_ep_out; } log_event_dbg("%s: xdci_connect done", __func__); @@ -733,6 +734,23 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) d_port->out_request.db_reg_phs_addr_msb = ipa_out_channel_out_params.db_reg_phs_addr_msb; } + + return ret; + +end_xfer_ep_out: + if (d_port->out_ep) + usb_gsi_ep_op(d_port->out_ep, NULL, + GSI_EP_OP_ENDXFER); +free_trb_ep_out: + if (d_port->out_ep) + usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, + GSI_EP_OP_FREE_TRBS); +end_xfer_ep_in: + usb_gsi_ep_op(d_port->in_ep, NULL, + GSI_EP_OP_ENDXFER); +free_trb_ep_in: + usb_gsi_ep_op(d_port->in_ep, &d_port->in_request, + GSI_EP_OP_FREE_TRBS); return ret; } @@ -821,9 +839,6 @@ static void ipa_disconnect_work_handler(struct gsi_data_port *d_port) if (gsi->d_port.out_ep) usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request, GSI_EP_OP_FREE_TRBS); - - /* free buffers allocated with each TRB */ - gsi_free_trb_buffer(gsi); } static int ipa_suspend_work_handler(struct gsi_data_port *d_port) @@ -931,19 +946,22 @@ static void ipa_work_handler(struct work_struct *w) usb_gadget_autopm_get(d_port->gadget); log_event_dbg("%s: get = %d", __func__, atomic_read(&gad_dev->power.usage_count)); - /* allocate buffers used with each TRB */ - ret = gsi_alloc_trb_buffer(gsi); - if (ret) { - log_event_err("%s: gsi_alloc_trb_failed\n", - __func__); - break; - } d_port->sm_state = STATE_CONNECT_IN_PROGRESS; log_event_dbg("%s: ST_INIT_EVT_CONN_IN_PROG", __func__); - if (peek_event(d_port) != EVT_DISCONNECTED) - ipa_connect_channels(d_port); + if (peek_event(d_port) != EVT_DISCONNECTED) { + ret = ipa_connect_channels(d_port); + if (ret) { + log_event_err("%s: ipa_connect_channels failed\n", + __func__); + usb_gadget_autopm_put_async( + d_port->gadget); + d_port->sm_state = STATE_INITIALIZED; + break; + } + } + } else if (event == EVT_HOST_READY) { /* * When in a composition such as RNDIS + ADB, @@ -958,15 +976,14 @@ static void ipa_work_handler(struct work_struct *w) usb_gadget_autopm_get(d_port->gadget); log_event_dbg("%s: get = %d", __func__, atomic_read(&gad_dev->power.usage_count)); - /* allocate buffers used with each TRB */ - ret = gsi_alloc_trb_buffer(gsi); + ret = ipa_connect_channels(d_port); if (ret) { - log_event_err("%s: gsi_alloc_trb_failed\n", - __func__); + log_event_err("%s: ipa_connect_channels failed\n", + __func__); + usb_gadget_autopm_put_async(d_port->gadget); break; } - ipa_connect_channels(d_port); ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; log_event_dbg("%s: ST_INIT_EVT_HOST_READY", __func__); @@ -1078,16 +1095,6 @@ static void ipa_work_handler(struct work_struct *w) log_event_dbg("%s: ST_CON_EVT_CON", __func__); } break; - case STATE_DISCONNECTED: - if (event == EVT_CONNECT_IN_PROGRESS) { - ipa_connect_channels(d_port); - d_port->sm_state = STATE_CONNECT_IN_PROGRESS; - log_event_dbg("%s: ST_DIS_EVT_CON_IN_PROG", __func__); - } else if (event == EVT_UNINITIALIZED) { - d_port->sm_state = STATE_UNINITIALIZED; - log_event_dbg("%s: ST_DIS_EVT_UNINIT", __func__); - } - break; case STATE_SUSPEND_IN_PROGRESS: if (event == EVT_IPA_SUSPEND) { d_port->sm_state = STATE_SUSPENDED; @@ -2310,106 +2317,6 @@ static int gsi_get_alt(struct usb_function *f, unsigned int intf) return -EINVAL; } -static int gsi_alloc_trb_buffer(struct f_gsi *gsi) -{ - u32 len_in = 0, len_out = 0; - int ret = 0; - struct device *dev; - - log_event_dbg("allocate trb's buffer\n"); - - dev = gsi->d_port.gadget->dev.parent; - if (gsi->d_port.in_ep && !gsi->d_port.in_request.buf_base_addr) { - log_event_dbg("IN: num_bufs:=%zu, buf_len=%zu\n", - gsi->d_port.in_request.num_bufs, - gsi->d_port.in_request.buf_len); - - len_in = gsi->d_port.in_request.buf_len * - gsi->d_port.in_request.num_bufs; - gsi->d_port.in_request.buf_base_addr = - dma_zalloc_coherent(dev->parent, - len_in, &gsi->d_port.in_request.dma, GFP_KERNEL); - if (!gsi->d_port.in_request.buf_base_addr) { - dev_err(&gsi->d_port.gadget->dev, - "IN buf_base_addr allocate failed %s\n", - gsi->function.name); - ret = -ENOMEM; - goto fail1; - } - - dma_get_sgtable(dev->parent, - &gsi->d_port.in_request.sgt_data_buff, - gsi->d_port.in_request.buf_base_addr, - gsi->d_port.in_request.dma, len_in); - } - - if (gsi->d_port.out_ep && !gsi->d_port.out_request.buf_base_addr) { - log_event_dbg("OUT: num_bufs:=%zu, buf_len=%zu\n", - gsi->d_port.out_request.num_bufs, - gsi->d_port.out_request.buf_len); - - len_out = gsi->d_port.out_request.buf_len * - gsi->d_port.out_request.num_bufs; - gsi->d_port.out_request.buf_base_addr = - dma_zalloc_coherent(dev->parent, - len_out, &gsi->d_port.out_request.dma, GFP_KERNEL); - if (!gsi->d_port.out_request.buf_base_addr) { - dev_err(&gsi->d_port.gadget->dev, - "OUT buf_base_addr allocate failed %s\n", - gsi->function.name); - ret = -ENOMEM; - goto fail; - } - - dma_get_sgtable(dev->parent, - &gsi->d_port.out_request.sgt_data_buff, - gsi->d_port.out_request.buf_base_addr, - gsi->d_port.out_request.dma, len_out); - } - - log_event_dbg("finished allocating trb's buffer\n"); - return ret; - -fail: - if (len_in && gsi->d_port.in_request.buf_base_addr) { - dma_free_coherent(dev->parent, len_in, - gsi->d_port.in_request.buf_base_addr, - gsi->d_port.in_request.dma); - gsi->d_port.in_request.buf_base_addr = NULL; - } -fail1: - return ret; -} - -static void gsi_free_trb_buffer(struct f_gsi *gsi) -{ - u32 len; - - log_event_dbg("freeing trb's buffer\n"); - - if (gsi->d_port.out_ep && - gsi->d_port.out_request.buf_base_addr) { - len = gsi->d_port.out_request.buf_len * - gsi->d_port.out_request.num_bufs; - dma_free_coherent(gsi->d_port.gadget->dev.parent->parent, len, - gsi->d_port.out_request.buf_base_addr, - gsi->d_port.out_request.dma); - gsi->d_port.out_request.buf_base_addr = NULL; - sg_free_table(&gsi->d_port.out_request.sgt_data_buff); - } - - if (gsi->d_port.in_ep && - gsi->d_port.in_request.buf_base_addr) { - len = gsi->d_port.in_request.buf_len * - gsi->d_port.in_request.num_bufs; - dma_free_coherent(gsi->d_port.gadget->dev.parent->parent, len, - gsi->d_port.in_request.buf_base_addr, - gsi->d_port.in_request.dma); - gsi->d_port.in_request.buf_base_addr = NULL; - sg_free_table(&gsi->d_port.in_request.sgt_data_buff); - } -} - static int gsi_set_alt(struct usb_function *f, unsigned int intf, unsigned int alt) { @@ -3185,7 +3092,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) gsi->d_port.in_aggr_size = GSI_IN_MBIM_AGGR_SIZE; info.in_req_buf_len = GSI_IN_MBIM_AGGR_SIZE; info.in_req_num_buf = GSI_NUM_IN_BUFFERS; - gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE; + gsi->d_port.out_aggr_size = GSI_OUT_MBIM_AGGR_SIZE; info.out_req_buf_len = GSI_OUT_MBIM_BUF_LEN; info.out_req_num_buf = GSI_NUM_OUT_BUFFERS; info.notify_buf_len = sizeof(struct usb_cdc_notification); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index cfb55662ec214237c83131f8c8e9623221b78ddb..5fff57dc9d7681ce812b22f0f9e9695d215306a6 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -53,8 +53,9 @@ #define GSI_OUT_AGGR_SIZE 24576 #define GSI_IN_RNDIS_AGGR_SIZE 16384 -#define GSI_IN_MBIM_AGGR_SIZE 16384 +#define GSI_IN_MBIM_AGGR_SIZE 31744 #define GSI_IN_RMNET_AGGR_SIZE 16384 +#define GSI_OUT_MBIM_AGGR_SIZE 16384 #define GSI_ECM_AGGR_SIZE 2048 #define GSI_OUT_MBIM_BUF_LEN 16384 @@ -771,7 +772,8 @@ static struct usb_gadget_strings *rndis_gsi_strings[] = { }; /* mbim device descriptors */ -#define MBIM_NTB_DEFAULT_IN_SIZE (0x4000) +#define MBIM_NTB_DEFAULT_IN_SIZE GSI_IN_MBIM_AGGR_SIZE +#define MBIM_NTB_DEFAULT_OUT_SIZE GSI_OUT_MBIM_AGGR_SIZE static struct usb_cdc_ncm_ntb_parameters mbim_gsi_ntb_parameters = { .wLength = sizeof(mbim_gsi_ntb_parameters), @@ -781,7 +783,7 @@ static struct usb_cdc_ncm_ntb_parameters mbim_gsi_ntb_parameters = { .wNdpInPayloadRemainder = cpu_to_le16(0), .wNdpInAlignment = cpu_to_le16(4), - .dwNtbOutMaxSize = cpu_to_le32(0x4000), + .dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_OUT_SIZE), .wNdpOutDivisor = cpu_to_le16(4), .wNdpOutPayloadRemainder = cpu_to_le16(0), .wNdpOutAlignment = cpu_to_le16(4), diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index e0759a826b60f27da5f8f3ae6a5364ae59047e44..7fb31a3b53e6e960d5689640239144049ddc712c 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -958,6 +958,7 @@ net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req) break; } if (&req->req != _req) { + ep->stopped = stopped; spin_unlock_irqrestore(&ep->dev->lock, flags); return -EINVAL; } diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 9cbb061582a774676eb6cf4d42b8d84eb19b10f3..170327f84ea1985e4d7237bc0e43497eb1ecc520 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -870,9 +870,6 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma) (void) readl(&ep->dev->pci->pcimstctl); writel(BIT(DMA_START), &dma->dmastat); - - if (!ep->is_in) - stop_out_naking(ep); } static void start_dma(struct net2280_ep *ep, struct net2280_request *req) @@ -911,6 +908,7 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req) writel(BIT(DMA_START), &dma->dmastat); return; } + stop_out_naking(ep); } tmp = dmactl_default; @@ -1279,9 +1277,9 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) break; } if (&req->req != _req) { + ep->stopped = stopped; spin_unlock_irqrestore(&ep->dev->lock, flags); - dev_err(&ep->dev->pdev->dev, "%s: Request mismatch\n", - __func__); + ep_dbg(ep->dev, "%s: Request mismatch\n", __func__); return -EINVAL; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 65c0086e25ae6d8ac1a302308e954ef15d88c41d..8d349230b2c73f6de698009c1162b8533969967c 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -3208,6 +3208,9 @@ static int __init u132_hcd_init(void) printk(KERN_INFO "driver %s\n", hcd_name); workqueue = create_singlethread_workqueue("u132"); retval = platform_driver_register(&u132_platform_driver); + if (retval) + destroy_workqueue(workqueue); + return retval; } diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c index a5dec0800d63dfbc3b62c5b72accead0f63ad96b..eecea3704be1ba27e33a9aef1f6b2d0143253a7a 100644 --- a/drivers/usb/misc/diag_bridge.c +++ b/drivers/usb/misc/diag_bridge.c @@ -646,6 +646,8 @@ static const struct usb_device_id diag_bridge_ids[] = { .driver_info = DEV_ID(1), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90F3, 0), .driver_info = DEV_ID(0), }, + { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90FD, 0), + .driver_info = DEV_ID(0), }, {} /* terminating entry */ }; diff --git a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c index e3a6e7bfca45abf02e409b8fefaef234c40f9d51..ec3783568653b7fd84206de2b618d6ab7720fcc4 100644 --- a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c +++ b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include @@ -85,9 +85,11 @@ enum operation_mode { enum channel_mode { CHAN_MODE_USB, CHAN_MODE_DP, - CHAN_MODE_NUM, + /* update CHAN_MODE_NUM if new mode is added */ }; +#define CHAN_MODE_NUM 2 + /** * struct ssusb_redriver - representation of USB re-driver * @dev: struct device pointer diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 135c91c434bfb878d170011580ec6d275fc48368..ba8fcdb377e8056e35e5dde233bca40e429d230f 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -530,7 +530,7 @@ static int usb251xb_probe(struct usb251xb *hub) dev); int err; - if (np) { + if (np && of_id) { err = usb251xb_get_ofdata(hub, (struct usb251xb_data *)of_id->data); if (err) { diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 4f48f5730e12664ecffd6b2c2cbecf8ad98aca43..8ee98bc6c468bc7b814fdf2beb4bc6aef424c333 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -318,6 +318,7 @@ static void yurex_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &yurex_class); /* prevent more I/O from starting */ + usb_poison_urb(dev->urb); mutex_lock(&dev->io_mutex); dev->interface = NULL; mutex_unlock(&dev->io_mutex); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 29aed6b118f0379c7a8b8ade9c1141c2ea04ad57..3cbe8b8a7768f615a92429f700ed0fdcc8435e4d 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -3105,6 +3105,7 @@ static void usbpd_sm(struct work_struct *w) memcpy(&pd->src_cap_ext_db, rx_msg->payload, sizeof(pd->src_cap_ext_db)); complete(&pd->is_ready); + break; } else if (IS_EXT(rx_msg, MSG_PPS_STATUS)) { if (rx_msg->data_len != sizeof(pd->pps_status_db)) { usbpd_err(&pd->dev, "Invalid pps status db\n"); @@ -3113,6 +3114,7 @@ static void usbpd_sm(struct work_struct *w) memcpy(&pd->pps_status_db, rx_msg->payload, sizeof(pd->pps_status_db)); complete(&pd->is_ready); + break; } else if (IS_EXT(rx_msg, MSG_STATUS)) { if (rx_msg->data_len != PD_STATUS_DB_LEN) { usbpd_err(&pd->dev, "Invalid status db\n"); @@ -3122,6 +3124,7 @@ static void usbpd_sm(struct work_struct *w) sizeof(pd->status_db)); kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); complete(&pd->is_ready); + break; } else if (IS_EXT(rx_msg, MSG_BATTERY_CAPABILITIES)) { if (rx_msg->data_len != PD_BATTERY_CAP_DB_LEN) { usbpd_err(&pd->dev, "Invalid battery cap db\n"); @@ -3130,6 +3133,7 @@ static void usbpd_sm(struct work_struct *w) memcpy(&pd->battery_cap_db, rx_msg->payload, sizeof(pd->battery_cap_db)); complete(&pd->is_ready); + break; } else if (IS_EXT(rx_msg, MSG_BATTERY_STATUS)) { if (rx_msg->data_len != sizeof(pd->battery_sts_dobj)) { usbpd_err(&pd->dev, "Invalid bat sts dobj\n"); @@ -3138,6 +3142,7 @@ static void usbpd_sm(struct work_struct *w) memcpy(&pd->battery_sts_dobj, rx_msg->payload, sizeof(pd->battery_sts_dobj)); complete(&pd->is_ready); + break; } else if (IS_CTRL(rx_msg, MSG_GET_SOURCE_CAP_EXTENDED)) { handle_get_src_cap_extended(pd); } else if (IS_EXT(rx_msg, MSG_GET_BATTERY_CAP)) { diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c index 0353f9aee409dea49714061f9dfbd97f33ed54aa..5fdb47b35e1bc19eb0630fdc9eee15a57813f5bc 100644 --- a/drivers/usb/phy/phy-msm-snps-hs.c +++ b/drivers/usb/phy/phy-msm-snps-hs.c @@ -510,16 +510,17 @@ static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { /* Bus suspend */ - if (phy->cable_connected || - (phy->phy.flags & PHY_HOST_MODE)) { + if (phy->cable_connected) { /* Enable auto-resume functionality by pulsing signal */ - msm_usb_write_readback(phy->base, - USB2_PHY_USB_PHY_HS_PHY_CTRL2, - USB2_AUTO_RESUME, USB2_AUTO_RESUME); - usleep_range(500, 1000); - msm_usb_write_readback(phy->base, - USB2_PHY_USB_PHY_HS_PHY_CTRL2, - USB2_AUTO_RESUME, 0); + if (phy->phy.flags & PHY_HOST_MODE) { + msm_usb_write_readback(phy->base, + USB2_PHY_USB_PHY_HS_PHY_CTRL2, + USB2_AUTO_RESUME, USB2_AUTO_RESUME); + usleep_range(500, 1000); + msm_usb_write_readback(phy->base, + USB2_PHY_USB_PHY_HS_PHY_CTRL2, + USB2_AUTO_RESUME, 0); + } msm_hsphy_enable_clocks(phy, false); } else {/* Cable disconnect */ @@ -593,6 +594,7 @@ static int msm_hsphy_dpdm_regulator_enable(struct regulator_dev *rdev) UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN, UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN); + msm_hsphy_enable_clocks(phy, false); phy->dpdm_enable = true; } mutex_unlock(&phy->phy_lock); @@ -611,7 +613,6 @@ static int msm_hsphy_dpdm_regulator_disable(struct regulator_dev *rdev) mutex_lock(&phy->phy_lock); if (phy->dpdm_enable) { if (!phy->cable_connected) { - msm_hsphy_enable_clocks(phy, false); ret = msm_hsphy_enable_power(phy, false); if (ret < 0) { mutex_unlock(&phy->phy_lock); diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index ec83b3b5efa97177182cc6cd11ab39689c3bc98b..1a6df40f8b53ea7e615d3fbcf4aec96658939455 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -775,18 +775,16 @@ static void rts51x_suspend_timer_fn(unsigned long data) break; case RTS51X_STAT_IDLE: case RTS51X_STAT_SS: - usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n", - atomic_read(&us->pusb_intf->pm_usage_cnt), + usb_stor_dbg(us, "RTS51X_STAT_SS, power.usage:%d\n", atomic_read(&us->pusb_intf->dev.power.usage_count)); - if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) { + if (atomic_read(&us->pusb_intf->dev.power.usage_count) > 0) { usb_stor_dbg(us, "Ready to enter SS state\n"); rts51x_set_stat(chip, RTS51X_STAT_SS); /* ignore mass storage interface's children */ pm_suspend_ignore_children(&us->pusb_intf->dev, true); usb_autopm_put_interface_async(us->pusb_intf); - usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n", - atomic_read(&us->pusb_intf->pm_usage_cnt), + usb_stor_dbg(us, "RTS51X_STAT_SS 01, power.usage:%d\n", atomic_read(&us->pusb_intf->dev.power.usage_count)); } break; @@ -819,11 +817,10 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) int ret; if (working_scsi(srb)) { - usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n", - atomic_read(&us->pusb_intf->pm_usage_cnt), + usb_stor_dbg(us, "working scsi, power.usage:%d\n", atomic_read(&us->pusb_intf->dev.power.usage_count)); - if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) { + if (atomic_read(&us->pusb_intf->dev.power.usage_count) <= 0) { ret = usb_autopm_get_interface(us->pusb_intf); usb_stor_dbg(us, "working scsi, ret=%d\n", ret); } diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 5b807185f79ec93ddfb48a54adbdec92ea4143ef..777a4058c407beee5abdacc72bd7c8c7644c3c00 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -383,16 +383,10 @@ static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu) } if (usb_endpoint_xfer_isoc(epd)) { - /* validate packet size and number of packets */ - unsigned int maxp, packets, bytes; - - maxp = usb_endpoint_maxp(epd); - maxp *= usb_endpoint_maxp_mult(epd); - bytes = pdu->u.cmd_submit.transfer_buffer_length; - packets = DIV_ROUND_UP(bytes, maxp); - + /* validate number of packets */ if (pdu->u.cmd_submit.number_of_packets < 0 || - pdu->u.cmd_submit.number_of_packets > packets) { + pdu->u.cmd_submit.number_of_packets > + USBIP_MAX_ISO_PACKETS) { dev_err(&sdev->udev->dev, "CMD_SUBMIT: isoc invalid num packets %d\n", pdu->u.cmd_submit.number_of_packets); diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index c81c44c13a5673872805e8bd09e603b73c169dca..59097145cfc029663c36160c32c51d3f990554c1 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -135,6 +135,13 @@ extern struct device_attribute dev_attr_usbip_debug; #define USBIP_DIR_OUT 0x00 #define USBIP_DIR_IN 0x01 +/* + * Arbitrary limit for the maximum number of isochronous packets in an URB, + * compare for example the uhci_submit_isochronous function in + * drivers/usb/host/uhci-q.c + */ +#define USBIP_MAX_ISO_PACKETS 1024 + /** * struct usbip_header_basic - data pertinent to every request * @command: the usbip request type diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 695b9d1a1aae235efd3e03ca4402513c4e33dcf4..6f5cc67e343e70833ee76eb06e5244fe4443d915 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1443,11 +1443,11 @@ static void __init vfio_pci_fill_ids(void) rc = pci_add_dynid(&vfio_pci_driver, vendor, device, subvendor, subdevice, class, class_mask, 0); if (rc) - pr_warn("failed to add dynamic id [%04hx:%04hx[%04hx:%04hx]] class %#08x/%08x (%d)\n", + pr_warn("failed to add dynamic id [%04x:%04x[%04x:%04x]] class %#08x/%08x (%d)\n", vendor, device, subvendor, subdevice, class, class_mask, rc); else - pr_info("add [%04hx:%04hx[%04hx:%04hx]] class %#08x/%08x\n", + pr_info("add [%04x:%04x[%04x:%04x]] class %#08x/%08x\n", vendor, device, subvendor, subdevice, class, class_mask); } diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 50eeb74ddc0aa71b07b911a393e21c93c9886e3a..f77a9b3370b5f6de7510f6c76fabcd401f6c77ee 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -58,12 +58,18 @@ module_param_named(disable_hugepages, MODULE_PARM_DESC(disable_hugepages, "Disable VFIO IOMMU support for IOMMU hugepages."); +static unsigned int dma_entry_limit __read_mostly = U16_MAX; +module_param_named(dma_entry_limit, dma_entry_limit, uint, 0644); +MODULE_PARM_DESC(dma_entry_limit, + "Maximum number of user DMA mappings per container (65535)."); + struct vfio_iommu { struct list_head domain_list; struct vfio_domain *external_domain; /* domain for external user */ struct mutex lock; struct rb_root dma_list; struct blocking_notifier_head notifier; + unsigned int dma_avail; bool v2; bool nesting; }; @@ -732,6 +738,7 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma) vfio_unlink_dma(iommu, dma); put_task_struct(dma->task); kfree(dma); + iommu->dma_avail++; } static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu) @@ -1003,12 +1010,18 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, goto out_unlock; } + if (!iommu->dma_avail) { + ret = -ENOSPC; + goto out_unlock; + } + dma = kzalloc(sizeof(*dma), GFP_KERNEL); if (!dma) { ret = -ENOMEM; goto out_unlock; } + iommu->dma_avail--; dma->iova = iova; dma->vaddr = vaddr; dma->prot = prot; @@ -1504,6 +1517,7 @@ static void *vfio_iommu_type1_open(unsigned long arg) INIT_LIST_HEAD(&iommu->domain_list); iommu->dma_list = RB_ROOT; + iommu->dma_avail = dma_entry_limit; mutex_init(&iommu->lock); BLOCKING_INIT_NOTIFIER_HEAD(&iommu->notifier); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index d7c22ae5c368e61e0495a18a21bd55cc31e2820b..0e93ac888a5f6e6c7ff9a2e262a2426b280c3d63 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -918,8 +918,12 @@ static int vhost_new_umem_range(struct vhost_umem *umem, u64 start, u64 size, u64 end, u64 userspace_addr, int perm) { - struct vhost_umem_node *tmp, *node = kmalloc(sizeof(*node), GFP_ATOMIC); + struct vhost_umem_node *tmp, *node; + if (!size) + return -EFAULT; + + node = kmalloc(sizeof(*node), GFP_ATOMIC); if (!node) return -ENOMEM; diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index bdd616aaa6ec8480173d2e81f26a732cf170a19d..ba3ed70eb0426ebb5c6dc8097f3d35a144668407 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -905,7 +905,8 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) { struct buf_data *pcmds = file->private_data; - int blen, len, i; + unsigned int len; + int blen, i; char *buf, *bufp, *bp; struct dsi_ctrl_hdr *dchdr; @@ -949,7 +950,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) while (len >= sizeof(*dchdr)) { dchdr = (struct dsi_ctrl_hdr *)bp; dchdr->dlen = ntohs(dchdr->dlen); - if (dchdr->dlen > len || dchdr->dlen < 0) { + if (dchdr->dlen > (len - sizeof(*dchdr)) || dchdr->dlen < 0) { pr_err("%s: dtsi cmd=%x error, len=%d\n", __func__, dchdr->dtype, dchdr->dlen); kfree(buf); diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 74dc7170fd351e02d1732357b0705f66c507f7ce..d9fe54f41e71a45b8dace012c3d87be6628da893 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -748,7 +748,7 @@ static void __exit virtio_mmio_exit(void) vm_unregister_cmdline_devices(); } -module_init(virtio_mmio_init); +arch_initcall(virtio_mmio_init); module_exit(virtio_mmio_exit); MODULE_AUTHOR("Pawel Moll "); diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 71458f493cf864aa260e493c0ef5ddc4d6c78274..cc9d421c0929b1ca7912212e86589e65a7dc52e7 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -1087,6 +1087,8 @@ struct virtqueue *vring_create_virtqueue( GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); if (queue) break; + if (!may_reduce_num) + return NULL; } if (!num) diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index c423bdb982bbad900cc2205edec4cf2477c1072b..2ec0dfcd5b9755aa7e4630b4bed37498a7474260 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -1018,15 +1018,15 @@ static int ds_probe(struct usb_interface *intf, /* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */ alt = 3; err = usb_set_interface(dev->udev, - intf->altsetting[alt].desc.bInterfaceNumber, alt); + intf->cur_altsetting->desc.bInterfaceNumber, alt); if (err) { dev_err(&dev->udev->dev, "Failed to set alternative setting %d " "for %d interface: err=%d.\n", alt, - intf->altsetting[alt].desc.bInterfaceNumber, err); + intf->cur_altsetting->desc.bInterfaceNumber, err); goto err_out_clear; } - iface_desc = &intf->altsetting[alt]; + iface_desc = intf->cur_altsetting; if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { pr_info("Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 8fb89ddc6cc7ec3be59236cd5e493ffcc44719ae..c52f10efdc9c67af076235d033a8b9db838981e5 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -61,6 +61,8 @@ enum { Opt_cache_loose, Opt_fscache, Opt_mmap, /* Access options */ Opt_access, Opt_posixacl, + /* Lock timeout option */ + Opt_locktimeout, /* Error token */ Opt_err }; @@ -80,6 +82,7 @@ static const match_table_t tokens = { {Opt_cachetag, "cachetag=%s"}, {Opt_access, "access=%s"}, {Opt_posixacl, "posixacl"}, + {Opt_locktimeout, "locktimeout=%u"}, {Opt_err, NULL} }; @@ -187,6 +190,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) #ifdef CONFIG_9P_FSCACHE v9ses->cachetag = NULL; #endif + v9ses->session_lock_timeout = P9_LOCK_TIMEOUT; if (!opts) return 0; @@ -360,6 +364,23 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) #endif break; + case Opt_locktimeout: + r = match_int(&args[0], &option); + if (r < 0) { + p9_debug(P9_DEBUG_ERROR, + "integer field, but no integer?\n"); + ret = r; + continue; + } + if (option < 1) { + p9_debug(P9_DEBUG_ERROR, + "locktimeout must be a greater than zero integer.\n"); + ret = -EINVAL; + continue; + } + v9ses->session_lock_timeout = (long)option * HZ; + break; + default: continue; } diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 982e017acadbc7f9efccf445876959e811d85aa4..129e5243a6bf6cfb4d7fb1793ebf5c99686b3c6b 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -116,6 +116,7 @@ struct v9fs_session_info { struct p9_client *clnt; /* 9p client */ struct list_head slist; /* list of sessions registered with v9fs */ struct rw_semaphore rename_sem; + long session_lock_timeout; /* retry interval for blocking locks */ }; /* cache_validity flags */ diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 48db9a9f13f9e1800a81fcd992c69bcb0aac069c..cb6c4031af552b010c2e8ff5469b9088c769b3b7 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -105,7 +105,6 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) int err = 0; struct p9_fid *fid; int buflen; - int reclen = 0; struct p9_rdir *rdir; struct kvec kvec; @@ -138,11 +137,10 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) while (rdir->head < rdir->tail) { err = p9stat_read(fid->clnt, rdir->buf + rdir->head, rdir->tail - rdir->head, &st); - if (err) { + if (err <= 0) { p9_debug(P9_DEBUG_VFS, "returned %d\n", err); return -EIO; } - reclen = st.size+2; over = !dir_emit(ctx, st.name, strlen(st.name), v9fs_qid2ino(&st.qid), dt_type(&st)); @@ -150,8 +148,8 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) if (over) return 0; - rdir->head += reclen; - ctx->pos += reclen; + rdir->head += err; + ctx->pos += err; } } } diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index af8cac975a7450475f96d43d93c8e496922a3b36..89e69904976a51d7234637214738861567279fd8 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -154,6 +154,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) uint8_t status = P9_LOCK_ERROR; int res = 0; unsigned char fl_type; + struct v9fs_session_info *v9ses; fid = filp->private_data; BUG_ON(fid == NULL); @@ -189,6 +190,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) if (IS_SETLKW(cmd)) flock.flags = P9_LOCK_FLAGS_BLOCK; + v9ses = v9fs_inode2v9ses(file_inode(filp)); + /* * if its a blocked request and we get P9_LOCK_BLOCKED as the status * for lock request, keep on trying @@ -202,7 +205,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) break; if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) break; - if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0) + if (schedule_timeout_interruptible(v9ses->session_lock_timeout) + != 0) break; /* * p9_client_lock_dotl overwrites flock.client_id with the diff --git a/fs/block_dev.c b/fs/block_dev.c index 3911c1a80219665089924ab3dc358c0531ac13b4..61949e3446e58b9790154ec0315def7733f445f1 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -306,10 +306,10 @@ static void blkdev_bio_end_io(struct bio *bio) struct blkdev_dio *dio = bio->bi_private; bool should_dirty = dio->should_dirty; - if (dio->multi_bio && !atomic_dec_and_test(&dio->ref)) { - if (bio->bi_status && !dio->bio.bi_status) - dio->bio.bi_status = bio->bi_status; - } else { + if (bio->bi_status && !dio->bio.bi_status) + dio->bio.bi_status = bio->bi_status; + + if (!dio->multi_bio || atomic_dec_and_test(&dio->ref)) { if (!dio->is_sync) { struct kiocb *iocb = dio->iocb; ssize_t ret; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index cddd63b9103fb1570021070e3f41a5ad435d3f4e..dd3b4820ac30d68b91e9bb1264849ff537b0f6de 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -357,6 +357,16 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; + /* + * If the fs is mounted with nologreplay, which requires it to be + * mounted in RO mode as well, we can not allow discard on free space + * inside block groups, because log trees refer to extents that are not + * pinned in a block group's free space cache (pinning the extents is + * precisely the first phase of replaying a log tree). + */ + if (btrfs_test_opt(fs_info, NOLOGREPLAY)) + return -EROFS; + rcu_read_lock(); list_for_each_entry_rcu(device, &fs_info->fs_devices->devices, dev_list) { diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c index cbabc6f2b3221b44a9b05988106348b6cc14c1f9..266f9069307b13534229d5958512bdaa0c59b591 100644 --- a/fs/btrfs/props.c +++ b/fs/btrfs/props.c @@ -386,11 +386,11 @@ int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans, static int prop_compression_validate(const char *value, size_t len) { - if (!strncmp("lzo", value, len)) + if (!strncmp("lzo", value, 3)) return 0; - else if (!strncmp("zlib", value, len)) + else if (!strncmp("zlib", value, 4)) return 0; - else if (!strncmp("zstd", value, len)) + else if (!strncmp("zstd", value, 4)) return 0; return -EINVAL; @@ -416,7 +416,7 @@ static int prop_compression_apply(struct inode *inode, btrfs_set_fs_incompat(fs_info, COMPRESS_LZO); } else if (!strncmp("zlib", value, 4)) { type = BTRFS_COMPRESS_ZLIB; - } else if (!strncmp("zstd", value, len)) { + } else if (!strncmp("zstd", value, 4)) { type = BTRFS_COMPRESS_ZSTD; btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD); } else { diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 8a5266699b67657b0ea9053a03fe0ed255abb293..56e8fc896f6babc161708446899206acd524d327 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1454,6 +1454,7 @@ void ceph_dentry_lru_del(struct dentry *dn) unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) { struct ceph_inode_info *dci = ceph_inode(dir); + unsigned hash; switch (dci->i_dir_layout.dl_dir_hash) { case 0: /* for backward compat */ @@ -1461,8 +1462,11 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) return dn->d_name.hash; default: - return ceph_str_hash(dci->i_dir_layout.dl_dir_hash, + spin_lock(&dn->d_lock); + hash = ceph_str_hash(dci->i_dir_layout.dl_dir_hash, dn->d_name.name, dn->d_name.len); + spin_unlock(&dn->d_lock); + return hash; } } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index a1492bdc6d030a92bf95676381ad9dc7a9e8a9b1..f2b722f0df5d0dbabdaa83528401dfdc6b883aef 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -520,6 +520,7 @@ static void ceph_i_callback(struct rcu_head *head) struct inode *inode = container_of(head, struct inode, i_rcu); struct ceph_inode_info *ci = ceph_inode(inode); + kfree(ci->i_symlink); kmem_cache_free(ceph_inode_cachep, ci); } @@ -551,7 +552,6 @@ void ceph_destroy_inode(struct inode *inode) ceph_put_snap_realm(mdsc, realm); } - kfree(ci->i_symlink); while ((n = rb_first(&ci->i_fragtree)) != NULL) { frag = rb_entry(n, struct ceph_inode_frag, node); rb_erase(n, &ci->i_fragtree); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index a48984dd642627239f33623e058d73e56a8afa60..e1ded4bd61154c56d05c7fc51e68618bfdbd39f9 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1219,6 +1219,15 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove); ci->i_prealloc_cap_flush = NULL; } + + if (drop && + ci->i_wrbuffer_ref_head == 0 && + ci->i_wr_ref == 0 && + ci->i_dirty_caps == 0 && + ci->i_flushing_caps == 0) { + ceph_put_snap_context(ci->i_head_snapc); + ci->i_head_snapc = NULL; + } } spin_unlock(&ci->i_ceph_lock); while (!list_empty(&to_remove)) { @@ -1863,10 +1872,39 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, return path; } +/* Duplicate the dentry->d_name.name safely */ +static int clone_dentry_name(struct dentry *dentry, const char **ppath, + int *ppathlen) +{ + u32 len; + char *name; + +retry: + len = READ_ONCE(dentry->d_name.len); + name = kmalloc(len + 1, GFP_NOFS); + if (!name) + return -ENOMEM; + + spin_lock(&dentry->d_lock); + if (dentry->d_name.len != len) { + spin_unlock(&dentry->d_lock); + kfree(name); + goto retry; + } + memcpy(name, dentry->d_name.name, len); + spin_unlock(&dentry->d_lock); + + name[len] = '\0'; + *ppath = name; + *ppathlen = len; + return 0; +} + static int build_dentry_path(struct dentry *dentry, struct inode *dir, const char **ppath, int *ppathlen, u64 *pino, - int *pfreepath) + bool *pfreepath, bool parent_locked) { + int ret; char *path; rcu_read_lock(); @@ -1875,8 +1913,15 @@ static int build_dentry_path(struct dentry *dentry, struct inode *dir, if (dir && ceph_snap(dir) == CEPH_NOSNAP) { *pino = ceph_ino(dir); rcu_read_unlock(); - *ppath = dentry->d_name.name; - *ppathlen = dentry->d_name.len; + if (parent_locked) { + *ppath = dentry->d_name.name; + *ppathlen = dentry->d_name.len; + } else { + ret = clone_dentry_name(dentry, ppath, ppathlen); + if (ret) + return ret; + *pfreepath = true; + } return 0; } rcu_read_unlock(); @@ -1884,13 +1929,13 @@ static int build_dentry_path(struct dentry *dentry, struct inode *dir, if (IS_ERR(path)) return PTR_ERR(path); *ppath = path; - *pfreepath = 1; + *pfreepath = true; return 0; } static int build_inode_path(struct inode *inode, const char **ppath, int *ppathlen, u64 *pino, - int *pfreepath) + bool *pfreepath) { struct dentry *dentry; char *path; @@ -1906,7 +1951,7 @@ static int build_inode_path(struct inode *inode, if (IS_ERR(path)) return PTR_ERR(path); *ppath = path; - *pfreepath = 1; + *pfreepath = true; return 0; } @@ -1917,7 +1962,7 @@ static int build_inode_path(struct inode *inode, static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, struct inode *rdiri, const char *rpath, u64 rino, const char **ppath, int *pathlen, - u64 *ino, int *freepath) + u64 *ino, bool *freepath, bool parent_locked) { int r = 0; @@ -1927,7 +1972,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, ceph_snap(rinode)); } else if (rdentry) { r = build_dentry_path(rdentry, rdiri, ppath, pathlen, ino, - freepath); + freepath, parent_locked); dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen, *ppath); } else if (rpath || rino) { @@ -1953,7 +1998,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, const char *path2 = NULL; u64 ino1 = 0, ino2 = 0; int pathlen1 = 0, pathlen2 = 0; - int freepath1 = 0, freepath2 = 0; + bool freepath1 = false, freepath2 = false; int len; u16 releases; void *p, *end; @@ -1961,16 +2006,19 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, ret = set_request_path_attr(req->r_inode, req->r_dentry, req->r_parent, req->r_path1, req->r_ino1.ino, - &path1, &pathlen1, &ino1, &freepath1); + &path1, &pathlen1, &ino1, &freepath1, + test_bit(CEPH_MDS_R_PARENT_LOCKED, + &req->r_req_flags)); if (ret < 0) { msg = ERR_PTR(ret); goto out; } + /* If r_old_dentry is set, then assume that its parent is locked */ ret = set_request_path_attr(NULL, req->r_old_dentry, req->r_old_dentry_dir, req->r_path2, req->r_ino2.ino, - &path2, &pathlen2, &ino2, &freepath2); + &path2, &pathlen2, &ino2, &freepath2, true); if (ret < 0) { msg = ERR_PTR(ret); goto out_free1; diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 9b6207c84b68941497b308ef46d8c0db3d30997a..a7e763dac03858812a4cb59e521b167c1c50333c 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -568,7 +568,12 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) old_snapc = NULL; update_snapc: - if (ci->i_head_snapc) { + if (ci->i_wrbuffer_ref_head == 0 && + ci->i_wr_ref == 0 && + ci->i_dirty_caps == 0 && + ci->i_flushing_caps == 0) { + ci->i_head_snapc = NULL; + } else { ci->i_head_snapc = ceph_get_snap_context(new_snapc); dout(" new snapc is %p\n", new_snapc); } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f29cdb1cdeb773670ce88c4074ba1e688b03df32..7b7ab10a9db1801a7feaa52d6d60a1e56edcaae0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1189,6 +1189,7 @@ cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file) } struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file); +void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_hdlr); void cifsFileInfo_put(struct cifsFileInfo *cifs_file); #define CIFS_CACHE_READ_FLG 1 @@ -1693,6 +1694,7 @@ GLOBAL_EXTERN spinlock_t gidsidlock; #endif /* CONFIG_CIFS_ACL */ void cifs_oplock_break(struct work_struct *work); +void cifs_queue_oplock_break(struct cifsFileInfo *cfile); extern const struct slow_work_ops cifs_oplock_break_ops; extern struct workqueue_struct *cifsiod_wq; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index cd69c1e9750f911b87723028fc9c93d747d9ff93..48ea9dfd5f02f47f48f7c12b6f640cfe0e26e8f2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -358,12 +358,30 @@ cifsFileInfo_get(struct cifsFileInfo *cifs_file) return cifs_file; } -/* - * Release a reference on the file private data. This may involve closing - * the filehandle out on the server. Must be called without holding - * tcon->open_file_lock and cifs_file->file_info_lock. +/** + * cifsFileInfo_put - release a reference of file priv data + * + * Always potentially wait for oplock handler. See _cifsFileInfo_put(). */ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) +{ + _cifsFileInfo_put(cifs_file, true); +} + +/** + * _cifsFileInfo_put - release a reference of file priv data + * + * This may involve closing the filehandle @cifs_file out on the + * server. Must be called without holding tcon->open_file_lock and + * cifs_file->file_info_lock. + * + * If @wait_for_oplock_handler is true and we are releasing the last + * reference, wait for any running oplock break handler of the file + * and cancel any pending one. If calling this function from the + * oplock break handler, you need to pass false. + * + */ +void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler) { struct inode *inode = d_inode(cifs_file->dentry); struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); @@ -411,7 +429,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) spin_unlock(&tcon->open_file_lock); - oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break); + oplock_break_cancelled = wait_oplock_handler ? + cancel_work_sync(&cifs_file->oplock_break) : false; if (!tcon->need_reconnect && !cifs_file->invalidHandle) { struct TCP_Server_Info *server = tcon->ses->server; @@ -4136,6 +4155,7 @@ void cifs_oplock_break(struct work_struct *work) cinode); cifs_dbg(FYI, "Oplock release rc = %d\n", rc); } + _cifsFileInfo_put(cfile, false /* do not wait for ourself */); cifs_done_oplock_break(cinode); } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a90a637ae79ab6d1f8fda503463396e26ba65acc..e7192ee7a89c5b4372b5027c5028909a18fa030f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -779,43 +779,50 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, } else if ((rc == -EACCES) && backup_cred(cifs_sb) && (strcmp(server->vals->version_string, SMB1_VERSION_STRING) == 0)) { - /* - * For SMB2 and later the backup intent flag is already - * sent if needed on open and there is no path based - * FindFirst operation to use to retry with - */ + /* + * For SMB2 and later the backup intent flag is already + * sent if needed on open and there is no path based + * FindFirst operation to use to retry with + */ - srchinf = kzalloc(sizeof(struct cifs_search_info), - GFP_KERNEL); - if (srchinf == NULL) { - rc = -ENOMEM; - goto cgii_exit; - } + srchinf = kzalloc(sizeof(struct cifs_search_info), + GFP_KERNEL); + if (srchinf == NULL) { + rc = -ENOMEM; + goto cgii_exit; + } - srchinf->endOfSearch = false; + srchinf->endOfSearch = false; + if (tcon->unix_ext) + srchinf->info_level = SMB_FIND_FILE_UNIX; + else if ((tcon->ses->capabilities & + tcon->ses->server->vals->cap_nt_find) == 0) + srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD; + else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; + else /* no srvino useful for fallback to some netapp */ + srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO; - srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | - CIFS_SEARCH_CLOSE_AT_END | - CIFS_SEARCH_BACKUP_SEARCH; + srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | + CIFS_SEARCH_CLOSE_AT_END | + CIFS_SEARCH_BACKUP_SEARCH; - rc = CIFSFindFirst(xid, tcon, full_path, - cifs_sb, NULL, srchflgs, srchinf, false); - if (!rc) { - data = - (FILE_ALL_INFO *)srchinf->srch_entries_start; + rc = CIFSFindFirst(xid, tcon, full_path, + cifs_sb, NULL, srchflgs, srchinf, false); + if (!rc) { + data = (FILE_ALL_INFO *)srchinf->srch_entries_start; - cifs_dir_info_to_fattr(&fattr, - (FILE_DIRECTORY_INFO *)data, cifs_sb); - fattr.cf_uniqueid = le64_to_cpu( - ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId); - validinum = true; + cifs_dir_info_to_fattr(&fattr, + (FILE_DIRECTORY_INFO *)data, cifs_sb); + fattr.cf_uniqueid = le64_to_cpu( + ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId); + validinum = true; - cifs_buf_release(srchinf->ntwrk_buf_start); - } - kfree(srchinf); - if (rc) - goto cgii_exit; + cifs_buf_release(srchinf->ntwrk_buf_start); + } + kfree(srchinf); + if (rc) + goto cgii_exit; } else goto cgii_exit; @@ -1723,6 +1730,10 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, if (rc == 0 || rc != -EBUSY) goto do_rename_exit; + /* Don't fall back to using SMB on SMB 2+ mount */ + if (server->vals->protocol_id != 0) + goto do_rename_exit; + /* open-file renames don't work across directories */ if (to_dentry->d_parent != from_dentry->d_parent) goto do_rename_exit; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index bcab30d4a6c7453c3588736e71e9f42fa812dd29..76f1649ab444f249f05972778a66917bcb3d695b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -486,8 +486,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &pCifsInode->flags); - queue_work(cifsoplockd_wq, - &netfile->oplock_break); + cifs_queue_oplock_break(netfile); netfile->oplock_break_cancelled = false; spin_unlock(&tcon->open_file_lock); @@ -584,6 +583,28 @@ void cifs_put_writer(struct cifsInodeInfo *cinode) spin_unlock(&cinode->writers_lock); } +/** + * cifs_queue_oplock_break - queue the oplock break handler for cfile + * + * This function is called from the demultiplex thread when it + * receives an oplock break for @cfile. + * + * Assumes the tcon->open_file_lock is held. + * Assumes cfile->file_info_lock is NOT held. + */ +void cifs_queue_oplock_break(struct cifsFileInfo *cfile) +{ + /* + * Bump the handle refcount now while we hold the + * open_file_lock to enforce the validity of it for the oplock + * break handler. The matching put is done at the end of the + * handler. + */ + cifsFileInfo_get(cfile); + + queue_work(cifsoplockd_wq, &cfile->oplock_break); +} + void cifs_done_oplock_break(struct cifsInodeInfo *cinode) { clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags); diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index d7e839cb773f79f1300c9d209c379157ef736313..92c9cdf4704df10b884e0757d53cd793048f4353 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -1035,7 +1035,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_UNFINISHED_CONTEXT_DELETED, -EIO, "STATUS_UNFINISHED_CONTEXT_DELETED"}, {STATUS_NO_TGT_REPLY, -EIO, "STATUS_NO_TGT_REPLY"}, - {STATUS_OBJECTID_NOT_FOUND, -EIO, "STATUS_OBJECTID_NOT_FOUND"}, + /* Note that ENOATTTR and ENODATA are the same errno */ + {STATUS_OBJECTID_NOT_FOUND, -ENODATA, "STATUS_OBJECTID_NOT_FOUND"}, {STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"}, {STATUS_WRONG_CREDENTIAL_HANDLE, -EIO, "STATUS_WRONG_CREDENTIAL_HANDLE"}, diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index a97a0e0b1a74d3130ad8721f6b12aa77dada578b..31f01f09d25a0d67802921d454ff1f8821c632ca 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -517,7 +517,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cinode->flags); - queue_work(cifsoplockd_wq, &cfile->oplock_break); + cifs_queue_oplock_break(cfile); kfree(lw); return true; } @@ -661,8 +661,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cinode->flags); spin_unlock(&cfile->file_info_lock); - queue_work(cifsoplockd_wq, - &cfile->oplock_break); + + cifs_queue_oplock_break(cfile); spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 5f790dfe9b98255c091516a4e89b5968dc290606..3d2286f36bf22d87679e621d30687275a628e3cf 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -167,19 +167,24 @@ static int debugfs_show_options(struct seq_file *m, struct dentry *root) return 0; } -static void debugfs_evict_inode(struct inode *inode) +static void debugfs_i_callback(struct rcu_head *head) { - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); + struct inode *inode = container_of(head, struct inode, i_rcu); if (S_ISLNK(inode->i_mode)) kfree(inode->i_link); + free_inode_nonrcu(inode); +} + +static void debugfs_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, debugfs_i_callback); } static const struct super_operations debugfs_super_operations = { .statfs = simple_statfs, .remount_fs = debugfs_remount, .show_options = debugfs_show_options, - .evict_inode = debugfs_evict_inode, + .destroy_inode = debugfs_destroy_inode, }; static void debugfs_release_dentry(struct dentry *dentry) diff --git a/fs/direct-io.c b/fs/direct-io.c index 552c50361d1d559ce4293e87df6d3dfe52cc9947..b88a0a9a66ddda701e0e3f07c040c515846b1da5 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -221,6 +221,27 @@ static inline struct page *dio_get_page(struct dio *dio, return dio->pages[sdio->head]; } +/* + * Warn about a page cache invalidation failure during a direct io write. + */ +void dio_warn_stale_pagecache(struct file *filp) +{ + static DEFINE_RATELIMIT_STATE(_rs, 86400 * HZ, DEFAULT_RATELIMIT_BURST); + char pathname[128]; + struct inode *inode = file_inode(filp); + char *path; + + errseq_set(&inode->i_mapping->wb_err, -EIO); + if (__ratelimit(&_rs)) { + path = file_path(filp, pathname, sizeof(pathname)); + if (IS_ERR(path)) + path = "(unknown)"; + pr_crit("Page cache invalidation failure on direct I/O. Possible data corruption due to collision with buffered I/O!\n"); + pr_crit("File: %s PID: %d Comm: %.20s\n", path, current->pid, + current->comm); + } +} + /** * dio_complete() - called when all DIO BIO I/O has been completed * @offset: the byte offset in the file of the completed operation @@ -292,7 +313,8 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, unsigned int flags) err = invalidate_inode_pages2_range(dio->inode->i_mapping, offset >> PAGE_SHIFT, (offset + ret - 1) >> PAGE_SHIFT); - WARN_ON_ONCE(err); + if (err) + dio_warn_stale_pagecache(dio->iocb->ki_filp); } if (!(dio->flags & DIO_SKIP_DIO_COUNT)) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 7917cc89ab21601e261b0082845910a9a2d24b89..3dbf4e4147064c353015a83854e94bcce7ba71bf 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -940,6 +940,13 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (!blk_queue_discard(q)) return -EOPNOTSUPP; + /* + * We haven't replayed the journal, so we cannot use our + * block-bitmap-guided storage zapping commands. + */ + if (test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) + return -EROFS; + if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range))) return -EFAULT; diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index cd8d481e0c4859bf779d4d06c6fbd6d53d1c101e..c15d0c29b2324592a40ae5776a8bb1cc90aa7531 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -602,11 +602,14 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, return -EOPNOTSUPP; } - if (ext4_encrypted_inode(orig_inode) || - ext4_encrypted_inode(donor_inode)) { - ext4_msg(orig_inode->i_sb, KERN_ERR, - "Online defrag not supported for encrypted files"); - return -EOPNOTSUPP; + if (!fscrypt_using_hardware_encryption(orig_inode) || + !fscrypt_using_hardware_encryption(donor_inode)) { + if (ext4_encrypted_inode(orig_inode) || + ext4_encrypted_inode(donor_inode)) { + ext4_msg(orig_inode->i_sb, KERN_ERR, + "Online defrag not supported for encrypted files"); + return -EOPNOTSUPP; + } } /* Protect orig and donor inodes against a truncate */ diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 6f0acfe3141841484534085e9a3f2daa68c5e59e..333fba05e1a5518108c5f9f4debb1856c74d5bcc 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -907,11 +907,18 @@ static int add_new_gdb_meta_bg(struct super_block *sb, memcpy(n_group_desc, o_group_desc, EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); n_group_desc[gdb_num] = gdb_bh; + + BUFFER_TRACE(gdb_bh, "get_write_access"); + err = ext4_journal_get_write_access(handle, gdb_bh); + if (err) { + kvfree(n_group_desc); + brelse(gdb_bh); + return err; + } + EXT4_SB(sb)->s_group_desc = n_group_desc; EXT4_SB(sb)->s_gdb_count++; kvfree(o_group_desc); - BUFFER_TRACE(gdb_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gdb_bh); return err; } @@ -2042,6 +2049,10 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) free_flex_gd(flex_gd); if (resize_inode != NULL) iput(resize_inode); - ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", n_blocks_count); + if (err) + ext4_warning(sb, "error (%d) occurred during " + "file system resize", err); + ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", + ext4_blocks_count(es)); return err; } diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 311761a6ef6d716f476fa52c6292bea4d7a95779..6761e905cab08af2f4819d17e2dd421767120a79 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -828,6 +828,7 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage) bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); if (IS_ERR(bh)) { ret = PTR_ERR(bh); + bh = NULL; goto out; } @@ -2905,6 +2906,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, if (error == -EIO) EXT4_ERROR_INODE(inode, "block %llu read error", EXT4_I(inode)->i_file_acl); + bh = NULL; goto cleanup; } error = ext4_xattr_check_block(inode, bh); @@ -3061,6 +3063,7 @@ ext4_xattr_block_cache_find(struct inode *inode, if (IS_ERR(bh)) { if (PTR_ERR(bh) == -ENOMEM) return NULL; + bh = NULL; EXT4_ERROR_INODE(inode, "block %lu read error", (unsigned long)ce->e_value); } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 9fdb0271af822a5361448be0070466f788f316bf..b53f3d8f75e0c58e276a10251c9f872e0f34fe00 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1991,10 +1991,8 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, rem += pipe->bufs[(pipe->curbuf + idx) & (pipe->buffers - 1)].len; ret = -EINVAL; - if (rem < len) { - pipe_unlock(pipe); - goto out; - } + if (rem < len) + goto out_free; rem = len; while (rem) { @@ -2012,7 +2010,9 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1); pipe->nrbufs--; } else { - pipe_buf_get(pipe, ibuf); + if (!pipe_buf_get(pipe, ibuf)) + goto out_free; + *obuf = *ibuf; obuf->flags &= ~PIPE_BUF_FLAG_GIFT; obuf->len = rem; @@ -2035,11 +2035,11 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, ret = fuse_dev_do_write(fud, &cs, len); pipe_lock(pipe); +out_free: for (idx = 0; idx < nbuf; idx++) pipe_buf_release(pipe, &bufs[idx]); pipe_unlock(pipe); -out: kfree(bufs); return ret; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index eb6f3de29f699f8dd37fa009648a9fd05ca5e114..dd28a9b287daa970c317d166536f275c2af54459 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -730,11 +730,17 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, umode_t mode, dev_t dev) { struct inode *inode; - struct resv_map *resv_map; + struct resv_map *resv_map = NULL; - resv_map = resv_map_alloc(); - if (!resv_map) - return NULL; + /* + * Reserve maps are only needed for inodes that can have associated + * page allocations. + */ + if (S_ISREG(mode) || S_ISLNK(mode)) { + resv_map = resv_map_alloc(); + if (!resv_map) + return NULL; + } inode = new_inode(sb); if (inode) { @@ -766,8 +772,10 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, break; } lockdep_annotate_inode_mutex_key(inode); - } else - kref_put(&resv_map->refs, resv_map_release); + } else { + if (resv_map) + kref_put(&resv_map->refs, resv_map_release); + } return inode; } diff --git a/fs/iomap.c b/fs/iomap.c index 8f7673a692736bb7f5d31977797b653bb9de442d..467d98bf70542a1dce182b7526a275e0f320afb4 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -753,7 +753,8 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) err = invalidate_inode_pages2_range(inode->i_mapping, offset >> PAGE_SHIFT, (offset + dio->size - 1) >> PAGE_SHIFT); - WARN_ON_ONCE(err); + if (err) + dio_warn_stale_pagecache(iocb->ki_filp); } inode_dio_end(file_inode(iocb->ki_filp)); @@ -1010,9 +1011,16 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, if (ret) goto out_free_dio; + /* + * Try to invalidate cache pages for the range we're direct + * writing. If this invalidation fails, tough, the write will + * still work, but racing two incompatible write paths is a + * pretty crazy thing to do, so we don't support it 100%. + */ ret = invalidate_inode_pages2_range(mapping, start >> PAGE_SHIFT, end >> PAGE_SHIFT); - WARN_ON_ONCE(ret); + if (ret) + dio_warn_stale_pagecache(iocb->ki_filp); ret = 0; if (iov_iter_rw(iter) == WRITE && !dio->wait_for_completion && diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 389ea53ea487538061ff3b6da78e27df2f894ac1..bccfc40b3a74ab002e45a07149afbe09634d8f64 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -1414,11 +1414,6 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); - if (f->target) { - kfree(f->target); - f->target = NULL; - } - fds = f->dents; while(fds) { fd = fds; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 83340496645ba08540974d1dec1bbd7e0befe3c3..9a9f30eddbbb1559556bf5c9fca4f0955eb0197f 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -47,7 +47,10 @@ static struct inode *jffs2_alloc_inode(struct super_block *sb) static void jffs2_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + + kfree(f->target); + kmem_cache_free(jffs2_inode_cachep, f); } static void jffs2_destroy_inode(struct inode *inode) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 7d6ddfd60271113739195bed0959464bbdbcca6b..a98d64a6eda5ca5f36b5f4df4aac34be4dcf34b7 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -459,7 +459,7 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto, case XPRT_TRANSPORT_RDMA: if (retrans == NFS_UNSPEC_RETRANS) to->to_retries = NFS_DEF_TCP_RETRANS; - if (timeo == NFS_UNSPEC_TIMEO || to->to_retries == 0) + if (timeo == NFS_UNSPEC_TIMEO || to->to_initval == 0) to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10; if (to->to_initval > NFS_MAX_TCP_TIMEOUT) to->to_initval = NFS_MAX_TCP_TIMEOUT; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 77d8d03344c818bad67249069bcd7697f71407ca..f464f8d9060c0461ce5eaf208c3702b03da83c10 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2044,7 +2044,8 @@ static int nfs23_validate_mount_data(void *options, memcpy(sap, &data->addr, sizeof(data->addr)); args->nfs_server.addrlen = sizeof(data->addr); args->nfs_server.port = ntohs(data->addr.sin_port); - if (!nfs_verify_server_address(sap)) + if (sap->sa_family != AF_INET || + !nfs_verify_server_address(sap)) goto out_no_address; if (!(data->flags & NFS_MOUNT_TCP)) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 49b0a9e7ff18bb70d8be183718c598eb90009a49..80aeb19b176b2e67413dadefd99544adbeb407cd 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -939,8 +939,9 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) cb->cb_seq_status = 1; cb->cb_status = 0; if (minorversion) { - if (!nfsd41_cb_get_slot(clp, task)) + if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task)) return; + cb->cb_holds_slot = true; } rpc_call_start(task); } @@ -967,6 +968,9 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback return true; } + if (!cb->cb_holds_slot) + goto need_restart; + switch (cb->cb_seq_status) { case 0: /* @@ -1004,6 +1008,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback cb->cb_seq_status); } + cb->cb_holds_slot = false; clear_bit(0, &clp->cl_cb_slot_busy); rpc_wake_up_next(&clp->cl_cb_waitq); dprintk("%s: freed slot, new seqid=%d\n", __func__, @@ -1211,6 +1216,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, cb->cb_seq_status = 1; cb->cb_status = 0; cb->cb_need_restart = false; + cb->cb_holds_slot = false; } void nfsd4_run_cb(struct nfsd4_callback *cb) diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 86aa92d200e1101a9f27608634fccf5e06f4f32d..133d8bf62a5cdae4d0e9d1ec4466eee31d63991b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -69,6 +69,7 @@ struct nfsd4_callback { int cb_seq_status; int cb_status; bool cb_need_restart; + bool cb_holds_slot; }; struct nfsd4_callback_ops { diff --git a/fs/pipe.c b/fs/pipe.c index 8f9628494981c3bf60c19d562896f5724e3c9f19..fa3c2c25cec595736066caf243fa663097688002 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -194,9 +194,9 @@ EXPORT_SYMBOL(generic_pipe_buf_steal); * in the tee() system call, when we duplicate the buffers in one * pipe into another. */ -void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) +bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { - get_page(buf->page); + return try_get_page(buf->page); } EXPORT_SYMBOL(generic_pipe_buf_get); diff --git a/fs/proc/base.c b/fs/proc/base.c index db3cf5c83bb4e216e6936f8466083e1921a6456b..e8f621589f6277246ce8fa28715962495839f1cc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -2979,6 +2980,116 @@ static const struct file_operations proc_hung_task_detection_enabled_operations }; #endif +static ssize_t proc_sched_task_boost_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file_inode(file)); + char buffer[PROC_NUMBUF]; + int sched_boost; + size_t len; + + if (!task) + return -ESRCH; + sched_boost = task->boost; + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", sched_boost); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static ssize_t proc_sched_task_boost_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file_inode(file)); + char buffer[PROC_NUMBUF]; + int sched_boost; + int err; + + if (!task) + return -ESRCH; + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + err = kstrtoint(strstrip(buffer), 0, &sched_boost); + if (err) + goto out; + if (sched_boost < 0 || sched_boost > 2) { + err = -EINVAL; + goto out; + } + + task->boost = sched_boost; + if (sched_boost == 0) + task->boost_period = 0; +out: + put_task_struct(task); + return err < 0 ? err : count; +} + +static ssize_t proc_sched_task_boost_period_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file_inode(file)); + char buffer[PROC_NUMBUF]; + u64 sched_boost_period_ms = 0; + size_t len; + + if (!task) + return -ESRCH; + sched_boost_period_ms = div64_ul(task->boost_period, 1000000UL); + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%llu\n", sched_boost_period_ms); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static ssize_t proc_sched_task_boost_period_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file_inode(file)); + char buffer[PROC_NUMBUF]; + unsigned int sched_boost_period; + int err; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + err = kstrtouint(strstrip(buffer), 0, &sched_boost_period); + if (err) + goto out; + if (task->boost == 0 && sched_boost_period) { + /* setting boost period without boost is invalid */ + err = -EINVAL; + goto out; + } + + task->boost_period = (u64)sched_boost_period * 1000 * 1000; + task->boost_expires = sched_clock() + task->boost_period; +out: + put_task_struct(task); + return err < 0 ? err : count; +} + +static const struct file_operations proc_task_boost_enabled_operations = { + .read = proc_sched_task_boost_read, + .write = proc_sched_task_boost_write, + .llseek = generic_file_llseek, +}; + +static const struct file_operations proc_task_boost_period_operations = { + .read = proc_sched_task_boost_period_read, + .write = proc_sched_task_boost_period_write, + .llseek = generic_file_llseek, +}; + #ifdef CONFIG_USER_NS static int proc_id_map_open(struct inode *inode, struct file *file, const struct seq_operations *seq_ops) @@ -3157,6 +3268,8 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_SCHED_WALT REG("sched_init_task_load", 00644, proc_pid_sched_init_task_load_operations), REG("sched_group_id", 00666, proc_pid_sched_group_id_operations), + REG("sched_boost", 0666, proc_task_boost_enabled_operations), + REG("sched_boost_period_ms", 0666, proc_task_boost_period_operations), #endif #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 8d5422bb9c1ac656dc48d6d7e8ef73632321a9d1..555698ddb943672bf4a5d2d4c837fafb44791e32 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1620,9 +1620,11 @@ static void drop_sysctl_table(struct ctl_table_header *header) if (--header->nreg) return; - if (parent) + if (parent) { put_links(header); - start_unregistering(header); + start_unregistering(header); + } + if (!--header->count) kfree_rcu(header, rcu); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 5001e939f1abf4df6ca096706c0fc7b6327c43e3..741364f8f5d8e024d8c25bb1dccd3269efeed803 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1230,6 +1230,24 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf, count = -EINTR; goto out_mm; } + /* + * Avoid to modify vma->vm_flags + * without locked ops while the + * coredump reads the vm_flags. + */ + if (!mmget_still_valid(mm)) { + /* + * Silently return "count" + * like if get_task_mm() + * failed. FIXME: should this + * function have returned + * -ESRCH if get_task_mm() + * failed like if + * get_proc_task() fails? + */ + up_write(&mm->mmap_sem); + goto out_mm; + } for (vma = mm->mmap; vma; vma = vma->vm_next) { vm_write_begin(vma); WRITE_ONCE(vma->vm_flags, diff --git a/fs/splice.c b/fs/splice.c index 00d2f142dcf98381aa8fd7edd58a12b495b974fe..c84ac7e97e215b4eb0985edebc8d2c87c3a8e0a7 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -332,8 +332,8 @@ const struct pipe_buf_operations default_pipe_buf_ops = { .get = generic_pipe_buf_get, }; -static int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) +int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) { return 1; } @@ -1571,7 +1571,11 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, * Get a reference to this pipe buffer, * so we can copy the contents over. */ - pipe_buf_get(ipipe, ibuf); + if (!pipe_buf_get(ipipe, ibuf)) { + if (ret == 0) + ret = -EFAULT; + break; + } *obuf = *ibuf; /* @@ -1645,7 +1649,11 @@ static int link_pipe(struct pipe_inode_info *ipipe, * Get a reference to this pipe buffer, * so we can copy the contents over. */ - pipe_buf_get(ipipe, ibuf); + if (!pipe_buf_get(ipipe, ibuf)) { + if (ret == 0) + ret = -EFAULT; + break; + } obuf = opipe->bufs + nbuf; *obuf = *ibuf; diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index d68495cb10c92a6b55e9124af6bce7848d310787..3659500f57e68f80332725619733a04d1109e561 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -627,6 +627,8 @@ 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); + /* no task can run (and in turn coredump) yet */ + VM_WARN_ON(!mmget_still_valid(mm)); for (vma = mm->mmap; vma; vma = vma->vm_next) if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) { vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; @@ -870,6 +872,8 @@ static int userfaultfd_release(struct inode *inode, struct file *file) * taking the mmap_sem for writing. */ down_write(&mm->mmap_sem); + if (!mmget_still_valid(mm)) + goto skip_mm; prev = NULL; for (vma = mm->mmap; vma; vma = vma->vm_next) { cond_resched(); @@ -895,6 +899,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file) vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; vm_write_end(vma); } +skip_mm: up_write(&mm->mmap_sem); mmput(mm); wakeup: @@ -1333,6 +1338,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx, goto out; down_write(&mm->mmap_sem); + if (!mmget_still_valid(mm)) + goto out_unlock; vma = find_vma_prev(mm, start, &prev); if (!vma) goto out_unlock; @@ -1523,6 +1530,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx, goto out; down_write(&mm->mmap_sem); + if (!mmget_still_valid(mm)) + goto out_unlock; vma = find_vma_prev(mm, start, &prev); if (!vma) goto out_unlock; diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index ea66f04f46f7e22c9b2c4c9ba381d1b47437ff28..e4265db08e4b30d34ac1e0dedcd566bf59a1a4bf 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -212,6 +212,7 @@ xfs_attr_set( int flags) { struct xfs_mount *mp = dp->i_mount; + struct xfs_buf *leaf_bp = NULL; struct xfs_da_args args; struct xfs_defer_ops dfops; struct xfs_trans_res tres; @@ -327,9 +328,16 @@ xfs_attr_set( * GROT: another possible req'mt for a double-split btree op. */ xfs_defer_init(args.dfops, args.firstblock); - error = xfs_attr_shortform_to_leaf(&args); + error = xfs_attr_shortform_to_leaf(&args, &leaf_bp); if (error) goto out_defer_cancel; + /* + * Prevent the leaf buffer from being unlocked so that a + * concurrent AIL push cannot grab the half-baked leaf + * buffer and run into problems with the write verifier. + */ + xfs_trans_bhold(args.trans, leaf_bp); + xfs_defer_bjoin(args.dfops, leaf_bp); xfs_defer_ijoin(args.dfops, dp); error = xfs_defer_finish(&args.trans, args.dfops); if (error) @@ -337,13 +345,14 @@ xfs_attr_set( /* * Commit the leaf transformation. We'll need another (linked) - * transaction to add the new attribute to the leaf. + * transaction to add the new attribute to the leaf, which + * means that we have to hold & join the leaf buffer here too. */ - error = xfs_trans_roll_inode(&args.trans, dp); if (error) goto out; - + xfs_trans_bjoin(args.trans, leaf_bp); + leaf_bp = NULL; } if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) @@ -374,8 +383,9 @@ xfs_attr_set( out_defer_cancel: xfs_defer_cancel(&dfops); - args.trans = NULL; out: + if (leaf_bp) + xfs_trans_brelse(args.trans, leaf_bp); if (args.trans) xfs_trans_cancel(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 40e53a4fc0a65ee479379a0e55c3c171539eb4a3..73a541755d5b73bb82b607480a6686765664495c 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -739,10 +739,13 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args) } /* - * Convert from using the shortform to the leaf. + * Convert from using the shortform to the leaf. On success, return the + * buffer so that we can keep it locked until we're totally done with it. */ int -xfs_attr_shortform_to_leaf(xfs_da_args_t *args) +xfs_attr_shortform_to_leaf( + struct xfs_da_args *args, + struct xfs_buf **leaf_bp) { xfs_inode_t *dp; xfs_attr_shortform_t *sf; @@ -821,7 +824,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) sfe = XFS_ATTR_SF_NEXTENTRY(sfe); } error = 0; - + *leaf_bp = bp; out: kmem_free(tmpbuffer); return error; diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h index f7dda0c237b044b166d6d178fca3178feff2b644..894124efb421e0d0674b0f39bf63dabfe7916937 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.h +++ b/fs/xfs/libxfs/xfs_attr_leaf.h @@ -48,7 +48,8 @@ void xfs_attr_shortform_create(struct xfs_da_args *args); void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); int xfs_attr_shortform_lookup(struct xfs_da_args *args); int xfs_attr_shortform_getvalue(struct xfs_da_args *args); -int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); +int xfs_attr_shortform_to_leaf(struct xfs_da_args *args, + struct xfs_buf **leaf_bp); int xfs_attr_shortform_remove(struct xfs_da_args *args); int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 072ebfe1d6aeb3e00e306a06d71a1b478382f3ad..087fea02c3892c34e1e63df2839bd8d804ba1f3f 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -249,6 +249,10 @@ xfs_defer_trans_roll( for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) xfs_trans_log_inode(*tp, dop->dop_inodes[i], XFS_ILOG_CORE); + /* Hold the (previously bjoin'd) buffer locked across the roll. */ + for (i = 0; i < XFS_DEFER_OPS_NR_BUFS && dop->dop_bufs[i]; i++) + xfs_trans_dirty_buf(*tp, dop->dop_bufs[i]); + trace_xfs_defer_trans_roll((*tp)->t_mountp, dop); /* Roll the transaction. */ @@ -264,6 +268,12 @@ xfs_defer_trans_roll( for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) xfs_trans_ijoin(*tp, dop->dop_inodes[i], 0); + /* Rejoin the buffers and dirty them so the log moves forward. */ + for (i = 0; i < XFS_DEFER_OPS_NR_BUFS && dop->dop_bufs[i]; i++) { + xfs_trans_bjoin(*tp, dop->dop_bufs[i]); + xfs_trans_bhold(*tp, dop->dop_bufs[i]); + } + return error; } @@ -295,6 +305,31 @@ xfs_defer_ijoin( } } + ASSERT(0); + return -EFSCORRUPTED; +} + +/* + * Add this buffer to the deferred op. Each joined buffer is relogged + * each time we roll the transaction. + */ +int +xfs_defer_bjoin( + struct xfs_defer_ops *dop, + struct xfs_buf *bp) +{ + int i; + + for (i = 0; i < XFS_DEFER_OPS_NR_BUFS; i++) { + if (dop->dop_bufs[i] == bp) + return 0; + else if (dop->dop_bufs[i] == NULL) { + dop->dop_bufs[i] = bp; + return 0; + } + } + + ASSERT(0); return -EFSCORRUPTED; } @@ -493,9 +528,7 @@ xfs_defer_init( struct xfs_defer_ops *dop, xfs_fsblock_t *fbp) { - dop->dop_committed = false; - dop->dop_low = false; - memset(&dop->dop_inodes, 0, sizeof(dop->dop_inodes)); + memset(dop, 0, sizeof(struct xfs_defer_ops)); *fbp = NULLFSBLOCK; INIT_LIST_HEAD(&dop->dop_intake); INIT_LIST_HEAD(&dop->dop_pending); diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index d4f046dd44bd4ae434d8104991d0327f2d2b9fc7..045beacdd37d81c9e01e0ab46ab2bbcbbb581fbb 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -59,6 +59,7 @@ enum xfs_defer_ops_type { }; #define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */ +#define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */ struct xfs_defer_ops { bool dop_committed; /* did any trans commit? */ @@ -66,8 +67,9 @@ struct xfs_defer_ops { struct list_head dop_intake; /* unlogged pending work */ struct list_head dop_pending; /* logged pending work */ - /* relog these inodes with each roll */ + /* relog these with each roll */ struct xfs_inode *dop_inodes[XFS_DEFER_OPS_NR_INODES]; + struct xfs_buf *dop_bufs[XFS_DEFER_OPS_NR_BUFS]; }; void xfs_defer_add(struct xfs_defer_ops *dop, enum xfs_defer_ops_type type, @@ -77,6 +79,7 @@ void xfs_defer_cancel(struct xfs_defer_ops *dop); void xfs_defer_init(struct xfs_defer_ops *dop, xfs_fsblock_t *fbp); bool xfs_defer_has_unfinished_work(struct xfs_defer_ops *dop); int xfs_defer_ijoin(struct xfs_defer_ops *dop, struct xfs_inode *ip); +int xfs_defer_bjoin(struct xfs_defer_ops *dop, struct xfs_buf *bp); /* Description of a deferred type. */ struct xfs_defer_op_type { diff --git a/include/dt-bindings/clock/qcom,gcc-sdmshrike.h b/include/dt-bindings/clock/qcom,gcc-sdmshrike.h index ef166ef737fdd98bf6f0ef5f68c74a9da7661c60..d1905dc61429b9683590d1d4c58cb7b4a7800fbc 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdmshrike.h +++ b/include/dt-bindings/clock/qcom,gcc-sdmshrike.h @@ -257,6 +257,10 @@ #define GPLL1 240 #define GPLL4 241 #define GPLL7 242 +#define GCC_PCIE_0_CLKREF_CLK 243 +#define GCC_PCIE_1_CLKREF_CLK 244 +#define GCC_USB3_PRIM_CLKREF_CLK 245 +#define GCC_USB3_SEC_CLKREF_CLK 246 #define GCC_EMAC_BCR 0 #define GCC_GPU_BCR 1 @@ -300,6 +304,8 @@ #define GCC_USB30_SEC_BCR 39 #define GCC_USB_PHY_CFG_AHB2PHY_BCR 40 #define GCC_VIDEO_AXIC_CLK_BCR 41 +#define GCC_VIDEO_AXI0_CLK_BCR 42 +#define GCC_VIDEO_AXI1_CLK_BCR 43 #define MMCX_CLK 0 #endif diff --git a/include/dt-bindings/clock/qcom,gcc-sm6150.h b/include/dt-bindings/clock/qcom,gcc-sm6150.h index 77a7fe92666c8c601ae0ce83e45c12325bc11c72..6778bb2b2bfdc4cdf4d2cf9435b61733441de4f4 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm6150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm6150.h @@ -193,6 +193,13 @@ #define GCC_USB2_PRIM_CLKREF_CLK 173 #define GCC_USB2_SEC_CLKREF_CLK 174 #define GCC_RX3_USB2_CLKREF_CLK 175 +#define GCC_SDR_CORE_CLK 176 +#define GCC_SDR_WR0_MEM_CLK 177 +#define GCC_SDR_WR1_MEM_CLK 178 +#define GCC_SDR_WR2_MEM_CLK 179 +#define GCC_SDR_CSR_HCLK 180 +#define GCC_SDR_PRI_MI2S_CLK 181 +#define GCC_SDR_SEC_MI2S_CLK 182 /* GCC Resets */ #define GCC_QUSB2PHY_PRIM_BCR 0 diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h index e0a2b41634cd2734cef3f68ff0d7f4cb53980b93..978b5e20eed634fb9ad157e03a77bfb210584ec4 100644 --- a/include/dt-bindings/msm/msm-bus-ids.h +++ b/include/dt-bindings/msm/msm-bus-ids.h @@ -50,6 +50,7 @@ #define MSM_BUS_FAB_GPU_VIRT 6158 #define MSM_BUS_FAB_MMNRT_VIRT 6159 #define MSM_BUS_FAB_MMRT_VIRT 6160 +#define MSM_BUS_FAB_NPU_NOC 6161 #define MSM_BUS_FAB_MC_VIRT_DISPLAY 26000 #define MSM_BUS_FAB_MEM_NOC_DISPLAY 26001 @@ -100,16 +101,17 @@ #define MSM_BUS_BCM_CO0 7041 #define MSM_BUS_BCM_CO1 7042 #define MSM_BUS_BCM_CO2 7043 -#define MSM_BUS_BCM_QP0 7044 -#define MSM_BUS_BCM_PN0 7045 -#define MSM_BUS_BCM_PN1 7046 -#define MSM_BUS_BCM_PN2 7047 -#define MSM_BUS_BCM_PN3 7048 -#define MSM_BUS_BCM_PN4 7049 -#define MSM_BUS_BCM_PN5 7050 -#define MSM_BUS_BCM_SH8 7051 -#define MSM_BUS_BCM_SH9 7052 -#define MSM_BUS_BCM_SH10 7053 +#define MSM_BUS_BCM_CO3 7044 +#define MSM_BUS_BCM_QP0 7045 +#define MSM_BUS_BCM_PN0 7046 +#define MSM_BUS_BCM_PN1 7047 +#define MSM_BUS_BCM_PN2 7048 +#define MSM_BUS_BCM_PN3 7049 +#define MSM_BUS_BCM_PN4 7050 +#define MSM_BUS_BCM_PN5 7051 +#define MSM_BUS_BCM_SH8 7052 +#define MSM_BUS_BCM_SH9 7053 +#define MSM_BUS_BCM_SH10 7054 #define MSM_BUS_RSC_APPS 8000 #define MSM_BUS_RSC_DISP 8001 @@ -308,6 +310,8 @@ #define MSM_BUS_MASTER_GPU_CDSP_PROC 182 #define MSM_BUS_MASTER_QUP_CORE_0 183 #define MSM_BUS_MASTER_QUP_CORE_1 184 +#define MSM_BUS_MASTER_NPU_PROC 185 +#define MSM_BUS_MASTER_NPU_SYS 186 #define MSM_BUS_MASTER_LLCC_DISPLAY 20000 #define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001 @@ -698,7 +702,20 @@ #define MSM_BUS_SLAVE_SNOC_BIMC_RT 819 #define MSM_BUS_SLAVE_GPU_CDSP_BIMC 820 #define MSM_BUS_SLAVE_QM_MPU_CFG 821 -#define MSM_BUS_SLAVE_CDSP_THROTTLE_CFG 822 +#define MSM_BUS_SLAVE_CDSP_THROTTLE_CFG 822 +#define MSM_BUS_MASTER_NPU_NOC_CFG 823 +#define MSM_BUS_SLAVE_NPU_CAL_DP0 824 +#define MSM_BUS_SLAVE_NPU_CP 825 +#define MSM_BUS_SLAVE_NPU_INT_DMA_BWMON_CFG 826 +#define MSM_BUS_SLAVE_NPU_DPM 827 +#define MSM_BUS_SLAVE_ISENSE_CFG 828 +#define MSM_BUS_SLAVE_NPU_LLM_CFG 829 +#define MSM_BUS_SLAVE_NPU_TCM 830 +#define MSM_BUS_SLAVE_NPU_COMPUTE_NOC 831 +#define MSM_BUS_SLAVE_SERVICE_NPU_NOC 832 +#define MSM_BUS_SLAVE_DISPLAY_RT_THROTTLE_CFG 833 +#define MSM_BUS_SLAVE_NPU_DMA_BWMON_CFG 834 +#define MSM_BUS_SLAVE_NPU_PROC_BWMON_CFG 835 #define MSM_BUS_SLAVE_EBI_CH0_DISPLAY 20512 #define MSM_BUS_SLAVE_LLCC_DISPLAY 20513 diff --git a/include/dt-bindings/phy/qcom,atoll-qmp-usb3.h b/include/dt-bindings/phy/qcom,atoll-qmp-usb3.h new file mode 100644 index 0000000000000000000000000000000000000000..8eb4783119752e677f7562856ef46154b769d328 --- /dev/null +++ b/include/dt-bindings/phy/qcom,atoll-qmp-usb3.h @@ -0,0 +1,646 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 _DT_BINDINGS_PHY_QCOM_ATOLL_QMP_USB_H +#define _DT_BINDINGS_PHY_QCOM_ATOLL_QMP_USB_H + +/* USB3-DP Combo PHY register offsets */ + +#define USB3_DP_COM_PHY_MODE_CTRL 0x0000 +#define USB3_DP_COM_SW_RESET 0x0004 +#define USB3_DP_COM_POWER_DOWN_CTRL 0x0008 +#define USB3_DP_COM_SWI_CTRL 0x000c +#define USB3_DP_COM_TYPEC_CTRL 0x0010 +#define USB3_DP_COM_TYPEC_PWRDN_CTRL 0x0014 +#define USB3_DP_COM_DP_BIST_CFG_0 0x0018 +#define USB3_DP_COM_RESET_OVRD_CTRL 0x001c +#define USB3_DP_COM_TYPEC_STATUS 0x0020 +#define USB3_DP_COM_PLACEHOLDER_STATUS 0x0024 +#define USB3_DP_COM_REVISION_ID0 0x0028 +#define USB3_DP_COM_REVISION_ID1 0x002c +#define USB3_DP_COM_REVISION_ID2 0x0030 +#define USB3_DP_COM_REVISION_ID3 0x0034 +#define USB3_DP_QSERDES_COM_ATB_SEL1 0x1000 +#define USB3_DP_QSERDES_COM_ATB_SEL2 0x1004 +#define USB3_DP_QSERDES_COM_FREQ_UPDATE 0x1008 +#define USB3_DP_QSERDES_COM_BG_TIMER 0x100c +#define USB3_DP_QSERDES_COM_SSC_EN_CENTER 0x1010 +#define USB3_DP_QSERDES_COM_SSC_ADJ_PER1 0x1014 +#define USB3_DP_QSERDES_COM_SSC_ADJ_PER2 0x1018 +#define USB3_DP_QSERDES_COM_SSC_PER1 0x101c +#define USB3_DP_QSERDES_COM_SSC_PER2 0x1020 +#define USB3_DP_QSERDES_COM_SSC_STEP_SIZE1 0x1024 +#define USB3_DP_QSERDES_COM_SSC_STEP_SIZE2 0x1028 +#define USB3_DP_QSERDES_COM_POST_DIV 0x102c +#define USB3_DP_QSERDES_COM_POST_DIV_MUX 0x1030 +#define USB3_DP_QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x1034 +#define USB3_DP_QSERDES_COM_CLK_ENABLE1 0x1038 +#define USB3_DP_QSERDES_COM_SYS_CLK_CTRL 0x103c +#define USB3_DP_QSERDES_COM_SYSCLK_BUF_ENABLE 0x1040 +#define USB3_DP_QSERDES_COM_PLL_EN 0x1044 +#define USB3_DP_QSERDES_COM_PLL_IVCO 0x1048 +#define USB3_DP_QSERDES_COM_CMN_IETRIM 0x104c +#define USB3_DP_QSERDES_COM_CMN_IPTRIM 0x1050 +#define USB3_DP_QSERDES_COM_EP_CLOCK_DETECT_CTRL 0x1054 +#define USB3_DP_QSERDES_COM_SYSCLK_DET_COMP_STATUS 0x1058 +#define USB3_DP_QSERDES_COM_CLK_EP_DIV 0x105c +#define USB3_DP_QSERDES_COM_CP_CTRL_MODE0 0x1060 +#define USB3_DP_QSERDES_COM_CP_CTRL_MODE1 0x1064 +#define USB3_DP_QSERDES_COM_PLL_RCTRL_MODE0 0x1068 +#define USB3_DP_QSERDES_COM_PLL_RCTRL_MODE1 0x106c +#define USB3_DP_QSERDES_COM_PLL_CCTRL_MODE0 0x1070 +#define USB3_DP_QSERDES_COM_PLL_CCTRL_MODE1 0x1074 +#define USB3_DP_QSERDES_COM_PLL_CNTRL 0x1078 +#define USB3_DP_QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x107c +#define USB3_DP_QSERDES_COM_SYSCLK_EN_SEL 0x1080 +#define USB3_DP_QSERDES_COM_CML_SYSCLK_SEL 0x1084 +#define USB3_DP_QSERDES_COM_RESETSM_CNTRL 0x1088 +#define USB3_DP_QSERDES_COM_RESETSM_CNTRL2 0x108c +#define USB3_DP_QSERDES_COM_LOCK_CMP_EN 0x1090 +#define USB3_DP_QSERDES_COM_LOCK_CMP_CFG 0x1094 +#define USB3_DP_QSERDES_COM_LOCK_CMP1_MODE0 0x1098 +#define USB3_DP_QSERDES_COM_LOCK_CMP2_MODE0 0x109c +#define USB3_DP_QSERDES_COM_LOCK_CMP3_MODE0 0x10a0 +#define USB3_DP_QSERDES_COM_LOCK_CMP1_MODE1 0x10a4 +#define USB3_DP_QSERDES_COM_LOCK_CMP2_MODE1 0x10a8 +#define USB3_DP_QSERDES_COM_LOCK_CMP3_MODE1 0x10ac +#define USB3_DP_QSERDES_COM_DEC_START_MODE0 0x10b0 +#define USB3_DP_QSERDES_COM_DEC_START_MODE1 0x10b4 +#define USB3_DP_QSERDES_COM_DIV_FRAC_START1_MODE0 0x10b8 +#define USB3_DP_QSERDES_COM_DIV_FRAC_START2_MODE0 0x10bc +#define USB3_DP_QSERDES_COM_DIV_FRAC_START3_MODE0 0x10c0 +#define USB3_DP_QSERDES_COM_DIV_FRAC_START1_MODE1 0x10c4 +#define USB3_DP_QSERDES_COM_DIV_FRAC_START2_MODE1 0x10c8 +#define USB3_DP_QSERDES_COM_DIV_FRAC_START3_MODE1 0x10cc +#define USB3_DP_QSERDES_COM_INTEGLOOP_INITVAL 0x10d0 +#define USB3_DP_QSERDES_COM_INTEGLOOP_EN 0x10d4 +#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x10d8 +#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10dc +#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x10e0 +#define USB3_DP_QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x10e4 +#define USB3_DP_QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x10e8 +#define USB3_DP_QSERDES_COM_VCO_TUNE_CTRL 0x10ec +#define USB3_DP_QSERDES_COM_VCO_TUNE_MAP 0x10f0 +#define USB3_DP_QSERDES_COM_VCO_TUNE1_MODE0 0x10f4 +#define USB3_DP_QSERDES_COM_VCO_TUNE2_MODE0 0x10f8 +#define USB3_DP_QSERDES_COM_VCO_TUNE1_MODE1 0x10fc +#define USB3_DP_QSERDES_COM_VCO_TUNE2_MODE1 0x1100 +#define USB3_DP_QSERDES_COM_VCO_TUNE_INITVAL1 0x1104 +#define USB3_DP_QSERDES_COM_VCO_TUNE_INITVAL2 0x1108 +#define USB3_DP_QSERDES_COM_VCO_TUNE_MINVAL1 0x110c +#define USB3_DP_QSERDES_COM_VCO_TUNE_MINVAL2 0x1110 +#define USB3_DP_QSERDES_COM_VCO_TUNE_MAXVAL1 0x1114 +#define USB3_DP_QSERDES_COM_VCO_TUNE_MAXVAL2 0x1118 +#define USB3_DP_QSERDES_COM_VCO_TUNE_TIMER1 0x111c +#define USB3_DP_QSERDES_COM_VCO_TUNE_TIMER2 0x1120 +#define USB3_DP_QSERDES_COM_CMN_STATUS 0x1124 +#define USB3_DP_QSERDES_COM_RESET_SM_STATUS 0x1128 +#define USB3_DP_QSERDES_COM_RESTRIM_CODE_STATUS 0x112c +#define USB3_DP_QSERDES_COM_PLLCAL_CODE1_STATUS 0x1130 +#define USB3_DP_QSERDES_COM_PLLCAL_CODE2_STATUS 0x1134 +#define USB3_DP_QSERDES_COM_CLK_SELECT 0x1138 +#define USB3_DP_QSERDES_COM_HSCLK_SEL 0x113c +#define USB3_DP_QSERDES_COM_INTEGLOOP_BINCODE_STATUS 0x1140 +#define USB3_DP_QSERDES_COM_PLL_ANALOG 0x1144 +#define USB3_DP_QSERDES_COM_CORECLK_DIV_MODE0 0x1148 +#define USB3_DP_QSERDES_COM_CORECLK_DIV_MODE1 0x114c +#define USB3_DP_QSERDES_COM_SW_RESET 0x1150 +#define USB3_DP_QSERDES_COM_CORE_CLK_EN 0x1154 +#define USB3_DP_QSERDES_COM_C_READY_STATUS 0x1158 +#define USB3_DP_QSERDES_COM_CMN_CONFIG 0x115c +#define USB3_DP_QSERDES_COM_CMN_RATE_OVERRIDE 0x1160 +#define USB3_DP_QSERDES_COM_SVS_MODE_CLK_SEL 0x1164 +#define USB3_DP_QSERDES_COM_DEBUG_BUS0 0x1168 +#define USB3_DP_QSERDES_COM_DEBUG_BUS1 0x116c +#define USB3_DP_QSERDES_COM_DEBUG_BUS2 0x1170 +#define USB3_DP_QSERDES_COM_DEBUG_BUS3 0x1174 +#define USB3_DP_QSERDES_COM_DEBUG_BUS_SEL 0x1178 +#define USB3_DP_QSERDES_COM_CMN_MISC1 0x117c +#define USB3_DP_QSERDES_COM_CMN_MISC2 0x1180 +#define USB3_DP_QSERDES_COM_CMN_MODE 0x1184 +#define USB3_DP_QSERDES_COM_CMN_VREG_SEL 0x1188 +#define USB3_DP_QSERDES_TXA_BIST_MODE_LANENO 0x1200 +#define USB3_DP_QSERDES_TXA_BIST_INVERT 0x1204 +#define USB3_DP_QSERDES_TXA_CLKBUF_ENABLE 0x1208 +#define USB3_DP_QSERDES_TXA_TX_EMP_POST1_LVL 0x120c +#define USB3_DP_QSERDES_TXA_TX_POST2_EMPH 0x1210 +#define USB3_DP_QSERDES_TXA_TX_BOOST_LVL_UP_DN 0x1214 +#define USB3_DP_QSERDES_TXA_TX_IDLE_LVL_LARGE_AMP 0x1218 +#define USB3_DP_QSERDES_TXA_TX_DRV_LVL 0x121c +#define USB3_DP_QSERDES_TXA_TX_DRV_LVL_OFFSET 0x1220 +#define USB3_DP_QSERDES_TXA_RESET_TSYNC_EN 0x1224 +#define USB3_DP_QSERDES_TXA_PRE_STALL_LDO_BOOST_EN 0x1228 +#define USB3_DP_QSERDES_TXA_TX_BAND 0x122c +#define USB3_DP_QSERDES_TXA_SLEW_CNTL 0x1230 +#define USB3_DP_QSERDES_TXA_INTERFACE_SELECT 0x1234 +#define USB3_DP_QSERDES_TXA_LPB_EN 0x1238 +#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_TX 0x123c +#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_RX 0x1240 +#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_OFFSET_TX 0x1244 +#define USB3_DP_QSERDES_TXA_RES_CODE_LANE_OFFSET_RX 0x1248 +#define USB3_DP_QSERDES_TXA_PERL_LENGTH1 0x124c +#define USB3_DP_QSERDES_TXA_PERL_LENGTH2 0x1250 +#define USB3_DP_QSERDES_TXA_SERDES_BYP_EN_OUT 0x1254 +#define USB3_DP_QSERDES_TXA_DEBUG_BUS_SEL 0x1258 +#define USB3_DP_QSERDES_TXA_TRANSCEIVER_BIAS_EN 0x125c +#define USB3_DP_QSERDES_TXA_HIGHZ_DRVR_EN 0x1260 +#define USB3_DP_QSERDES_TXA_TX_POL_INV 0x1264 +#define USB3_DP_QSERDES_TXA_PARRATE_REC_DETECT_IDLE_EN 0x1268 +#define USB3_DP_QSERDES_TXA_BIST_PATTERN1 0x126c +#define USB3_DP_QSERDES_TXA_BIST_PATTERN2 0x1270 +#define USB3_DP_QSERDES_TXA_BIST_PATTERN3 0x1274 +#define USB3_DP_QSERDES_TXA_BIST_PATTERN4 0x1278 +#define USB3_DP_QSERDES_TXA_BIST_PATTERN5 0x127c +#define USB3_DP_QSERDES_TXA_BIST_PATTERN6 0x1280 +#define USB3_DP_QSERDES_TXA_BIST_PATTERN7 0x1284 +#define USB3_DP_QSERDES_TXA_BIST_PATTERN8 0x1288 +#define USB3_DP_QSERDES_TXA_LANE_MODE_1 0x128c +#define USB3_DP_QSERDES_TXA_LANE_MODE_2 0x1290 +#define USB3_DP_QSERDES_TXA_LANE_MODE_3 0x1294 +#define USB3_DP_QSERDES_TXA_ATB_SEL1 0x1298 +#define USB3_DP_QSERDES_TXA_ATB_SEL2 0x129c +#define USB3_DP_QSERDES_TXA_RCV_DETECT_LVL 0x12a0 +#define USB3_DP_QSERDES_TXA_RCV_DETECT_LVL_2 0x12a4 +#define USB3_DP_QSERDES_TXA_PRBS_SEED1 0x12a8 +#define USB3_DP_QSERDES_TXA_PRBS_SEED2 0x12ac +#define USB3_DP_QSERDES_TXA_PRBS_SEED3 0x12b0 +#define USB3_DP_QSERDES_TXA_PRBS_SEED4 0x12b4 +#define USB3_DP_QSERDES_TXA_RESET_GEN 0x12b8 +#define USB3_DP_QSERDES_TXA_RESET_GEN_MUXES 0x12bc +#define USB3_DP_QSERDES_TXA_TRAN_DRVR_EMP_EN 0x12c0 +#define USB3_DP_QSERDES_TXA_TX_INTERFACE_MODE 0x12c4 +#define USB3_DP_QSERDES_TXA_PWM_CTRL 0x12c8 +#define USB3_DP_QSERDES_TXA_PWM_ENCODED_OR_DATA 0x12cc +#define USB3_DP_QSERDES_TXA_PWM_GEAR_1_DIVIDER_BAND2 0x12d0 +#define USB3_DP_QSERDES_TXA_PWM_GEAR_2_DIVIDER_BAND2 0x12d4 +#define USB3_DP_QSERDES_TXA_PWM_GEAR_3_DIVIDER_BAND2 0x12d8 +#define USB3_DP_QSERDES_TXA_PWM_GEAR_4_DIVIDER_BAND2 0x12dc +#define USB3_DP_QSERDES_TXA_PWM_GEAR_1_DIVIDER_BAND0_1 0x12e0 +#define USB3_DP_QSERDES_TXA_PWM_GEAR_2_DIVIDER_BAND0_1 0x12e4 +#define USB3_DP_QSERDES_TXA_PWM_GEAR_3_DIVIDER_BAND0_1 0x12e8 +#define USB3_DP_QSERDES_TXA_PWM_GEAR_4_DIVIDER_BAND0_1 0x12ec +#define USB3_DP_QSERDES_TXA_VMODE_CTRL1 0x12f0 +#define USB3_DP_QSERDES_TXA_ALOG_OBSV_BUS_CTRL_1 0x12f4 +#define USB3_DP_QSERDES_TXA_BIST_STATUS 0x12f8 +#define USB3_DP_QSERDES_TXA_BIST_ERROR_COUNT1 0x12fc +#define USB3_DP_QSERDES_TXA_BIST_ERROR_COUNT2 0x1300 +#define USB3_DP_QSERDES_TXA_ALOG_OBSV_BUS_STATUS_1 0x1304 +#define USB3_DP_QSERDES_RXA_UCDR_FO_GAIN_HALF 0x1400 +#define USB3_DP_QSERDES_RXA_UCDR_FO_GAIN_QUARTER 0x1404 +#define USB3_DP_QSERDES_RXA_UCDR_FO_GAIN 0x1408 +#define USB3_DP_QSERDES_RXA_UCDR_SO_GAIN_HALF 0x140c +#define USB3_DP_QSERDES_RXA_UCDR_SO_GAIN_QUARTER 0x1410 +#define USB3_DP_QSERDES_RXA_UCDR_SO_GAIN 0x1414 +#define USB3_DP_QSERDES_RXA_UCDR_SVS_FO_GAIN_HALF 0x1418 +#define USB3_DP_QSERDES_RXA_UCDR_SVS_FO_GAIN_QUARTER 0x141c +#define USB3_DP_QSERDES_RXA_UCDR_SVS_FO_GAIN 0x1420 +#define USB3_DP_QSERDES_RXA_UCDR_SVS_SO_GAIN_HALF 0x1424 +#define USB3_DP_QSERDES_RXA_UCDR_SVS_SO_GAIN_QUARTER 0x1428 +#define USB3_DP_QSERDES_RXA_UCDR_SVS_SO_GAIN 0x142c +#define USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_FO_GAIN 0x1430 +#define USB3_DP_QSERDES_RXA_UCDR_SO_SATURATION_AND_ENABLE 0x1434 +#define USB3_DP_QSERDES_RXA_UCDR_FO_TO_SO_DELAY 0x1438 +#define USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_COUNT_LOW 0x143c +#define USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_COUNT_HIGH 0x1440 +#define USB3_DP_QSERDES_RXA_UCDR_PI_CONTROLS 0x1444 +#define USB3_DP_QSERDES_RXA_UCDR_SB2_THRESH1 0x1448 +#define USB3_DP_QSERDES_RXA_UCDR_SB2_THRESH2 0x144c +#define USB3_DP_QSERDES_RXA_UCDR_SB2_GAIN1 0x1450 +#define USB3_DP_QSERDES_RXA_UCDR_SB2_GAIN2 0x1454 +#define USB3_DP_QSERDES_RXA_AUX_CONTROL 0x1458 +#define USB3_DP_QSERDES_RXA_AUX_DATA_TCOARSE_TFINE 0x145c +#define USB3_DP_QSERDES_RXA_RCLK_AUXDATA_SEL 0x1460 +#define USB3_DP_QSERDES_RXA_AC_JTAG_ENABLE 0x1464 +#define USB3_DP_QSERDES_RXA_AC_JTAG_INITP 0x1468 +#define USB3_DP_QSERDES_RXA_AC_JTAG_INITN 0x146c +#define USB3_DP_QSERDES_RXA_AC_JTAG_LVL 0x1470 +#define USB3_DP_QSERDES_RXA_AC_JTAG_MODE 0x1474 +#define USB3_DP_QSERDES_RXA_AC_JTAG_RESET 0x1478 +#define USB3_DP_QSERDES_RXA_RX_TERM_BW 0x147c +#define USB3_DP_QSERDES_RXA_RX_RCVR_IQ_EN 0x1480 +#define USB3_DP_QSERDES_RXA_RX_IDAC_I_DC_OFFSETS 0x1484 +#define USB3_DP_QSERDES_RXA_RX_IDAC_IBAR_DC_OFFSETS 0x1488 +#define USB3_DP_QSERDES_RXA_RX_IDAC_Q_DC_OFFSETS 0x148c +#define USB3_DP_QSERDES_RXA_RX_IDAC_QBAR_DC_OFFSETS 0x1490 +#define USB3_DP_QSERDES_RXA_RX_IDAC_A_DC_OFFSETS 0x1494 +#define USB3_DP_QSERDES_RXA_RX_IDAC_ABAR_DC_OFFSETS 0x1498 +#define USB3_DP_QSERDES_RXA_RX_IDAC_EN 0x149c +#define USB3_DP_QSERDES_RXA_RX_IDAC_ENABLES 0x14a0 +#define USB3_DP_QSERDES_RXA_RX_IDAC_SIGN 0x14a4 +#define USB3_DP_QSERDES_RXA_RX_HIGHZ_HIGHRATE 0x14a8 +#define USB3_DP_QSERDES_RXA_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x14ac +#define USB3_DP_QSERDES_RXA_DFE_1 0x14b0 +#define USB3_DP_QSERDES_RXA_DFE_2 0x14b4 +#define USB3_DP_QSERDES_RXA_DFE_3 0x14b8 +#define USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL1 0x14bc +#define USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL2 0x14c0 +#define USB3_DP_QSERDES_RXA_GM_CAL 0x14c4 +#define USB3_DP_QSERDES_RXA_RX_EQ_GAIN2_LSB 0x14c8 +#define USB3_DP_QSERDES_RXA_RX_EQ_GAIN2_MSB 0x14cc +#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL1 0x14d0 +#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL2 0x14d4 +#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL3 0x14d8 +#define USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL4 0x14dc +#define USB3_DP_QSERDES_RXA_RX_IDAC_TSETTLE_LOW 0x14e0 +#define USB3_DP_QSERDES_RXA_RX_IDAC_TSETTLE_HIGH 0x14e4 +#define USB3_DP_QSERDES_RXA_RX_IDAC_MEASURE_TIME 0x14e8 +#define USB3_DP_QSERDES_RXA_RX_IDAC_ACCUMULATOR 0x14ec +#define USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_LSB 0x14f0 +#define USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_MSB 0x14f4 +#define USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x14f8 +#define USB3_DP_QSERDES_RXA_RX_OFFSET_ADAPTOR_CNTRL2 0x14fc +#define USB3_DP_QSERDES_RXA_SIGDET_ENABLES 0x1500 +#define USB3_DP_QSERDES_RXA_SIGDET_CNTRL 0x1504 +#define USB3_DP_QSERDES_RXA_SIGDET_LVL 0x1508 +#define USB3_DP_QSERDES_RXA_SIGDET_DEGLITCH_CNTRL 0x150c +#define USB3_DP_QSERDES_RXA_RX_BAND 0x1510 +#define USB3_DP_QSERDES_RXA_CDR_FREEZE_UP_DN 0x1514 +#define USB3_DP_QSERDES_RXA_CDR_RESET_OVERRIDE 0x1518 +#define USB3_DP_QSERDES_RXA_RX_INTERFACE_MODE 0x151c +#define USB3_DP_QSERDES_RXA_JITTER_GEN_MODE 0x1520 +#define USB3_DP_QSERDES_RXA_BUJ_AMP 0x1524 +#define USB3_DP_QSERDES_RXA_SJ_AMP1 0x1528 +#define USB3_DP_QSERDES_RXA_SJ_AMP2 0x152c +#define USB3_DP_QSERDES_RXA_SJ_PER1 0x1530 +#define USB3_DP_QSERDES_RXA_SJ_PER2 0x1534 +#define USB3_DP_QSERDES_RXA_BUJ_STEP_FREQ1 0x1538 +#define USB3_DP_QSERDES_RXA_BUJ_STEP_FREQ2 0x153c +#define USB3_DP_QSERDES_RXA_PPM_OFFSET1 0x1540 +#define USB3_DP_QSERDES_RXA_PPM_OFFSET2 0x1544 +#define USB3_DP_QSERDES_RXA_SIGN_PPM_PERIOD1 0x1548 +#define USB3_DP_QSERDES_RXA_SIGN_PPM_PERIOD2 0x154c +#define USB3_DP_QSERDES_RXA_RX_PWM_ENABLE_AND_DATA 0x1550 +#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR1_TIMEOUT_COUNT 0x1554 +#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR2_TIMEOUT_COUNT 0x1558 +#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR3_TIMEOUT_COUNT 0x155c +#define USB3_DP_QSERDES_RXA_RX_PWM_GEAR4_TIMEOUT_COUNT 0x1560 +#define USB3_DP_QSERDES_RXA_RX_MODE_00 0x1564 +#define USB3_DP_QSERDES_RXA_RX_MODE_01 0x1568 +#define USB3_DP_QSERDES_RXA_RX_MODE_10 0x156c +#define USB3_DP_QSERDES_RXA_ALOG_OBSV_BUS_CTRL_1 0x1570 +#define USB3_DP_QSERDES_RXA_PI_CTRL1 0x1574 +#define USB3_DP_QSERDES_RXA_PI_CTRL2 0x1578 +#define USB3_DP_QSERDES_RXA_PI_QUAD 0x157c +#define USB3_DP_QSERDES_RXA_IDATA1 0x1580 +#define USB3_DP_QSERDES_RXA_IDATA2 0x1584 +#define USB3_DP_QSERDES_RXA_AUX_DATA1 0x1588 +#define USB3_DP_QSERDES_RXA_AUX_DATA2 0x158c +#define USB3_DP_QSERDES_RXA_AC_JTAG_OUTP 0x1590 +#define USB3_DP_QSERDES_RXA_AC_JTAG_OUTN 0x1594 +#define USB3_DP_QSERDES_RXA_RX_SIGDET 0x1598 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_I 0x159c +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_IBAR 0x15a0 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_Q 0x15a4 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_QBAR 0x15a8 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_A 0x15ac +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_ABAR 0x15b0 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_SM_ON 0x15b4 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_CAL_DONE 0x15b8 +#define USB3_DP_QSERDES_RXA_IDAC_STATUS_SIGNERROR 0x15bc +#define USB3_DP_QSERDES_RXA_READ_EQCODE 0x15c0 +#define USB3_DP_QSERDES_RXA_READ_OFFSETCODE 0x15c4 +#define USB3_DP_QSERDES_RXA_IA_ERROR_COUNTER_LOW 0x15c8 +#define USB3_DP_QSERDES_RXA_IA_ERROR_COUNTER_HIGH 0x15cc +#define USB3_DP_QSERDES_RXA_VGA_READ_CODE 0x15d0 +#define USB3_DP_QSERDES_RXA_DFE_TAP1_READ_CODE 0x15d4 +#define USB3_DP_QSERDES_RXA_DFE_TAP2_READ_CODE 0x15d8 +#define USB3_DP_QSERDES_RXA_ALOG_OBSV_BUS_STATUS_1 0x15dc +#define USB3_DP_QSERDES_TXB_BIST_MODE_LANENO 0x1600 +#define USB3_DP_QSERDES_TXB_BIST_INVERT 0x1604 +#define USB3_DP_QSERDES_TXB_CLKBUF_ENABLE 0x1608 +#define USB3_DP_QSERDES_TXB_TX_EMP_POST1_LVL 0x160c +#define USB3_DP_QSERDES_TXB_TX_POST2_EMPH 0x1610 +#define USB3_DP_QSERDES_TXB_TX_BOOST_LVL_UP_DN 0x1614 +#define USB3_DP_QSERDES_TXB_TX_IDLE_LVL_LARGE_AMP 0x1618 +#define USB3_DP_QSERDES_TXB_TX_DRV_LVL 0x161c +#define USB3_DP_QSERDES_TXB_TX_DRV_LVL_OFFSET 0x1620 +#define USB3_DP_QSERDES_TXB_RESET_TSYNC_EN 0x1624 +#define USB3_DP_QSERDES_TXB_PRE_STALL_LDO_BOOST_EN 0x1628 +#define USB3_DP_QSERDES_TXB_TX_BAND 0x162c +#define USB3_DP_QSERDES_TXB_SLEW_CNTL 0x1630 +#define USB3_DP_QSERDES_TXB_INTERFACE_SELECT 0x1634 +#define USB3_DP_QSERDES_TXB_LPB_EN 0x1638 +#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_TX 0x163c +#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_RX 0x1640 +#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_OFFSET_TX 0x1644 +#define USB3_DP_QSERDES_TXB_RES_CODE_LANE_OFFSET_RX 0x1648 +#define USB3_DP_QSERDES_TXB_PERL_LENGTH1 0x164c +#define USB3_DP_QSERDES_TXB_PERL_LENGTH2 0x1650 +#define USB3_DP_QSERDES_TXB_SERDES_BYP_EN_OUT 0x1654 +#define USB3_DP_QSERDES_TXB_DEBUG_BUS_SEL 0x1658 +#define USB3_DP_QSERDES_TXB_TRANSCEIVER_BIAS_EN 0x165c +#define USB3_DP_QSERDES_TXB_HIGHZ_DRVR_EN 0x1660 +#define USB3_DP_QSERDES_TXB_TX_POL_INV 0x1664 +#define USB3_DP_QSERDES_TXB_PARRATE_REC_DETECT_IDLE_EN 0x1668 +#define USB3_DP_QSERDES_TXB_BIST_PATTERN1 0x166c +#define USB3_DP_QSERDES_TXB_BIST_PATTERN2 0x1670 +#define USB3_DP_QSERDES_TXB_BIST_PATTERN3 0x1674 +#define USB3_DP_QSERDES_TXB_BIST_PATTERN4 0x1678 +#define USB3_DP_QSERDES_TXB_BIST_PATTERN5 0x167c +#define USB3_DP_QSERDES_TXB_BIST_PATTERN6 0x1680 +#define USB3_DP_QSERDES_TXB_BIST_PATTERN7 0x1684 +#define USB3_DP_QSERDES_TXB_BIST_PATTERN8 0x1688 +#define USB3_DP_QSERDES_TXB_LANE_MODE_1 0x168c +#define USB3_DP_QSERDES_TXB_LANE_MODE_2 0x1690 +#define USB3_DP_QSERDES_TXB_LANE_MODE_3 0x1694 +#define USB3_DP_QSERDES_TXB_ATB_SEL1 0x1698 +#define USB3_DP_QSERDES_TXB_ATB_SEL2 0x169c +#define USB3_DP_QSERDES_TXB_RCV_DETECT_LVL 0x16a0 +#define USB3_DP_QSERDES_TXB_RCV_DETECT_LVL_2 0x16a4 +#define USB3_DP_QSERDES_TXB_PRBS_SEED1 0x16a8 +#define USB3_DP_QSERDES_TXB_PRBS_SEED2 0x16ac +#define USB3_DP_QSERDES_TXB_PRBS_SEED3 0x16b0 +#define USB3_DP_QSERDES_TXB_PRBS_SEED4 0x16b4 +#define USB3_DP_QSERDES_TXB_RESET_GEN 0x16b8 +#define USB3_DP_QSERDES_TXB_RESET_GEN_MUXES 0x16bc +#define USB3_DP_QSERDES_TXB_TRAN_DRVR_EMP_EN 0x16c0 +#define USB3_DP_QSERDES_TXB_TX_INTERFACE_MODE 0x16c4 +#define USB3_DP_QSERDES_TXB_PWM_CTRL 0x16c8 +#define USB3_DP_QSERDES_TXB_PWM_ENCODED_OR_DATA 0x16cc +#define USB3_DP_QSERDES_TXB_PWM_GEAR_1_DIVIDER_BAND2 0x16d0 +#define USB3_DP_QSERDES_TXB_PWM_GEAR_2_DIVIDER_BAND2 0x16d4 +#define USB3_DP_QSERDES_TXB_PWM_GEAR_3_DIVIDER_BAND2 0x16d8 +#define USB3_DP_QSERDES_TXB_PWM_GEAR_4_DIVIDER_BAND2 0x16dc +#define USB3_DP_QSERDES_TXB_PWM_GEAR_1_DIVIDER_BAND0_1 0x16e0 +#define USB3_DP_QSERDES_TXB_PWM_GEAR_2_DIVIDER_BAND0_1 0x16e4 +#define USB3_DP_QSERDES_TXB_PWM_GEAR_3_DIVIDER_BAND0_1 0x16e8 +#define USB3_DP_QSERDES_TXB_PWM_GEAR_4_DIVIDER_BAND0_1 0x16ec +#define USB3_DP_QSERDES_TXB_VMODE_CTRL1 0x16f0 +#define USB3_DP_QSERDES_TXB_ALOG_OBSV_BUS_CTRL_1 0x16f4 +#define USB3_DP_QSERDES_TXB_BIST_STATUS 0x16f8 +#define USB3_DP_QSERDES_TXB_BIST_ERROR_COUNT1 0x16fc +#define USB3_DP_QSERDES_TXB_BIST_ERROR_COUNT2 0x1700 +#define USB3_DP_QSERDES_TXB_ALOG_OBSV_BUS_STATUS_1 0x1704 +#define USB3_DP_QSERDES_RXB_UCDR_FO_GAIN_HALF 0x1800 +#define USB3_DP_QSERDES_RXB_UCDR_FO_GAIN_QUARTER 0x1804 +#define USB3_DP_QSERDES_RXB_UCDR_FO_GAIN 0x1808 +#define USB3_DP_QSERDES_RXB_UCDR_SO_GAIN_HALF 0x180c +#define USB3_DP_QSERDES_RXB_UCDR_SO_GAIN_QUARTER 0x1810 +#define USB3_DP_QSERDES_RXB_UCDR_SO_GAIN 0x1814 +#define USB3_DP_QSERDES_RXB_UCDR_SVS_FO_GAIN_HALF 0x1818 +#define USB3_DP_QSERDES_RXB_UCDR_SVS_FO_GAIN_QUARTER 0x181c +#define USB3_DP_QSERDES_RXB_UCDR_SVS_FO_GAIN 0x1820 +#define USB3_DP_QSERDES_RXB_UCDR_SVS_SO_GAIN_HALF 0x1824 +#define USB3_DP_QSERDES_RXB_UCDR_SVS_SO_GAIN_QUARTER 0x1828 +#define USB3_DP_QSERDES_RXB_UCDR_SVS_SO_GAIN 0x182c +#define USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_FO_GAIN 0x1830 +#define USB3_DP_QSERDES_RXB_UCDR_SO_SATURATION_AND_ENABLE 0x1834 +#define USB3_DP_QSERDES_RXB_UCDR_FO_TO_SO_DELAY 0x1838 +#define USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_COUNT_LOW 0x183c +#define USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_COUNT_HIGH 0x1840 +#define USB3_DP_QSERDES_RXB_UCDR_PI_CONTROLS 0x1844 +#define USB3_DP_QSERDES_RXB_UCDR_SB2_THRESH1 0x1848 +#define USB3_DP_QSERDES_RXB_UCDR_SB2_THRESH2 0x184c +#define USB3_DP_QSERDES_RXB_UCDR_SB2_GAIN1 0x1850 +#define USB3_DP_QSERDES_RXB_UCDR_SB2_GAIN2 0x1854 +#define USB3_DP_QSERDES_RXB_AUX_CONTROL 0x1858 +#define USB3_DP_QSERDES_RXB_AUX_DATA_TCOARSE_TFINE 0x185c +#define USB3_DP_QSERDES_RXB_RCLK_AUXDATA_SEL 0x1860 +#define USB3_DP_QSERDES_RXB_AC_JTAG_ENABLE 0x1864 +#define USB3_DP_QSERDES_RXB_AC_JTAG_INITP 0x1868 +#define USB3_DP_QSERDES_RXB_AC_JTAG_INITN 0x186c +#define USB3_DP_QSERDES_RXB_AC_JTAG_LVL 0x1870 +#define USB3_DP_QSERDES_RXB_AC_JTAG_MODE 0x1874 +#define USB3_DP_QSERDES_RXB_AC_JTAG_RESET 0x1878 +#define USB3_DP_QSERDES_RXB_RX_TERM_BW 0x187c +#define USB3_DP_QSERDES_RXB_RX_RCVR_IQ_EN 0x1880 +#define USB3_DP_QSERDES_RXB_RX_IDAC_I_DC_OFFSETS 0x1884 +#define USB3_DP_QSERDES_RXB_RX_IDAC_IBAR_DC_OFFSETS 0x1888 +#define USB3_DP_QSERDES_RXB_RX_IDAC_Q_DC_OFFSETS 0x188c +#define USB3_DP_QSERDES_RXB_RX_IDAC_QBAR_DC_OFFSETS 0x1890 +#define USB3_DP_QSERDES_RXB_RX_IDAC_A_DC_OFFSETS 0x1894 +#define USB3_DP_QSERDES_RXB_RX_IDAC_ABAR_DC_OFFSETS 0x1898 +#define USB3_DP_QSERDES_RXB_RX_IDAC_EN 0x189c +#define USB3_DP_QSERDES_RXB_RX_IDAC_ENABLES 0x18a0 +#define USB3_DP_QSERDES_RXB_RX_IDAC_SIGN 0x18a4 +#define USB3_DP_QSERDES_RXB_RX_HIGHZ_HIGHRATE 0x18a8 +#define USB3_DP_QSERDES_RXB_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x18ac +#define USB3_DP_QSERDES_RXB_DFE_1 0x18b0 +#define USB3_DP_QSERDES_RXB_DFE_2 0x18b4 +#define USB3_DP_QSERDES_RXB_DFE_3 0x18b8 +#define USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL1 0x18bc +#define USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL2 0x18c0 +#define USB3_DP_QSERDES_RXB_GM_CAL 0x18c4 +#define USB3_DP_QSERDES_RXB_RX_EQ_GAIN2_LSB 0x18c8 +#define USB3_DP_QSERDES_RXB_RX_EQ_GAIN2_MSB 0x18cc +#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL1 0x18d0 +#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL2 0x18d4 +#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL3 0x18d8 +#define USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL4 0x18dc +#define USB3_DP_QSERDES_RXB_RX_IDAC_TSETTLE_LOW 0x18e0 +#define USB3_DP_QSERDES_RXB_RX_IDAC_TSETTLE_HIGH 0x18e4 +#define USB3_DP_QSERDES_RXB_RX_IDAC_MEASURE_TIME 0x18e8 +#define USB3_DP_QSERDES_RXB_RX_IDAC_ACCUMULATOR 0x18ec +#define USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_LSB 0x18f0 +#define USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_MSB 0x18f4 +#define USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x18f8 +#define USB3_DP_QSERDES_RXB_RX_OFFSET_ADAPTOR_CNTRL2 0x18fc +#define USB3_DP_QSERDES_RXB_SIGDET_ENABLES 0x1900 +#define USB3_DP_QSERDES_RXB_SIGDET_CNTRL 0x1904 +#define USB3_DP_QSERDES_RXB_SIGDET_LVL 0x1908 +#define USB3_DP_QSERDES_RXB_SIGDET_DEGLITCH_CNTRL 0x190c +#define USB3_DP_QSERDES_RXB_RX_BAND 0x1910 +#define USB3_DP_QSERDES_RXB_CDR_FREEZE_UP_DN 0x1914 +#define USB3_DP_QSERDES_RXB_CDR_RESET_OVERRIDE 0x1918 +#define USB3_DP_QSERDES_RXB_RX_INTERFACE_MODE 0x191c +#define USB3_DP_QSERDES_RXB_JITTER_GEN_MODE 0x1920 +#define USB3_DP_QSERDES_RXB_BUJ_AMP 0x1924 +#define USB3_DP_QSERDES_RXB_SJ_AMP1 0x1928 +#define USB3_DP_QSERDES_RXB_SJ_AMP2 0x192c +#define USB3_DP_QSERDES_RXB_SJ_PER1 0x1930 +#define USB3_DP_QSERDES_RXB_SJ_PER2 0x1934 +#define USB3_DP_QSERDES_RXB_BUJ_STEP_FREQ1 0x1938 +#define USB3_DP_QSERDES_RXB_BUJ_STEP_FREQ2 0x193c +#define USB3_DP_QSERDES_RXB_PPM_OFFSET1 0x1940 +#define USB3_DP_QSERDES_RXB_PPM_OFFSET2 0x1944 +#define USB3_DP_QSERDES_RXB_SIGN_PPM_PERIOD1 0x1948 +#define USB3_DP_QSERDES_RXB_SIGN_PPM_PERIOD2 0x194c +#define USB3_DP_QSERDES_RXB_RX_PWM_ENABLE_AND_DATA 0x1950 +#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR1_TIMEOUT_COUNT 0x1954 +#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR2_TIMEOUT_COUNT 0x1958 +#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR3_TIMEOUT_COUNT 0x195c +#define USB3_DP_QSERDES_RXB_RX_PWM_GEAR4_TIMEOUT_COUNT 0x1960 +#define USB3_DP_QSERDES_RXB_RX_MODE_00 0x1964 +#define USB3_DP_QSERDES_RXB_RX_MODE_01 0x1968 +#define USB3_DP_QSERDES_RXB_RX_MODE_10 0x196c +#define USB3_DP_QSERDES_RXB_ALOG_OBSV_BUS_CTRL_1 0x1970 +#define USB3_DP_QSERDES_RXB_PI_CTRL1 0x1974 +#define USB3_DP_QSERDES_RXB_PI_CTRL2 0x1978 +#define USB3_DP_QSERDES_RXB_PI_QUAD 0x197c +#define USB3_DP_QSERDES_RXB_IDATA1 0x1980 +#define USB3_DP_QSERDES_RXB_IDATA2 0x1984 +#define USB3_DP_QSERDES_RXB_AUX_DATA1 0x1988 +#define USB3_DP_QSERDES_RXB_AUX_DATA2 0x198c +#define USB3_DP_QSERDES_RXB_AC_JTAG_OUTP 0x1990 +#define USB3_DP_QSERDES_RXB_AC_JTAG_OUTN 0x1994 +#define USB3_DP_QSERDES_RXB_RX_SIGDET 0x1998 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_I 0x199c +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_IBAR 0x19a0 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_Q 0x19a4 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_QBAR 0x19a8 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_A 0x19ac +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_ABAR 0x19b0 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_SM_ON 0x19b4 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_CAL_DONE 0x19b8 +#define USB3_DP_QSERDES_RXB_IDAC_STATUS_SIGNERROR 0x19bc +#define USB3_DP_QSERDES_RXB_READ_EQCODE 0x19c0 +#define USB3_DP_QSERDES_RXB_READ_OFFSETCODE 0x19c4 +#define USB3_DP_QSERDES_RXB_IA_ERROR_COUNTER_LOW 0x19c8 +#define USB3_DP_QSERDES_RXB_IA_ERROR_COUNTER_HIGH 0x19cc +#define USB3_DP_QSERDES_RXB_VGA_READ_CODE 0x19d0 +#define USB3_DP_QSERDES_RXB_DFE_TAP1_READ_CODE 0x19d4 +#define USB3_DP_QSERDES_RXB_DFE_TAP2_READ_CODE 0x19d8 +#define USB3_DP_QSERDES_RXB_ALOG_OBSV_BUS_STATUS_1 0x19dc +#define USB3_DP_PCS_MISC_TYPEC_CTRL 0x1a00 +#define USB3_DP_PCS_MISC_TYPEC_PWRDN_CTRL 0x1a04 +#define USB3_DP_PCS_MISC_PCS_MISC_CONFIG1 0x1a08 +#define USB3_DP_PCS_MISC_CLAMP_ENABLE 0x1a0c +#define USB3_DP_PCS_MISC_TYPEC_STATUS 0x1a10 +#define USB3_DP_PCS_MISC_PLACEHOLDER_STATUS 0x1a14 +#define USB3_DP_PCS_SW_RESET 0x1c00 +#define USB3_DP_PCS_POWER_DOWN_CONTROL 0x1c04 +#define USB3_DP_PCS_START_CONTROL 0x1c08 +#define USB3_DP_PCS_TXMGN_V0 0x1c0c +#define USB3_DP_PCS_TXMGN_V1 0x1c10 +#define USB3_DP_PCS_TXMGN_V2 0x1c14 +#define USB3_DP_PCS_TXMGN_V3 0x1c18 +#define USB3_DP_PCS_TXMGN_V4 0x1c1c +#define USB3_DP_PCS_TXMGN_LS 0x1c20 +#define USB3_DP_PCS_TXDEEMPH_M6DB_V0 0x1c24 +#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V0 0x1c28 +#define USB3_DP_PCS_TXDEEMPH_M6DB_V1 0x1c2c +#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V1 0x1c30 +#define USB3_DP_PCS_TXDEEMPH_M6DB_V2 0x1c34 +#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V2 0x1c38 +#define USB3_DP_PCS_TXDEEMPH_M6DB_V3 0x1c3c +#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V3 0x1c40 +#define USB3_DP_PCS_TXDEEMPH_M6DB_V4 0x1c44 +#define USB3_DP_PCS_TXDEEMPH_M3P5DB_V4 0x1c48 +#define USB3_DP_PCS_TXDEEMPH_M6DB_LS 0x1c4c +#define USB3_DP_PCS_TXDEEMPH_M3P5DB_LS 0x1c50 +#define USB3_DP_PCS_ENDPOINT_REFCLK_DRIVE 0x1c54 +#define USB3_DP_PCS_RX_IDLE_DTCT_CNTRL 0x1c58 +#define USB3_DP_PCS_RATE_SLEW_CNTRL 0x1c5c +#define USB3_DP_PCS_POWER_STATE_CONFIG1 0x1c60 +#define USB3_DP_PCS_POWER_STATE_CONFIG2 0x1c64 +#define USB3_DP_PCS_POWER_STATE_CONFIG3 0x1c68 +#define USB3_DP_PCS_POWER_STATE_CONFIG4 0x1c6c +#define USB3_DP_PCS_RCVR_DTCT_DLY_P1U2_L 0x1c70 +#define USB3_DP_PCS_RCVR_DTCT_DLY_P1U2_H 0x1c74 +#define USB3_DP_PCS_RCVR_DTCT_DLY_U3_L 0x1c78 +#define USB3_DP_PCS_RCVR_DTCT_DLY_U3_H 0x1c7c +#define USB3_DP_PCS_LOCK_DETECT_CONFIG1 0x1c80 +#define USB3_DP_PCS_LOCK_DETECT_CONFIG2 0x1c84 +#define USB3_DP_PCS_LOCK_DETECT_CONFIG3 0x1c88 +#define USB3_DP_PCS_TSYNC_RSYNC_TIME 0x1c8c +#define USB3_DP_PCS_SIGDET_LOW_2_IDLE_TIME 0x1c90 +#define USB3_DP_PCS_BEACON_2_IDLE_TIME_L 0x1c94 +#define USB3_DP_PCS_BEACON_2_IDLE_TIME_H 0x1c98 +#define USB3_DP_PCS_PWRUP_RESET_DLY_TIME_SYSCLK 0x1c9c +#define USB3_DP_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x1ca0 +#define USB3_DP_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x1ca4 +#define USB3_DP_PCS_PLL_LOCK_CHK_DLY_TIME 0x1ca8 +#define USB3_DP_PCS_LFPS_DET_HIGH_COUNT_VAL 0x1cac +#define USB3_DP_PCS_LFPS_TX_ECSTART_EQTLOCK 0x1cb0 +#define USB3_DP_PCS_LFPS_TX_END_CNT_P2U3_START 0x1cb4 +#define USB3_DP_PCS_RXEQTRAINING_WAIT_TIME 0x1cb8 +#define USB3_DP_PCS_RXEQTRAINING_RUN_TIME 0x1cbc +#define USB3_DP_PCS_TXONESZEROS_RUN_LENGTH 0x1cc0 +#define USB3_DP_PCS_FLL_CNTRL1 0x1cc4 +#define USB3_DP_PCS_FLL_CNTRL2 0x1cc8 +#define USB3_DP_PCS_FLL_CNT_VAL_L 0x1ccc +#define USB3_DP_PCS_FLL_CNT_VAL_H_TOL 0x1cd0 +#define USB3_DP_PCS_FLL_MAN_CODE 0x1cd4 +#define USB3_DP_PCS_AUTONOMOUS_MODE_CTRL 0x1cd8 +#define USB3_DP_PCS_LFPS_RXTERM_IRQ_CLEAR 0x1cdc +#define USB3_DP_PCS_ARCVR_DTCT_EN_PERIOD 0x1ce0 +#define USB3_DP_PCS_ARCVR_DTCT_CM_DLY 0x1ce4 +#define USB3_DP_PCS_ALFPS_DEGLITCH_VAL 0x1ce8 +#define USB3_DP_PCS_INSIG_SW_CTRL1 0x1cec +#define USB3_DP_PCS_INSIG_SW_CTRL2 0x1cf0 +#define USB3_DP_PCS_INSIG_SW_CTRL3 0x1cf4 +#define USB3_DP_PCS_INSIG_MX_CTRL1 0x1cf8 +#define USB3_DP_PCS_INSIG_MX_CTRL2 0x1cfc +#define USB3_DP_PCS_INSIG_MX_CTRL3 0x1d00 +#define USB3_DP_PCS_OUTSIG_SW_CTRL1 0x1d04 +#define USB3_DP_PCS_OUTSIG_MX_CTRL1 0x1d08 +#define USB3_DP_PCS_CLK_DEBUG_BYPASS_CTRL 0x1d0c +#define USB3_DP_PCS_TEST_CONTROL 0x1d10 +#define USB3_DP_PCS_TEST_CONTROL2 0x1d14 +#define USB3_DP_PCS_TEST_CONTROL3 0x1d18 +#define USB3_DP_PCS_TEST_CONTROL4 0x1d1c +#define USB3_DP_PCS_TEST_CONTROL5 0x1d20 +#define USB3_DP_PCS_TEST_CONTROL6 0x1d24 +#define USB3_DP_PCS_TEST_CONTROL7 0x1d28 +#define USB3_DP_PCS_COM_RESET_CONTROL 0x1d2c +#define USB3_DP_PCS_BIST_CTRL 0x1d30 +#define USB3_DP_PCS_PRBS_POLY0 0x1d34 +#define USB3_DP_PCS_PRBS_POLY1 0x1d38 +#define USB3_DP_PCS_PRBS_SEED0 0x1d3c +#define USB3_DP_PCS_PRBS_SEED1 0x1d40 +#define USB3_DP_PCS_FIXED_PAT_CTRL 0x1d44 +#define USB3_DP_PCS_FIXED_PAT0 0x1d48 +#define USB3_DP_PCS_FIXED_PAT1 0x1d4c +#define USB3_DP_PCS_FIXED_PAT2 0x1d50 +#define USB3_DP_PCS_FIXED_PAT3 0x1d54 +#define USB3_DP_PCS_COM_CLK_SWITCH_CTRL 0x1d58 +#define USB3_DP_PCS_ELECIDLE_DLY_SEL 0x1d5c +#define USB3_DP_PCS_SPARE1 0x1d60 +#define USB3_DP_PCS_BIST_CHK_ERR_CNT_L_STATUS 0x1d64 +#define USB3_DP_PCS_BIST_CHK_ERR_CNT_H_STATUS 0x1d68 +#define USB3_DP_PCS_BIST_CHK_STATUS 0x1d6c +#define USB3_DP_PCS_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x1d70 +#define USB3_DP_PCS_PCS_STATUS 0x1d74 +#define USB3_DP_PCS_PCS_STATUS2 0x1d78 +#define USB3_DP_PCS_PCS_STATUS3 0x1d7c +#define USB3_DP_PCS_COM_RESET_STATUS 0x1d80 +#define USB3_DP_PCS_OSC_DTCT_STATUS 0x1d84 +#define USB3_DP_PCS_REVISION_ID0 0x1d88 +#define USB3_DP_PCS_REVISION_ID1 0x1d8c +#define USB3_DP_PCS_REVISION_ID2 0x1d90 +#define USB3_DP_PCS_REVISION_ID3 0x1d94 +#define USB3_DP_PCS_DEBUG_BUS_0_STATUS 0x1d98 +#define USB3_DP_PCS_DEBUG_BUS_1_STATUS 0x1d9c +#define USB3_DP_PCS_DEBUG_BUS_2_STATUS 0x1da0 +#define USB3_DP_PCS_DEBUG_BUS_3_STATUS 0x1da4 +#define USB3_DP_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1da8 +#define USB3_DP_PCS_OSC_DTCT_ACTIONS 0x1dac +#define USB3_DP_PCS_SIGDET_CNTRL 0x1db0 +#define USB3_DP_PCS_IDAC_CAL_CNTRL 0x1db4 +#define USB3_DP_PCS_CMN_ACK_OUT_SEL 0x1db8 +#define USB3_DP_PCS_PLL_LOCK_CHK_DLY_TIME_SYSCLK 0x1dbc +#define USB3_DP_PCS_AUTONOMOUS_MODE_STATUS 0x1dc0 +#define USB3_DP_PCS_ENDPOINT_REFCLK_CNTRL 0x1dc4 +#define USB3_DP_PCS_EPCLK_PRE_PLL_LOCK_DLY_SYSCLK 0x1dc8 +#define USB3_DP_PCS_EPCLK_PRE_PLL_LOCK_DLY_AUXCLK 0x1dcc +#define USB3_DP_PCS_EPCLK_DLY_COUNT_VAL_L 0x1dd0 +#define USB3_DP_PCS_EPCLK_DLY_COUNT_VAL_H 0x1dd4 +#define USB3_DP_PCS_RX_SIGDET_LVL 0x1dd8 +#define USB3_DP_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1ddc +#define USB3_DP_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1de0 +#define USB3_DP_PCS_AUTONOMOUS_MODE_CTRL2 0x1de4 +#define USB3_DP_PCS_RXTERMINATION_DLY_SEL 0x1de8 +#define USB3_DP_PCS_LFPS_PER_TIMER_VAL 0x1dec +#define USB3_DP_PCS_SIGDET_STARTUP_TIMER_VAL 0x1df0 +#define USB3_DP_PCS_LOCK_DETECT_CONFIG4 0x1df4 +#define USB3_DP_PCS_RX_SIGDET_DTCT_CNTRL 0x1df8 +#define USB3_DP_PCS_PCS_STATUS4 0x1dfc +#define USB3_DP_PCS_PCS_STATUS4_CLEAR 0x1e00 +#define USB3_DP_PCS_DEC_ERROR_COUNT_STATUS 0x1e04 +#define USB3_DP_PCS_COMMA_POS_STATUS 0x1e08 +#define USB3_DP_PCS_REFGEN_REQ_CONFIG1 0x1e0c +#define USB3_DP_PCS_REFGEN_REQ_CONFIG2 0x1e10 +#define USB3_DP_PCS_REFGEN_REQ_CONFIG3 0x1e14 +#define USB3_DP_PHY_DP_DP_PHY_PD_CTL 0x2a18 + +#endif /* _DT_BINDINGS_PHY_QCOM_ATOLL_QMP_USB_H */ diff --git a/include/dt-bindings/thermal/qmi_thermal.h b/include/dt-bindings/thermal/qmi_thermal.h new file mode 100644 index 0000000000000000000000000000000000000000..d41157d9d73c632faa2b318fe2f9f4a696c6b03a --- /dev/null +++ b/include/dt-bindings/thermal/qmi_thermal.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This 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 _DT_BINDINGS_QCOM_QMI_THERMAL_H +#define _DT_BINDINGS_QCOM_QMI_THERMAL_H + +#define QMI_PA 0 +#define QMI_PA_1 1 +#define QMI_PA_2 2 +#define QMI_QFE_PA_0 3 +#define QMI_QFE_WTR_0 4 +#define QMI_MODEM_TSENS 5 +#define QMI_QFE_MMW_0 6 +#define QMI_QFE_MMW_1 7 +#define QMI_QFE_MMW_2 8 +#define QMI_QFE_MMW_3 9 +#define QMI_XO_THERM 10 +#define QMI_QFE_PA_MDM 11 +#define QMI_QFE_PA_WTR 12 +#define QMI_QFE_MMW_STREAMER_0 13 +#define QMI_QFE_MMW_0_MOD 14 +#define QMI_QFE_MMW_1_MOD 15 +#define QMI_QFE_MMW_2_MOD 16 +#define QMI_QFE_MMW_3_MOD 17 +#define QMI_QFE_RET_PA_0 18 +#define QMI_QFE_WTR_PA_0 19 +#define QMI_QFE_WTR_PA_1 20 +#define QMI_QFE_WTR_PA_2 21 +#define QMI_QFE_WTR_PA_3 22 +#define QMI_SYS_THERM_1 23 +#define QMI_SYS_THERM_2 24 +#define QMI_MODEM_TSENS_1 25 + +#define QMI_MODEM_INST_ID 0x0 +#define QMI_ADSP_INST_ID 0x1 +#define QMI_CDSP_INST_ID 0x43 +#define QMI_SLPI_INST_ID 0x53 +#define QMI_MODEM_NR_INST_ID 0x64 + +#endif diff --git a/include/linux/atalk.h b/include/linux/atalk.h index 4d356e168692514c3e09e4686289693ab8b74579..03885e63f92b856ecc43c0435285bc494c624b19 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -151,19 +151,29 @@ extern int sysctl_aarp_retransmit_limit; extern int sysctl_aarp_resolve_time; #ifdef CONFIG_SYSCTL -extern void atalk_register_sysctl(void); +extern int atalk_register_sysctl(void); extern void atalk_unregister_sysctl(void); #else -#define atalk_register_sysctl() do { } while(0) -#define atalk_unregister_sysctl() do { } while(0) +static inline int atalk_register_sysctl(void) +{ + return 0; +} +static inline void atalk_unregister_sysctl(void) +{ +} #endif #ifdef CONFIG_PROC_FS extern int atalk_proc_init(void); extern void atalk_proc_exit(void); #else -#define atalk_proc_init() ({ 0; }) -#define atalk_proc_exit() do { } while(0) +static inline int atalk_proc_init(void) +{ + return 0; +} +static inline void atalk_proc_exit(void) +{ +} #endif /* CONFIG_PROC_FS */ #endif /* __LINUX_ATALK_H__ */ diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h index 50fb0dee23e8662120461cd227cf11f548939339..d35b8ec1c485cba58a658b34edd2f9621cd20639 100644 --- a/include/linux/bitrev.h +++ b/include/linux/bitrev.h @@ -34,41 +34,41 @@ static inline u32 __bitrev32(u32 x) #define __constant_bitrev32(x) \ ({ \ - u32 __x = x; \ - __x = (__x >> 16) | (__x << 16); \ - __x = ((__x & (u32)0xFF00FF00UL) >> 8) | ((__x & (u32)0x00FF00FFUL) << 8); \ - __x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \ - __x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \ - __x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \ - __x; \ + u32 ___x = x; \ + ___x = (___x >> 16) | (___x << 16); \ + ___x = ((___x & (u32)0xFF00FF00UL) >> 8) | ((___x & (u32)0x00FF00FFUL) << 8); \ + ___x = ((___x & (u32)0xF0F0F0F0UL) >> 4) | ((___x & (u32)0x0F0F0F0FUL) << 4); \ + ___x = ((___x & (u32)0xCCCCCCCCUL) >> 2) | ((___x & (u32)0x33333333UL) << 2); \ + ___x = ((___x & (u32)0xAAAAAAAAUL) >> 1) | ((___x & (u32)0x55555555UL) << 1); \ + ___x; \ }) #define __constant_bitrev16(x) \ ({ \ - u16 __x = x; \ - __x = (__x >> 8) | (__x << 8); \ - __x = ((__x & (u16)0xF0F0U) >> 4) | ((__x & (u16)0x0F0FU) << 4); \ - __x = ((__x & (u16)0xCCCCU) >> 2) | ((__x & (u16)0x3333U) << 2); \ - __x = ((__x & (u16)0xAAAAU) >> 1) | ((__x & (u16)0x5555U) << 1); \ - __x; \ + u16 ___x = x; \ + ___x = (___x >> 8) | (___x << 8); \ + ___x = ((___x & (u16)0xF0F0U) >> 4) | ((___x & (u16)0x0F0FU) << 4); \ + ___x = ((___x & (u16)0xCCCCU) >> 2) | ((___x & (u16)0x3333U) << 2); \ + ___x = ((___x & (u16)0xAAAAU) >> 1) | ((___x & (u16)0x5555U) << 1); \ + ___x; \ }) #define __constant_bitrev8x4(x) \ ({ \ - u32 __x = x; \ - __x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \ - __x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \ - __x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \ - __x; \ + u32 ___x = x; \ + ___x = ((___x & (u32)0xF0F0F0F0UL) >> 4) | ((___x & (u32)0x0F0F0F0FUL) << 4); \ + ___x = ((___x & (u32)0xCCCCCCCCUL) >> 2) | ((___x & (u32)0x33333333UL) << 2); \ + ___x = ((___x & (u32)0xAAAAAAAAUL) >> 1) | ((___x & (u32)0x55555555UL) << 1); \ + ___x; \ }) #define __constant_bitrev8(x) \ ({ \ - u8 __x = x; \ - __x = (__x >> 4) | (__x << 4); \ - __x = ((__x & (u8)0xCCU) >> 2) | ((__x & (u8)0x33U) << 2); \ - __x = ((__x & (u8)0xAAU) >> 1) | ((__x & (u8)0x55U) << 1); \ - __x; \ + u8 ___x = x; \ + ___x = (___x >> 4) | (___x << 4); \ + ___x = ((___x & (u8)0xCCU) >> 2) | ((___x & (u8)0x33U) << 2); \ + ___x = ((___x & (u8)0xAAU) >> 1) | ((___x & (u8)0x55U) << 1); \ + ___x; \ }) #define bitrev32(x) \ diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 8458cc5fbce5728dc2038451d26b37a8edd9d22c..d8b3240cfe6eed50fab4521eba48bdf5e000871e 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -91,14 +91,20 @@ enum bpf_stack_slot_type { #define BPF_REG_SIZE 8 /* size of eBPF register in bytes */ +struct bpf_stack_state { + struct bpf_reg_state spilled_ptr; + u8 slot_type[BPF_REG_SIZE]; +}; + /* state of the program: * type of all registers and stack info */ struct bpf_verifier_state { struct bpf_reg_state regs[MAX_BPF_REG]; - u8 stack_slot_type[MAX_BPF_STACK]; - struct bpf_reg_state spilled_regs[MAX_BPF_STACK / BPF_REG_SIZE]; struct bpf_verifier_state *parent; + int allocated_stack; + struct bpf_stack_state *stack; + bool speculative; }; /* linked list of verifier states used to prune search */ @@ -107,14 +113,24 @@ struct bpf_verifier_state_list { struct bpf_verifier_state_list *next; }; +/* Possible states for alu_state member. */ +#define BPF_ALU_SANITIZE_SRC 1U +#define BPF_ALU_SANITIZE_DST 2U +#define BPF_ALU_NEG_VALUE (1U << 2) +#define BPF_ALU_NON_POINTER (1U << 3) +#define BPF_ALU_SANITIZE (BPF_ALU_SANITIZE_SRC | \ + BPF_ALU_SANITIZE_DST) + struct bpf_insn_aux_data { union { enum bpf_reg_type ptr_type; /* pointer type for load/store insns */ struct bpf_map *map_ptr; /* pointer for call insn into lookup_elem */ + u32 alu_limit; /* limit for add/sub register with pointer */ }; int ctx_field_size; /* the ctx field size for load insn, maybe 0 */ int sanitize_stack_off; /* stack slot to be cleared */ bool seen; /* this insn was processed by the verifier */ + u8 alu_state; /* used in combination with alu_limit */ }; #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ @@ -129,11 +145,13 @@ struct bpf_ext_analyzer_ops { * one verifier_env per bpf_check() call */ struct bpf_verifier_env { + u32 insn_idx; + u32 prev_insn_idx; struct bpf_prog *prog; /* eBPF program being verified */ struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */ int stack_size; /* number of states to be processed */ bool strict_alignment; /* perform strict pointer alignment checks */ - struct bpf_verifier_state cur_state; /* current verifier state */ + struct bpf_verifier_state *cur_state; /* current verifier state */ struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ const struct bpf_ext_analyzer_ops *analyzer_ops; /* external analyzer ops */ void *analyzer_priv; /* pointer to external analyzer's private data */ @@ -145,6 +163,11 @@ struct bpf_verifier_env { struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ }; +static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env) +{ + return env->cur_state->regs; +} + int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, void *priv); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b53b4812290a72827f5fc33602acde753df3ef9f..4cd30f8ad9070f980a7017fa748de3adf253e9eb 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -310,7 +310,6 @@ struct regulator; * @level_votes: array of votes for each level * @num_levels: specifies the size of level_votes array * @skip_handoff: do not vote for the max possible voltage during init - * @use_max_uV: use INT_MAX for max_uV when calling regulator_set_voltage * @cur_level: the currently set voltage level * @lock: lock to protect this struct */ @@ -323,7 +322,6 @@ struct clk_vdd_class { int *level_votes; int num_levels; bool skip_handoff; - bool use_max_uV; unsigned long cur_level; struct mutex lock; }; diff --git a/include/linux/compiler.h b/include/linux/compiler.h index a704d032713b9d74129e36a7a499c9d100901d8f..67c3934fb9edb41e6a2886528eb2191f2e449e16 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -119,7 +119,10 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, # define ASM_UNREACHABLE #endif #ifndef unreachable -# define unreachable() do { annotate_reachable(); do { } while (1); } while (0) +# define unreachable() do { \ + annotate_unreachable(); \ + __builtin_unreachable(); \ +} while (0) #endif /* diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 3266e07e1d7ef66f03cc232fee78717932a3660e..f4954a6389aee34e92cf3f8aef4a93f74c09a667 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -278,7 +278,7 @@ extern int coresight_timeout(void __iomem *addr, u32 offset, int position, int value); extern void coresight_abort(void); extern void coresight_disable_reg_clk(struct coresight_device *csdev); -extern void coresight_enable_reg_clk(struct coresight_device *csdev); +extern int coresight_enable_reg_clk(struct coresight_device *csdev); #else static inline struct coresight_device * coresight_register(struct coresight_desc *desc) { return NULL; } @@ -290,7 +290,10 @@ static inline int coresight_timeout(void __iomem *addr, u32 offset, int position, int value) { return 1; } static inline void coresight_abort(void) {} static inline void coresight_disable_reg_clk(struct coresight_device *csdev) {} -static inline void coresight_enable_reg_clk(struct coresight_device *csdev) {} +static inline int coresight_enable_reg_clk(struct coresight_device *csdev) +{ + return -EINVAL; +} #endif #if defined(CONFIG_OF) && defined(CONFIG_CORESIGHT) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 829b7a9613c491cba3e2e8d53e2d619ade6150a8..ed0ff153804937f4155a3dd01da9ec3bf4bc49ea 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -541,13 +541,17 @@ static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy) __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); } -static inline void cpufreq_policy_apply_limits_fast(struct cpufreq_policy - *policy) +static inline unsigned int +cpufreq_policy_apply_limits_fast(struct cpufreq_policy *policy) { + unsigned int ret = 0; + if (policy->max < policy->cur) - cpufreq_driver_fast_switch(policy, policy->max); + ret = cpufreq_driver_fast_switch(policy, policy->max); else if (policy->min > policy->cur) - cpufreq_driver_fast_switch(policy, policy->min); + ret = cpufreq_driver_fast_switch(policy, policy->min); + + return ret; } /* Governor attribute set */ diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 21b29707bfedf11c7caf6c38948e29275952d320..72b41a1d129608de2e289ecfd7845b79ccc28fef 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -149,7 +149,7 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0xCA7 +#define APPS_EVENT_LAST_ID 0xCAA #define MSG_SSID_0 0 #define MSG_SSID_0_LAST 130 @@ -184,7 +184,7 @@ #define MSG_SSID_15 8000 #define MSG_SSID_15_LAST 8000 #define MSG_SSID_16 8500 -#define MSG_SSID_16_LAST 8531 +#define MSG_SSID_16_LAST 8532 #define MSG_SSID_17 9000 #define MSG_SSID_17_LAST 9008 #define MSG_SSID_18 9500 @@ -784,7 +784,8 @@ static const uint32_t msg_bld_masks_16[] = { MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | MSG_LVL_FATAL, MSG_LVL_MED, - MSG_LVL_MED + MSG_LVL_MED, + MSG_LVL_LOW }; static const uint32_t msg_bld_masks_17[] = { @@ -922,7 +923,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1C94, /* EQUIP ID 1 */ + 0x1C9A, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ diff --git a/include/linux/esoc_client.h b/include/linux/esoc_client.h index 9a4167a18c82eef43d9a362cbc9b2ab237f2233b..7540fe72bcd608a9fa272f2667d9c57a333d9738 100644 --- a/include/linux/esoc_client.h +++ b/include/linux/esoc_client.h @@ -38,6 +38,7 @@ struct esoc_client_hook { int (*esoc_link_power_on)(void *priv, unsigned int flags); void (*esoc_link_power_off)(void *priv, unsigned int flags); u64 (*esoc_link_get_id)(void *priv); + void (*esoc_link_mdm_crash)(void *priv); }; /* diff --git a/include/linux/filter.h b/include/linux/filter.h index 56d2cda9931b51187c4ce2b6f79b21d545bbfa87..ac2272778f2ef21d73ccf90ec585ed2e273054e8 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -46,14 +46,10 @@ struct bpf_prog_aux; #define BPF_REG_X BPF_REG_7 #define BPF_REG_TMP BPF_REG_8 -/* Kernel hidden auxiliary/helper register for hardening step. - * Only used by eBPF JITs. It's nothing more than a temporary - * register that JITs use internally, only that here it's part - * of eBPF instructions that have been rewritten for blinding - * constants. See JIT pre-step in bpf_jit_blind_constants(). - */ +/* Kernel hidden auxiliary/helper register. */ #define BPF_REG_AX MAX_BPF_REG -#define MAX_BPF_JIT_REG (MAX_BPF_REG + 1) +#define MAX_BPF_EXT_REG (MAX_BPF_REG + 1) +#define MAX_BPF_JIT_REG MAX_BPF_EXT_REG /* unused opcode to mark special call to bpf_tail_call() helper */ #define BPF_TAIL_CALL 0xf0 diff --git a/include/linux/fs.h b/include/linux/fs.h index 2126808f0eaaee9059b3bb70d6d85d2e581392c5..5714582226daae14fc58ebbb06fffe3a77a44e51 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2994,6 +2994,7 @@ enum { }; void dio_end_io(struct bio *bio); +void dio_warn_stale_pagecache(struct file *filp); ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, struct block_device *bdev, struct iov_iter *iter, diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 550fa358893ae9555d24dc0dea6791f56cd51224..19687c9bc4d2b93868c2d2d51b788ee11542cd1b 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -141,6 +141,7 @@ struct hd_struct { #define GENHD_FL_NATIVE_CAPACITY 128 #define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE 256 #define GENHD_FL_NO_PART_SCAN 512 +#define GENHD_FL_NO_RANDOMIZE 1024 enum { DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */ diff --git a/include/linux/ipa_eth.h b/include/linux/ipa_eth.h index 58e34e5dcebf1786fc3c01a9aa64d544c6d4d738..04eed6ad42366bb4834fff1b3b580a3dc21a3690 100644 --- a/include/linux/ipa_eth.h +++ b/include/linux/ipa_eth.h @@ -26,7 +26,22 @@ #include #include -#define IPA_ETH_API_VER 1 +/** + * API Version Changes + * --------------------------------------------------------------------------- + * 1 - Initial version + * 2 - API separation for use by network and offload drivers + * - New ipa_eth_net_*() APIs offer safer interface for offload + * drivers to call into ipa_eth_net_ops + * - ipa_eth_net_ops.request_channel() to accept additional + * memory allocation params, including custom memory allocator + * defined via struct ipa_eth_dma_allocator interface + * - probe() and remove() offload bus ops are replaced by pair() + * and unpair() callbacks respectively + * 3 - Added .save_regs() callback for network and offload drivers + */ + +#define IPA_ETH_API_VER 3 /** * enum ipa_eth_dev_features - Features supported by an ethernet device or @@ -147,22 +162,216 @@ struct ipa_eth_resource { void *vaddr; dma_addr_t daddr; phys_addr_t paddr; +}; + +/** + * ipa_eth_mem_it_t() - Callback used by the ipa_eth_dma_allocator.walk() as it + * iterates through each contiguous chunk of memory + * @eth_dev: Device to which the memory belong + * @cmem: Contigous mapping. If cmem->paddr is NULL, it could be determined from + * ipa_eth_dma_allocator.paddr(cmem->vaddr) + * @arg: Private argument passed to ipa_eth_dma_allocator.walk() that can hold + * necessary context required by the iterator + * + * See &struct ipa_eth_dma_allocator for more details. + */ +typedef int (*ipa_eth_mem_it_t)(struct ipa_eth_device *eth_dev, + const struct ipa_eth_resource *cmem, void *arg); + +/** + * struct ipa_eth_dma_allocator - Custom DMA memory allocator interface + * @name: Name of the allocator + */ +struct ipa_eth_dma_allocator { + const char *name; + + /** + * .paddr() - Convert a virtual address previously allocated by this + * ipa_eth_dma_allocator, to physical address + * @eth_dev: Device which owns the memory + * @vaddr: Kernel mapped address of the resource + * + * Return: Physical address of @vaddr + */ + phys_addr_t (*paddr)(struct ipa_eth_device *eth_dev, + const void *vaddr); + /** + * .alloc() - Allocates DMA memory for a given device + * @eth_dev: Device which will own the memory. Note that @eth_dev->dev + * should be a valid struct device pointer. + * @size: Minimum number of bytes to allocate + * @gfp: Kernel GFP_* flags to use, if the allocator supports it + * @mem: Memory info if the allocation was successful. @mem->paddr may + * be NUll or not valid, use ipa_eth_dma_allocator.paddr() to get + * the correct physical address for a page of virtual address. + * + * This API callback is typically called by the network driver to + * allocate memory for descriptor rings, buffers, etc. Any memory + * allocated by this callback should be traversable by the .remap() + * API callback implementation. + * + * Return: 0 on success, non-zero otherwise + */ + int (*alloc)(struct ipa_eth_device *eth_dev, size_t size, gfp_t gfp, + struct ipa_eth_resource *mem); + + /** + * .free() - Free a memory previously allocated using .alloc() API + * @eth_dev: Device which owns the memory + * @mem: Memory info + * + * This API callback is typically called by the network driver to free + * memory resources associated with descriptor rings, buffers, etc. once + * their associated hardware queues are stopped. + */ + void (*free)(struct ipa_eth_device *eth_dev, + struct ipa_eth_resource *mem); + + /** + * .walk() - Iterates over memory previously allocated by .alloc() + * @eth_dev: Device which owns the memory + * @mem: Allocated memory that need to be iterated over + * @it: Iterator that is invoked for each chunk (typically PAGE_SIZE) + * of memory + * @arg: Private argument passed to @it for each invocation + * + * This API is expected to iterate over pieces of an allocated memory + * for typical purposes remapping to additional peripherals, and later + * unmapping from them. .walk() is responsible to invoke the iterator + * @it for each mappable region within an allocated space, which is + * typically page sized. + * + * Iteration is expected to stop either when the page walk completes or + * when any of the @it() invocations return failure. Iterator can add + * additional checks for memory alignments, addressability, etc. that + * can also fail. In any case, the API is expected to return the number + * of bytes (<= mem->size) from the given memory that was successfully + * iterated. Although the API may re-align memory regions while invoking + * the iterator, it should still return only the number of bytes of the + * original memory that was successfully iterated. + * + * .walk() API could be used for any purpose of iteration, not limited + * to memory mapping and unmapping. Implementation of the API should be + * flexible for generalized use-cases. Caller of this API should always + * check for the return value against @mem->size to make sure if the + * intended operation was successful, and explicitly revert any partial + * operation. Ex, + * + * mapped_bytes = alctr->walk(dev, mem_region, iommu_mapper, map_ctx); + * if (mapped_bytes != mem_region->size) { + * struct ipa_eth_resource unmap_region = *mem_region; + * unmap_region.size = mapped_bytes; + * alctr->walk(dev, unmap_region, smmu_map, ctx); + * return -ENOMEM; + * } + * + * Return: the number of bytes in @mem that were successfully iterated + */ + size_t (*walk)(struct ipa_eth_device *eth_dev, + const struct ipa_eth_resource *mem, + ipa_eth_mem_it_t it, void *arg); +}; + +/** + * enum ipa_eth_hw_type - Types of hardware used in an offload path + * @IPA_ETH_HW_UC: IPA uC + * @IPA_ETH_HW_GSI: GSI + * @IPA_ETH_HW_IPA: IPA hardware/endpoint + */ +enum ipa_eth_hw_type { + IPA_ETH_HW_UC, + IPA_ETH_HW_GSI, + IPA_ETH_HW_IPA, + IPA_ETH_HW_MAX, +}; + +/** + * struct ipa_eth_hw_map_param - Params for mapping memory to IPA hardware + * @map: If true, perform mapping of memory to the given hardware + * @sym: If true, performs symmetric mapping where IO virtual address (IOVA) + * used is the same as the one used on original device. + * @read: Memory should be readable by hardware + * @write: Memory should be writable by hardware + */ +struct ipa_eth_hw_map_param { + bool map; + bool sym; + bool read; + bool write; +}; + +/** + * struct ipa_eth_desc_params - Params for allocating descriptor memory + * @size: Size of each descriptor. This field is usually filled in by the + * network driver. + * @count: Number of descriptors to be allocated + * @allocator: DMA allocator to be used for IO memory allocation and mapping + * @hw_map_params: Info on memory mapping requirements to IPA CBs + */ +struct ipa_eth_desc_params { + size_t size; + size_t count; + struct ipa_eth_dma_allocator *allocator; + struct ipa_eth_hw_map_param hw_map_params[IPA_ETH_HW_MAX]; +}; + +/** + * struct ipa_eth_buff_params - Params for allocating buffer memory + * @size: Size of data buffer associated with a descriptor + * @count: Number of buffers. This ield is usually filled in by the network + * driver and is typically the same value as descriptor count. + * @allocator: DMA allocator to be used for IO memory allocation and mapping + * @maps: Info on memory mapping requirements to IPA CBs + */ +struct ipa_eth_buff_params { + size_t size; + size_t count; + struct ipa_eth_dma_allocator *allocator; + struct ipa_eth_hw_map_param hw_map_params[IPA_ETH_HW_MAX]; +}; + +/** + * struct ipa_eth_channel_mem_params - Params for various channel memory + * @desc: Descriptor memory parameters + * @buff: Buffer memory parameters + */ +struct ipa_eth_channel_mem_params { + struct ipa_eth_desc_params desc; + struct ipa_eth_buff_params buff; +}; + +/** + * struct ipa_eth_channel_mem - Represents a piece of memory used by the + * network device channel for descriptrors, buffers, etc. + * @mem_list_entry: list entry in either of ipa_eth_channel.desc_mem or + * ipa_eth_channel.buff_mem + * @mem: Memory mapping info as used by the network device/driver + * @cb_mem: Memory mapping info as used by each of IPA context banks. When a + * mapping is present, cb_mem[cb_type].size would be non-zero. + */ +struct ipa_eth_channel_mem { + struct list_head mem_list_entry; + + struct ipa_eth_resource mem; + +/* private: for internal use by offload sub-system */ + struct ipa_eth_resource *cb_mem; }; /** * struct ipa_eth_channel - Represents a network device channel + * @channel_list: list entry in either of ipa_eth_device.rx_channels or + * ipa_eth_device.tx_channels * @nd_priv: Private field for use by network driver * @events: Events supported by the channel * @features: Features enabled in the channel * @direction: Channel direction + * @mem_params: Channel memory params filled in collectively by Offload driver, + * Network driver and Offload sub-system * @queue: Network device queue/ring number - * @desc_size: Size of each descriptor - * @desc_count: Number of descriptors in the ring - * @desc_mem: Descriptor ring memory base - * @buff_size: Size of each data buffer - * @buff_count: Number of data buffers - * @buff_mem: Data buffer memory base + * @desc_mem: Descriptor ring memory list + * @buff_mem: Data buffer memory list * @od_priv: Private field for use by offload driver * @eth_dev: Associated ipa_eth_device * @ipa_client: IPA client type enum to be used for the channel @@ -176,22 +385,19 @@ struct ipa_eth_resource { * into IPA */ struct ipa_eth_channel { + struct list_head channel_list; + /* fields managed by network driver */ void *nd_priv; unsigned long events; unsigned long features; enum ipa_eth_channel_dir direction; + struct ipa_eth_channel_mem_params mem_params; int queue; - - u16 desc_size; - u32 desc_count; - struct ipa_eth_resource desc_mem; - - u16 buff_size; - u32 buff_count; - struct ipa_eth_resource buff_mem; + struct list_head desc_mem; + struct list_head buff_mem; /* fields managed by offload driver */ void *od_priv; @@ -215,13 +421,13 @@ struct ipa_eth_channel { /** * struct ipa_eth_device - Represents an ethernet device + * @device_list: Entry in the global offload device list + * @bus_device_list: Entry in the per-bus offload device list * @net_dev: Netdev registered by the network driver * @nd_priv: Private field for use by network driver - * @ch_rx: Rx channel allocated for the offload path - * @ch_tx: Tx channel allocated for the offload path * @od_priv: Private field for use by offload driver - * @device_list: Entry in the global offload device list - * @bus_device_list: Entry in the per-bus offload device list + * @rx_channels: Rx channels allocated for the offload path + * @tx_channels: Tx channels allocated for the offload path * @of_state: Offload state of the device * @dev: Pointer to struct device * @nd: IPA offload net driver associated with the device @@ -238,18 +444,19 @@ struct ipa_eth_channel { * @refresh: Work struct used to perform device refresh */ struct ipa_eth_device { + struct list_head device_list; + struct list_head bus_device_list; + /* fields managed by the network driver */ struct net_device *net_dev; void *nd_priv; /* fields managed by offload driver */ - struct ipa_eth_channel *ch_rx; - struct ipa_eth_channel *ch_tx; void *od_priv; /* fields managed by offload subsystem */ - struct list_head device_list; - struct list_head bus_device_list; + struct list_head rx_channels; + struct list_head tx_channels; enum ipa_eth_offload_state of_state; @@ -272,16 +479,27 @@ struct ipa_eth_device { struct work_struct refresh; }; +#ifdef IPA_ETH_NET_DRIVER + /** * struct ipa_eth_net_ops - Network device operations required for IPA offload */ struct ipa_eth_net_ops { /** - * .open_device() - Initialize the network device if needed before - * channels and events are configured. + * .open_device() - Initialize the network device if needed and fill in + * @eth_dev->net_dev field * @eth_dev: Device to initialize * - * Typically this is API is functionally equivalent to .ndo_open() + * Some network perform complete device initialization only in driver + * .ndo_open(). Offload sub-system may try to use the network hardware + * for offload path even before .ndo_open() is called. .open_device() is + * expected to perform all device initialization that may be required + * to make the hardware functional for offload path, irrespective of + * whether .ndo_open() gets called. + * + * Once the device is initialized, .open_device() should initialize the + * @eth_dev->net_dev field with the driver struct net_device pointer + * before returning. * * Return: 0 on success, negative errno otherwise */ @@ -302,7 +520,7 @@ struct ipa_eth_net_ops { void (*close_device)(struct ipa_eth_device *eth_dev); /** - * .request_channel() - Allocate a channel/ring for IPA offload data + * .request_channel() - Request a channel/ring for IPA offload data * path to use * @eth_dev: Device from which to allocate channel * @dir: Requested channel direction @@ -310,6 +528,11 @@ struct ipa_eth_net_ops { * more IPA_ETH_DEV_EV_* flags. * @features: Device featured requested for the channel. Value is zero * or more IPA_ETH_DEV_F_* feature flags. + * @mem_params: Channel memory parameters. Values to be passed in is + * specific to the network driver. This info is typically + * passed on to ipa_eth_net_alloc_channel() which will + * memcpy() the contents to mem_params inside the + * ipa_eth_channel that is returned back. * * Arguments @dir, @features and @events are used to inform the network * driver about the capabilities of the offload subsystem/driver. The @@ -319,14 +542,17 @@ struct ipa_eth_net_ops { * allocated capability set is acceptable for data path operation. * * The allocated channel is expected to be in disabled state with no - * events allocated or enabled. + * events allocated or enabled. It is recommended to use the offload + * sub-system API ipa_eth_net_alloc_channel() for allocating the + * ipa_eth_channel object. * * Return: Channel object pointer, or NULL if the channel allocation * failed */ struct ipa_eth_channel * (*request_channel)( struct ipa_eth_device *eth_dev, enum ipa_eth_channel_dir dir, - unsigned long events, unsigned long features); + unsigned long events, unsigned long features, + const struct ipa_eth_channel_mem_params *mem_params); /** * .release_channel() - Free a channel/ring previously allocated using @@ -462,6 +688,17 @@ struct ipa_eth_net_ops { */ int (*transmit_skb)(struct ipa_eth_device *eth_dev, struct sk_buff *skb); + + /** + * .save_regs() - Save registers for debugging + * @eth_dev: Offloaded device + * @regs: if not NULL, write saved data address to the given pointer + * @size: if not NULL, write the size of saved data to the given pointer + * + * Return: 0 on success, errno otherwise. + */ + int (*save_regs)(struct ipa_eth_device *eth_dev, + void **regs, size_t *size); }; /** @@ -498,51 +735,15 @@ struct ipa_eth_net_driver { int ipa_eth_register_net_driver(struct ipa_eth_net_driver *nd); void ipa_eth_unregister_net_driver(struct ipa_eth_net_driver *nd); -/** - * struct ipa_eth_bus_ops - Offload driver callbacks for bus operations - * - * These APIS are implemented by the offload driver for receiving bus level - * notifications like probe, remove, suspend, resume, etc. - */ -struct ipa_eth_bus_ops { - /** - * .probe() - Probe new device for offload ability - * @eth_dev: Device being probed - * - * This API is implemented by the offload driver and called immediately - * after the network driver (PCI/plaform) probe. Offload driver is - * expected to check if the device is compatible with the driver and - * that the driver has enough offload resources for offloading the - * device to IPA. - * - * The API implementation can expect the eth_dev->dev and eth_dev->nd - * to have been already initialized by the offload subsystem. The API - * is expected to perform at least the following: - * - * 1. Ensure the device is compatible with the offload driver. For - * plaform drivers, the .compatible DT property could be used while - * PCI IDs could be used for matching with a PCI device. - * 2. If multiple network devices of the same type can be managed by the - * offload driver, it may attempt to pair @eth_dev with an available - * resource set for a single instance. - * 3. Initialize the network device, typically by calling open_device() - * callback provided by the network driver. - * - * Return: 0 on success, negative errno otherwise - */ - int (*probe)(struct ipa_eth_device *eth_dev); +struct ipa_eth_channel *ipa_eth_net_alloc_channel( + struct ipa_eth_device *eth_dev, enum ipa_eth_channel_dir dir, + unsigned long events, unsigned long features, + const struct ipa_eth_channel_mem_params *mem_params); +void ipa_eth_net_free_channel(struct ipa_eth_channel *channel); - /** - * .remove() - Handle device removal - * @eth_dev: Device being removed - * - * The API implementation should assume the device to be no more - * physically connected. - */ - void (*remove)(struct ipa_eth_device *eth_dev); +#endif /* IPA_ETH_NET_DRIVER */ - /* dev_pm_ops go here */ -}; +#ifdef IPA_ETH_OFFLOAD_DRIVER /** * struct ipa_eth_offload_link_stats - Stats for each link within an @@ -578,6 +779,46 @@ struct ipa_eth_offload_stats { * struct ipa_eth_offload_ops - Offload operations provided by an offload driver */ struct ipa_eth_offload_ops { + /** + * .pair() - Pair a new device, if compatible, with the offload driver + * @eth_dev: Device to pair with the offload driver + * + * This API is called by offload sub-system in order to pair an ethernet + * device with the offload driver. Typically this API is called soon + * after the device probe is completed and registered with the offload + * sub-system. When the API is called, offload driver is expected to + * check if the device is compatible with the driver and that the driver + * has enough offload resources for offloading the device to IPA. + * + * The API implementation can expect the eth_dev->dev to have been + * already initialized by the offload subsystem, from which a bus + * specific device pointer (pci_dev, platform_device, etc.) can be + * derived. The API is expected to perform at least the following: + * + * 1. Ensure the device is compatible with the offload driver. For + * plaform drivers, the .compatible DT property could be used while + * PCI IDs could be used for matching with a PCI device. + * 2. If multiple network devices of the same type can be managed by the + * offload driver, it may attempt to pair @eth_dev with an available + * resource set for a single instance. + * + * Return: 0 on success, negative errno otherwise + */ + int (*pair)(struct ipa_eth_device *eth_dev); + + /** + * .unpair() - Unpair a device from the offload driver + * @eth_dev: Device to unpair + * + * Unpairing the device from offload driver should make sure that all + * resources allocated for the device are freed and the data path is + * stopped and deinitialized, and device is readied for removal. The + * implementation should be able to handle plug-n-play devices by not + * assuming the device to be connected anymore to the bus/system when + * this API is called. + */ + void (*unpair)(struct ipa_eth_device *eth_dev); + /** * .init_tx() - Initialize offload path in Tx direction * @@ -648,6 +889,17 @@ struct ipa_eth_offload_ops { * Return: 0 on success, negative errno otherwise */ int (*clear_stats)(struct ipa_eth_device *eth_dev); + + /** + * .save_regs() - Save registers for debugging + * @eth_dev: Offloaded device + * @regs: if not NULL, write saved data address to the given pointer + * @size: if not NULL, write the size of saved data to the given pointer + * + * Return: 0 on success, errno otherwise. + */ + int (*save_regs)(struct ipa_eth_device *eth_dev, + void **regs, size_t *size); }; /** @@ -667,7 +919,6 @@ struct ipa_eth_offload_driver { struct bus_type *bus; struct ipa_eth_offload_ops *ops; - struct ipa_eth_bus_ops *bus_ops; struct dentry *debugfs; }; @@ -675,6 +926,33 @@ struct ipa_eth_offload_driver { int ipa_eth_register_offload_driver(struct ipa_eth_offload_driver *od); void ipa_eth_unregister_offload_driver(struct ipa_eth_offload_driver *od); +struct ipa_eth_channel *ipa_eth_net_request_channel( + struct ipa_eth_device *eth_dev, enum ipa_client_type ipa_client, + unsigned long events, unsigned long features, + const struct ipa_eth_channel_mem_params *mem_params); +void ipa_eth_net_release_channel(struct ipa_eth_channel *ch); +int ipa_eth_net_enable_channel(struct ipa_eth_channel *ch); +int ipa_eth_net_disable_channel(struct ipa_eth_channel *ch); + +int ipa_eth_net_request_event(struct ipa_eth_channel *ch, unsigned long event, + phys_addr_t addr, u64 data); +void ipa_eth_net_release_event(struct ipa_eth_channel *ch, unsigned long event); +int ipa_eth_net_enable_event(struct ipa_eth_channel *ch, unsigned long event); +int ipa_eth_net_disable_event(struct ipa_eth_channel *ch, unsigned long event); +int ipa_eth_net_moderate_event(struct ipa_eth_channel *ch, unsigned long event, + u64 min_count, u64 max_count, + u64 min_usecs, u64 max_usecs); + +int ipa_eth_net_receive_skb(struct ipa_eth_device *eth_dev, + struct sk_buff *skb); +int ipa_eth_net_transmit_skb(struct ipa_eth_device *eth_dev, + struct sk_buff *skb); + +struct ipa_eth_resource *ipa_eth_net_ch_to_cb_mem( + struct ipa_eth_channel *ch, + struct ipa_eth_channel_mem *ch_mem, + enum ipa_eth_hw_type hw_type); + int ipa_eth_ep_init(struct ipa_eth_channel *ch); int ipa_eth_ep_start(struct ipa_eth_channel *ch); int ipa_eth_ep_stop(struct ipa_eth_channel *ch); @@ -736,6 +1014,8 @@ int ipa_eth_uc_iommu_vamap(dma_addr_t daddr, void *vaddr, size_t size, int prot, bool split); int ipa_eth_uc_iommu_unmap(dma_addr_t daddr, size_t size, bool split); +#endif /* IPA_ETH_OFFLOAD_DRIVER */ + /* IPC logging interface */ #define ipa_eth_ipc_do_log(ipcbuf, fmt, args...) \ diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index bd2684700b74cd5c97ada00a53fbea3242a15397..520702b821340db484ccea1677e078d5f1a6e643 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -198,6 +198,7 @@ struct kretprobe_instance { struct kretprobe *rp; kprobe_opcode_t *ret_addr; struct task_struct *task; + void *fp; char data[0]; }; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index ca05705ad7b157d23f4314123b5d350fd6a92f0e..76db830c5de30ce21856c363cba6db092a605b6e 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -28,8 +28,10 @@ struct mhi_buf_info; * @MHI_CB_LPM_ENTER: MHI host entered low power mode * @MHI_CB_LPM_EXIT: MHI host about to exit low power mode * @MHI_CB_EE_RDDM: MHI device entered RDDM execution enviornment + * @MHI_CB_EE_MISSION_MODE: MHI device entered Mission Mode ee * @MHI_CB_SYS_ERROR: MHI device enter error state (may recover) * @MHI_CB_FATAL_ERROR: MHI device entered fatal error + * @MHI_CB_BW_REQ: Received a bandwidth switch request from device */ enum MHI_CB { MHI_CB_IDLE, @@ -37,8 +39,10 @@ enum MHI_CB { MHI_CB_LPM_ENTER, MHI_CB_LPM_EXIT, MHI_CB_EE_RDDM, + MHI_CB_EE_MISSION_MODE, MHI_CB_SYS_ERROR, MHI_CB_FATAL_ERROR, + MHI_CB_BW_REQ, }; /** @@ -110,11 +114,25 @@ enum mhi_dev_state { MHI_STATE_M1 = 0x3, MHI_STATE_M2 = 0x4, MHI_STATE_M3 = 0x5, + MHI_STATE_M3_FAST = 0x6, MHI_STATE_BHI = 0x7, MHI_STATE_SYS_ERR = 0xFF, MHI_STATE_MAX, }; +/** + * struct mhi_link_info - bw requirement + * target_link_speed - as defined by TLS bits in LinkControl reg + * target_link_width - as defined by NLW bits in LinkStatus reg + */ +struct mhi_link_info { + unsigned int target_link_speed; + unsigned int target_link_width; +}; + +#define MHI_VOTE_BUS BIT(0) /* do not disable the bus */ +#define MHI_VOTE_DEVICE BIT(1) /* prevent mhi device from entering lpm */ + /** * struct image_info - firmware and rddm table table * @mhi_buf - Contain device firmware and rddm table @@ -164,6 +182,7 @@ struct image_info { * @pm_state: Power management state * @ee: MHI device execution environment * @dev_state: MHI STATE + * @mhi_link_info: requested link bandwidth by device * @status_cb: CB function to notify various power states to but master * @link_status: Query link status in case of abnormal value read from device * @runtime_get: Async runtime resume function @@ -243,10 +262,12 @@ struct mhi_controller { bool pre_init; rwlock_t pm_lock; u32 pm_state; + u32 saved_pm_state; /* saved state during fast suspend */ u32 db_access; /* db access only on these states */ enum mhi_ee ee; u32 ee_table[MHI_EE_MAX]; /* ee conversion from dev to host */ enum mhi_dev_state dev_state; + enum mhi_dev_state saved_dev_state; bool wake_set; atomic_t dev_wake; atomic_t alloc_size; @@ -255,8 +276,11 @@ struct mhi_controller { spinlock_t transition_lock; spinlock_t wlock; + /* target bandwidth info */ + struct mhi_link_info mhi_link_info; + /* debug counters */ - u32 M0, M2, M3; + u32 M0, M2, M3, M3_FAST; /* worker for different state transitions */ struct work_struct st_worker; @@ -279,6 +303,7 @@ struct mhi_controller { struct mhi_buf_info *buf); void (*unmap_single)(struct mhi_controller *mhi_cntrl, struct mhi_buf_info *buf); + void (*tsync_log)(struct mhi_controller *mhi_cntrl, u64 remote_time); /* channel to control DTR messaging */ struct mhi_device *dtr_dev; @@ -290,6 +315,8 @@ struct mhi_controller { /* supports time sync feature */ struct mhi_timesync *mhi_tsync; struct mhi_device *tsync_dev; + u64 local_timer_freq; + u64 remote_timer_freq; /* kernel log level */ enum MHI_DEBUG_LEVEL klog_lvl; @@ -311,6 +338,10 @@ struct mhi_controller { * @ul_chan_id: MHI channel id for UL transfer * @dl_chan_id: MHI channel id for DL transfer * @tiocm: Device current terminal settings + * @early_notif: This device needs an early notification in case of error + * with external modem. + * @dev_vote: Keep external device in active state + * @bus_vote: Keep physical bus (pci, spi) in active state * @priv: Driver private data */ struct mhi_device { @@ -325,12 +356,14 @@ struct mhi_device { int ul_event_id; int dl_event_id; u32 tiocm; + bool early_notif; const struct mhi_device_id *id; const char *chan_name; struct mhi_controller *mhi_cntrl; struct mhi_chan *ul_chan; struct mhi_chan *dl_chan; - atomic_t dev_wake; + atomic_t dev_vote; + atomic_t bus_vote; enum mhi_device_type dev_type; void *priv_data; int (*ul_xfer)(struct mhi_device *, struct mhi_chan *, void *, @@ -469,26 +502,29 @@ int mhi_device_configure(struct mhi_device *mhi_div, int elements); /** - * mhi_device_get - disable all low power modes + * mhi_device_get - disable low power modes * Only disables lpm, does not immediately exit low power mode * if controller already in a low power mode * @mhi_dev: Device associated with the channels + * @vote: requested vote (bus, device or both) */ -void mhi_device_get(struct mhi_device *mhi_dev); +void mhi_device_get(struct mhi_device *mhi_dev, int vote); /** - * mhi_device_get_sync - disable all low power modes - * Synchronously disable all low power, exit low power mode if + * mhi_device_get_sync - disable low power modes + * Synchronously disable device & or bus low power, exit low power mode if * controller already in a low power state * @mhi_dev: Device associated with the channels + * @vote: requested vote (bus, device or both) */ -int mhi_device_get_sync(struct mhi_device *mhi_dev); +int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote); /** * mhi_device_put - re-enable low power modes * @mhi_dev: Device associated with the channels + * @vote: vote to remove */ -void mhi_device_put(struct mhi_device *mhi_dev); +void mhi_device_put(struct mhi_device *mhi_dev, int vote); /** * mhi_prepare_for_transfer - setup channel for data transfer @@ -596,6 +632,14 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl); */ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl); +/** + * mhi_pm_fast_suspend - Move host into suspend state while keeping + * the device in active state. + * @mhi_cntrl: MHI controller + * @notify_client: if true, clients will get a notification about lpm transition + */ +int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client); + /** * mhi_pm_resume - Resume MHI from suspended state * Transition to MHI state M0 state from M3 state @@ -603,6 +647,13 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl); */ int mhi_pm_resume(struct mhi_controller *mhi_cntrl); +/** + * mhi_pm_fast_resume - Move host into resume state from fast suspend state + * @mhi_cntrl: MHI controller + * @notify_client: if true, clients will get a notification about lpm transition + */ +int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client); + /** * mhi_download_rddm_img - Download ramdump image from device for * debugging purpose. @@ -654,9 +705,17 @@ static inline bool mhi_is_active(struct mhi_device *mhi_dev) struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; return (mhi_cntrl->dev_state >= MHI_STATE_M0 && - mhi_cntrl->dev_state <= MHI_STATE_M3); + mhi_cntrl->dev_state <= MHI_STATE_M3_FAST); } +/** + * mhi_control_error - MHI controller went into unrecoverable error state. + * Will transition MHI into Linkdown state. Do not call from atomic + * context. + * @mhi_cntrl: MHI controller + */ +void mhi_control_error(struct mhi_controller *mhi_cntrl); + /** * mhi_debug_reg_dump - dump MHI registers for debug purpose * @mhi_cntrl: MHI controller diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 88f0c530fe9cc15022337350f546192ed1e54cef..32d4453151285e5de99474b6f8a753c84d1349f3 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -743,6 +743,8 @@ struct mlx5_pagefault { }; struct mlx5_td { + /* protects tirs list changes while tirs refresh */ + struct mutex list_lock; struct list_head tirs_list; u32 tdn; }; diff --git a/include/linux/mm.h b/include/linux/mm.h index fad2a257e730bee24c01a99e53d0b016f5452604..9d22cd94b400be8ca73fbc2423e5bb1e01772381 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -837,6 +837,10 @@ static inline bool is_device_public_page(const struct page *page) #endif /* CONFIG_DEVICE_PRIVATE || CONFIG_DEVICE_PUBLIC */ +/* 127: arbitrary random number, small enough to assemble well */ +#define page_ref_zero_or_close_to_overflow(page) \ + ((unsigned int) page_ref_count(page) + 127u <= 127u) + static inline void get_page(struct page *page) { page = compound_head(page); @@ -844,8 +848,17 @@ static inline void get_page(struct page *page) * Getting a normal page or the head of a compound page * requires to already have an elevated page->_refcount. */ - VM_BUG_ON_PAGE(page_ref_count(page) <= 0, page); + VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(page), page); + page_ref_inc(page); +} + +static inline __must_check bool try_get_page(struct page *page) +{ + page = compound_head(page); + if (WARN_ON_ONCE(page_ref_count(page) <= 0)) + return false; page_ref_inc(page); + return true; } static inline void put_page(struct page *page) diff --git a/include/linux/msm_adreno_devfreq.h b/include/linux/msm_adreno_devfreq.h index c99beecf3cf2c9d5556e3dec2504e7cd31ff70fe..4976ce78bd6c1c6d8a23845710b8b1cccdfd063a 100644 --- a/include/linux/msm_adreno_devfreq.h +++ b/include/linux/msm_adreno_devfreq.h @@ -79,4 +79,13 @@ int devfreq_vbif_update_bw(unsigned long ib, unsigned long ab); int devfreq_vbif_register_callback(void *callback); #endif +#ifdef CONFIG_DEVFREQ_GOV_QCOM_ADRENO_TZ +int msm_adreno_devfreq_init_tz(struct devfreq *devfreq); +#else +static inline int msm_adreno_devfreq_init_tz(struct devfreq *devfreq) +{ + return 0; +} +#endif + #endif diff --git a/include/linux/msm_mhi_dev.h b/include/linux/msm_mhi_dev.h index ba4ac4358ac3bc91c5efdff51fd43e47ff5eb37f..88ec5492ca75944bbc392229b63b4c3266104149 100644 --- a/include/linux/msm_mhi_dev.h +++ b/include/linux/msm_mhi_dev.h @@ -97,8 +97,8 @@ enum mhi_client_channel { MHI_CLIENT_IP_CTRL_0_IN = 17, MHI_CLIENT_IP_CTRL_1_OUT = 18, MHI_CLIENT_IP_CTRL_1_IN = 19, - MHI_CLIENT_DCI_OUT = 20, - MHI_CLIENT_DCI_IN = 21, + MHI_CLIENT_IPCR_OUT = 20, + MHI_CLIENT_IPCR_IN = 21, MHI_CLIENT_IP_CTRL_3_OUT = 22, MHI_CLIENT_IP_CTRL_3_IN = 23, MHI_CLIENT_IP_CTRL_4_OUT = 24, diff --git a/include/linux/msm_pcie.h b/include/linux/msm_pcie.h index aa89ae1e179c54c65714ec770a9120b95e2c9379..58d4fb22733d260cabe214bf9a4ca77f9a1fd16b 100644 --- a/include/linux/msm_pcie.h +++ b/include/linux/msm_pcie.h @@ -61,9 +61,14 @@ struct msm_pcie_register_event { }; #ifdef CONFIG_PCI_MSM_MSI +void msm_msi_config_access(struct irq_domain *domain, bool allow); void msm_msi_config(struct irq_domain *domain); int msm_msi_init(struct device *dev); #else +static inline void msm_msi_config_access(struct irq_domain *domain, bool allow) +{ +} + static inline void msm_msi_config(struct irq_domain *domain) { } diff --git a/include/linux/pci.h b/include/linux/pci.h index b1abbcc614cf9b0e86e4b6a67abe187de5b296fc..95dcc8cfc139201f028ea14e087b8b22ffe8c911 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -337,6 +337,7 @@ struct pci_dev { unsigned int d2_support:1; /* Low power state D2 is supported */ unsigned int no_d1d2:1; /* D1 and D2 are forbidden */ unsigned int no_d3cold:1; /* D3cold is forbidden */ + unsigned int no_d3hot:1; /* D3hot is forbidden */ unsigned int bridge_d3:1; /* Allow D3 for bridge */ unsigned int d3cold_allowed:1; /* D3cold is allowed by user */ unsigned int mmio_always_on:1; /* disallow turning off io/mem diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index befdcd304b3d92e7727c03cc76d992a27e2af674..c251ad7173450c631efd5d9f41b95568270e6e1d 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -108,18 +108,20 @@ struct pipe_buf_operations { /* * Get a reference to the pipe buffer. */ - void (*get)(struct pipe_inode_info *, struct pipe_buffer *); + bool (*get)(struct pipe_inode_info *, struct pipe_buffer *); }; /** * pipe_buf_get - get a reference to a pipe_buffer * @pipe: the pipe that the buffer belongs to * @buf: the buffer to get a reference to + * + * Return: %true if the reference was successfully obtained. */ -static inline void pipe_buf_get(struct pipe_inode_info *pipe, +static inline __must_check bool pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { - buf->ops->get(pipe, buf); + return buf->ops->get(pipe, buf); } /** @@ -179,9 +181,10 @@ struct pipe_inode_info *alloc_pipe_info(void); void free_pipe_info(struct pipe_inode_info *); /* Generic pipe buffer ops functions */ -void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); +bool generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *); int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); +int generic_pipe_buf_nosteal(struct pipe_inode_info *, struct pipe_buffer *); void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *); void pipe_buf_mark_unmergeable(struct pipe_buffer *buf); diff --git a/include/linux/platform_data/x86/clk-pmc-atom.h b/include/linux/platform_data/x86/clk-pmc-atom.h index 3ab892208343c2d22d71a630f1097d6941534518..7a37ac27d0fb21d9f8afde973c7618e42574534b 100644 --- a/include/linux/platform_data/x86/clk-pmc-atom.h +++ b/include/linux/platform_data/x86/clk-pmc-atom.h @@ -35,10 +35,13 @@ struct pmc_clk { * * @base: PMC clock register base offset * @clks: pointer to set of registered clocks, typically 0..5 + * @critical: flag to indicate if firmware enabled pmc_plt_clks + * should be marked as critial or not */ struct pmc_clk_data { void __iomem *base; const struct pmc_clk *clks; + bool critical; }; #endif /* __PLATFORM_DATA_X86_CLK_PMC_ATOM_H */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 8ae999f3f21862ebb8ec536b66066893debfd698..27493b041092f928222a3eda6b26f6ccad404d46 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -337,6 +337,11 @@ enum power_supply_property { POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT, POWER_SUPPLY_PROP_REAL_CAPACITY, POWER_SUPPLY_PROP_ESR_SW_CONTROL, + POWER_SUPPLY_PROP_FORCE_MAIN_ICL, + POWER_SUPPLY_PROP_FORCE_MAIN_FCC, + POWER_SUPPLY_PROP_COMP_CLAMP_LEVEL, + POWER_SUPPLY_PROP_ADAPTER_CC_MODE, + POWER_SUPPLY_PROP_SKIN_HEALTH, /* Charge pump properties */ POWER_SUPPLY_PROP_CP_STATUS1, POWER_SUPPLY_PROP_CP_STATUS2, diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index 21aee963e37b5799433bcafe5882cdd90bb96ec2..85028238b94af09f32892c68764afb3e60a69b2e 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -138,6 +138,7 @@ struct se_geni_rsc { #define SE_DMA_DEBUG_REG0 (0xE40) #define SLAVE_MODE_EN (BIT(3)) #define START_TRIGGER (BIT(0)) +#define QUPV3_HW_VER (0x4) /* GENI_OUTPUT_CTRL fields */ #define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0)) diff --git a/include/linux/qcomwlan_secif.h b/include/linux/qcomwlan_secif.h new file mode 100644 index 0000000000000000000000000000000000000000..2d140e845fc236cd6bfeeb8143d7655eae41763d --- /dev/null +++ b/include/linux/qcomwlan_secif.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2011-2013, 2019, The Linux Foundation. All rights reserved. + * + * This 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 __QCOM_WLAN_SECIF_H__ +#define __QCOM_WLAN_SECIF_H__ + +#include + +#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ + +/* + * Prototypes for WLAN Security Interface Functions + */ + +extern struct crypto_ahash * +wcnss_wlan_crypto_alloc_ahash(const char *alg_name, u32 type, u32 mask); + +extern int wcnss_wlan_crypto_ahash_digest(struct ahash_request *req); +extern void wcnss_wlan_crypto_free_ahash(struct crypto_ahash *tfm); +extern int wcnss_wlan_crypto_ahash_setkey(struct crypto_ahash *tfm, + const u8 *key, unsigned int keylen); +extern struct crypto_ablkcipher * +wcnss_wlan_crypto_alloc_ablkcipher(const char *alg_name, u32 type, u32 mask); +extern void wcnss_wlan_ablkcipher_request_free(struct ablkcipher_request *req); +extern void wcnss_wlan_crypto_free_cipher(struct crypto_cipher *tfm); +extern void wcnss_wlan_crypto_free_ablkcipher(struct crypto_ablkcipher *tfm); +extern struct crypto_cipher * +wcnss_wlan_crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask); +extern void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, + u16 length, u8 *mac); + +#endif /* __QCOM_WLAN_SECIF_H__ */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 3511ef6af4d385ac634c7c09a960c2110962c0bc..8dc7f180aee3910e26e19acf9682c44ab29c9b35 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -274,6 +274,7 @@ extern int __must_check io_schedule_prepare(void); extern void io_schedule_finish(int token); extern long io_schedule_timeout(long timeout); extern void io_schedule(void); +extern int set_task_boost(int boost, u64 period); /** * struct prev_cputime - snapshot of system and user cputime @@ -777,7 +778,11 @@ struct task_struct { const struct sched_class *sched_class; struct sched_entity se; struct sched_rt_entity rt; - u64 last_sleep_ts; + u64 last_sleep_ts; + + int boost; + u64 boost_period; + u64 boost_expires; #ifdef CONFIG_SCHED_WALT struct ravg ravg; /* diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h index c0ae949102773b3e358db5ce90f607847db76b02..e22dcbd7d18e2de67d3a80538e76d582f00605b7 100644 --- a/include/linux/sched/mm.h +++ b/include/linux/sched/mm.h @@ -57,6 +57,27 @@ static inline void mmdrop_async(struct mm_struct *mm) } } +/* + * This has to be called after a get_task_mm()/mmget_not_zero() + * followed by taking the mmap_sem for writing before modifying the + * vmas or anything the coredump pretends not to change from under it. + * + * NOTE: find_extend_vma() called from GUP context is the only place + * that can modify the "mm" (notably the vm_start/end) under mmap_sem + * for reading and outside the context of the process, so it is also + * the only case that holds the mmap_sem for reading that must call + * this function. Generally if the mmap_sem is hold for reading + * there's no need of this check after get_task_mm()/mmget_not_zero(). + * + * This function can be obsoleted and the check can be removed, after + * the coredump code will hold the mmap_sem for writing before + * invoking the ->core_dump methods. + */ +static inline bool mmget_still_valid(struct mm_struct *mm) +{ + return likely(!mm->core_state); +} + /** * mmget() - Pin the address space associated with a &struct mm_struct. * @mm: The address space to pin. diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index fbf86ecd149d3826f519964dd61e6ef15efb2450..bcaba7e8ca6eafe08b2e1eecab57cc8a8f73a7bb 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -377,10 +377,20 @@ static inline void set_restore_sigmask(void) set_thread_flag(TIF_RESTORE_SIGMASK); WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } + +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} + static inline void clear_restore_sigmask(void) { clear_thread_flag(TIF_RESTORE_SIGMASK); } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} static inline bool test_restore_sigmask(void) { return test_thread_flag(TIF_RESTORE_SIGMASK); @@ -398,6 +408,10 @@ static inline void set_restore_sigmask(void) current->restore_sigmask = true; WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + tsk->restore_sigmask = false; +} static inline void clear_restore_sigmask(void) { current->restore_sigmask = false; @@ -406,6 +420,10 @@ static inline bool test_restore_sigmask(void) { return current->restore_sigmask; } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return tsk->restore_sigmask; +} static inline bool test_and_clear_restore_sigmask(void) { if (!current->restore_sigmask) diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h index 8a0fa18fa14fc9c4fa6841e8a1619fc5b4316ee2..e18648be7747044dda90d701c5c401de6918ddca 100644 --- a/include/linux/soc/qcom/qmi.h +++ b/include/linux/soc/qcom/qmi.h @@ -166,7 +166,6 @@ struct qmi_ops { * struct qmi_txn - transaction context * @qmi: QMI handle this transaction is associated with * @id: transaction id - * @lock: for synchronization between handler and waiter of messages * @completion: completion object as the transaction receives a response * @result: result code for the completed transaction * @ei: description of the QMI encoded response (optional) @@ -177,7 +176,6 @@ struct qmi_txn { u16 id; - struct mutex lock; struct completion completion; int result; diff --git a/include/linux/string.h b/include/linux/string.h index 96115bf561b452112f411ecbcd61f5e016b00911..3d43329c20bef14019f6e3fc6d3c2cda87ce1abe 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -142,6 +142,9 @@ extern void * memscan(void *,int,__kernel_size_t); #ifndef __HAVE_ARCH_MEMCMP extern int memcmp(const void *,const void *,__kernel_size_t); #endif +#ifndef __HAVE_ARCH_BCMP +extern int bcmp(const void *,const void *,__kernel_size_t); +#endif #ifndef __HAVE_ARCH_MEMCHR extern void * memchr(const void *,int,__kernel_size_t); #endif diff --git a/include/linux/swap.h b/include/linux/swap.h index c0dbf1c0d3e2a75872ec09db763e0ec099eb6787..b06261d7678714ec7312ed489c0fa6850feb8bf4 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -155,9 +155,9 @@ struct swap_extent { /* * Max bad pages in the new format.. */ -#define __swapoffset(x) ((unsigned long)&((union swap_header *)0)->x) #define MAX_SWAP_BADPAGES \ - ((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int)) + ((offsetof(union swap_header, magic.magic) - \ + offsetof(union swap_header, info.badpages)) / sizeof(int)) enum { SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 841262739972aa7158d33466326384a765beb300..eccb7a30adf7f951e80b41fd77cb6afde5f0773a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -200,7 +200,6 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt, * @dev: driver model's view of this device * @usb_dev: if an interface is bound to the USB major, this will point * to the sysfs representation for that device. - * @pm_usage_cnt: PM usage counter for this interface * @reset_ws: Used for scheduling resets from atomic context. * @resetting_device: USB core reset the device, so use alt setting 0 as * current; needs bandwidth alloc after reset. @@ -257,7 +256,6 @@ struct usb_interface { struct device dev; /* interface specific device info */ struct device *usb_dev; - atomic_t pm_usage_cnt; /* usage counter for autosuspend */ struct work_struct reset_ws; /* for resets in atomic context */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) diff --git a/include/linux/virtio_clk.h b/include/linux/virtio_clk.h new file mode 100644 index 0000000000000000000000000000000000000000..552f5049a0e3fd726ff10fea6eb638e23e10ca03 --- /dev/null +++ b/include/linux/virtio_clk.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 _LINUX_VIRTIO_CLK_H +#define _LINUX_VIRTIO_CLK_H + +#include +#include +#include +#include + +/* Feature bits */ +#define VIRTIO_CLK_F_RESET 1 /* Support reset */ +#define VIRTIO_CLK_F_NAME 2 /* Support clock name */ + +/* Configuration layout */ +struct virtio_clk_config { + __u32 num_clks; + __u32 num_resets; + __u8 name[20]; +} __packed; + +/* Request/response message format */ +struct virtio_clk_msg { + u8 name[40]; + __virtio32 id; + __virtio32 type; + __virtio32 result; + __virtio32 data[4]; +}; + +/* Request type */ +#define VIRTIO_CLK_T_ENABLE 0 +#define VIRTIO_CLK_T_DISABLE 1 +#define VIRTIO_CLK_T_SET_RATE 2 +#define VIRTIO_CLK_T_GET_RATE 3 +#define VIRTIO_CLK_T_ROUND_RATE 4 +#define VIRTIO_CLK_T_RESET 5 +#define VIRTIO_CLK_T_SET_FLAGS 6 + +#endif /* _LINUX_VIRTIO_CLK_H */ diff --git a/include/linux/virtio_regulator.h b/include/linux/virtio_regulator.h new file mode 100644 index 0000000000000000000000000000000000000000..1189bbda2a8fb58245bb90fc45346acdeebbf8a1 --- /dev/null +++ b/include/linux/virtio_regulator.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 _LINUX_VIRTIO_REGULATOR_H +#define _LINUX_VIRTIO_REGULATOR_H + +#include +#include +#include +#include + +/* Request/response message format */ +struct virtio_regulator_msg { + u8 name[20]; + __virtio32 type; + __virtio32 result; + __virtio32 data[4]; +}; + +/* Request type */ +#define VIRTIO_REGULATOR_T_ENABLE 0 +#define VIRTIO_REGULATOR_T_DISABLE 1 +#define VIRTIO_REGULATOR_T_SET_VOLTAGE 2 +#define VIRTIO_REGULATOR_T_GET_VOLTAGE 3 +#define VIRTIO_REGULATOR_T_SET_CURRENT_LIMIT 4 +#define VIRTIO_REGULATOR_T_GET_CURRENT_LIMIT 5 +#define VIRTIO_REGULATOR_T_SET_MODE 6 +#define VIRTIO_REGULATOR_T_GET_MODE 7 +#define VIRTIO_REGULATOR_T_SET_LOAD 8 + +#endif /* _LINUX_VIRTIO_REGULATOR_H */ diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index bbf32524ab279d8e353ca3d9d854a1ab2a12805c..75007e648dfacba9c1f8fb42a6bd791fbe14b725 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -63,7 +63,7 @@ struct virtqueue; /* * Creates a virtqueue and allocates the descriptor ring. If * may_reduce_num is set, then this may allocate a smaller ring than - * expected. The caller should query virtqueue_get_ring_size to learn + * expected. The caller should query virtqueue_get_vring_size to learn * the actual size of the ring. */ struct virtqueue *vring_create_virtqueue(unsigned int index, diff --git a/include/linux/virtio_spmi.h b/include/linux/virtio_spmi.h new file mode 100644 index 0000000000000000000000000000000000000000..d3224983fa93595c8f6f79bbbc4bbea02af4de0b --- /dev/null +++ b/include/linux/virtio_spmi.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 _LINUX_VIRTIO_SPMI_H +#define _LINUX_VIRTIO_SPMI_H + +#include +#include +#include +#include + +/* Feature bits */ +#define VIRTIO_SPMI_F_INT 1 /* Support interrupt */ + +#define VM_MAX_PERIPHS 512 + +/* Configuration layout */ +struct virtio_spmi_config { + __u16 ppid_allowed[VM_MAX_PERIPHS]; +} __packed; + +struct payload_cmd { + __virtio32 data[2]; +}; + +struct payload_irq { + __virtio32 ppid; + __virtio32 val; +}; + +union payload_data { + struct payload_cmd cmdd; + struct payload_irq irqd; +}; + +struct virtio_spmi_msg { + __virtio32 type; + __virtio32 len; + __virtio32 res; + union { + __virtio32 cmd; + __virtio32 cnt; + } u; + union payload_data payload[]; +}; + +/* Virtio SPMI message type */ +enum vio_spmi_msg_type { + VIO_SPMI_BUS_WRITE = 0, + VIO_SPMI_BUS_READ = 1, + VIO_ACC_ENABLE_WR = 2, + VIO_ACC_ENABLE_RD = 3, + VIO_IRQ_CLEAR = 4, + VIO_IRQ_STATUS = 5, +}; + +/* Virtio SPMI message type */ +enum vio_spmi_msg_res { + VIO_SPMI_DONE = 0, + VIO_SPMI_ERR = 1, +}; + +/* payload fix size and one payload_data size */ +#define MSG_FIX_SZ (sizeof(struct virtio_spmi_msg)) +#define PER_PLD_SZ (sizeof(union payload_data)) +#define MSG_SZ(x) (MSG_FIX_SZ + ((PER_PLD_SZ) * (x))) + +#endif /* _LINUX_VIRTIO_SPMI_H */ diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 599b8d0361e7b134b8e605b007d3841f84496d46..e7ade838a54187f2d6cdd3c0d67d030c1dddd03a 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -18,6 +18,8 @@ #include +#define SECURE_CAM_RST_MODULES + #ifdef CONFIG_COMPAT struct msm_sensor_power_setting32 { @@ -85,6 +87,8 @@ struct msm_camera_csid_params32 { struct msm_camera_csid_lut_params32 lut_params; uint8_t csi_3p_sel; uint8_t is_secure; + uint32_t topology; + uint8_t is_streamon; }; struct msm_camera_csi2_params32 { diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h index fe328c52c46bd179b651d6bbb14e58a89f017557..801489bb14c3437d3419a6dd00766787b6fce100 100644 --- a/include/net/caif/cfpkt.h +++ b/include/net/caif/cfpkt.h @@ -32,6 +32,33 @@ void cfpkt_destroy(struct cfpkt *pkt); */ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len); +static inline u8 cfpkt_extr_head_u8(struct cfpkt *pkt) +{ + u8 tmp; + + cfpkt_extr_head(pkt, &tmp, 1); + + return tmp; +} + +static inline u16 cfpkt_extr_head_u16(struct cfpkt *pkt) +{ + __le16 tmp; + + cfpkt_extr_head(pkt, &tmp, 2); + + return le16_to_cpu(tmp); +} + +static inline u32 cfpkt_extr_head_u32(struct cfpkt *pkt) +{ + __le32 tmp; + + cfpkt_extr_head(pkt, &tmp, 4); + + return le32_to_cpu(tmp); +} + /* * Peek header from packet. * Reads data from packet without changing packet. diff --git a/include/net/cnss.h b/include/net/cnss.h new file mode 100644 index 0000000000000000000000000000000000000000..d7b059aa4c1d996e8332b82a3619debc60218fdd --- /dev/null +++ b/include/net/cnss.h @@ -0,0 +1,271 @@ +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * + * This 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 _NET_CNSS_H_ +#define _NET_CNSS_H_ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_CNSS +#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024) +#define CNSS_MAX_FILE_NAME 20 +#define PINCTRL_SLEEP 0 +#define PINCTRL_ACTIVE 1 + +enum cnss_bus_width_type { + CNSS_BUS_WIDTH_NONE, + CNSS_BUS_WIDTH_LOW, + CNSS_BUS_WIDTH_MEDIUM, + CNSS_BUS_WIDTH_HIGH +}; + +enum cnss_cc_src { + CNSS_SOURCE_CORE, + CNSS_SOURCE_11D, + CNSS_SOURCE_USER +}; + +/* FW image files */ +struct cnss_fw_files { + char image_file[CNSS_MAX_FILE_NAME]; + char board_data[CNSS_MAX_FILE_NAME]; + char otp_data[CNSS_MAX_FILE_NAME]; + char utf_file[CNSS_MAX_FILE_NAME]; + char utf_board_data[CNSS_MAX_FILE_NAME]; + char epping_file[CNSS_MAX_FILE_NAME]; + char evicted_data[CNSS_MAX_FILE_NAME]; +}; + +struct cnss_wlan_runtime_ops { + int (*runtime_suspend)(struct pci_dev *pdev); + int (*runtime_resume)(struct pci_dev *pdev); +}; + +struct cnss_wlan_driver { + char *name; + int (*probe)(struct pci_dev *pdev, const struct pci_device_id *id); + void (*remove)(struct pci_dev *pdev); + int (*reinit)(struct pci_dev *pdev, const struct pci_device_id *id); + void (*shutdown)(struct pci_dev *pdev); + void (*crash_shutdown)(struct pci_dev *pdev); + int (*suspend)(struct pci_dev *pdev, pm_message_t state); + int (*resume)(struct pci_dev *pdev); + void (*modem_status)(struct pci_dev *, int state); + void (*update_status)(struct pci_dev *pdev, uint32_t status); + struct cnss_wlan_runtime_ops *runtime_ops; + const struct pci_device_id *id_table; +}; + +/* + * codeseg_total_bytes: Total bytes across all the codesegment blocks + * num_codesegs: No of Pages used + * codeseg_size: Size of each segment. Should be power of 2 and multiple of 4K + * codeseg_size_log2: log2(codeseg_size) + * codeseg_busaddr: Physical address of the DMAble memory;4K aligned + */ + +#define CODESWAP_MAX_CODESEGS 16 +struct codeswap_codeseg_info { + u32 codeseg_total_bytes; + u32 num_codesegs; + u32 codeseg_size; + u32 codeseg_size_log2; + void *codeseg_busaddr[CODESWAP_MAX_CODESEGS]; +}; + +struct image_desc_info { + dma_addr_t fw_addr; + u32 fw_size; + dma_addr_t bdata_addr; + u32 bdata_size; +}; + +/* platform capabilities */ +enum cnss_platform_cap_flag { + CNSS_HAS_EXTERNAL_SWREG = 0x01, + CNSS_HAS_UART_ACCESS = 0x02, +}; + +struct cnss_platform_cap { + u32 cap_flag; +}; + +/* WLAN driver status, keep it aligned with cnss2 */ +enum cnss_driver_status { + CNSS_UNINITIALIZED, + CNSS_INITIALIZED, + CNSS_LOAD_UNLOAD, + CNSS_RECOVERY, + CNSS_FW_DOWN, + CNSS_SSR_FAIL, +}; + +enum cnss_runtime_request { + CNSS_PM_RUNTIME_GET, + CNSS_PM_RUNTIME_PUT, + CNSS_PM_RUNTIME_MARK_LAST_BUSY, + CNSS_PM_RUNTIME_RESUME, + CNSS_PM_RUNTIME_PUT_NOIDLE, + CNSS_PM_REQUEST_RESUME, + CNSS_PM_RUNTIME_PUT_AUTO, + CNSS_PM_GET_NORESUME, +}; + +extern struct dma_iommu_mapping *cnss_smmu_get_mapping(void); +extern int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size); +extern int cnss_get_fw_image(struct image_desc_info *image_desc_info); +extern void cnss_runtime_init(struct device *dev, int auto_delay); +extern void cnss_runtime_exit(struct device *dev); +extern void cnss_wlan_pci_link_down(void); +extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable); +extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver); +extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver); +extern int cnss_get_fw_files(struct cnss_fw_files *pfw_files); +extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files, + u32 target_type, u32 target_version); +extern void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files, + u32 size, u32 tufello_dual_fw); + +extern int cnss_request_bus_bandwidth(int bandwidth); + +#ifdef CONFIG_CNSS_SECURE_FW +extern int cnss_get_sha_hash(const u8 *data, u32 data_len, + u8 *hash_idx, u8 *out); +extern void *cnss_get_fw_ptr(void); +#endif + +extern int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg); +extern int cnss_get_bmi_setup(void); + +#ifdef CONFIG_PCI_MSM +extern int cnss_wlan_pm_control(bool vote); +#endif +extern void cnss_lock_pm_sem(void); +extern void cnss_release_pm_sem(void); + +extern void cnss_request_pm_qos_type(int latency_type, u32 qos_val); +extern void cnss_request_pm_qos(u32 qos_val); +extern void cnss_remove_pm_qos(void); + +extern void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val); +extern void cnss_pci_request_pm_qos(u32 qos_val); +extern void cnss_pci_remove_pm_qos(void); + +extern void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val); +extern void cnss_sdio_request_pm_qos(u32 qos_val); +extern void cnss_sdio_remove_pm_qos(void); + +extern int cnss_get_platform_cap(struct cnss_platform_cap *cap); +extern void cnss_set_driver_status(enum cnss_driver_status driver_status); + +#ifndef CONFIG_WCNSS_MEM_PRE_ALLOC +static inline int wcnss_pre_alloc_reset(void) { return 0; } +#endif + +extern int msm_pcie_enumerate(u32 rc_idx); +extern int cnss_auto_suspend(void); +extern int cnss_auto_resume(void); +extern int cnss_prevent_auto_suspend(const char *caller_func); +extern int cnss_allow_auto_suspend(const char *caller_func); +extern int cnss_is_auto_suspend_allowed(const char *caller_func); + +extern int cnss_pm_runtime_request(struct device *dev, enum + cnss_runtime_request request); +extern void cnss_set_cc_source(enum cnss_cc_src cc_source); +extern enum cnss_cc_src cnss_get_cc_source(void); +#endif + +extern void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name); +extern void cnss_pm_wake_lock(struct wakeup_source *ws); + +extern void cnss_device_crashed(void); +extern void cnss_device_self_recovery(void); +extern void *cnss_get_virt_ramdump_mem(unsigned long *size); + +extern void cnss_schedule_recovery_work(void); +extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len); +extern u8 *cnss_get_wlan_mac_address(struct device *dev, uint32_t *num); +extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len); + +enum { + CNSS_RESET_SOC = 0, + CNSS_RESET_SUBSYS_COUPLED, + CNSS_RESET_LEVEL_MAX +}; +extern int cnss_get_restart_level(void); + +struct cnss_sdio_wlan_driver { + const char *name; + const struct sdio_device_id *id_table; + int (*probe)(struct sdio_func *, const struct sdio_device_id *); + void (*remove)(struct sdio_func *); + int (*reinit)(struct sdio_func *, const struct sdio_device_id *); + void (*shutdown)(struct sdio_func *); + void (*crash_shutdown)(struct sdio_func *); + int (*suspend)(struct device *); + int (*resume)(struct device *); +}; + +extern int cnss_sdio_wlan_register_driver( + struct cnss_sdio_wlan_driver *driver); +extern void cnss_sdio_wlan_unregister_driver( + struct cnss_sdio_wlan_driver *driver); + +typedef void (*oob_irq_handler_t)(void *dev_para); +extern int cnss_wlan_query_oob_status(void); +extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, + void *pm_oob); +extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob); + + +extern void cnss_dump_stack(struct task_struct *task); +extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num); +extern void cnss_init_work(struct work_struct *work, work_func_t func); +extern void cnss_flush_delayed_work(void *dwork); +extern void cnss_flush_work(void *work); +extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec); +extern void cnss_pm_wake_lock_release(struct wakeup_source *ws); +extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws); +extern void cnss_get_monotonic_boottime(struct timespec *ts); +extern void cnss_get_boottime(struct timespec *ts); +extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t + func); +extern int cnss_vendor_cmd_reply(struct sk_buff *skb); +extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu); +extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count); +extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, + u16 buf_len); +extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len); +extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len); +extern int cnss_common_request_bus_bandwidth(struct device *dev, int + bandwidth); +extern void cnss_common_device_crashed(struct device *dev); +extern void cnss_common_device_self_recovery(struct device *dev); +extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long + *size); +extern void cnss_common_schedule_recovery_work(struct device *dev); +extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in, + uint32_t len); +extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num); +extern int cnss_power_up(struct device *dev); +extern int cnss_power_down(struct device *dev); +extern int cnss_sdio_configure_spdt(bool state); + +extern int cnss_common_register_tsf_captured_handler(struct device *dev, + irq_handler_t handler, + void *ctx); +extern int cnss_common_unregister_tsf_captured_handler(struct device *dev, + void *ctx); +#endif /* _NET_CNSS_H_ */ diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 335cf7851f129e6130c07e8aefc3cfb98d9d7450..008f64823c4187e3ea72f6ab90d6134ea82168c1 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -77,8 +77,8 @@ struct inet_frag_queue { struct timer_list timer; spinlock_t lock; refcount_t refcnt; - struct sk_buff *fragments; /* Used in IPv6. */ - struct rb_root rb_fragments; /* Used in IPv4. */ + struct sk_buff *fragments; /* used in 6lopwpan IPv6. */ + struct rb_root rb_fragments; /* Used in IPv4/IPv6. */ struct sk_buff *fragments_tail; struct sk_buff *last_run_head; ktime_t stamp; @@ -153,4 +153,16 @@ static inline void add_frag_mem_limit(struct netns_frags *nf, long val) extern const u8 ip_frag_ecn_table[16]; +/* Return values of inet_frag_queue_insert() */ +#define IPFRAG_OK 0 +#define IPFRAG_DUP 1 +#define IPFRAG_OVERLAP 2 +int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb, + int offset, int end); +void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb, + struct sk_buff *parent); +void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head, + void *reasm_data); +struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q); + #endif diff --git a/include/net/ip.h b/include/net/ip.h index ec3e06417133c035837bfbc510347cd3ed88a977..dd24eac2d51d30a3c0ec3adadb418e113eb9e45f 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -607,7 +607,7 @@ int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp, unsigned char __user *data, int optlen); void ip_options_undo(struct ip_options *opt); void ip_forward_options(struct sk_buff *skb); -int ip_options_rcv_srr(struct sk_buff *skb); +int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev); /* * Functions provided by ip_sockglue.c diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 10a7a880c81caf369727c7eedc522f9a177c3570..5ea1bb50bb40a78fcc98f0e89626a36b01c4c53b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -513,35 +513,6 @@ static inline bool ipv6_prefix_equal(const struct in6_addr *addr1, } #endif -struct inet_frag_queue; - -enum ip6_defrag_users { - IP6_DEFRAG_LOCAL_DELIVER, - IP6_DEFRAG_CONNTRACK_IN, - __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX, - IP6_DEFRAG_CONNTRACK_OUT, - __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX, - IP6_DEFRAG_CONNTRACK_BRIDGE_IN, - __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, -}; - -void ip6_frag_init(struct inet_frag_queue *q, const void *a); -extern const struct rhashtable_params ip6_rhash_params; - -/* - * Equivalent of ipv4 struct ip - */ -struct frag_queue { - struct inet_frag_queue q; - - int iif; - unsigned int csum; - __u16 nhoffset; - u8 ecn; -}; - -void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq); - static inline bool ipv6_addr_any(const struct in6_addr *a) { #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 diff --git a/include/net/ipv6_frag.h b/include/net/ipv6_frag.h new file mode 100644 index 0000000000000000000000000000000000000000..28aa9b30aeceac9a86ee6754e4b5809be115e947 --- /dev/null +++ b/include/net/ipv6_frag.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _IPV6_FRAG_H +#define _IPV6_FRAG_H +#include +#include +#include +#include + +enum ip6_defrag_users { + IP6_DEFRAG_LOCAL_DELIVER, + IP6_DEFRAG_CONNTRACK_IN, + __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX, + IP6_DEFRAG_CONNTRACK_OUT, + __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX, + IP6_DEFRAG_CONNTRACK_BRIDGE_IN, + __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, +}; + +/* + * Equivalent of ipv4 struct ip + */ +struct frag_queue { + struct inet_frag_queue q; + + int iif; + __u16 nhoffset; + u8 ecn; +}; + +#if IS_ENABLED(CONFIG_IPV6) +static inline void ip6frag_init(struct inet_frag_queue *q, const void *a) +{ + struct frag_queue *fq = container_of(q, struct frag_queue, q); + const struct frag_v6_compare_key *key = a; + + q->key.v6 = *key; + fq->ecn = 0; +} + +static inline u32 ip6frag_key_hashfn(const void *data, u32 len, u32 seed) +{ + return jhash2(data, + sizeof(struct frag_v6_compare_key) / sizeof(u32), seed); +} + +static inline u32 ip6frag_obj_hashfn(const void *data, u32 len, u32 seed) +{ + const struct inet_frag_queue *fq = data; + + return jhash2((const u32 *)&fq->key.v6, + sizeof(struct frag_v6_compare_key) / sizeof(u32), seed); +} + +static inline int +ip6frag_obj_cmpfn(struct rhashtable_compare_arg *arg, const void *ptr) +{ + const struct frag_v6_compare_key *key = arg->key; + const struct inet_frag_queue *fq = ptr; + + return !!memcmp(&fq->key, key, sizeof(*key)); +} + +static inline void +ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq) +{ + struct net_device *dev = NULL; + struct sk_buff *head; + + rcu_read_lock(); + spin_lock(&fq->q.lock); + + if (fq->q.flags & INET_FRAG_COMPLETE) + goto out; + + inet_frag_kill(&fq->q); + + dev = dev_get_by_index_rcu(net, fq->iif); + if (!dev) + goto out; + + __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); + __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); + + /* Don't send error if the first segment did not arrive. */ + if (!(fq->q.flags & INET_FRAG_FIRST_IN)) + goto out; + + /* sk_buff::dev and sk_buff::rbnode are unionized. So we + * pull the head out of the tree in order to be able to + * deal with head->dev. + */ + head = inet_frag_pull_head(&fq->q); + if (!head) + goto out; + + head->dev = dev; + skb_get(head); + spin_unlock(&fq->q.lock); + + icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); + kfree_skb(head); + goto out_rcu_unlock; + +out: + spin_unlock(&fq->q.lock); +out_rcu_unlock: + rcu_read_unlock(); + inet_frag_put(&fq->q); +} +#endif +#endif diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index f4bf75fac349ca66f1345854406c64bb71a74af4..d96c9d9cca96560143ca5ba6a31106c8115bb4b4 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -56,6 +56,7 @@ struct net { */ spinlock_t rules_mod_lock; + u32 hash_mix; atomic64_t cookie_gen; struct list_head list; /* list of network namespaces */ diff --git a/include/net/netns/hash.h b/include/net/netns/hash.h index 24c78183a4c262e086c29cde1e61b7f397d8bab0..d9b665151f3d9e916f35620141542a5a145e6123 100644 --- a/include/net/netns/hash.h +++ b/include/net/netns/hash.h @@ -2,21 +2,10 @@ #ifndef __NET_NS_HASH_H__ #define __NET_NS_HASH_H__ -#include - -struct net; +#include static inline u32 net_hash_mix(const struct net *net) { -#ifdef CONFIG_NET_NS - /* - * shift this right to eliminate bits, that are - * always zeroed - */ - - return (u32)(((unsigned long)net) >> L1_CACHE_SHIFT); -#else - return 0; -#endif + return net->hash_mix; } #endif diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index b55c6a48a20696328e918155d310132160f87f64..d44d17b29189245cb295a26ac87507c416f00bcd 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -104,7 +104,6 @@ enum sctp_verb { SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ SCTP_CMD_SEND_MSG, /* Send the whole use message */ - SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */ SCTP_CMD_PURGE_ASCONF_QUEUE, /* Purge all asconf queues.*/ SCTP_CMD_SET_ASOC, /* Restore association context */ SCTP_CMD_LAST diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h index e82d93346b6352beaa7f14d9b03f5ca4cabdf614..bb74ea83d57db1cd2c420ccdf60369e1e58bc65a 100644 --- a/include/net/tc_act/tc_gact.h +++ b/include/net/tc_act/tc_gact.h @@ -51,7 +51,7 @@ static inline bool is_tcf_gact_goto_chain(const struct tc_action *a) static inline u32 tcf_gact_goto_chain_index(const struct tc_action *a) { - return a->goto_chain->index; + return READ_ONCE(a->tcfa_action) & TC_ACT_EXT_VAL_MASK; } #endif /* __NET_TC_GACT_H */ diff --git a/include/net/udp.h b/include/net/udp.h index 47ca7e8aa2607e2deec6815e994fd0d60c08e113..8058ca671c73e7c185bdfab98a3a8d321bf4c8c3 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -461,12 +461,19 @@ void udpv6_encap_enable(void); static inline struct sk_buff *udp_rcv_segment(struct sock *sk, struct sk_buff *skb, bool ipv4) { + netdev_features_t features = NETIF_F_SG; struct sk_buff *segs; + /* Avoid csum recalculation by skb_segment unless userspace explicitly + * asks for the final checksum values + */ + if (!inet_get_convert_csum(sk)) + features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + /* the GSO CB lays after the UDP one, no need to save and restore any * CB fragment */ - segs = __skb_gso_segment(skb, NETIF_F_SG, false); + segs = __skb_gso_segment(skb, features, false); if (unlikely(IS_ERR_OR_NULL(segs))) { int segs_nr = skb_shinfo(skb)->gso_segs; diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 0717cd12dfdeb0110657e3a104d7ccd818cde4eb..54f2a51123e62bac8e1973bcf0a9ea696131a24d 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -50,6 +50,8 @@ struct icnss_driver_ops { int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent); + int (*idle_shutdown)(struct device *dev); + int (*idle_restart)(struct device *dev); }; @@ -146,4 +148,6 @@ extern bool icnss_is_rejuvenate(void); extern int icnss_trigger_recovery(struct device *dev); extern void icnss_block_shutdown(bool status); extern bool icnss_is_pdr(void); +extern int icnss_idle_restart(struct device *dev); +extern int icnss_idle_shutdown(struct device *dev); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index ac6791a9952771f7289e3a0d915def9ae82dbdf0..2797a090d40d6f4b4c05f0c36b4cb67ec421f18e 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -79,6 +79,10 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs403") #define early_machine_is_qcs401() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs401") +#define early_machine_is_qcs404() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs404") +#define early_machine_is_qcs407() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs407") #define early_machine_is_sdxprairie() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdxprairie") #define early_machine_is_sdmmagpie() \ @@ -128,6 +132,8 @@ #define early_machine_is_qcs405() 0 #define early_machine_is_qcs403() 0 #define early_machine_is_qcs401() 0 +#define early_machine_is_qcs404() 0 +#define early_machine_is_qcs407() 0 #define early_machine_is_sdxprairie() 0 #define early_machine_is_sdmmagpie() 0 #define early_machine_is_sdmmagpiep() 0 @@ -169,6 +175,8 @@ enum msm_cpu { MSM_CPU_QCS405, MSM_CPU_QCS403, MSM_CPU_QCS401, + MSM_CPU_QCS404, + MSM_CPU_QCS407, SDX_CPU_SDXPRAIRIE, MSM_CPU_SDMMAGPIE, MSM_CPU_SDMMAGPIEP, diff --git a/include/trace/events/dfc.h b/include/trace/events/dfc.h index 70eec100c2e3c8b09fa8e78e9642c4a4996e94b7..28810f781fc2ac3b878bb95fc450a8b651780018 100644 --- a/include/trace/events/dfc.h +++ b/include/trace/events/dfc.h @@ -20,15 +20,14 @@ TRACE_EVENT(dfc_qmi_tc, - TP_PROTO(const char *name, u8 bearer_id, u32 flow_id, u32 grant, + TP_PROTO(const char *name, u8 bearer_id, u32 grant, int qlen, u32 tcm_handle, int enable), - TP_ARGS(name, bearer_id, flow_id, grant, qlen, tcm_handle, enable), + TP_ARGS(name, bearer_id, grant, qlen, tcm_handle, enable), TP_STRUCT__entry( __string(dev_name, name) __field(u8, bid) - __field(u32, fid) __field(u32, grant) __field(int, qlen) __field(u32, tcm_handle) @@ -38,16 +37,15 @@ TRACE_EVENT(dfc_qmi_tc, TP_fast_assign( __assign_str(dev_name, name); __entry->bid = bearer_id; - __entry->fid = flow_id; __entry->grant = grant; __entry->qlen = qlen; __entry->tcm_handle = tcm_handle; __entry->enable = enable; ), - TP_printk("dev=%s bearer_id=%u grant=%u len=%d flow_id=%u q=%d %s", + TP_printk("dev=%s bearer_id=%u grant=%u len=%d mq=%u %s", __get_str(dev_name), - __entry->bid, __entry->grant, __entry->qlen, __entry->fid, + __entry->bid, __entry->grant, __entry->qlen, __entry->tcm_handle, __entry->enable ? "enable" : "disable") ); @@ -90,14 +88,16 @@ TRACE_EVENT(dfc_flow_ind, TRACE_EVENT(dfc_flow_check, - TP_PROTO(const char *name, u8 bearer_id, unsigned int len, u32 grant), + TP_PROTO(const char *name, u8 bearer_id, unsigned int len, + u32 mark, u32 grant), - TP_ARGS(name, bearer_id, len, grant), + TP_ARGS(name, bearer_id, len, mark, grant), TP_STRUCT__entry( __string(dev_name, name) __field(u8, bearer_id) __field(unsigned int, len) + __field(u32, mark) __field(u32, grant) ), @@ -105,12 +105,13 @@ TRACE_EVENT(dfc_flow_check, __assign_str(dev_name, name) __entry->bearer_id = bearer_id; __entry->len = len; + __entry->mark = mark; __entry->grant = grant; ), - TP_printk("dev=%s bearer_id=%u skb_len=%u current_grant=%u", - __get_str(dev_name), - __entry->bearer_id, __entry->len, __entry->grant) + TP_printk("dev=%s bearer_id=%u skb_len=%u mark=%u current_grant=%u", + __get_str(dev_name), __entry->bearer_id, + __entry->len, __entry->mark, __entry->grant) ); TRACE_EVENT(dfc_flow_info, @@ -138,7 +139,7 @@ TRACE_EVENT(dfc_flow_info, __entry->action = add; ), - TP_printk("%s: dev=%s bearer_id=%u flow_id=%u ip_type=%d q=%d", + TP_printk("%s: dev=%s bearer_id=%u flow_id=%u ip_type=%d mq=%d", __entry->action ? "add flow" : "delete flow", __get_str(dev_name), __entry->bid, __entry->fid, __entry->ip, __entry->handle) diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h index 9761aa1ae3b01a58070b16c24c030899691a5f3f..631fa449c3866f99beb499cec689f490ee792ab2 100644 --- a/include/uapi/linux/esoc_ctrl.h +++ b/include/uapi/linux/esoc_ctrl.h @@ -14,12 +14,25 @@ #define ESOC_REG_REQ_ENG _IO(ESOC_CODE, 7) #define ESOC_REG_CMD_ENG _IO(ESOC_CODE, 8) #define ESOC_GET_LINK_ID _IOWR(ESOC_CODE, 9, __u64) +#define ESOC_SET_BOOT_FAIL_ACT _IOW(ESOC_CODE, 10, unsigned int) +#define ESOC_SET_N_PON_TRIES _IOW(ESOC_CODE, 11, unsigned int) #define ESOC_REQ_SEND_SHUTDOWN ESOC_REQ_SEND_SHUTDOWN #define ESOC_REQ_CRASH_SHUTDOWN ESOC_REQ_CRASH_SHUTDOWN #define ESOC_PON_RETRY ESOC_PON_RETRY +#define ESOC_BOOT_FAIL_ACTION #define ESOC_LINK_ID +enum esoc_boot_fail_action { + BOOT_FAIL_ACTION_RETRY, + BOOT_FAIL_ACTION_COLD_RESET, + BOOT_FAIL_ACTION_SHUTDOWN, + BOOT_FAIL_ACTION_PANIC, + BOOT_FAIL_ACTION_NOP, + BOOT_FAIL_ACTION_S3_RESET, + BOOT_FAIL_ACTION_LAST, +}; + enum esoc_evt { ESOC_RUN_STATE = 0x1, ESOC_UNEXPECTED_RESET, diff --git a/include/uapi/linux/ipa_qmi_service_v01.h b/include/uapi/linux/ipa_qmi_service_v01.h index 461ccc862ee636d0e735e46cbce020da63e87855..eee60ddbee743811f554b21ed0a6a7d8347bef47 100644 --- a/include/uapi/linux/ipa_qmi_service_v01.h +++ b/include/uapi/linux/ipa_qmi_service_v01.h @@ -64,6 +64,7 @@ * Indicates presence of newly added member to support HW stats. */ #define IPA_QMI_SUPPORTS_STATS +#define IPA_QMI_SUPPORT_MHI_DEFAULT #define IPA_INT_MAX ((int)(~0U>>1)) #define IPA_INT_MIN (-IPA_INT_MAX - 1) @@ -2606,8 +2607,14 @@ struct ipa_add_offload_connection_req_msg_v01 { /* Must be set to true if embedded_call_mux_id is being passed */ uint32_t embedded_call_mux_id; /* Mux ID for the new embedded call */ + /* Optional */ + /* Default MHI path */ + uint8_t default_mhi_path_valid; + /* Must be set to true if default_mhi_path is being passed */ + uint8_t default_mhi_path; + /* Default MHI path */ }; /* Message */ -#define IPA_ADD_OFFLOAD_CONNECTION_REQ_MSG_V01_MAX_MSG_LEN 11357 +#define IPA_ADD_OFFLOAD_CONNECTION_REQ_MSG_V01_MAX_MSG_LEN 11361 struct ipa_add_offload_connection_resp_msg_v01 { /* Result Code */ @@ -2630,8 +2637,14 @@ struct ipa_remove_offload_connection_req_msg_v01 { uint32_t filter_handle_list_len; struct ipa_filter_rule_identifier_to_handle_map_v01 filter_handle_list[QMI_IPA_MAX_FILTERS_V01]; + /* Optional */ + /* Clean All rules */ + uint8_t clean_all_rules_valid; + /* Must be set to true if clean_all_rules is being passed */ + uint8_t clean_all_rules; + /* Clean All rules */ }; /* Message */ -#define IPA_REMOVE_OFFLOAD_CONNECTION_REQ_MSG_V01_MAX_MSG_LEN 516 +#define IPA_REMOVE_OFFLOAD_CONNECTION_REQ_MSG_V01_MAX_MSG_LEN 520 struct ipa_remove_offload_connection_resp_msg_v01 { /* optional */ diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 568ecb0bea07b02272a1e7e25e54815f204b9fe9..3c5560c78e834f4dbddbea197c00abbc50991118 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -1962,6 +1962,8 @@ struct ipa_ioc_ext_intf_prop { uint8_t is_xlat_rule; uint32_t rule_id; uint8_t is_rule_hashable; +#define IPA_V6_UL_WL_FIREWALL_HANDLE + uint8_t replicate_needed; }; /** diff --git a/include/uapi/linux/netfilter/xt_cgroup.h b/include/uapi/linux/netfilter/xt_cgroup.h index e96dfa1b34f7ff8a118105b936b2e1324d7ebe94..b74e370d613346b1669082313ef6de4b6ed3ed4b 100644 --- a/include/uapi/linux/netfilter/xt_cgroup.h +++ b/include/uapi/linux/netfilter/xt_cgroup.h @@ -22,4 +22,20 @@ struct xt_cgroup_info_v1 { void *priv __attribute__((aligned(8))); }; +#define XT_CGROUP_PATH_MAX 512 + +struct xt_cgroup_info_v2 { + __u8 has_path; + __u8 has_classid; + __u8 invert_path; + __u8 invert_classid; + union { + char path[XT_CGROUP_PATH_MAX]; + __u32 classid; + }; + + /* kernel internal data */ + void *priv __attribute__((aligned(8))); +}; + #endif /* _UAPI_XT_CGROUP_H */ diff --git a/include/uapi/linux/qbt1000.h b/include/uapi/linux/qbt1000.h index 0012d23029cec5fcd241e3f10997a9f19b23cd3b..41c6a0bfcbbbed291f63f924a5e28dd5ac6b32c1 100644 --- a/include/uapi/linux/qbt1000.h +++ b/include/uapi/linux/qbt1000.h @@ -21,6 +21,8 @@ enum qbt1000_commands { QBT1000_CONFIGURE_POWER_KEY = 104 }; #define QBT1000_ENABLE_GESTURES 105 +#define QBT1000_ACQUIRE_WAKELOCK 106 +#define QBT1000_RELEASE_WAKELOCK 107 /* * enum qbt1000_fw_event - diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index dbb39efbf3e5575c88ea09519531d7ca092fb3f2..5af6fb88086e32aeb83894d144d313866fa3ca18 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -735,6 +735,9 @@ enum v4l2_mpeg_vidc_extradata { V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW = 8, V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 9, V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB = 11, +#define V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP \ + V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP + V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP = 13, V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO = 15, V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP = 16, V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA = 17, diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 6d5c3b2d4f4d55368564e6e2ce003a1cb0b6d33b..c9c11445593be16b8ab58ae2eb657b8ce19f8a39 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -43,5 +43,10 @@ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ +#define VIRTIO_ID_CLOCK 30 /* virtio clock */ +#define VIRTIO_ID_REGULATOR 31 /* virtio regulator */ + +#define VIRTIO_ID_I2C 32 /* virtio i2c */ +#define VIRTIO_ID_SPMI 33 /* virtio spmi */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index de32a61b539c43a5ac810c782bd9a790995824c9..68e8446f1585c1f07f5b430d45c67d4efbe154b2 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -91,6 +91,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 #define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP 10 /* Per Path Usage Data */ #define CAM_ISP_USAGE_INVALID 0 @@ -500,4 +501,14 @@ struct cam_isp_acquire_hw_info { #define CAM_ISP_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_out_port_info) +/** + * struct cam_isp_init_frame_drop_config - init frame drop configuration + * + * @init_frame_drop: Initial number of frames needs to drop + */ + +struct cam_isp_init_frame_drop_config { + uint32_t init_frame_drop; +} __attribute__((packed)); + #endif /* __UAPI_CAM_ISP_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index b903078dccbdeddd65953b2e284078ab16e428f5..defed877b52d3653b1f5d31ed7a0e4ed2f3de85b 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -24,6 +24,7 @@ #define CAM_FLASH_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 11) #define CAM_EEPROM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 12) #define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13) +#define CAM_IRLED_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 14) /* cam_req_mgr hdl info */ #define CAM_REQ_MGR_HDL_IDX_POS 8 @@ -35,6 +36,7 @@ * It includes both session and device handles */ #define CAM_REQ_MGR_MAX_HANDLES 64 +#define CAM_REQ_MGR_MAX_HANDLES_V2 128 #define MAX_LINKS_PER_SESSION 2 /* V4L event type which user space will subscribe to */ @@ -121,6 +123,20 @@ struct cam_req_mgr_link_info { int32_t link_hdl; }; +struct cam_req_mgr_link_info_v2 { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES_V2]; + int32_t link_hdl; +}; + +struct cam_req_mgr_ver_info { + uint32_t version; + union { + struct cam_req_mgr_link_info link_info_v1; + struct cam_req_mgr_link_info_v2 link_info_v2; + } u; +}; /** * struct cam_req_mgr_unlink_info * @session_hdl: input param - session handle @@ -230,6 +246,7 @@ struct cam_req_mgr_link_control { #define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11) #define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) #define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) +#define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) /* end of cam_req_mgr opcodes */ #define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index f5af6047f5ac8801288f90c8a736a7f0ff4024e9..8fc180b7b632594f8efd81068da8f4f6ba32007c 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -9,6 +9,7 @@ #define CAM_FLASH_MAX_LED_TRIGGERS 3 #define MAX_OIS_NAME_SIZE 32 #define CAM_CSIPHY_SECURE_MODE_ENABLED 1 +#define CAM_IR_LED_SUPPORTED /** * struct cam_sensor_query_cap - capabilities info for sensor * @@ -22,6 +23,7 @@ * @ois_slot_id : OIS slot id which connected to sensor * @flash_slot_id : Flash slot id which connected to sensor * @csiphy_slot_id : CSIphy slot id which connected to sensor + * @irled_slot_id : IRLED slot id which connected to sensor * */ struct cam_sensor_query_cap { @@ -35,6 +37,7 @@ struct cam_sensor_query_cap { uint32_t ois_slot_id; uint32_t flash_slot_id; uint32_t csiphy_slot_id; + uint32_t ir_led_slot_id; } __attribute__((packed)); /** @@ -474,4 +477,32 @@ struct cam_flash_query_cap_info { uint32_t max_current_torch[CAM_FLASH_MAX_LED_TRIGGERS]; } __attribute__ ((packed)); +/** + * struct cam_ir_led_query_cap : capabilities info for ir_led + * + * @slot_info : Indicates about the slotId or cell Index + * + */ +struct cam_ir_led_query_cap_info { + uint32_t slot_info; +} __attribute__ ((packed)); + +/** + * struct cam_ir_ledset_on_off : led turn on/off command buffer + * + * @opcode : command buffer opcodes + * @cmd_type : command buffer operation type + * @ir_led_intensity : ir led intensity level + * @pwm_duty_on_ns : PWM duty cycle in ns for IRLED intensity + * @pwm_period_ns : PWM period in ns + * + */ +struct cam_ir_led_set_on_off { + uint16_t reserved; + uint8_t opcode; + uint8_t cmd_type; + uint32_t ir_led_intensity; + uint32_t pwm_duty_on_ns; + uint32_t pwm_period_ns; +} __attribute__((packed)); #endif diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h index 18276f5c27e13105d581ac5f9f94f1f16e6cb8ca..4a86e1f3084ead69247f95452be0ad778f0642e1 100644 --- a/include/uapi/media/msm_cam_sensor.h +++ b/include/uapi/media/msm_cam_sensor.h @@ -155,6 +155,8 @@ enum csid_cfg_type_t { CSID_CFG, CSID_TESTMODE_CFG, CSID_RELEASE, + CSID_SECCAM_TOPOLOGY, + CSID_SECCAM_RESET, }; enum csiphy_cfg_type_t { diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h index 224ef9cdc3f983eb82173cf18f73b7277892f90f..13dd801678d01a6025c5d46d58b92fada031a61c 100644 --- a/include/uapi/media/msm_camera.h +++ b/include/uapi/media/msm_camera.h @@ -1367,6 +1367,7 @@ struct msm_camera_csid_params { uint8_t lane_cnt; uint16_t lane_assign; uint8_t phy_sel; + uint32_t topology; struct msm_camera_csid_lut_params lut_params; }; @@ -1411,6 +1412,8 @@ struct csic_cfg_data { enum csid_cfg_type_t { CSID_INIT, CSID_CFG, + CSID_SECCAM_TOPOLOGY, + CSID_SECCAM_RESET, }; struct csid_cfg_data { diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h index 082a83e386c6213637453df063c1e459c9258eb0..b5ff07592ad9496878ae156461e0968e6a447ac1 100644 --- a/include/uapi/media/msm_camsensor_sdk.h +++ b/include/uapi/media/msm_camsensor_sdk.h @@ -54,6 +54,8 @@ #define SECURE_CAMERA +#define SECURE_CAM_RST_MODULES + enum msm_sensor_camera_id_t { CAMERA_0, CAMERA_1, @@ -355,6 +357,8 @@ struct msm_camera_csid_params { struct msm_camera_csid_lut_params lut_params; unsigned char csi_3p_sel; unsigned char is_secure; + uint32_t topology; + unsigned char is_streamon; }; struct msm_camera_csid_testmode_parms { diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index c77824ae6d66665768b3c86269c2bd154baf2cf0..5ef82a4c8de902d435745f844569166d0e907962 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -657,6 +657,7 @@ enum msm_isp_event_mask_index { ISP_EVENT_MASK_INDEX_REG_UPDATE_MISSING = 10, ISP_EVENT_MASK_INDEX_PING_PONG_MISMATCH = 11, ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR = 12, + ISP_EVENT_MASK_INDEX_SOF_UPDATE_NANOSEC = 13, }; @@ -701,6 +702,9 @@ enum msm_isp_event_mask_index { #define ISP_EVENT_SUBS_MASK_BUF_FATAL_ERROR \ (1 << ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR) +#define ISP_EVENT_SUBS_MASK_SOF_UPDATE_NANOSEC \ + (1 << ISP_EVENT_MASK_INDEX_SOF_UPDATE_NANOSEC) + enum msm_isp_event_idx { ISP_REG_UPDATE = 0, ISP_EPOCH_0 = 1, @@ -738,6 +742,7 @@ enum msm_isp_event_idx { #define ISP_EVENT_ERROR (ISP_EVENT_BASE + ISP_ERROR) #define ISP_EVENT_SOF (ISP_CAMIF_EVENT_BASE) #define ISP_EVENT_EOF (ISP_CAMIF_EVENT_BASE + 1) +#define ISP_EVENT_SOF_UPDATE_NANOSEC (ISP_CAMIF_EVENT_BASE + 512) #define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE) #define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE) #define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE) @@ -872,6 +877,12 @@ struct msm_isp_event_data { } u; /* union can have max 52 bytes */ }; +struct msm_isp_event_data_nanosec { + /* nano second timestamp */ + uint64_t nano_timestamp; + uint32_t frame_id; +}; + struct msm_isp32_event_data { /*Wall clock except for buffer divert events *which use monotonic clock @@ -923,6 +934,10 @@ struct msm_vfe_dual_vfe_sync_mode { uint32_t enable; }; +struct msm_vfe_nano_sec_timestamp { + uint32_t enable; +}; + #define V4L2_PIX_FMT_QBGGR8 v4l2_fourcc('Q', 'B', 'G', '8') #define V4L2_PIX_FMT_QGBRG8 v4l2_fourcc('Q', 'G', 'B', '8') #define V4L2_PIX_FMT_QGRBG8 v4l2_fourcc('Q', 'G', 'R', '8') @@ -991,6 +1006,7 @@ enum msm_isp_ioctl_cmd_code { MSM_ISP32_REQUEST_STREAM, MSM_ISP_DUAL_SYNC_CFG, MSM_ISP_DUAL_SYNC_CFG_VER2, + MSM_ISP_NANOSEC_TIMESTAMP, }; #define VIDIOC_MSM_VFE_REG_CFG \ @@ -1129,4 +1145,8 @@ enum msm_isp_ioctl_cmd_code { _IOWR('V', MSM_ISP_DUAL_SYNC_CFG_VER2, \ struct msm_vfe_dual_vfe_sync_mode) +#define VIDIOC_MSM_ISP_NANOSEC_TIMESTAMP \ + _IOW('V', MSM_ISP_NANOSEC_TIMESTAMP, \ + struct msm_vfe_nano_sec_timestamp) + #endif /* __MSMB_ISP__ */ diff --git a/init/Makefile b/init/Makefile index 0320e1a0705d20778f016cee1c425b5da278868b..00b39d4cf5d998d78bee468eb8a08e59331afcc8 100644 --- a/init/Makefile +++ b/init/Makefile @@ -19,6 +19,7 @@ mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o mounts-$(CONFIG_BLK_DEV_DM) += do_mounts_dm.o +mounts-$(CONFIG_BLK_DEV_DM) += do_mounts_verity.o # dependencies on generated files need to be listed explicitly $(obj)/version.o: include/generated/compile.h diff --git a/init/do_mounts.c b/init/do_mounts.c index ca5de99f311ce57f8826b607c4750def57c959b3..f44460bc83724d7f8312cb833ca8d87d757046e2 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -576,6 +576,7 @@ void __init prepare_namespace(void) md_run_setup(); dm_run_setup(); + dm_verity_setup(); if (saved_root_name[0]) { root_device_name = saved_root_name; diff --git a/init/do_mounts.h b/init/do_mounts.h index cd201124714b5c35c8776f34a1b325e5a888a306..9dfd4138aca8f03ad7e0d1f399c27714c102b813 100644 --- a/init/do_mounts.h +++ b/init/do_mounts.h @@ -8,6 +8,8 @@ #include #include #include +#include "uapi/linux/dm-ioctl.h" +#include void change_floppy(char *fmt, ...); void mount_block_root(char *name, int flags); @@ -71,3 +73,15 @@ void dm_run_setup(void); static inline void dm_run_setup(void) {} #endif + +#ifdef CONFIG_BLK_DEV_DM + +void dm_verity_setup(void); +extern int dm_ioctrl(uint cmd, struct dm_ioctl *param); +extern void dm_table_destroy(struct dm_table *t); + +#else + +static inline void dm_verity_setup(void) {} + +#endif diff --git a/init/do_mounts_verity.c b/init/do_mounts_verity.c new file mode 100644 index 0000000000000000000000000000000000000000..aa5893db2a017de5f3c38776e528b63346f47483 --- /dev/null +++ b/init/do_mounts_verity.c @@ -0,0 +1,193 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "uapi/linux/dm-ioctl.h" +#include +#include +#include "do_mounts.h" + +#define DM_BUF_SIZE 4096 + +#define DM_MSG_PREFIX "verity" + +static void __init init_param(struct dm_ioctl *param, const char *name) +{ + memset(param, 0, DM_BUF_SIZE); + param->data_size = DM_BUF_SIZE; + param->data_start = sizeof(struct dm_ioctl); + param->version[0] = 4; + param->version[1] = 0; + param->version[2] = 0; + param->flags = DM_READONLY_FLAG; + strlcpy(param->name, name, sizeof(param->name)); +} + +static void __init dm_setup_drive(void) +{ + struct device_node *dt_node; + const char *name; + const char *version; + const char *data_device; + const char *hash_device; + const char *data_block_size; + const char *hash_block_size; + const char *number_of_data_blocks; + const char *hash_start_block; + const char *algorithm; + const char *digest; + const char *salt; + const char *opt; + int len; + unsigned long long data_blocks; + char dummy; + char *verity_params; + size_t bufsize; + char *buffer = kzalloc(DM_BUF_SIZE, GFP_KERNEL); + struct dm_ioctl *param = (struct dm_ioctl *) buffer; + size_t dm_sz = sizeof(struct dm_ioctl); + struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[dm_sz]; + + if (!buffer) + goto fail; + dt_node = of_find_node_by_path("/soc/dm_verity"); + if (!dt_node) { + DMERR("(E) Failed to find device-tree node: /soc/dm_verity"); + goto fail; + } + + name = of_get_property(dt_node, "dmname", &len); + if (name == NULL) + goto fail; + DMDEBUG("(I) name=%s", name); + + if (strcmp(name, "disabled") == 0) { + pr_info("dm: dm-verity is disabled."); + kfree(buffer); + return; + } + + version = of_get_property(dt_node, "version", &len); + if (version == NULL) + goto fail; + DMDEBUG("(I) version=%s", version); + + data_device = of_get_property(dt_node, "data_device", &len); + if (data_device == NULL) + goto fail; + DMDEBUG("(I) data_device=%s", data_device); + + hash_device = of_get_property(dt_node, "hash_device", &len); + if (hash_device == NULL) + goto fail; + DMDEBUG("(I) hash_device=%s", hash_device); + + data_block_size = of_get_property(dt_node, "data_block_size", &len); + if (data_block_size == NULL) + goto fail; + DMDEBUG("(I) data_block_size=%s", data_block_size); + + hash_block_size = of_get_property(dt_node, "hash_block_size", &len); + if (hash_block_size == NULL) + goto fail; + DMDEBUG("(I) hash_block_size=%s", hash_block_size); + + number_of_data_blocks = of_get_property(dt_node, + "number_of_data_blocks", + &len); + if (number_of_data_blocks == NULL) + goto fail; + DMDEBUG("(I) number_of_data_blocks=%s", number_of_data_blocks); + + hash_start_block = of_get_property(dt_node, "hash_start_block", &len); + if (hash_start_block == NULL) + goto fail; + DMDEBUG("(I) hash_start_block=%s", hash_start_block); + + algorithm = of_get_property(dt_node, "algorithm", &len); + if (algorithm == NULL) + goto fail; + DMDEBUG("(I) algorithm=%s", algorithm); + + digest = of_get_property(dt_node, "digest", &len); + if (digest == NULL) + goto fail; + DMDEBUG("(I) digest=%s", digest); + + salt = of_get_property(dt_node, "salt", &len); + if (salt == NULL) + goto fail; + DMDEBUG("(I) salt=%s", salt); + + opt = of_get_property(dt_node, "opt", &len); + if (opt == NULL) + goto fail; + DMDEBUG("(I) opt=%s", opt); + + init_param(param, name); + if (dm_ioctrl(DM_DEV_CREATE_CMD, param)) { + DMERR("(E) failed to create the device"); + goto fail; + } + + init_param(param, name); + param->target_count = 1; + /* set tgt arguments */ + tgt->status = 0; + tgt->sector_start = 0; + if (sscanf(number_of_data_blocks, "%llu%c", &data_blocks, &dummy) != 1) + goto fail; + + tgt->length = data_blocks*4096/512; /* size in sector of data dev */ + strlcpy(tgt->target_type, "verity", sizeof(tgt->target_type)); + /* build the verity params here */ + verity_params = buffer + dm_sz + sizeof(struct dm_target_spec); + bufsize = DM_BUF_SIZE - (verity_params - buffer); + + verity_params += snprintf(verity_params, bufsize, + "%s %s %s %s %s %s %s %s %s %s 1 %s", + version, + data_device, hash_device, + data_block_size, hash_block_size, + number_of_data_blocks, hash_start_block, + algorithm, digest, salt, opt); + + tgt->next = verity_params - buffer; + if (dm_ioctrl(DM_TABLE_LOAD_CMD, param)) { + DMERR("(E) failed to load the device"); + goto fail; + } + + init_param(param, name); + if (dm_ioctrl(DM_DEV_SUSPEND_CMD, param)) { + DMERR("(E) failed to suspend the device"); + goto fail; + } + + pr_info("dm: dm-0 (%s) is ready", data_device); + kfree(buffer); + return; + +fail: + pr_info("dm: starting dm-0 failed"); + kfree(buffer); + return; + +} + +void __init dm_verity_setup(void) +{ + pr_info("dm: attempting early device configuration."); + dm_setup_drive(); +} diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index d203a5d6b726d6bb80cb7162b0a6e7c534ef67df..e46106c6ac393033eeb2d39660f20d5a37548b30 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -51,6 +51,7 @@ #define DST regs[insn->dst_reg] #define SRC regs[insn->src_reg] #define FP regs[BPF_REG_FP] +#define AX regs[BPF_REG_AX] #define ARG1 regs[BPF_REG_ARG1] #define CTX regs[BPF_REG_CTX] #define IMM insn->imm @@ -552,6 +553,26 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from, BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG); BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG); + /* Constraints on AX register: + * + * AX register is inaccessible from user space. It is mapped in + * all JITs, and used here for constant blinding rewrites. It is + * typically "stateless" meaning its contents are only valid within + * the executed instruction, but not across several instructions. + * There are a few exceptions however which are further detailed + * below. + * + * Constant blinding is only used by JITs, not in the interpreter. + * The interpreter uses AX in some occasions as a local temporary + * register e.g. in DIV or MOD instructions. + * + * In restricted circumstances, the verifier can also use the AX + * register for rewrites as long as they do not interfere with + * the above cases! + */ + if (from->dst_reg == BPF_REG_AX || from->src_reg == BPF_REG_AX) + goto out; + if (from->imm == 0 && (from->code == (BPF_ALU | BPF_MOV | BPF_K) || from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) { @@ -939,22 +960,22 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, ALU64_MOD_X: if (unlikely(SRC == 0)) return 0; - div64_u64_rem(DST, SRC, &tmp); - DST = tmp; + div64_u64_rem(DST, SRC, &AX); + DST = AX; CONT; ALU_MOD_X: if (unlikely((u32)SRC == 0)) return 0; - tmp = (u32) DST; - DST = do_div(tmp, (u32) SRC); + AX = (u32) DST; + DST = do_div(AX, (u32) SRC); CONT; ALU64_MOD_K: - div64_u64_rem(DST, IMM, &tmp); - DST = tmp; + div64_u64_rem(DST, IMM, &AX); + DST = AX; CONT; ALU_MOD_K: - tmp = (u32) DST; - DST = do_div(tmp, (u32) IMM); + AX = (u32) DST; + DST = do_div(AX, (u32) IMM); CONT; ALU64_DIV_X: if (unlikely(SRC == 0)) @@ -964,17 +985,17 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, ALU_DIV_X: if (unlikely((u32)SRC == 0)) return 0; - tmp = (u32) DST; - do_div(tmp, (u32) SRC); - DST = (u32) tmp; + AX = (u32) DST; + do_div(AX, (u32) SRC); + DST = (u32) AX; CONT; ALU64_DIV_K: DST = div64_u64(DST, IMM); CONT; ALU_DIV_K: - tmp = (u32) DST; - do_div(tmp, (u32) IMM); - DST = (u32) tmp; + AX = (u32) DST; + do_div(AX, (u32) IMM); + DST = (u32) AX; CONT; ALU_END_TO_BE: switch (IMM) { @@ -1278,7 +1299,7 @@ STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */ static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \ { \ u64 stack[stack_size / sizeof(u64)]; \ - u64 regs[MAX_BPF_REG]; \ + u64 regs[MAX_BPF_EXT_REG]; \ \ FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \ ARG1 = (u64) (unsigned long) ctx; \ diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 01aaef1a77c5af164660b0f75ac99e4bd7c55a52..e2821e8834f2d008218ffcad5a0f9a193d1da7f3 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -370,19 +370,6 @@ int bpf_obj_get_user(const char __user *pathname, int flags) } EXPORT_SYMBOL_GPL(bpf_obj_get_user); -static void bpf_evict_inode(struct inode *inode) -{ - enum bpf_type type; - - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); - - if (S_ISLNK(inode->i_mode)) - kfree(inode->i_link); - if (!bpf_inode_type(inode, &type)) - bpf_any_put(inode->i_private, type); -} - /* * Display the mount options in /proc/mounts. */ @@ -395,11 +382,28 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) return 0; } +static void bpf_destroy_inode_deferred(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + enum bpf_type type; + + if (S_ISLNK(inode->i_mode)) + kfree(inode->i_link); + if (!bpf_inode_type(inode, &type)) + bpf_any_put(inode->i_private, type); + free_inode_nonrcu(inode); +} + +static void bpf_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, bpf_destroy_inode_deferred); +} + static const struct super_operations bpf_super_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .show_options = bpf_show_options, - .evict_inode = bpf_evict_inode, + .destroy_inode = bpf_destroy_inode, }; enum { diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index 1da574612bea75dabfe60c6967dce9c55a5e662b..c0c494b7647bd6fdd365dab749768f46dc29a2a3 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -12,6 +12,7 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) { struct bpf_map *inner_map, *inner_map_meta; + u32 inner_map_meta_size; struct fd f; f = fdget(inner_map_ufd); @@ -34,7 +35,12 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) return ERR_PTR(-EINVAL); } - inner_map_meta = kzalloc(sizeof(*inner_map_meta), GFP_USER); + inner_map_meta_size = sizeof(*inner_map_meta); + /* In some cases verifier needs to access beyond just base map. */ + if (inner_map->ops == &array_map_ops) + inner_map_meta_size = sizeof(struct bpf_array); + + inner_map_meta = kzalloc(inner_map_meta_size, GFP_USER); if (!inner_map_meta) { fdput(f); return ERR_PTR(-ENOMEM); @@ -44,9 +50,16 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) inner_map_meta->key_size = inner_map->key_size; inner_map_meta->value_size = inner_map->value_size; inner_map_meta->map_flags = inner_map->map_flags; - inner_map_meta->ops = inner_map->ops; inner_map_meta->max_entries = inner_map->max_entries; + /* Misc members not needed in bpf_map_meta_equal() check. */ + inner_map_meta->ops = inner_map->ops; + if (inner_map->ops == &array_map_ops) { + inner_map_meta->unpriv_array = inner_map->unpriv_array; + container_of(inner_map_meta, struct bpf_array, map)->index_mask = + container_of(inner_map, struct bpf_array, map)->index_mask; + } + fdput(f); return inner_map_meta; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f6755fd5bae2897ff73f97c255fe068e296336e0..a4875ff0bab197f8e71aa0b0d3fdea141e55c5a6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -265,10 +265,11 @@ static void print_verifier_state(struct bpf_verifier_state *state) verbose(")"); } } - for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { - if (state->stack_slot_type[i] == STACK_SPILL) - verbose(" fp%d=%s", -MAX_BPF_STACK + i, - reg_type_str[state->spilled_regs[i / BPF_REG_SIZE].type]); + for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { + if (state->stack[i].slot_type[0] == STACK_SPILL) + verbose(" fp%d=%s", + (-i - 1) * BPF_REG_SIZE, + reg_type_str[state->stack[i].spilled_ptr.type]); } verbose("\n"); } @@ -434,40 +435,133 @@ static void print_bpf_insn(const struct bpf_verifier_env *env, } } -static int pop_stack(struct bpf_verifier_env *env, int *prev_insn_idx) +static int copy_stack_state(struct bpf_verifier_state *dst, + const struct bpf_verifier_state *src) { - struct bpf_verifier_stack_elem *elem; - int insn_idx; + if (!src->stack) + return 0; + if (WARN_ON_ONCE(dst->allocated_stack < src->allocated_stack)) { + /* internal bug, make state invalid to reject the program */ + memset(dst, 0, sizeof(*dst)); + return -EFAULT; + } + memcpy(dst->stack, src->stack, + sizeof(*src->stack) * (src->allocated_stack / BPF_REG_SIZE)); + return 0; +} + +/* do_check() starts with zero-sized stack in struct bpf_verifier_state to + * make it consume minimal amount of memory. check_stack_write() access from + * the program calls into realloc_verifier_state() to grow the stack size. + * Note there is a non-zero 'parent' pointer inside bpf_verifier_state + * which this function copies over. It points to previous bpf_verifier_state + * which is never reallocated + */ +static int realloc_verifier_state(struct bpf_verifier_state *state, int size, + bool copy_old) +{ + u32 old_size = state->allocated_stack; + struct bpf_stack_state *new_stack; + int slot = size / BPF_REG_SIZE; + + if (size <= old_size || !size) { + if (copy_old) + return 0; + state->allocated_stack = slot * BPF_REG_SIZE; + if (!size && old_size) { + kfree(state->stack); + state->stack = NULL; + } + return 0; + } + new_stack = kmalloc_array(slot, sizeof(struct bpf_stack_state), + GFP_KERNEL); + if (!new_stack) + return -ENOMEM; + if (copy_old) { + if (state->stack) + memcpy(new_stack, state->stack, + sizeof(*new_stack) * (old_size / BPF_REG_SIZE)); + memset(new_stack + old_size / BPF_REG_SIZE, 0, + sizeof(*new_stack) * (size - old_size) / BPF_REG_SIZE); + } + state->allocated_stack = slot * BPF_REG_SIZE; + kfree(state->stack); + state->stack = new_stack; + return 0; +} + +static void free_verifier_state(struct bpf_verifier_state *state, + bool free_self) +{ + kfree(state->stack); + if (free_self) + kfree(state); +} + +/* copy verifier state from src to dst growing dst stack space + * when necessary to accommodate larger src stack + */ +static int copy_verifier_state(struct bpf_verifier_state *dst, + const struct bpf_verifier_state *src) +{ + int err; + + err = realloc_verifier_state(dst, src->allocated_stack, false); + if (err) + return err; + memcpy(dst, src, offsetof(struct bpf_verifier_state, allocated_stack)); + return copy_stack_state(dst, src); +} + +static int pop_stack(struct bpf_verifier_env *env, int *prev_insn_idx, + int *insn_idx) +{ + struct bpf_verifier_state *cur = env->cur_state; + struct bpf_verifier_stack_elem *elem, *head = env->head; + int err; if (env->head == NULL) - return -1; + return -ENOENT; - memcpy(&env->cur_state, &env->head->st, sizeof(env->cur_state)); - insn_idx = env->head->insn_idx; + if (cur) { + err = copy_verifier_state(cur, &head->st); + if (err) + return err; + } + if (insn_idx) + *insn_idx = head->insn_idx; if (prev_insn_idx) - *prev_insn_idx = env->head->prev_insn_idx; - elem = env->head->next; - kfree(env->head); + *prev_insn_idx = head->prev_insn_idx; + elem = head->next; + free_verifier_state(&head->st, false); + kfree(head); env->head = elem; env->stack_size--; - return insn_idx; + return 0; } static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env, - int insn_idx, int prev_insn_idx) + int insn_idx, int prev_insn_idx, + bool speculative) { struct bpf_verifier_stack_elem *elem; + struct bpf_verifier_state *cur = env->cur_state; + int err; - elem = kmalloc(sizeof(struct bpf_verifier_stack_elem), GFP_KERNEL); + elem = kzalloc(sizeof(struct bpf_verifier_stack_elem), GFP_KERNEL); if (!elem) goto err; - memcpy(&elem->st, &env->cur_state, sizeof(env->cur_state)); elem->insn_idx = insn_idx; elem->prev_insn_idx = prev_insn_idx; elem->next = env->head; + elem->st.speculative |= speculative; env->head = elem; env->stack_size++; + err = copy_verifier_state(&elem->st, cur); + if (err) + goto err; if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) { verbose("BPF program is too complex\n"); goto err; @@ -475,7 +569,7 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env, return &elem->st; err: /* pop all elements and return */ - while (pop_stack(env, NULL) >= 0); + while (!pop_stack(env, NULL, NULL)); return NULL; } @@ -671,7 +765,7 @@ static void mark_reg_read(const struct bpf_verifier_state *state, u32 regno) static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, enum reg_arg_type t) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = env->cur_state->regs; if (regno >= MAX_BPF_REG) { verbose("R%d is invalid\n", regno); @@ -684,7 +778,7 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, verbose("R%d !read_ok\n", regno); return -EACCES; } - mark_reg_read(&env->cur_state, regno); + mark_reg_read(env->cur_state, regno); } else { /* check whether register used as dest operand can be written to */ if (regno == BPF_REG_FP) { @@ -721,10 +815,21 @@ static int check_stack_write(struct bpf_verifier_env *env, struct bpf_verifier_state *state, int off, int size, int value_regno, int insn_idx) { - int i, spi = (MAX_BPF_STACK + off) / BPF_REG_SIZE; + int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err; + + err = realloc_verifier_state(state, round_up(slot + 1, BPF_REG_SIZE), + true); + if (err) + return err; /* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0, * so it's aligned access and [off, off + size) are within stack limits */ + if (!env->allow_ptr_leaks && + state->stack[spi].slot_type[0] == STACK_SPILL && + size != BPF_REG_SIZE) { + verbose("attempt to corrupt spilled pointer on stack\n"); + return -EACCES; + } if (value_regno >= 0 && is_spillable_regtype(state->regs[value_regno].type)) { @@ -736,11 +841,11 @@ static int check_stack_write(struct bpf_verifier_env *env, } /* save register state */ - state->spilled_regs[spi] = state->regs[value_regno]; - state->spilled_regs[spi].live |= REG_LIVE_WRITTEN; + state->stack[spi].spilled_ptr = state->regs[value_regno]; + state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; for (i = 0; i < BPF_REG_SIZE; i++) { - if (state->stack_slot_type[MAX_BPF_STACK + off + i] == STACK_MISC && + if (state->stack[spi].slot_type[i] == STACK_MISC && !env->allow_ptr_leaks) { int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off; int soff = (-spi - 1) * BPF_REG_SIZE; @@ -763,14 +868,15 @@ static int check_stack_write(struct bpf_verifier_env *env, } *poff = soff; } - state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_SPILL; + state->stack[spi].slot_type[i] = STACK_SPILL; } } else { /* regular write of data into stack */ - state->spilled_regs[spi] = (struct bpf_reg_state) {}; + state->stack[spi].spilled_ptr = (struct bpf_reg_state) {}; for (i = 0; i < size; i++) - state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_MISC; + state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] = + STACK_MISC; } return 0; } @@ -781,10 +887,10 @@ static void mark_stack_slot_read(const struct bpf_verifier_state *state, int slo while (parent) { /* if read wasn't screened by an earlier write ... */ - if (state->spilled_regs[slot].live & REG_LIVE_WRITTEN) + if (state->stack[slot].spilled_ptr.live & REG_LIVE_WRITTEN) break; /* ... then we depend on parent's value */ - parent->spilled_regs[slot].live |= REG_LIVE_READ; + parent->stack[slot].spilled_ptr.live |= REG_LIVE_READ; state = parent; parent = state->parent; } @@ -793,34 +899,37 @@ static void mark_stack_slot_read(const struct bpf_verifier_state *state, int slo static int check_stack_read(struct bpf_verifier_state *state, int off, int size, int value_regno) { - u8 *slot_type; - int i, spi; + int i, slot = -off - 1, spi = slot / BPF_REG_SIZE; + u8 *stype; - slot_type = &state->stack_slot_type[MAX_BPF_STACK + off]; + if (state->allocated_stack <= slot) { + verbose("invalid read from stack off %d+0 size %d\n", + off, size); + return -EACCES; + } + stype = state->stack[spi].slot_type; - if (slot_type[0] == STACK_SPILL) { + if (stype[0] == STACK_SPILL) { if (size != BPF_REG_SIZE) { verbose("invalid size of register spill\n"); return -EACCES; } for (i = 1; i < BPF_REG_SIZE; i++) { - if (slot_type[i] != STACK_SPILL) { + if (stype[(slot - i) % BPF_REG_SIZE] != STACK_SPILL) { verbose("corrupted spill memory\n"); return -EACCES; } } - spi = (MAX_BPF_STACK + off) / BPF_REG_SIZE; - if (value_regno >= 0) { /* restore register state from stack */ - state->regs[value_regno] = state->spilled_regs[spi]; + state->regs[value_regno] = state->stack[spi].spilled_ptr; mark_stack_slot_read(state, spi); } return 0; } else { for (i = 0; i < size; i++) { - if (slot_type[i] != STACK_MISC) { + if (stype[(slot - i) % BPF_REG_SIZE] != STACK_MISC) { verbose("invalid read from stack off %d+%d size %d\n", off, i, size); return -EACCES; @@ -833,11 +942,37 @@ static int check_stack_read(struct bpf_verifier_state *state, int off, int size, } } +static int check_stack_access(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, + int off, int size) +{ + /* Stack accesses must be at a fixed offset, so that we + * can determine what type of data were returned. See + * check_stack_read(). + */ + if (!tnum_is_const(reg->var_off)) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose("variable stack access var_off=%s off=%d size=%d", + tn_buf, off, size); + return -EACCES; + } + + if (off >= 0 || off < -MAX_BPF_STACK) { + verbose("invalid stack off=%d size=%d\n", off, size); + return -EACCES; + } + + return 0; +} + /* check read/write into map element returned by bpf_map_lookup_elem() */ static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off, int size) { - struct bpf_map *map = env->cur_state.regs[regno].map_ptr; + struct bpf_reg_state *regs = cur_regs(env); + struct bpf_map *map = regs[regno].map_ptr; if (off < 0 || size <= 0 || off + size > map->value_size) { verbose("invalid access to map value, value_size=%d off=%d size=%d\n", @@ -849,9 +984,9 @@ static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off, /* check read/write into a map element with possible variable offset */ static int check_map_access(struct bpf_verifier_env *env, u32 regno, - int off, int size) + int off, int size) { - struct bpf_verifier_state *state = &env->cur_state; + struct bpf_verifier_state *state = env->cur_state; struct bpf_reg_state *reg = &state->regs[regno]; int err; @@ -861,13 +996,17 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, */ if (log_level) print_verifier_state(state); + /* The minimum value is only important with signed * comparisons where we can't assume the floor of a * value is 0. If we are using signed variables for our * index'es we need to make sure that whatever we use * will have a set floor within our range. */ - if (reg->smin_value < 0) { + if (reg->smin_value < 0 && + (reg->smin_value == S64_MIN || + (off + reg->smin_value != (s64)(s32)(off + reg->smin_value)) || + reg->smin_value + off < 0)) { verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", regno); return -EACCES; @@ -924,7 +1063,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env, static int __check_packet_access(struct bpf_verifier_env *env, u32 regno, int off, int size) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = ®s[regno]; if (off < 0 || size <= 0 || (u64)off + size > reg->range) { @@ -938,7 +1077,7 @@ static int __check_packet_access(struct bpf_verifier_env *env, u32 regno, static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off, int size) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = ®s[regno]; int err; @@ -1008,19 +1147,19 @@ static bool __is_pointer_value(bool allow_ptr_leaks, static bool is_pointer_value(struct bpf_verifier_env *env, int regno) { - return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]); + return __is_pointer_value(env->allow_ptr_leaks, cur_regs(env) + regno); } static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) { - const struct bpf_reg_state *reg = &env->cur_state.regs[regno]; + const struct bpf_reg_state *reg = cur_regs(env) + regno; return reg->type == PTR_TO_CTX; } static bool is_pkt_reg(struct bpf_verifier_env *env, int regno) { - const struct bpf_reg_state *reg = &env->cur_state.regs[regno]; + const struct bpf_reg_state *reg = cur_regs(env) + regno; return reg->type == PTR_TO_PACKET; } @@ -1145,8 +1284,9 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn int off, int bpf_size, enum bpf_access_type t, int value_regno, bool strict_alignment_once) { - struct bpf_verifier_state *state = &env->cur_state; - struct bpf_reg_state *reg = &state->regs[regno]; + struct bpf_verifier_state *state = env->cur_state; + struct bpf_reg_state *regs = cur_regs(env); + struct bpf_reg_state *reg = regs + regno; int size, err = 0; size = bpf_size_to_bytes(bpf_size); @@ -1170,7 +1310,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn err = check_map_access(env, regno, off, size); if (!err && t == BPF_READ && value_regno >= 0) - mark_reg_unknown(state->regs, value_regno); + mark_reg_unknown(regs, value_regno); } else if (reg->type == PTR_TO_CTX) { enum bpf_reg_type reg_type = SCALAR_VALUE; @@ -1203,49 +1343,29 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn * the offset is zero. */ if (reg_type == SCALAR_VALUE) - mark_reg_unknown(state->regs, value_regno); + mark_reg_unknown(regs, value_regno); else - mark_reg_known_zero(state->regs, value_regno); - state->regs[value_regno].id = 0; - state->regs[value_regno].off = 0; - state->regs[value_regno].range = 0; - state->regs[value_regno].type = reg_type; + mark_reg_known_zero(regs, value_regno); + regs[value_regno].id = 0; + regs[value_regno].off = 0; + regs[value_regno].range = 0; + regs[value_regno].type = reg_type; } } else if (reg->type == PTR_TO_STACK) { - /* stack accesses must be at a fixed offset, so that we can - * determine what type of data were returned. - * See check_stack_read(). - */ - if (!tnum_is_const(reg->var_off)) { - char tn_buf[48]; - - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose("variable stack access var_off=%s off=%d size=%d", - tn_buf, off, size); - return -EACCES; - } off += reg->var_off.value; - if (off >= 0 || off < -MAX_BPF_STACK) { - verbose("invalid stack off=%d size=%d\n", off, size); - return -EACCES; - } + err = check_stack_access(env, reg, off, size); + if (err) + return err; if (env->prog->aux->stack_depth < -off) env->prog->aux->stack_depth = -off; - if (t == BPF_WRITE) { - if (!env->allow_ptr_leaks && - state->stack_slot_type[MAX_BPF_STACK + off] == STACK_SPILL && - size != BPF_REG_SIZE) { - verbose("attempt to corrupt spilled pointer on stack\n"); - return -EACCES; - } + if (t == BPF_WRITE) err = check_stack_write(env, state, off, size, value_regno, insn_idx); - } else { + else err = check_stack_read(state, off, size, value_regno); - } } else if (reg->type == PTR_TO_PACKET) { if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) { verbose("cannot write into packet\n"); @@ -1258,7 +1378,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn } err = check_packet_access(env, regno, off, size); if (!err && t == BPF_READ && value_regno >= 0) - mark_reg_unknown(state->regs, value_regno); + mark_reg_unknown(regs, value_regno); } else { verbose("R%d invalid mem access '%s'\n", regno, reg_type_str[reg->type]); @@ -1266,9 +1386,9 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn } if (!err && size < BPF_REG_SIZE && value_regno >= 0 && t == BPF_READ && - state->regs[value_regno].type == SCALAR_VALUE) { + regs[value_regno].type == SCALAR_VALUE) { /* b/h/w load zero-extends, mark upper bits as known 0 */ - coerce_reg_to_size(&state->regs[value_regno], size); + coerce_reg_to_size(®s[value_regno], size); } return err; } @@ -1333,9 +1453,9 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno, int access_size, bool zero_size_allowed, struct bpf_call_arg_meta *meta) { - struct bpf_verifier_state *state = &env->cur_state; + struct bpf_verifier_state *state = env->cur_state; struct bpf_reg_state *regs = state->regs; - int off, i; + int off, i, slot, spi; if (regs[regno].type != PTR_TO_STACK) { /* Allow zero-byte read from NULL, regardless of pointer type */ @@ -1376,7 +1496,11 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno, } for (i = 0; i < access_size; i++) { - if (state->stack_slot_type[MAX_BPF_STACK + off + i] != STACK_MISC) { + slot = -(off + i) - 1; + spi = slot / BPF_REG_SIZE; + if (state->allocated_stack <= slot || + state->stack[spi].slot_type[slot % BPF_REG_SIZE] != + STACK_MISC) { verbose("invalid indirect read from stack off %d+%d size %d\n", off, i, access_size); return -EACCES; @@ -1389,7 +1513,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno, int access_size, bool zero_size_allowed, struct bpf_call_arg_meta *meta) { - struct bpf_reg_state *regs = env->cur_state.regs, *reg = ®s[regno]; + struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; switch (reg->type) { case PTR_TO_PACKET: @@ -1406,7 +1530,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta) { - struct bpf_reg_state *regs = env->cur_state.regs, *reg = ®s[regno]; + struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; enum bpf_reg_type expected_type, type = reg->type; int err = 0; @@ -1678,7 +1802,7 @@ static int check_raw_mode(const struct bpf_func_proto *fn) */ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) { - struct bpf_verifier_state *state = &env->cur_state; + struct bpf_verifier_state *state = env->cur_state; struct bpf_reg_state *regs = state->regs, *reg; int i; @@ -1687,10 +1811,10 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) regs[i].type == PTR_TO_PACKET_END) mark_reg_unknown(regs, i); - for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { - if (state->stack_slot_type[i] != STACK_SPILL) + for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { + if (state->stack[i].slot_type[0] != STACK_SPILL) continue; - reg = &state->spilled_regs[i / BPF_REG_SIZE]; + reg = &state->stack[i].spilled_ptr; if (reg->type != PTR_TO_PACKET && reg->type != PTR_TO_PACKET_END) continue; @@ -1700,9 +1824,8 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) { - struct bpf_verifier_state *state = &env->cur_state; const struct bpf_func_proto *fn = NULL; - struct bpf_reg_state *regs = state->regs; + struct bpf_reg_state *regs; struct bpf_call_arg_meta meta; bool changes_data; int i, err; @@ -1776,6 +1899,7 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) return err; } + regs = cur_regs(env); /* reset caller saved regs */ for (i = 0; i < CALLER_SAVED_REGS; i++) { mark_reg_not_init(regs, caller_saved[i]); @@ -1880,6 +2004,125 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env, return true; } +static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env) +{ + return &env->insn_aux_data[env->insn_idx]; +} + +static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, + u32 *ptr_limit, u8 opcode, bool off_is_neg) +{ + bool mask_to_left = (opcode == BPF_ADD && off_is_neg) || + (opcode == BPF_SUB && !off_is_neg); + u32 off; + + switch (ptr_reg->type) { + case PTR_TO_STACK: + off = ptr_reg->off + ptr_reg->var_off.value; + if (mask_to_left) + *ptr_limit = MAX_BPF_STACK + off; + else + *ptr_limit = -off; + return 0; + case PTR_TO_MAP_VALUE: + if (mask_to_left) { + *ptr_limit = ptr_reg->umax_value + ptr_reg->off; + } else { + off = ptr_reg->smin_value + ptr_reg->off; + *ptr_limit = ptr_reg->map_ptr->value_size - off; + } + return 0; + default: + return -EINVAL; + } +} + +static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env, + const struct bpf_insn *insn) +{ + return env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K; +} + +static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux, + u32 alu_state, u32 alu_limit) +{ + /* If we arrived here from different branches with different + * state or limits to sanitize, then this won't work. + */ + if (aux->alu_state && + (aux->alu_state != alu_state || + aux->alu_limit != alu_limit)) + return -EACCES; + + /* Corresponding fixup done in fixup_bpf_calls(). */ + aux->alu_state = alu_state; + aux->alu_limit = alu_limit; + return 0; +} + +static int sanitize_val_alu(struct bpf_verifier_env *env, + struct bpf_insn *insn) +{ + struct bpf_insn_aux_data *aux = cur_aux(env); + + if (can_skip_alu_sanitation(env, insn)) + return 0; + + return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0); +} + +static int sanitize_ptr_alu(struct bpf_verifier_env *env, + struct bpf_insn *insn, + const struct bpf_reg_state *ptr_reg, + struct bpf_reg_state *dst_reg, + bool off_is_neg) +{ + struct bpf_verifier_state *vstate = env->cur_state; + struct bpf_insn_aux_data *aux = cur_aux(env); + bool ptr_is_dst_reg = ptr_reg == dst_reg; + u8 opcode = BPF_OP(insn->code); + u32 alu_state, alu_limit; + struct bpf_reg_state tmp; + bool ret; + + if (can_skip_alu_sanitation(env, insn)) + return 0; + + /* We already marked aux for masking from non-speculative + * paths, thus we got here in the first place. We only care + * to explore bad access from here. + */ + if (vstate->speculative) + goto do_sim; + + alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0; + alu_state |= ptr_is_dst_reg ? + BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST; + + if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg)) + return 0; + if (update_alu_sanitation_state(aux, alu_state, alu_limit)) + return -EACCES; +do_sim: + /* Simulate and find potential out-of-bounds access under + * speculative execution from truncation as a result of + * masking when off was not within expected range. If off + * sits in dst, then we temporarily need to move ptr there + * to simulate dst (== 0) +/-= ptr. Needed, for example, + * for cases where we use K-based arithmetic in one direction + * and truncated reg-based in the other in order to explore + * bad access. + */ + if (!ptr_is_dst_reg) { + tmp = *dst_reg; + *dst_reg = *ptr_reg; + } + ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true); + if (!ptr_is_dst_reg && ret) + *dst_reg = tmp; + return !ret ? -EFAULT : 0; +} + /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. * Caller should also handle BPF_MOV case separately. * If we return -EACCES, caller may want to try again treating pointer as a @@ -1890,14 +2133,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, const struct bpf_reg_state *ptr_reg, const struct bpf_reg_state *off_reg) { - struct bpf_reg_state *regs = env->cur_state.regs, *dst_reg; + struct bpf_reg_state *regs = cur_regs(env), *dst_reg; bool known = tnum_is_const(off_reg->var_off); s64 smin_val = off_reg->smin_value, smax_val = off_reg->smax_value, smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value; u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value, umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value; + u32 dst = insn->dst_reg, src = insn->src_reg; u8 opcode = BPF_OP(insn->code); - u32 dst = insn->dst_reg; + int ret; dst_reg = ®s[dst]; @@ -1949,6 +2193,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, switch (opcode) { case BPF_ADD: + ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0); + if (ret < 0) { + verbose("R%d tried to add from different maps or paths\n", dst); + return ret; + } /* We can take a fixed offset as long as it doesn't overflow * the s32 'off' field */ @@ -1999,6 +2248,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, } break; case BPF_SUB: + ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0); + if (ret < 0) { + verbose("R%d tried to sub from different maps or paths\n", dst); + return ret; + } if (dst_reg == off_reg) { /* scalar -= pointer. Creates an unknown scalar */ if (!env->allow_ptr_leaks) @@ -2071,6 +2325,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, verbose("R%d bitwise operator %s on pointer prohibited\n", dst, bpf_alu_string[opcode >> 4]); return -EACCES; + case PTR_TO_MAP_VALUE: + if (!env->allow_ptr_leaks && !known && (smin_val < 0) != (smax_val < 0)) { + verbose("R%d has unknown scalar with mixed signed bounds, pointer arithmetic with it prohibited for !root\n", + off_reg == dst_reg ? dst : src); + return -EACCES; + } + /* fall-through */ default: /* other operators (e.g. MUL,LSH) produce non-pointer results */ if (!env->allow_ptr_leaks) @@ -2085,6 +2346,25 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, __update_reg_bounds(dst_reg); __reg_deduce_bounds(dst_reg); __reg_bound_offset(dst_reg); + + /* For unprivileged we require that resulting offset must be in bounds + * in order to be able to sanitize access later on. + */ + if (!env->allow_ptr_leaks) { + if (dst_reg->type == PTR_TO_MAP_VALUE && + check_map_access(env, dst, dst_reg->off, 1)) { + verbose("R%d pointer arithmetic of map value goes out of range, " + "prohibited for !root\n", dst); + return -EACCES; + } else if (dst_reg->type == PTR_TO_STACK && + check_stack_access(env, dst_reg, dst_reg->off + + dst_reg->var_off.value, 1)) { + verbose("R%d stack pointer arithmetic goes out of range, " + "prohibited for !root\n", dst); + return -EACCES; + } + } + return 0; } @@ -2097,12 +2377,14 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, struct bpf_reg_state *dst_reg, struct bpf_reg_state src_reg) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = cur_regs(env); u8 opcode = BPF_OP(insn->code); bool src_known, dst_known; s64 smin_val, smax_val; u64 umin_val, umax_val; u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32; + u32 dst = insn->dst_reg; + int ret; if (insn_bitness == 32) { /* Relevant for 32-bit RSH: Information can propagate towards @@ -2137,6 +2419,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, switch (opcode) { case BPF_ADD: + ret = sanitize_val_alu(env, insn); + if (ret < 0) { + verbose("R%d tried to add from different pointers or scalars\n", dst); + return ret; + } if (signed_add_overflows(dst_reg->smin_value, smin_val) || signed_add_overflows(dst_reg->smax_value, smax_val)) { dst_reg->smin_value = S64_MIN; @@ -2156,6 +2443,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off); break; case BPF_SUB: + ret = sanitize_val_alu(env, insn); + if (ret < 0) { + verbose("R%d tried to sub from different pointers or scalars\n", dst); + return ret; + } if (signed_sub_overflows(dst_reg->smin_value, smax_val) || signed_sub_overflows(dst_reg->smax_value, smin_val)) { /* Overflow possible, we know nothing */ @@ -2345,7 +2637,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn *insn) { - struct bpf_reg_state *regs = env->cur_state.regs, *dst_reg, *src_reg; + struct bpf_reg_state *regs = cur_regs(env), *dst_reg, *src_reg; struct bpf_reg_state *ptr_reg = NULL, off_reg = {0}; u8 opcode = BPF_OP(insn->code); int rc; @@ -2419,12 +2711,12 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, /* Got here implies adding two SCALAR_VALUEs */ if (WARN_ON_ONCE(ptr_reg)) { - print_verifier_state(&env->cur_state); + print_verifier_state(env->cur_state); verbose("verifier internal error: unexpected ptr_reg\n"); return -EINVAL; } if (WARN_ON(!src_reg)) { - print_verifier_state(&env->cur_state); + print_verifier_state(env->cur_state); verbose("verifier internal error: no src_reg\n"); return -EINVAL; } @@ -2434,7 +2726,7 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, /* check validity of 32-bit and 64-bit arithmetic operations */ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = cur_regs(env); u8 opcode = BPF_OP(insn->code); int err; @@ -2661,10 +2953,10 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, /* keep the maximum range already checked */ regs[i].range = max(regs[i].range, new_range); - for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { - if (state->stack_slot_type[i] != STACK_SPILL) + for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { + if (state->stack[i].slot_type[0] != STACK_SPILL) continue; - reg = &state->spilled_regs[i / BPF_REG_SIZE]; + reg = &state->stack[i].spilled_ptr; if (reg->type == PTR_TO_PACKET && reg->id == dst_reg->id) reg->range = max(reg->range, new_range); } @@ -2914,17 +3206,17 @@ static void mark_map_regs(struct bpf_verifier_state *state, u32 regno, for (i = 0; i < MAX_BPF_REG; i++) mark_map_reg(regs, i, id, is_null); - for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { - if (state->stack_slot_type[i] != STACK_SPILL) + for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { + if (state->stack[i].slot_type[0] != STACK_SPILL) continue; - mark_map_reg(state->spilled_regs, i / BPF_REG_SIZE, id, is_null); + mark_map_reg(&state->stack[i].spilled_ptr, 0, id, is_null); } } static int check_cond_jmp_op(struct bpf_verifier_env *env, struct bpf_insn *insn, int *insn_idx) { - struct bpf_verifier_state *other_branch, *this_branch = &env->cur_state; + struct bpf_verifier_state *other_branch, *this_branch = env->cur_state; struct bpf_reg_state *regs = this_branch->regs, *dst_reg; u8 opcode = BPF_OP(insn->code); int err; @@ -2984,7 +3276,8 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, } } - other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx); + other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx, + false); if (!other_branch) return -EFAULT; @@ -3087,7 +3380,7 @@ static struct bpf_map *ld_imm64_to_map_ptr(struct bpf_insn *insn) /* verify BPF_LD_IMM64 instruction */ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = cur_regs(env); int err; if (BPF_SIZE(insn->code) != BPF_DW) { @@ -3148,7 +3441,7 @@ static bool may_access_skb(enum bpf_prog_type type) */ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) { - struct bpf_reg_state *regs = env->cur_state.regs; + struct bpf_reg_state *regs = cur_regs(env); u8 mode = BPF_MODE(insn->code); int i, err; @@ -3534,6 +3827,57 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, return false; } +static bool stacksafe(struct bpf_verifier_state *old, + struct bpf_verifier_state *cur, + struct idpair *idmap) +{ + int i, spi; + + /* if explored stack has more populated slots than current stack + * such stacks are not equivalent + */ + if (old->allocated_stack > cur->allocated_stack) + return false; + + /* walk slots of the explored stack and ignore any additional + * slots in the current stack, since explored(safe) state + * didn't use them + */ + for (i = 0; i < old->allocated_stack; i++) { + spi = i / BPF_REG_SIZE; + + if (old->stack[spi].slot_type[i % BPF_REG_SIZE] == STACK_INVALID) + continue; + if (old->stack[spi].slot_type[i % BPF_REG_SIZE] != + cur->stack[spi].slot_type[i % BPF_REG_SIZE]) + /* Ex: old explored (safe) state has STACK_SPILL in + * this stack slot, but current has has STACK_MISC -> + * this verifier states are not equivalent, + * return false to continue verification of this path + */ + return false; + if (i % BPF_REG_SIZE) + continue; + if (old->stack[spi].slot_type[0] != STACK_SPILL) + continue; + if (!regsafe(&old->stack[spi].spilled_ptr, + &cur->stack[spi].spilled_ptr, + idmap)) + /* when explored and current stack slot are both storing + * spilled registers, check that stored pointers types + * are the same as well. + * Ex: explored safe path could have stored + * (bpf_reg_state) {.type = PTR_TO_STACK, .off = -8} + * but current path has stored: + * (bpf_reg_state) {.type = PTR_TO_STACK, .off = -16} + * such verifier states are not equivalent. + * return false to continue verification of this path + */ + return false; + } + return true; +} + /* compare two verifier states * * all states stored in state_list are known to be valid, since @@ -3568,6 +3912,12 @@ static bool states_equal(struct bpf_verifier_env *env, bool ret = false; int i; + /* Verification state from speculative execution simulation + * must never prune a non-speculative execution one. + */ + if (old->speculative && !cur->speculative) + return false; + idmap = kcalloc(ID_MAP_SIZE, sizeof(struct idpair), GFP_KERNEL); /* If we failed to allocate the idmap, just say it's not safe */ if (!idmap) @@ -3578,37 +3928,8 @@ static bool states_equal(struct bpf_verifier_env *env, goto out_free; } - for (i = 0; i < MAX_BPF_STACK; i++) { - if (old->stack_slot_type[i] == STACK_INVALID) - continue; - if (old->stack_slot_type[i] != cur->stack_slot_type[i]) - /* Ex: old explored (safe) state has STACK_SPILL in - * this stack slot, but current has has STACK_MISC -> - * this verifier states are not equivalent, - * return false to continue verification of this path - */ - goto out_free; - if (i % BPF_REG_SIZE) - continue; - if (old->stack_slot_type[i] != STACK_SPILL) - continue; - if (!regsafe(&old->spilled_regs[i / BPF_REG_SIZE], - &cur->spilled_regs[i / BPF_REG_SIZE], - idmap)) - /* when explored and current stack slot are both storing - * spilled registers, check that stored pointers types - * are the same as well. - * Ex: explored safe path could have stored - * (bpf_reg_state) {.type = PTR_TO_STACK, .off = -8} - * but current path has stored: - * (bpf_reg_state) {.type = PTR_TO_STACK, .off = -16} - * such verifier states are not equivalent. - * return false to continue verification of this path - */ - goto out_free; - else - continue; - } + if (!stacksafe(old, cur, idmap)) + goto out_free; ret = true; out_free: kfree(idmap); @@ -3644,17 +3965,19 @@ static bool do_propagate_liveness(const struct bpf_verifier_state *state, } } /* ... and stack slots */ - for (i = 0; i < MAX_BPF_STACK / BPF_REG_SIZE; i++) { - if (parent->stack_slot_type[i * BPF_REG_SIZE] != STACK_SPILL) + for (i = 0; i < state->allocated_stack / BPF_REG_SIZE && + i < parent->allocated_stack / BPF_REG_SIZE; i++) { + if (parent->stack[i].slot_type[0] != STACK_SPILL) continue; - if (state->stack_slot_type[i * BPF_REG_SIZE] != STACK_SPILL) + if (state->stack[i].slot_type[0] != STACK_SPILL) continue; - if (parent->spilled_regs[i].live & REG_LIVE_READ) + if (parent->stack[i].spilled_ptr.live & REG_LIVE_READ) continue; - if (writes && (state->spilled_regs[i].live & REG_LIVE_WRITTEN)) + if (writes && + (state->stack[i].spilled_ptr.live & REG_LIVE_WRITTEN)) continue; - if (state->spilled_regs[i].live & REG_LIVE_READ) { - parent->spilled_regs[i].live |= REG_LIVE_READ; + if (state->stack[i].spilled_ptr.live & REG_LIVE_READ) { + parent->stack[i].spilled_ptr.live |= REG_LIVE_READ; touched = true; } } @@ -3684,7 +4007,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) { struct bpf_verifier_state_list *new_sl; struct bpf_verifier_state_list *sl; - int i; + struct bpf_verifier_state *cur = env->cur_state; + int i, err; sl = env->explored_states[insn_idx]; if (!sl) @@ -3694,7 +4018,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) return 0; while (sl != STATE_LIST_MARK) { - if (states_equal(env, &sl->state, &env->cur_state)) { + if (states_equal(env, &sl->state, cur)) { /* reached equivalent register/stack state, * prune the search. * Registers read by the continuation are read by us. @@ -3705,7 +4029,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) * they'll be immediately forgotten as we're pruning * this state and will pop a new one. */ - propagate_liveness(&sl->state, &env->cur_state); + propagate_liveness(&sl->state, cur); return 1; } sl = sl->next; @@ -3717,16 +4041,21 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) * it will be rejected. Since there are no loops, we won't be * seeing this 'insn_idx' instruction again on the way to bpf_exit */ - new_sl = kmalloc(sizeof(struct bpf_verifier_state_list), GFP_USER); + new_sl = kzalloc(sizeof(struct bpf_verifier_state_list), GFP_KERNEL); if (!new_sl) return -ENOMEM; /* add new state to the head of linked list */ - memcpy(&new_sl->state, &env->cur_state, sizeof(env->cur_state)); + err = copy_verifier_state(&new_sl->state, cur); + if (err) { + free_verifier_state(&new_sl->state, false); + kfree(new_sl); + return err; + } new_sl->next = env->explored_states[insn_idx]; env->explored_states[insn_idx] = new_sl; /* connect new state to parentage chain */ - env->cur_state.parent = &new_sl->state; + cur->parent = &new_sl->state; /* clear write marks in current state: the writes we did are not writes * our child did, so they don't screen off its reads from us. * (There are no read marks in current state, because reads always mark @@ -3734,10 +4063,10 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) * explored_states can get read marks.) */ for (i = 0; i < BPF_REG_FP; i++) - env->cur_state.regs[i].live = REG_LIVE_NONE; - for (i = 0; i < MAX_BPF_STACK / BPF_REG_SIZE; i++) - if (env->cur_state.stack_slot_type[i * BPF_REG_SIZE] == STACK_SPILL) - env->cur_state.spilled_regs[i].live = REG_LIVE_NONE; + cur->regs[i].live = REG_LIVE_NONE; + for (i = 0; i < cur->allocated_stack / BPF_REG_SIZE; i++) + if (cur->stack[i].slot_type[0] == STACK_SPILL) + cur->stack[i].spilled_ptr.live = REG_LIVE_NONE; return 0; } @@ -3752,29 +4081,31 @@ static int ext_analyzer_insn_hook(struct bpf_verifier_env *env, static int do_check(struct bpf_verifier_env *env) { - struct bpf_verifier_state *state = &env->cur_state; + struct bpf_verifier_state *state; struct bpf_insn *insns = env->prog->insnsi; - struct bpf_reg_state *regs = state->regs; + struct bpf_reg_state *regs; int insn_cnt = env->prog->len; - int insn_idx, prev_insn_idx = 0; int insn_processed = 0; bool do_print_state = false; - init_reg_state(regs); + state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + env->cur_state = state; + init_reg_state(state->regs); state->parent = NULL; - insn_idx = 0; for (;;) { struct bpf_insn *insn; u8 class; int err; - if (insn_idx >= insn_cnt) { + if (env->insn_idx >= insn_cnt) { verbose("invalid insn idx %d insn_cnt %d\n", - insn_idx, insn_cnt); + env->insn_idx, insn_cnt); return -EFAULT; } - insn = &insns[insn_idx]; + insn = &insns[env->insn_idx]; class = BPF_CLASS(insn->code); if (++insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) { @@ -3783,17 +4114,19 @@ static int do_check(struct bpf_verifier_env *env) return -E2BIG; } - err = is_state_visited(env, insn_idx); + err = is_state_visited(env, env->insn_idx); if (err < 0) return err; if (err == 1) { /* found equivalent state, can prune the search */ if (log_level) { if (do_print_state) - verbose("\nfrom %d to %d: safe\n", - prev_insn_idx, insn_idx); + verbose("\nfrom %d to %d%s: safe\n", + env->prev_insn_idx, env->insn_idx, + env->cur_state->speculative ? + " (speculative execution)" : ""); else - verbose("%d: safe\n", insn_idx); + verbose("%d: safe\n", env->insn_idx); } goto process_bpf_exit; } @@ -3803,24 +4136,27 @@ static int do_check(struct bpf_verifier_env *env) if (log_level > 1 || (log_level && do_print_state)) { if (log_level > 1) - verbose("%d:", insn_idx); + verbose("%d:", env->insn_idx); else - verbose("\nfrom %d to %d:", - prev_insn_idx, insn_idx); - print_verifier_state(&env->cur_state); + verbose("\nfrom %d to %d%s:", + env->prev_insn_idx, env->insn_idx, + env->cur_state->speculative ? + " (speculative execution)" : ""); + print_verifier_state(env->cur_state); do_print_state = false; } if (log_level) { - verbose("%d: ", insn_idx); + verbose("%d: ", env->insn_idx); print_bpf_insn(env, insn); } - err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx); + err = ext_analyzer_insn_hook(env, env->insn_idx, env->prev_insn_idx); if (err) return err; - env->insn_aux_data[insn_idx].seen = true; + regs = cur_regs(env); + env->insn_aux_data[env->insn_idx].seen = true; if (class == BPF_ALU || class == BPF_ALU64) { err = check_alu_op(env, insn); if (err) @@ -3845,13 +4181,13 @@ static int do_check(struct bpf_verifier_env *env) /* check that memory (src_reg + off) is readable, * the state of dst_reg will be updated by this func */ - err = check_mem_access(env, insn_idx, insn->src_reg, insn->off, - BPF_SIZE(insn->code), BPF_READ, - insn->dst_reg, false); + err = check_mem_access(env, env->insn_idx, insn->src_reg, + insn->off, BPF_SIZE(insn->code), + BPF_READ, insn->dst_reg, false); if (err) return err; - prev_src_type = &env->insn_aux_data[insn_idx].ptr_type; + prev_src_type = &env->insn_aux_data[env->insn_idx].ptr_type; if (*prev_src_type == NOT_INIT) { /* saw a valid insn @@ -3878,10 +4214,10 @@ static int do_check(struct bpf_verifier_env *env) enum bpf_reg_type *prev_dst_type, dst_reg_type; if (BPF_MODE(insn->code) == BPF_XADD) { - err = check_xadd(env, insn_idx, insn); + err = check_xadd(env, env->insn_idx, insn); if (err) return err; - insn_idx++; + env->insn_idx++; continue; } @@ -3897,13 +4233,13 @@ static int do_check(struct bpf_verifier_env *env) dst_reg_type = regs[insn->dst_reg].type; /* check that memory (dst_reg + off) is writeable */ - err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, - BPF_SIZE(insn->code), BPF_WRITE, - insn->src_reg, false); + err = check_mem_access(env, env->insn_idx, insn->dst_reg, + insn->off, BPF_SIZE(insn->code), + BPF_WRITE, insn->src_reg, false); if (err) return err; - prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type; + prev_dst_type = &env->insn_aux_data[env->insn_idx].ptr_type; if (*prev_dst_type == NOT_INIT) { *prev_dst_type = dst_reg_type; @@ -3932,9 +4268,9 @@ static int do_check(struct bpf_verifier_env *env) } /* check that memory (dst_reg + off) is writeable */ - err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, - BPF_SIZE(insn->code), BPF_WRITE, - -1, false); + err = check_mem_access(env, env->insn_idx, insn->dst_reg, + insn->off, BPF_SIZE(insn->code), + BPF_WRITE, -1, false); if (err) return err; @@ -3950,7 +4286,7 @@ static int do_check(struct bpf_verifier_env *env) return -EINVAL; } - err = check_call(env, insn->imm, insn_idx); + err = check_call(env, insn->imm, env->insn_idx); if (err) return err; @@ -3963,7 +4299,7 @@ static int do_check(struct bpf_verifier_env *env) return -EINVAL; } - insn_idx += insn->off + 1; + env->insn_idx += insn->off + 1; continue; } else if (opcode == BPF_EXIT) { @@ -3991,15 +4327,17 @@ static int do_check(struct bpf_verifier_env *env) } process_bpf_exit: - insn_idx = pop_stack(env, &prev_insn_idx); - if (insn_idx < 0) { + err = pop_stack(env, &env->prev_insn_idx, &env->insn_idx); + if (err < 0) { + if (err != -ENOENT) + return err; break; } else { do_print_state = true; continue; } } else { - err = check_cond_jmp_op(env, insn, &insn_idx); + err = check_cond_jmp_op(env, insn, &env->insn_idx); if (err) return err; } @@ -4016,8 +4354,8 @@ static int do_check(struct bpf_verifier_env *env) if (err) return err; - insn_idx++; - env->insn_aux_data[insn_idx].seen = true; + env->insn_idx++; + env->insn_aux_data[env->insn_idx].seen = true; } else { verbose("invalid BPF_LD mode\n"); return -EINVAL; @@ -4027,7 +4365,7 @@ static int do_check(struct bpf_verifier_env *env) return -EINVAL; } - insn_idx++; + env->insn_idx++; } verbose("processed %d insns, stack depth %d\n", @@ -4402,6 +4740,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) struct bpf_prog *new_prog; struct bpf_map *map_ptr; int i, cnt, delta = 0; + struct bpf_insn_aux_data *aux; for (i = 0; i < insn_cnt; i++, insn++) { if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) || @@ -4422,6 +4761,58 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) continue; } + if (insn->code == (BPF_ALU64 | BPF_ADD | BPF_X) || + insn->code == (BPF_ALU64 | BPF_SUB | BPF_X)) { + const u8 code_add = BPF_ALU64 | BPF_ADD | BPF_X; + const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X; + struct bpf_insn insn_buf[16]; + struct bpf_insn *patch = &insn_buf[0]; + bool issrc, isneg; + u32 off_reg; + + aux = &env->insn_aux_data[i + delta]; + if (!aux->alu_state || + aux->alu_state == BPF_ALU_NON_POINTER) + continue; + + isneg = aux->alu_state & BPF_ALU_NEG_VALUE; + issrc = (aux->alu_state & BPF_ALU_SANITIZE) == + BPF_ALU_SANITIZE_SRC; + + off_reg = issrc ? insn->src_reg : insn->dst_reg; + if (isneg) + *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); + *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit - 1); + *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg); + *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg); + *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0); + *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63); + if (issrc) { + *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, + off_reg); + insn->src_reg = BPF_REG_AX; + } else { + *patch++ = BPF_ALU64_REG(BPF_AND, off_reg, + BPF_REG_AX); + } + if (isneg) + insn->code = insn->code == code_add ? + code_sub : code_add; + *patch++ = *insn; + if (issrc && isneg) + *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); + cnt = patch - insn_buf; + + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); + if (!new_prog) + return -ENOMEM; + + delta += cnt - 1; + env->prog = prog = new_prog; + insn = new_prog->insnsi + i + delta; + continue; + } + if (insn->code != (BPF_JMP | BPF_CALL)) continue; @@ -4557,6 +4948,7 @@ static void free_states(struct bpf_verifier_env *env) if (sl) while (sl != STATE_LIST_MARK) { sln = sl->next; + free_verifier_state(&sl->state, false); kfree(sl); sl = sln; } @@ -4633,9 +5025,13 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); ret = do_check(env); + if (env->cur_state) { + free_verifier_state(env->cur_state, true); + env->cur_state = NULL; + } skip_full_check: - while (pop_stack(env, NULL) >= 0); + while (!pop_stack(env, NULL, NULL)); free_states(env); if (ret == 0) @@ -4741,9 +5137,13 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); ret = do_check(env); + if (env->cur_state) { + free_verifier_state(env->cur_state, true); + env->cur_state = NULL; + } skip_full_check: - while (pop_stack(env, NULL) >= 0); + while (!pop_stack(env, NULL, NULL)); free_states(env); mutex_unlock(&bpf_verifier_lock); diff --git a/kernel/cfi.c b/kernel/cfi.c index 3265b55efc2283af7df176667387f6e9e91a9f1f..967b0755c00e2155764f9997ecee5bfdfd391962 100644 --- a/kernel/cfi.c +++ b/kernel/cfi.c @@ -229,7 +229,6 @@ static inline cfi_check_fn ptr_to_check_fn(const struct cfi_shadow __rcu *s, unsigned long ptr) { int index; - unsigned long check; if (unlikely(!s)) return NULL; /* No shadow available */ diff --git a/kernel/cpu.c b/kernel/cpu.c index ba4610936ca016fb8f2d25c2e39f62fadde96b02..f15acf252bb176b949c42e30f6764f1d7bf746d6 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1269,6 +1269,13 @@ int freeze_secondary_cpus(int primary) for_each_online_cpu(cpu) { if (cpu == primary) continue; + + if (pm_wakeup_pending()) { + pr_info("Wakeup pending. Abort CPU freeze\n"); + error = -EBUSY; + break; + } + trace_suspend_resume(TPS("CPU_OFF"), cpu, true); error = _cpu_down(cpu, 1, CPUHP_OFFLINE); trace_suspend_resume(TPS("CPU_OFF"), cpu, false); diff --git a/kernel/events/core.c b/kernel/events/core.c index b151be9324c453d37a8dfe0fea95568d2c98961e..e615c9f2887cb7b7264074e25a8d4cc616ee8e1f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7117,6 +7117,7 @@ static void perf_event_mmap_output(struct perf_event *event, struct perf_output_handle handle; struct perf_sample_data sample; int size = mmap_event->event_id.header.size; + u32 type = mmap_event->event_id.header.type; int ret; if (!perf_event_mmap_match(event, data)) @@ -7160,6 +7161,7 @@ static void perf_event_mmap_output(struct perf_event *event, perf_output_end(&handle); out: mmap_event->event_id.header.size = size; + mmap_event->event_id.header.type = type; } static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 381085b2bf5f40498affba46a297e8834473092d..a9cdea43d863af0f9103ac2c1257839de703738b 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -244,6 +245,28 @@ void reset_hung_task_detector(void) } EXPORT_SYMBOL_GPL(reset_hung_task_detector); +static bool hung_detector_suspended; + +static int hungtask_pm_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + switch (action) { + case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + hung_detector_suspended = true; + break; + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + hung_detector_suspended = false; + break; + default: + break; + } + return NOTIFY_OK; +} + /* * kthread which checks for tasks stuck in D state */ @@ -258,7 +281,8 @@ static int watchdog(void *dummy) long t = hung_timeout_jiffies(hung_last_checked, timeout); if (t <= 0) { - if (!atomic_xchg(&reset_hung_task, 0)) + if (!atomic_xchg(&reset_hung_task, 0) && + !hung_detector_suspended) check_hung_uninterruptible_tasks(timeout); hung_last_checked = jiffies; continue; @@ -272,6 +296,10 @@ static int watchdog(void *dummy) static int __init hung_task_init(void) { atomic_notifier_chain_register(&panic_notifier_list, &panic_block); + + /* Disable hung task detector on suspend */ + pm_notifier(hungtask_pm_notify, 0); + watchdog_task = kthread_run(watchdog, NULL, "khungtaskd"); return 0; diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 0fa7ef74303b1cb009ae26d3315243f7f6ce1600..317fc759de76160061cda5699a63998d2b3e8dc0 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -1363,6 +1363,10 @@ int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info) int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on) { data = data->parent_data; + + if (data->chip->flags & IRQCHIP_SKIP_SET_WAKE) + return 0; + if (data->chip->irq_set_wake) return data->chip->irq_set_wake(data, on); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index c2bfb11a9d055ee175c892c995a29c82ae889a8f..aa08d4184608c849185f3c1ed2d16be3ca1f7785 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -535,6 +535,7 @@ int __init early_irq_init(void) alloc_masks(&desc[i], node); raw_spin_lock_init(&desc[i].lock); lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); + mutex_init(&desc[i].request_mutex); desc_set_defaults(i, &desc[i], node, NULL, NULL); } return arch_early_irq_init(); diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5cbad4fb9107112278e6de5c1d71831f9cca7436..ec11bb986a8b471cfe96920c3c19691f96530abe 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -703,7 +703,6 @@ static void unoptimize_kprobe(struct kprobe *p, bool force) static int reuse_unused_kprobe(struct kprobe *ap) { struct optimized_kprobe *op; - int ret; BUG_ON(!kprobe_unused(ap)); /* @@ -717,9 +716,8 @@ static int reuse_unused_kprobe(struct kprobe *ap) /* Enable the probe again */ ap->flags &= ~KPROBE_FLAG_DISABLED; /* Optimize it again (remove from op->list) */ - ret = kprobe_optready(ap); - if (ret) - return ret; + if (!kprobe_optready(ap)) + return -EINVAL; optimize_kprobe(ap); return 0; diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index e57be7031cb34a15c0b6b9a39cf2a2679fe4d85a..bf694c709b96f56825694df6b2fa1ce41affcd52 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3650,9 +3650,6 @@ __lock_set_class(struct lockdep_map *lock, const char *name, unsigned int depth; int i; - if (unlikely(!debug_locks)) - return 0; - depth = curr->lockdep_depth; /* * This function is about (re)setting the class of a held lock, diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 0972a8e09d082d99c7f197cbe6bd4fdb6475ba33..b7a6889439a7f603f0bb3e42639627b0320d28f1 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1257,6 +1257,33 @@ static inline void *saveable_highmem_page(struct zone *z, unsigned long p) } #endif /* CONFIG_HIGHMEM */ +static bool kernel_pte_present(struct page *page) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long addr = (unsigned long)page_address(page); + + pgd = pgd_offset_k(addr); + if (pgd_none(*pgd)) + return false; + + pud = pud_offset(pgd, addr); + if (pud_none(*pud)) + return false; + if (pud_sect(*pud)) + return true; + + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) + return false; + if (pmd_sect(*pmd)) + return true; + + pte = pte_offset_kernel(pmd, addr); + return pte_valid(*pte); +} /** * saveable_page - Check if the given page is saveable. * @@ -1287,6 +1314,14 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) && (!kernel_page_present(page) || pfn_is_nosave(pfn))) return NULL; + /* + * Even if page is not reserved and if it's not present in kernel PTE; + * don't snapshot it ! This happens to the pages allocated using + * __dma_alloc_coherent with DMA_ATTR_NO_KERNEL_MAPPING flag set. + */ + if (!kernel_pte_present(page)) + return NULL; + if (page_is_guard(page)) return NULL; diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 52623f04f18f5e61c7b2e6566a235371f4200290..75164e041b8ec47286bc0678830667e4d3430349 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -43,6 +43,7 @@ */ static bool clean_pages_on_read; static bool clean_pages_on_decompress; +static bool noswap_randomize; /* * The swap map is a data structure used for keeping track of each page @@ -1533,6 +1534,9 @@ int swsusp_check(void) FMODE_READ, NULL); if (!IS_ERR(hib_resume_bdev)) { set_blocksize(hib_resume_bdev, PAGE_SIZE); + if (noswap_randomize) + hib_resume_bdev->bd_disk->flags |= + GENHD_FL_NO_RANDOMIZE; clear_page(swsusp_header); error = hib_submit_io(REQ_OP_READ, 0, swsusp_resume_block, @@ -1620,3 +1624,11 @@ static int swsusp_header_init(void) } core_initcall(swsusp_header_init); + +static int __init noswap_randomize_setup(char *str) +{ + noswap_randomize = true; + return 1; +} + +__setup("noswap_randomize", noswap_randomize_setup); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 84b1367935e410f79770c06efadc20deb51346b3..f1c85b6c39ae70fbb06a1ea943ab7e00797e1db8 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * Access another process' address space via ptrace. @@ -925,18 +926,26 @@ int ptrace_request(struct task_struct *child, long request, ret = ptrace_setsiginfo(child, &siginfo); break; - case PTRACE_GETSIGMASK: + case PTRACE_GETSIGMASK: { + sigset_t *mask; + if (addr != sizeof(sigset_t)) { ret = -EINVAL; break; } - if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t))) + if (test_tsk_restore_sigmask(child)) + mask = &child->saved_sigmask; + else + mask = &child->blocked; + + if (copy_to_user(datavp, mask, sizeof(sigset_t))) ret = -EFAULT; else ret = 0; break; + } case PTRACE_SETSIGMASK: { sigset_t new_set; @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long request, child->blocked = new_set; spin_unlock_irq(&child->sighand->siglock); + clear_tsk_restore_sigmask(child); + ret = 0; break; } diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 6f82ff44881d3dd5f76ea32de10038ebb1e0945a..17c8b715af7ed07cc86dc96675b53ee7138363a5 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2293,6 +2293,9 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) p->se.nr_migrations = 0; p->se.vruntime = 0; p->last_sleep_ts = 0; + p->boost = 0; + p->boost_expires = 0; + p->boost_period = 0; INIT_LIST_HEAD(&p->se.group_node); @@ -6256,6 +6259,7 @@ int sched_cpu_starting(unsigned int cpu) { set_cpu_rq_start_time(cpu); sched_rq_cpu_starting(cpu); + clear_walt_request(cpu); return 0; } @@ -7489,6 +7493,26 @@ const u32 sched_prio_to_wmult[40] = { /* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153, }; +/* + *@boost:should be 0,1,2. + *@period:boost time based on ms units. + */ +int set_task_boost(int boost, u64 period) +{ + if (boost < 0 || boost > 2) + return -EINVAL; + if (boost) { + current->boost = boost; + current->boost_period = (u64)period * 1000 * 1000; + current->boost_expires = sched_clock() + current->boost_period; + } else { + current->boost = 0; + current->boost_expires = 0; + current->boost_period = 0; + } + return 0; +} + #ifdef CONFIG_SCHED_WALT /* * sched_exit() - Set EXITING_TASK_MARKER in task's ravg.demand field diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index c57673e5152c97c55ba81d024e10709ae04d8bba..f8231399358f1f0ffb4d2a660ea262beff2d022d 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -1067,6 +1067,8 @@ static void sugov_limits(struct cpufreq_policy *policy) { struct sugov_policy *sg_policy = policy->governor_data; unsigned long flags; + unsigned int ret; + int cpu; if (!policy->fast_switch_enabled) { mutex_lock(&sg_policy->work_lock); @@ -1080,7 +1082,12 @@ static void sugov_limits(struct cpufreq_policy *policy) raw_spin_lock_irqsave(&sg_policy->update_lock, flags); sugov_track_cycles(sg_policy, sg_policy->policy->cur, ktime_get_ns()); - cpufreq_policy_apply_limits_fast(policy); + ret = cpufreq_policy_apply_limits_fast(policy); + if (ret && policy->cur != ret) { + policy->cur = ret; + for_each_cpu(cpu, policy->cpus) + trace_cpu_frequency(ret, cpu); + } raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags); } diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index d835802da38b6b139413f9b7dfa2af5c64cbd83d..f0fc6dfd3081686b622714130dfe1c1cecebf578 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -220,7 +220,6 @@ static void task_non_contending(struct task_struct *p) if (dl_se->dl_runtime == 0) return; - WARN_ON(hrtimer_active(&dl_se->inactive_timer)); WARN_ON(dl_se->dl_non_contending); zerolag_time = dl_se->deadline - @@ -237,7 +236,7 @@ static void task_non_contending(struct task_struct *p) * If the "0-lag time" already passed, decrease the active * utilization now, instead of starting a timer */ - if (zerolag_time < 0) { + if ((zerolag_time < 0) || hrtimer_active(&dl_se->inactive_timer)) { if (dl_task(p)) sub_running_bw(dl_se->dl_bw, dl_rq); if (!dl_task(p) || p->state == TASK_DEAD) { diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 42379e6979daf0362aec426e7392e100692b52cb..0f3ae67ee1928f6dac0a5209e3f696f8ece991f2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2097,6 +2097,10 @@ static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period) if (p->last_task_numa_placement) { delta = runtime - p->last_sum_exec_runtime; *period = now - p->last_task_numa_placement; + + /* Avoid time going backwards, prevent potential divide error: */ + if (unlikely((s64)*period < 0)) + *period = 0; } else { delta = p->se.avg.load_sum / p->se.load.weight; *period = LOAD_AVG_MAX; @@ -2886,6 +2890,18 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq) } } +static inline int per_task_boost(struct task_struct *p) +{ + if (p->boost_period) { + if (sched_clock() > p->boost_expires) { + p->boost_period = 0; + p->boost_expires = 0; + p->boost = 0; + } + } + return p->boost; +} + #ifdef CONFIG_SMP /* * Approximate: @@ -4222,6 +4238,7 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr) { struct sched_entity *left = __pick_first_entity(cfs_rq); struct sched_entity *se; + bool strict_skip = false; /* * If curr is set we have to see if its left of the leftmost entity @@ -4241,13 +4258,16 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr) if (se == curr) { second = __pick_first_entity(cfs_rq); + if (sched_feat(STRICT_SKIP_BUDDY)) + strict_skip = true; } else { second = __pick_next_entity(se); if (!second || (curr && entity_before(curr, second))) second = curr; } - if (second && wakeup_preempt_entity(second, left) < 1) + if (second && (strict_skip || + wakeup_preempt_entity(second, left) < 1)) se = second; } @@ -4986,12 +5006,15 @@ static enum hrtimer_restart sched_cfs_slack_timer(struct hrtimer *timer) return HRTIMER_NORESTART; } +extern const u64 max_cfs_quota_period; + static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer) { struct cfs_bandwidth *cfs_b = container_of(timer, struct cfs_bandwidth, period_timer); int overrun; int idle = 0; + int count = 0; raw_spin_lock(&cfs_b->lock); for (;;) { @@ -4999,6 +5022,28 @@ static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer) if (!overrun) break; + if (++count > 3) { + u64 new, old = ktime_to_ns(cfs_b->period); + + new = (old * 147) / 128; /* ~115% */ + new = min(new, max_cfs_quota_period); + + cfs_b->period = ns_to_ktime(new); + + /* since max is 1s, this is limited to 1e9^2, which fits in u64 */ + cfs_b->quota *= new; + cfs_b->quota = div64_u64(cfs_b->quota, old); + + pr_warn_ratelimited( + "cfs_period_timer[cpu%d]: period too short, scaling up (new cfs_period_us %lld, cfs_quota_us = %lld)\n", + smp_processor_id(), + div_u64(new, NSEC_PER_USEC), + div_u64(cfs_b->quota, NSEC_PER_USEC)); + + /* reset count so we don't come right back in here */ + count = 0; + } + idle = do_sched_cfs_period_timer(cfs_b, overrun); } if (idle) @@ -7306,14 +7351,20 @@ static inline bool task_fits_max(struct task_struct *p, int cpu) { unsigned long capacity = capacity_orig_of(cpu); unsigned long max_capacity = cpu_rq(cpu)->rd->max_cpu_capacity.val; + unsigned long task_boost = per_task_boost(p); if (capacity == max_capacity) return true; - if ((task_boost_policy(p) == SCHED_BOOST_ON_BIG || - schedtune_task_boost(p) > 0) && - is_min_capacity_cpu(cpu)) - return false; + if (is_min_capacity_cpu(cpu)) { + if (task_boost_policy(p) == SCHED_BOOST_ON_BIG || + task_boost > 0 || + schedtune_task_boost(p) > 0) + return false; + } else { /* mid cap cpu */ + if (task_boost > 1) + return false; + } return task_fits_capacity(p, capacity, cpu); } @@ -8082,7 +8133,7 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, int placement_boost = task_boost_policy(p); u64 start_t = 0; int next_cpu = -1, backup_cpu = -1; - int boosted = (schedtune_task_boost(p) > 0); + int boosted = (schedtune_task_boost(p) > 0 || per_task_boost(p) > 0); fbt_env.fastpath = 0; @@ -9275,7 +9326,17 @@ static int detach_tasks(struct lb_env *env) if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed) goto next; - if ((load / 2) > env->imbalance) + /* + * p is not running task when we goes until here, so if p is one + * of the 2 task in src cpu rq and not the running one, + * that means it is the only task that can be balanced. + * So only when there is other tasks can be balanced or + * there is situation to ignore big task, it is needed + * to skip the task load bigger than 2*imbalance. + */ + if (((cpu_rq(env->src_cpu)->nr_running > 2) || + (env->flags & LBF_IGNORE_BIG_TASKS)) && + ((load / 2) > env->imbalance)) goto next; detach_task(p, env); @@ -9438,10 +9499,10 @@ static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq) if (cfs_rq->last_h_load_update == now) return; - cfs_rq->h_load_next = NULL; + WRITE_ONCE(cfs_rq->h_load_next, NULL); for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); - cfs_rq->h_load_next = se; + WRITE_ONCE(cfs_rq->h_load_next, se); if (cfs_rq->last_h_load_update == now) break; } @@ -9451,7 +9512,7 @@ static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq) cfs_rq->last_h_load_update = now; } - while ((se = cfs_rq->h_load_next) != NULL) { + while ((se = READ_ONCE(cfs_rq->h_load_next)) != NULL) { load = cfs_rq->h_load; load = div64_ul(load * se->avg.load_avg, cfs_rq_load_avg(cfs_rq) + 1); @@ -9646,8 +9707,8 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) mcc->cpu = cpu; #ifdef CONFIG_SCHED_DEBUG raw_spin_unlock_irqrestore(&mcc->lock, flags); - printk_deferred("CPU%d: update max cpu_capacity %lu\n", - cpu, capacity); + printk_deferred(KERN_INFO "CPU%d: update max cpu_capacity %lu\n", + cpu, capacity); goto skip_unlock; #endif } @@ -10808,8 +10869,10 @@ static int need_active_balance(struct lb_env *env) * It's worth migrating the task if the src_cpu's capacity is reduced * because of other sched_class or IRQs if more capacity stays * available on dst_cpu. + * Avoid pulling the CFS task if it is the only task running. */ if ((env->idle != CPU_NOT_IDLE) && + (env->src_rq->nr_running > 1) && (env->src_rq->cfs.h_nr_running == 1)) { if ((check_cpu_capacity(env->src_rq, sd)) && (capacity_of(env->src_cpu)*sd->imbalance_pct < capacity_of(env->dst_cpu)*100)) @@ -10819,6 +10882,7 @@ static int need_active_balance(struct lb_env *env) if ((env->idle != CPU_NOT_IDLE) && (capacity_of(env->src_cpu) < capacity_of(env->dst_cpu)) && ((capacity_orig_of(env->src_cpu) < capacity_orig_of(env->dst_cpu))) && + (env->src_grp_nr_running == 1) && env->src_rq->cfs.h_nr_running == 1 && cpu_overutilized(env->src_cpu) && !cpu_overutilized(env->dst_cpu)) { @@ -11120,6 +11184,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, busiest->active_balance = 1; busiest->push_cpu = this_cpu; active_balance = 1; + mark_reserved(this_cpu); } raw_spin_unlock_irqrestore(&busiest->lock, flags); @@ -11504,6 +11569,7 @@ static int active_load_balance_cpu_stop(void *data) busiest_rq->active_balance = 0; push_task = busiest_rq->push_task; target_cpu = busiest_rq->push_cpu; + clear_reserved(target_cpu); if (push_task) busiest_rq->push_task = NULL; @@ -11514,7 +11580,6 @@ static int active_load_balance_cpu_stop(void *data) if (push_task_detached) attach_one_task(target_rq, push_task); put_task_struct(push_task); - clear_reserved(target_cpu); } if (p) @@ -13016,13 +13081,13 @@ void check_for_migration(struct rq *rq, struct task_struct *p) rcu_read_lock(); new_cpu = find_energy_efficient_cpu(sd, p, cpu, prev_cpu, 0); rcu_read_unlock(); - if ((new_cpu != -1) && - (capacity_orig_of(new_cpu) > capacity_orig_of(cpu))) { + if ((new_cpu != prev_cpu) && (capacity_orig_of(new_cpu) > + capacity_orig_of(prev_cpu))) { active_balance = kick_active_balance(rq, p, new_cpu); if (active_balance) { mark_reserved(new_cpu); raw_spin_unlock(&migration_lock); - stop_one_cpu_nowait(cpu, + stop_one_cpu_nowait(prev_cpu, active_load_balance_cpu_stop, rq, &rq->active_balance_work); return; diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 68c92b6709e9b30b8f06d5379a9290ad52f356af..96636034bb2a89892590624364eed20c18033469 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -26,6 +26,12 @@ SCHED_FEAT(NEXT_BUDDY, false) */ SCHED_FEAT(LAST_BUDDY, true) +/* + * skip buddy i.e task called yield() is always skipped and the + * next entity is selected to run irrespective of the vruntime + */ +SCHED_FEAT(STRICT_SKIP_BUDDY, true) + /* * Consider buddies to be cache hot, decreases the likelyness of a * cache buddy being migrated away, increases cache locality. diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 20f1a0a804ec8d006ced9403cb2b3f61ace8c5f0..95179b0a138225dedfb70a9131dd09a161c581e5 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -127,6 +127,7 @@ static int __maybe_unused one = 1; static int __maybe_unused two = 2; static int __maybe_unused three = 3; static int __maybe_unused four = 4; +static unsigned long zero_ul; static unsigned long one_ul = 1; static unsigned long long_max = LONG_MAX; static int one_hundred = 100; @@ -1889,7 +1890,7 @@ static struct ctl_table fs_table[] = { .maxlen = sizeof(files_stat.max_files), .mode = 0644, .proc_handler = proc_doulongvec_minmax, - .extra1 = &zero, + .extra1 = &zero_ul, .extra2 = &long_max, }, { diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index dbe98d612eb5fe68055036e691d937d5731960b6..b6cc535ecd77704b7a1ef5f28169046ce9bf4aae 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -624,7 +624,7 @@ static ktime_t alarm_timer_remaining(struct k_itimer *timr, ktime_t now) { struct alarm *alarm = &timr->it.alarm.alarmtimer; - return ktime_sub(now, alarm->node.expires); + return ktime_sub(alarm->node.expires, now); } /** diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f0246b9a0e09c6892c2bbb2dfb0c8b91fb682801..e33f1a0175faccafc8c9ee43afff6d72aca40514 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -6036,7 +6037,7 @@ void ftrace_reset_array_ops(struct trace_array *tr) tr->ops->func = ftrace_stub; } -static inline void +static nokprobe_inline void __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ignored, struct pt_regs *regs) { @@ -6099,12 +6100,14 @@ static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, { __ftrace_ops_list_func(ip, parent_ip, NULL, regs); } +NOKPROBE_SYMBOL(ftrace_ops_list_func); #else static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs) { __ftrace_ops_list_func(ip, parent_ip, NULL, NULL); } +NOKPROBE_SYMBOL(ftrace_ops_no_ops); #endif /* @@ -6134,6 +6137,7 @@ static void ftrace_ops_assist_func(unsigned long ip, unsigned long parent_ip, preempt_enable_notrace(); trace_clear_recursion(bit); } +NOKPROBE_SYMBOL(ftrace_ops_assist_func); /** * ftrace_ops_get_func - get the function a trampoline should call diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 5f7f4f07499fe045f6937cbb9836286eef2aaefa..8123a8b53c54b2c13e470bef8e971a8509011149 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -700,7 +700,7 @@ u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu) preempt_disable_notrace(); time = rb_time_stamp(buffer); - preempt_enable_no_resched_notrace(); + preempt_enable_notrace(); return time; } diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2adbd23be06386fd241c26fb70bc5f829c29d732..00a2ddaa64167400da1f267f0fac1c3bbfc4cb48 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -495,8 +495,10 @@ int trace_pid_write(struct trace_pid_list *filtered_pids, * not modified. */ pid_list = kmalloc(sizeof(*pid_list), GFP_KERNEL); - if (!pid_list) + if (!pid_list) { + trace_parser_put(&parser); return -ENOMEM; + } pid_list->pid_max = READ_ONCE(pid_max); @@ -506,6 +508,7 @@ int trace_pid_write(struct trace_pid_list *filtered_pids, pid_list->pids = vzalloc((pid_list->pid_max + 7) >> 3); if (!pid_list->pids) { + trace_parser_put(&parser); kfree(pid_list); return -ENOMEM; } @@ -6727,28 +6730,36 @@ struct buffer_ref { struct ring_buffer *buffer; void *page; int cpu; - int ref; + refcount_t refcount; }; +static void buffer_ref_release(struct buffer_ref *ref) +{ + if (!refcount_dec_and_test(&ref->refcount)) + return; + ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->page); + kfree(ref); +} + static void buffer_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { struct buffer_ref *ref = (struct buffer_ref *)buf->private; - if (--ref->ref) - return; - - ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->page); - kfree(ref); + buffer_ref_release(ref); buf->private = 0; } -static void buffer_pipe_buf_get(struct pipe_inode_info *pipe, +static bool buffer_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { struct buffer_ref *ref = (struct buffer_ref *)buf->private; - ref->ref++; + if (refcount_read(&ref->refcount) > INT_MAX/2) + return false; + + refcount_inc(&ref->refcount); + return true; } /* Pipe buffer operations for a buffer. */ @@ -6756,7 +6767,7 @@ static const struct pipe_buf_operations buffer_pipe_buf_ops = { .can_merge = 0, .confirm = generic_pipe_buf_confirm, .release = buffer_pipe_buf_release, - .steal = generic_pipe_buf_steal, + .steal = generic_pipe_buf_nosteal, .get = buffer_pipe_buf_get, }; @@ -6769,11 +6780,7 @@ static void buffer_spd_release(struct splice_pipe_desc *spd, unsigned int i) struct buffer_ref *ref = (struct buffer_ref *)spd->partial[i].private; - if (--ref->ref) - return; - - ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->page); - kfree(ref); + buffer_ref_release(ref); spd->partial[i].private = 0; } @@ -6828,7 +6835,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, break; } - ref->ref = 1; + refcount_set(&ref->refcount, 1); ref->buffer = iter->trace_buffer->buffer; ref->page = ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file); if (IS_ERR(ref->page)) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 7d0fa2f9f4314387913fff2c9a01aa4956730e4c..335b0fac8893ff20fe9b39cf4a5347eb95ae51e1 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2006,6 +2006,7 @@ config TEST_KMOD depends on m depends on BLOCK && (64BIT || LBDAF) # for XFS, BTRFS depends on NETDEVICES && NET_CORE && INET # for TUN + depends on BLOCK select TEST_LKM select XFS_FS select TUN diff --git a/lib/Makefile b/lib/Makefile index 2f5e08eb4264b48d7a6d77ad4926149fae419d9c..76eb6a7602c0bc685fb8799b7b7c286b740d0e2f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o obj-$(CONFIG_TEST_KASAN) += test_kasan.o +CFLAGS_test_kasan.o += -fno-builtin obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o obj-$(CONFIG_TEST_LKM) += test_module.o diff --git a/lib/div64.c b/lib/div64.c index 58e2a404097e9f5a47269138dcb843d1a39084a8..a2688b882461fd2c24228d9edd1b3e938852bb85 100644 --- a/lib/div64.c +++ b/lib/div64.c @@ -103,7 +103,7 @@ u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) quot = div_u64_rem(dividend, divisor, &rem32); *remainder = rem32; } else { - int n = 1 + fls(high); + int n = fls(high); quot = div_u64(dividend >> n, divisor >> n); if (quot != 0) @@ -141,7 +141,7 @@ u64 div64_u64(u64 dividend, u64 divisor) if (high == 0) { quot = div_u64(dividend, divisor); } else { - int n = 1 + fls(high); + int n = fls(high); quot = div_u64(dividend >> n, divisor >> n); if (quot != 0) diff --git a/lib/string.c b/lib/string.c index 5e8d410a93df5eb569e15815782be2027ec69d6e..1530643edf006016cca818b2b038e428175222c5 100644 --- a/lib/string.c +++ b/lib/string.c @@ -865,6 +865,26 @@ __visible int memcmp(const void *cs, const void *ct, size_t count) EXPORT_SYMBOL(memcmp); #endif +#ifndef __HAVE_ARCH_BCMP +/** + * bcmp - returns 0 if and only if the buffers have identical contents. + * @a: pointer to first buffer. + * @b: pointer to second buffer. + * @len: size of buffers. + * + * The sign or magnitude of a non-zero return value has no particular + * meaning, and architectures may implement their own more efficient bcmp(). So + * while this particular implementation is a simple (tail) call to memcmp, do + * not rely on anything but whether the return value is zero or non-zero. + */ +#undef bcmp +int bcmp(const void *a, const void *b, size_t len) +{ + return memcmp(a, b, len); +} +EXPORT_SYMBOL(bcmp); +#endif + #ifndef __HAVE_ARCH_MEMSCAN /** * memscan - Find a character in an area of memory. diff --git a/lib/test_kasan.c b/lib/test_kasan.c index f7ca1f02025eb04be8d7fc913072105036c1d465..38055c694767d3e8f5a2aced96290142739575f9 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -420,7 +420,7 @@ static noinline void __init kasan_stack_oob(void) static noinline void __init ksize_unpoisons_memory(void) { char *ptr; - size_t size = 123, real_size = size; + size_t size = 123, real_size; pr_info("ksize() unpoisons the whole allocated chunk\n"); ptr = kmalloc(size, GFP_KERNEL); diff --git a/mm/gup.c b/mm/gup.c index 7c0e5b1bbcd4c5fcceeac86c63380673381cb2e9..babcbd6d99c359f46c1c1f98dd131df3230b9ad9 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -153,7 +153,10 @@ static struct page *follow_page_pte(struct vm_area_struct *vma, } if (flags & FOLL_GET) { - get_page(page); + if (unlikely(!try_get_page(page))) { + page = ERR_PTR(-ENOMEM); + goto out; + } /* drop the pgmap reference now that we hold the page */ if (pgmap) { @@ -280,7 +283,10 @@ static struct page *follow_pmd_mask(struct vm_area_struct *vma, if (pmd_trans_unstable(pmd)) ret = -EBUSY; } else { - get_page(page); + if (unlikely(!try_get_page(page))) { + spin_unlock(ptl); + return ERR_PTR(-ENOMEM); + } spin_unlock(ptl); lock_page(page); ret = split_huge_page(page); @@ -464,7 +470,10 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address, if (is_device_public_page(*page)) goto unmap; } - get_page(*page); + if (unlikely(!try_get_page(*page))) { + ret = -ENOMEM; + goto unmap; + } out: ret = 0; unmap: @@ -1365,6 +1374,20 @@ static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages) } } +/* + * Return the compund head page with ref appropriately incremented, + * or NULL if that failed. + */ +static inline struct page *try_get_compound_head(struct page *page, int refs) +{ + struct page *head = compound_head(page); + if (WARN_ON_ONCE(page_ref_count(head) < 0)) + return NULL; + if (unlikely(!page_cache_add_speculative(head, refs))) + return NULL; + return head; +} + #ifdef __HAVE_ARCH_PTE_SPECIAL static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) @@ -1399,9 +1422,9 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, VM_BUG_ON(!pfn_valid(pte_pfn(pte))); page = pte_page(pte); - head = compound_head(page); - if (!page_cache_get_speculative(head)) + head = try_get_compound_head(page, 1); + if (!head) goto pte_unmap; if (unlikely(pte_val(pte) != pte_val(*ptep))) { @@ -1537,8 +1560,8 @@ static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr, refs++; } while (addr += PAGE_SIZE, addr != end); - head = compound_head(pmd_page(orig)); - if (!page_cache_add_speculative(head, refs)) { + head = try_get_compound_head(pmd_page(orig), refs); + if (!head) { *nr -= refs; return 0; } @@ -1575,8 +1598,8 @@ static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr, refs++; } while (addr += PAGE_SIZE, addr != end); - head = compound_head(pud_page(orig)); - if (!page_cache_add_speculative(head, refs)) { + head = try_get_compound_head(pud_page(orig), refs); + if (!head) { *nr -= refs; return 0; } @@ -1612,8 +1635,8 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr, refs++; } while (addr += PAGE_SIZE, addr != end); - head = compound_head(pgd_page(orig)); - if (!page_cache_add_speculative(head, refs)) { + head = try_get_compound_head(pgd_page(orig), refs); + if (!head) { *nr -= refs; return 0; } diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 6ae10dca7538960e3f48bbc32070401758b5c35a..d1477993f556b6dd020443c1ff8592e27e4f88d7 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4257,6 +4257,19 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, pfn_offset = (vaddr & ~huge_page_mask(h)) >> PAGE_SHIFT; page = pte_page(huge_ptep_get(pte)); + + /* + * Instead of doing 'try_get_page()' below in the same_page + * loop, just check the count once here. + */ + if (unlikely(page_count(page) <= 0)) { + if (pages) { + spin_unlock(ptl); + remainder = 0; + err = -ENOMEM; + break; + } + } same_page: if (pages) { pages[i] = mem_map_offset(page, pfn_offset); diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 559ceb4d187ebe7e146e35bff9691c7f3e9a5ecb..a65804dcd54ba81d57d283b5ae44bdf5f5576cf4 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1376,6 +1376,7 @@ static void scan_block(void *_start, void *_end, /* * Scan a large memory block in MAX_SCAN_SIZE chunks to reduce the latency. */ +#ifdef CONFIG_SMP static void scan_large_block(void *start, void *end) { void *next; @@ -1387,6 +1388,7 @@ static void scan_large_block(void *start, void *end) cond_resched(); } } +#endif /* * Scan a memory block corresponding to a kmemleak_object. A condition is @@ -1504,11 +1506,6 @@ static void kmemleak_scan(void) } rcu_read_unlock(); - /* data/bss scanning */ - scan_large_block(_sdata, _edata); - scan_large_block(__bss_start, __bss_stop); - scan_large_block(__start_ro_after_init, __end_ro_after_init); - #ifdef CONFIG_SMP /* per-cpu sections scanning */ for_each_possible_cpu(i) @@ -2039,6 +2036,17 @@ void __init kmemleak_init(void) } local_irq_restore(flags); + /* register the data/bss sections */ + create_object((unsigned long)_sdata, _edata - _sdata, + KMEMLEAK_GREY, GFP_ATOMIC); + create_object((unsigned long)__bss_start, __bss_stop - __bss_start, + KMEMLEAK_GREY, GFP_ATOMIC); + /* only register .data..ro_after_init if not within .data */ + if (__start_ro_after_init < _sdata || __end_ro_after_init > _edata) + create_object((unsigned long)__start_ro_after_init, + __end_ro_after_init - __start_ro_after_init, + KMEMLEAK_GREY, GFP_ATOMIC); + /* * This is the point where tracking allocations is safe. Automatic * scanning is started during the late initcall. Add the early logged diff --git a/mm/memory.c b/mm/memory.c index 4469b592603a70aac08aeed6a904c4ec220c4d32..f513cbc9a3806b3f54365c32e92a0f55f294a1ec 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1818,10 +1818,15 @@ static int insert_pfn(struct vm_area_struct *vma, unsigned long addr, * in may not match the PFN we have mapped if the * mapped PFN is a writeable COW page. In the mkwrite * case we are creating a writable PTE for a shared - * mapping and we expect the PFNs to match. + * mapping and we expect the PFNs to match. If they + * don't match, we are likely racing with block + * allocation and mapping invalidation so just skip the + * update. */ - if (WARN_ON_ONCE(pte_pfn(*pte) != pfn_t_to_pfn(pfn))) + if (pte_pfn(*pte) != pfn_t_to_pfn(pfn)) { + WARN_ON_ONCE(!is_zero_pfn(pte_pfn(*pte))); goto out_unlock; + } entry = *pte; goto out_mkwrite; } else diff --git a/mm/mmap.c b/mm/mmap.c index 4f4a84054dbe99dcabf097099290222b0d0d0e7b..84d04d1bd2708396b4f5cb22f104d43f833bdd50 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -2559,7 +2560,8 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) vma = find_vma_prev(mm, addr, &prev); if (vma && (vma->vm_start <= addr)) return vma; - if (!prev || expand_stack(prev, addr)) + /* don't alter vm_end if the coredump is running */ + if (!prev || !mmget_still_valid(mm) || expand_stack(prev, addr)) return NULL; if (prev->vm_flags & VM_LOCKED) populate_vma_page_range(prev, addr, prev->vm_end, NULL); @@ -2585,6 +2587,9 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) return vma; if (!(vma->vm_flags & VM_GROWSDOWN)) return NULL; + /* don't alter vm_start if the coredump is running */ + if (!mmget_still_valid(mm)) + return NULL; start = vma->vm_start; if (expand_stack(vma, addr)) return NULL; diff --git a/mm/percpu.c b/mm/percpu.c index 3074148b7e0d3e7acf912d2c7ca30e576b0a68a9..0c06e2f549a7bab4f2d4f4a9663d4e64d31a55b3 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -2507,8 +2507,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, ai->groups[group].base_offset = areas[group] - base; } - pr_info("Embedded %zu pages/cpu @%p s%zu r%zu d%zu u%zu\n", - PFN_DOWN(size_sum), base, ai->static_size, ai->reserved_size, + pr_info("Embedded %zu pages/cpu s%zu r%zu d%zu u%zu\n", + PFN_DOWN(size_sum), ai->static_size, ai->reserved_size, ai->dyn_size, ai->unit_size); rc = pcpu_setup_first_chunk(ai, base); @@ -2629,8 +2629,8 @@ int __init pcpu_page_first_chunk(size_t reserved_size, } /* we're ready, commit */ - pr_info("%d %s pages/cpu @%p s%zu r%zu d%zu\n", - unit_pages, psize_str, vm.addr, ai->static_size, + pr_info("%d %s pages/cpu s%zu r%zu d%zu\n", + unit_pages, psize_str, ai->static_size, ai->reserved_size, ai->dyn_size); rc = pcpu_setup_first_chunk(ai, vm.addr); diff --git a/mm/swapfile.c b/mm/swapfile.c index f1f8dcc4453a2ceb214f54ce5abc5b8627b2d48c..4c7fa1c020055bc1cec8e95cad591d62243ff005 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2645,7 +2645,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (p->flags & SWP_CONTINUED) free_swap_count_continuations(p); - if (!p->bdev || !blk_queue_nonrot(bdev_get_queue(p->bdev))) + if (!p->bdev || (p->bdev->bd_disk->flags & GENHD_FL_NO_RANDOMIZE) || + !blk_queue_nonrot(bdev_get_queue(p->bdev))) atomic_dec(&nr_rotate_swap); mutex_lock(&swapon_mutex); @@ -3220,7 +3221,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (bdi_cap_synchronous_io(inode_to_bdi(inode))) p->flags |= SWP_SYNCHRONOUS_IO; - if (p->bdev && blk_queue_nonrot(bdev_get_queue(p->bdev))) { + if (p->bdev && !(p->bdev->bd_disk->flags & GENHD_FL_NO_RANDOMIZE) && + blk_queue_nonrot(bdev_get_queue(p->bdev))) { int cpu; unsigned long ci, nr_cluster; diff --git a/mm/vmscan.c b/mm/vmscan.c index 736459ba475289d5d0577eca1ecf5a7ae7d58b9e..08aae8a232f85b8248891defb248a0b33ba68e42 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -502,6 +502,15 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid, sc.nid = 0; freed += do_shrink_slab(&sc, shrinker, priority); + /* + * Bail out if someone want to register a new shrinker to + * prevent the regsitration from being stalled for long periods + * by parallel ongoing shrinking. + */ + if (rwsem_is_contended(&shrinker_rwsem)) { + freed = freed ? : 1; + break; + } } up_read(&shrinker_rwsem); diff --git a/mm/vmstat.c b/mm/vmstat.c index 41327c050a3881c8db1f1b3faa0401c683d50101..ea5653252461d32984715cbd476e82e37eb2a491 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1204,13 +1204,8 @@ const char * const vmstat_text[] = { #endif #endif /* CONFIG_MEMORY_BALLOON */ #ifdef CONFIG_DEBUG_TLBFLUSH -#ifdef CONFIG_SMP "nr_tlb_remote_flush", "nr_tlb_remote_flush_received", -#else - "", /* nr_tlb_remote_flush */ - "", /* nr_tlb_remote_flush_received */ -#endif /* CONFIG_SMP */ "nr_tlb_local_flush_all", "nr_tlb_local_flush_one", #endif /* CONFIG_DEBUG_TLBFLUSH */ diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 9743837aebc60347911f90a3e243ebd808390a9b..766d1ef4640a316022f91bcc3e4e9a495e4a7e56 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -570,9 +570,10 @@ int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st) if (ret) { p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); trace_9p_protocol_dump(clnt, &fake_pdu); + return ret; } - return ret; + return fake_pdu.offset; } EXPORT_SYMBOL(p9stat_read); diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c index af46bc49e1e9946ce1ff4ff0fc772ce14a231670..b5f84f428aa6c15c37212ae0c5c5acb4348a0339 100644 --- a/net/appletalk/atalk_proc.c +++ b/net/appletalk/atalk_proc.c @@ -293,7 +293,7 @@ int __init atalk_proc_init(void) goto out; } -void __exit atalk_proc_exit(void) +void atalk_proc_exit(void) { remove_proc_entry("interface", atalk_proc_dir); remove_proc_entry("route", atalk_proc_dir); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 5d035c1f1156e45540a6bf935341e5799b11ca85..d1b68cc7da8992904141c6fd9bcc32a85e598847 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1912,12 +1912,16 @@ static const char atalk_err_snap[] __initconst = /* Called by proto.c on kernel start up */ static int __init atalk_init(void) { - int rc = proto_register(&ddp_proto, 0); + int rc; - if (rc != 0) + rc = proto_register(&ddp_proto, 0); + if (rc) goto out; - (void)sock_register(&atalk_family_ops); + rc = sock_register(&atalk_family_ops); + if (rc) + goto out_proto; + ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv); if (!ddp_dl) printk(atalk_err_snap); @@ -1925,12 +1929,33 @@ static int __init atalk_init(void) dev_add_pack(<alk_packet_type); dev_add_pack(&ppptalk_packet_type); - register_netdevice_notifier(&ddp_notifier); + rc = register_netdevice_notifier(&ddp_notifier); + if (rc) + goto out_sock; + aarp_proto_init(); - atalk_proc_init(); - atalk_register_sysctl(); + rc = atalk_proc_init(); + if (rc) + goto out_aarp; + + rc = atalk_register_sysctl(); + if (rc) + goto out_proc; out: return rc; +out_proc: + atalk_proc_exit(); +out_aarp: + aarp_cleanup_module(); + unregister_netdevice_notifier(&ddp_notifier); +out_sock: + dev_remove_pack(&ppptalk_packet_type); + dev_remove_pack(<alk_packet_type); + unregister_snap_client(ddp_dl); + sock_unregister(PF_APPLETALK); +out_proto: + proto_unregister(&ddp_proto); + goto out; } module_init(atalk_init); diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c index c744a853fa5f7eeee06910e909dd8fa4980db3ee..d945b7c0176dba5807195eda77c8413b3920bf10 100644 --- a/net/appletalk/sysctl_net_atalk.c +++ b/net/appletalk/sysctl_net_atalk.c @@ -45,9 +45,12 @@ static struct ctl_table atalk_table[] = { static struct ctl_table_header *atalk_table_header; -void atalk_register_sysctl(void) +int __init atalk_register_sysctl(void) { atalk_table_header = register_net_sysctl(&init_net, "net/appletalk", atalk_table); + if (!atalk_table_header) + return -ENOMEM; + return 0; } void atalk_unregister_sysctl(void) diff --git a/net/atm/lec.c b/net/atm/lec.c index 9f2365694ad4a4e76dec293fdcfed6705338f6bc..85ce89c8a35c993f534769e0e28f3e7aead9d381 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -710,7 +710,10 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) static int lec_mcast_attach(struct atm_vcc *vcc, int arg) { - if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) + if (arg < 0 || arg >= MAX_LEC_ITF) + return -EINVAL; + arg = array_index_nospec(arg, MAX_LEC_ITF); + if (!dev_lec[arg]) return -EINVAL; vcc->proto_data = dev_lec[arg]; return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc); @@ -728,6 +731,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg) i = arg; if (arg >= MAX_LEC_ITF) return -EINVAL; + i = array_index_nospec(arg, MAX_LEC_ITF); if (!dev_lec[i]) { int size; diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index c3c848f64fdd57e607617a644888dec70df858e3..c761c0c233e4b4765abdf818b14028808520cec7 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -803,6 +803,8 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, const u8 *mac, const unsigned short vid) { struct batadv_bla_claim search_claim, *claim; + struct batadv_bla_claim *claim_removed_entry; + struct hlist_node *claim_removed_node; ether_addr_copy(search_claim.addr, mac); search_claim.vid = vid; @@ -813,10 +815,18 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): %pM, vid %d\n", __func__, mac, batadv_print_vid(vid)); - batadv_hash_remove(bat_priv->bla.claim_hash, batadv_compare_claim, - batadv_choose_claim, claim); - batadv_claim_put(claim); /* reference from the hash is gone */ + claim_removed_node = batadv_hash_remove(bat_priv->bla.claim_hash, + batadv_compare_claim, + batadv_choose_claim, claim); + if (!claim_removed_node) + goto free_claim; + /* reference from the hash is gone */ + claim_removed_entry = hlist_entry(claim_removed_node, + struct batadv_bla_claim, hash_entry); + batadv_claim_put(claim_removed_entry); + +free_claim: /* don't need the reference from hash_find() anymore */ batadv_claim_put(claim); } diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 9da3455847ffabf831a135cda1f63c010f2b8387..020a8adc4cce8524ac38497eb8122a2bdc545d53 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -614,14 +614,26 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global, const char *message) { + struct batadv_tt_global_entry *tt_removed_entry; + struct hlist_node *tt_removed_node; + batadv_dbg(BATADV_DBG_TT, bat_priv, "Deleting global tt entry %pM (vid: %d): %s\n", tt_global->common.addr, batadv_print_vid(tt_global->common.vid), message); - batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, - batadv_choose_tt, &tt_global->common); - batadv_tt_global_entry_put(tt_global); + tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash, + batadv_compare_tt, + batadv_choose_tt, + &tt_global->common); + if (!tt_removed_node) + return; + + /* drop reference of remove hash entry */ + tt_removed_entry = hlist_entry(tt_removed_node, + struct batadv_tt_global_entry, + common.hash_entry); + batadv_tt_global_entry_put(tt_removed_entry); } /** @@ -1313,9 +1325,10 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid, const char *message, bool roaming) { + struct batadv_tt_local_entry *tt_removed_entry; struct batadv_tt_local_entry *tt_local_entry; u16 flags, curr_flags = BATADV_NO_FLAGS; - void *tt_entry_exists; + struct hlist_node *tt_removed_node; tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) @@ -1344,15 +1357,18 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, */ batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); - tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, + tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash, batadv_compare_tt, batadv_choose_tt, &tt_local_entry->common); - if (!tt_entry_exists) + if (!tt_removed_node) goto out; - /* extra call to free the local tt entry */ - batadv_tt_local_entry_put(tt_local_entry); + /* drop reference of remove hash entry */ + tt_removed_entry = hlist_entry(tt_removed_node, + struct batadv_tt_local_entry, + common.hash_entry); + batadv_tt_local_entry_put(tt_removed_entry); out: if (tt_local_entry) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 7637f58c12263bae0bc907d01d0838c1fd68cf5c..10fa84056cb5286fff78256836e02a311ad55b13 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -236,13 +236,10 @@ static void __br_handle_local_finish(struct sk_buff *skb) /* note: already called with rcu_read_lock */ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { - struct net_bridge_port *p = br_port_get_rcu(skb->dev); - __br_handle_local_finish(skb); - BR_INPUT_SKB_CB(skb)->brdev = p->br->dev; - br_pass_frame_up(skb); - return 0; + /* return 1 to signal the okfn() was called so it's ok to use the skb */ + return 1; } /* @@ -318,10 +315,18 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) goto forward; } - /* Deliver packet to local host only */ - NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev), - NULL, skb, skb->dev, NULL, br_handle_local_finish); - return RX_HANDLER_CONSUMED; + /* The else clause should be hit when nf_hook(): + * - returns < 0 (drop/error) + * - returns = 0 (stolen/nf_queue) + * Thus return 1 from the okfn() to signal the skb is ok to pass + */ + if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, + dev_net(skb->dev), NULL, skb, skb->dev, NULL, + br_handle_local_finish) == 1) { + return RX_HANDLER_PASS; + } else { + return RX_HANDLER_CONSUMED; + } } forward: diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 8dc5c8d69bcd732ff365cd52cd54c386c874335e..e83048cb53cef360bf96884194836eb99217632c 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -2119,7 +2119,8 @@ static void br_multicast_start_querier(struct net_bridge *br, __br_multicast_open(br, query); - list_for_each_entry(port, &br->port_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(port, &br->port_list, list) { if (port->state == BR_STATE_DISABLED || port->state == BR_STATE_BLOCKING) continue; @@ -2131,6 +2132,7 @@ static void br_multicast_start_querier(struct net_bridge *br, br_multicast_enable(&port->ip6_own_query); #endif } + rcu_read_unlock(); } int br_multicast_toggle(struct net_bridge *br, unsigned long val) diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 5fd283d9929e28f7395ecbda4109223328cb2b7e..89936e0d55c9b5d08f8d04a0914b2d81cb5b9812 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -512,6 +512,7 @@ static unsigned int br_nf_pre_routing(void *priv, nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr; skb->protocol = htons(ETH_P_IP); + skb->transport_header = skb->network_header + ip_hdr(skb)->ihl * 4; NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->net, state->sk, skb, skb->dev, NULL, diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c index 5811208863b732293678f003671e1fd580d663c5..09d5e0c7b3ba4270ee24fbe3762cfe6f459aed65 100644 --- a/net/bridge/br_netfilter_ipv6.c +++ b/net/bridge/br_netfilter_ipv6.c @@ -235,6 +235,8 @@ unsigned int br_nf_pre_routing_ipv6(void *priv, nf_bridge->ipv6_daddr = ipv6_hdr(skb)->daddr; skb->protocol = htons(ETH_P_IPV6); + skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); + NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, state->net, state->sk, skb, skb->dev, NULL, br_nf_pre_routing_finish_ipv6); diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 38b3309edba8b325863af7ea0c4add4b65ec6c71..b967bd51bf1f95d180e82610173e4c64e00b61d2 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -2030,7 +2030,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, if (match_kern) match_kern->match_size = ret; - if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) + /* rule should have no remaining data after target */ + if (type == EBT_COMPAT_TARGET && size_left) return -EINVAL; match32 = (struct compat_ebt_entry_mwt *) buf; diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index f5afda1abc76fe908e8cce160ad032870972424c..4dc82e9a855d3803ffda0a3406e6ce7d25f6c009 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -352,15 +352,14 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) u8 cmdrsp; u8 cmd; int ret = -1; - u16 tmp16; u8 len; u8 param[255]; - u8 linkid; + u8 linkid = 0; struct cfctrl *cfctrl = container_obj(layer); struct cfctrl_request_info rsp, *req; - cfpkt_extr_head(pkt, &cmdrsp, 1); + cmdrsp = cfpkt_extr_head_u8(pkt); cmd = cmdrsp & CFCTRL_CMD_MASK; if (cmd != CFCTRL_CMD_LINK_ERR && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp) @@ -378,13 +377,12 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) u8 physlinkid; u8 prio; u8 tmp; - u32 tmp32; u8 *cp; int i; struct cfctrl_link_param linkparam; memset(&linkparam, 0, sizeof(linkparam)); - cfpkt_extr_head(pkt, &tmp, 1); + tmp = cfpkt_extr_head_u8(pkt); serv = tmp & CFCTRL_SRV_MASK; linkparam.linktype = serv; @@ -392,13 +390,13 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) servtype = tmp >> 4; linkparam.chtype = servtype; - cfpkt_extr_head(pkt, &tmp, 1); + tmp = cfpkt_extr_head_u8(pkt); physlinkid = tmp & 0x07; prio = tmp >> 3; linkparam.priority = prio; linkparam.phyid = physlinkid; - cfpkt_extr_head(pkt, &endpoint, 1); + endpoint = cfpkt_extr_head_u8(pkt); linkparam.endpoint = endpoint & 0x03; switch (serv) { @@ -407,45 +405,43 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) if (CFCTRL_ERR_BIT & cmdrsp) break; /* Link ID */ - cfpkt_extr_head(pkt, &linkid, 1); + linkid = cfpkt_extr_head_u8(pkt); break; case CFCTRL_SRV_VIDEO: - cfpkt_extr_head(pkt, &tmp, 1); + tmp = cfpkt_extr_head_u8(pkt); linkparam.u.video.connid = tmp; if (CFCTRL_ERR_BIT & cmdrsp) break; /* Link ID */ - cfpkt_extr_head(pkt, &linkid, 1); + linkid = cfpkt_extr_head_u8(pkt); break; case CFCTRL_SRV_DATAGRAM: - cfpkt_extr_head(pkt, &tmp32, 4); linkparam.u.datagram.connid = - le32_to_cpu(tmp32); + cfpkt_extr_head_u32(pkt); if (CFCTRL_ERR_BIT & cmdrsp) break; /* Link ID */ - cfpkt_extr_head(pkt, &linkid, 1); + linkid = cfpkt_extr_head_u8(pkt); break; case CFCTRL_SRV_RFM: /* Construct a frame, convert * DatagramConnectionID * to network format long and copy it out... */ - cfpkt_extr_head(pkt, &tmp32, 4); linkparam.u.rfm.connid = - le32_to_cpu(tmp32); + cfpkt_extr_head_u32(pkt); cp = (u8 *) linkparam.u.rfm.volume; - for (cfpkt_extr_head(pkt, &tmp, 1); + for (tmp = cfpkt_extr_head_u8(pkt); cfpkt_more(pkt) && tmp != '\0'; - cfpkt_extr_head(pkt, &tmp, 1)) + tmp = cfpkt_extr_head_u8(pkt)) *cp++ = tmp; *cp = '\0'; if (CFCTRL_ERR_BIT & cmdrsp) break; /* Link ID */ - cfpkt_extr_head(pkt, &linkid, 1); + linkid = cfpkt_extr_head_u8(pkt); break; case CFCTRL_SRV_UTIL: @@ -454,13 +450,11 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) * to network format long and copy it out... */ /* Fifosize KB */ - cfpkt_extr_head(pkt, &tmp16, 2); linkparam.u.utility.fifosize_kb = - le16_to_cpu(tmp16); + cfpkt_extr_head_u16(pkt); /* Fifosize bufs */ - cfpkt_extr_head(pkt, &tmp16, 2); linkparam.u.utility.fifosize_bufs = - le16_to_cpu(tmp16); + cfpkt_extr_head_u16(pkt); /* name */ cp = (u8 *) linkparam.u.utility.name; caif_assert(sizeof(linkparam.u.utility.name) @@ -468,24 +462,24 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) for (i = 0; i < UTILITY_NAME_LENGTH && cfpkt_more(pkt); i++) { - cfpkt_extr_head(pkt, &tmp, 1); + tmp = cfpkt_extr_head_u8(pkt); *cp++ = tmp; } /* Length */ - cfpkt_extr_head(pkt, &len, 1); + len = cfpkt_extr_head_u8(pkt); linkparam.u.utility.paramlen = len; /* Param Data */ cp = linkparam.u.utility.params; while (cfpkt_more(pkt) && len--) { - cfpkt_extr_head(pkt, &tmp, 1); + tmp = cfpkt_extr_head_u8(pkt); *cp++ = tmp; } if (CFCTRL_ERR_BIT & cmdrsp) break; /* Link ID */ - cfpkt_extr_head(pkt, &linkid, 1); + linkid = cfpkt_extr_head_u8(pkt); /* Length */ - cfpkt_extr_head(pkt, &len, 1); + len = cfpkt_extr_head_u8(pkt); /* Param Data */ cfpkt_extr_head(pkt, ¶m, len); break; @@ -522,7 +516,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) } break; case CFCTRL_CMD_LINK_DESTROY: - cfpkt_extr_head(pkt, &linkid, 1); + linkid = cfpkt_extr_head_u8(pkt); cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid); break; case CFCTRL_CMD_LINK_ERR: diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 41161b899b1ec3d2140994312112d74e4df56d6e..050c42fe573936ea06e7231972874ce1cc63b351 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1817,11 +1817,15 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) WARN_ON_ONCE(!ret); gstrings.len = ret; - data = vzalloc(gstrings.len * ETH_GSTRING_LEN); - if (gstrings.len && !data) - return -ENOMEM; + if (gstrings.len) { + data = vzalloc(gstrings.len * ETH_GSTRING_LEN); + if (!data) + return -ENOMEM; - __ethtool_get_strings(dev, gstrings.string_set, data); + __ethtool_get_strings(dev, gstrings.string_set, data); + } else { + data = NULL; + } ret = -EFAULT; if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) @@ -1917,11 +1921,14 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) return -EFAULT; stats.n_stats = n_stats; - data = vzalloc(n_stats * sizeof(u64)); - if (n_stats && !data) - return -ENOMEM; - - ops->get_ethtool_stats(dev, &stats, data); + if (n_stats) { + data = vzalloc(n_stats * sizeof(u64)); + if (!data) + return -ENOMEM; + ops->get_ethtool_stats(dev, &stats, data); + } else { + data = NULL; + } ret = -EFAULT; if (copy_to_user(useraddr, &stats, sizeof(stats))) @@ -1957,13 +1964,17 @@ static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr) return -EFAULT; stats.n_stats = n_stats; - data = vzalloc(n_stats * sizeof(u64)); - if (n_stats && !data) - return -ENOMEM; + if (n_stats) { + data = vzalloc(n_stats * sizeof(u64)); + if (!data) + return -ENOMEM; - mutex_lock(&phydev->lock); - phydev->drv->get_stats(phydev, &stats, data); - mutex_unlock(&phydev->lock); + mutex_lock(&phydev->lock); + phydev->drv->get_stats(phydev, &stats, data); + mutex_unlock(&phydev->lock); + } else { + data = NULL; + } ret = -EFAULT; if (copy_to_user(useraddr, &stats, sizeof(stats))) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 0dd6359e5924286ac42efb309067f35447fe0f4f..60b88718b1d48573440278150ec740a2ec935861 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -285,6 +285,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) atomic_set(&net->count, 1); refcount_set(&net->passive, 1); + get_random_bytes(&net->hash_mix, sizeof(u32)); net->dev_base_seq = 1; net->user_ns = user_ns; idr_init(&net->netns_ids); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 56ac81ea44e9706ee6b04e71b7d5cdb17e3f3453..e4a13134e3a18d8868d07a63c94510385fd43445 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3812,7 +3812,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) struct sk_buff *lp, *p = *head; unsigned int delta_truesize; - if (unlikely(p->len + len >= 65536)) + if (unlikely(p->len + len >= 65536 || NAPI_GRO_CB(skb)->flush)) return -E2BIG; lp = NAPI_GRO_CB(p)->last; diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index 2cc224106b6928bafd92460ba59ea69db0778761..ec7a5da561290ac92c234338d306fb300e46e62c 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include "6lowpan_i.h" diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index c9ec1603666bffcfb24597b933a05f53b6d83440..665f11d7388e5cb2c72b35cb055c67c9b49215f8 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -120,6 +120,7 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) struct guehdr *guehdr; void *data; u16 doffset = 0; + u8 proto_ctype; if (!fou) return 1; @@ -211,13 +212,14 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) if (unlikely(guehdr->control)) return gue_control_message(skb, guehdr); + proto_ctype = guehdr->proto_ctype; __skb_pull(skb, sizeof(struct udphdr) + hdrlen); skb_reset_transport_header(skb); if (iptunnel_pull_offloads(skb)) goto drop; - return -guehdr->proto_ctype; + return -proto_ctype; drop: kfree_skb(skb); diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 1d2fb4ac4c6aea9014e7f7108e1f44b448608a07..720ff249e7d7f31a458a7409ef95bf7c3c6df1cd 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -24,6 +24,62 @@ #include #include #include +#include +#include + +/* Use skb->cb to track consecutive/adjacent fragments coming at + * the end of the queue. Nodes in the rb-tree queue will + * contain "runs" of one or more adjacent fragments. + * + * Invariants: + * - next_frag is NULL at the tail of a "run"; + * - the head of a "run" has the sum of all fragment lengths in frag_run_len. + */ +struct ipfrag_skb_cb { + union { + struct inet_skb_parm h4; + struct inet6_skb_parm h6; + }; + struct sk_buff *next_frag; + int frag_run_len; +}; + +#define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb)) + +static void fragcb_clear(struct sk_buff *skb) +{ + RB_CLEAR_NODE(&skb->rbnode); + FRAG_CB(skb)->next_frag = NULL; + FRAG_CB(skb)->frag_run_len = skb->len; +} + +/* Append skb to the last "run". */ +static void fragrun_append_to_last(struct inet_frag_queue *q, + struct sk_buff *skb) +{ + fragcb_clear(skb); + + FRAG_CB(q->last_run_head)->frag_run_len += skb->len; + FRAG_CB(q->fragments_tail)->next_frag = skb; + q->fragments_tail = skb; +} + +/* Create a new "run" with the skb. */ +static void fragrun_create(struct inet_frag_queue *q, struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct ipfrag_skb_cb) > sizeof(skb->cb)); + fragcb_clear(skb); + + if (q->last_run_head) + rb_link_node(&skb->rbnode, &q->last_run_head->rbnode, + &q->last_run_head->rbnode.rb_right); + else + rb_link_node(&skb->rbnode, NULL, &q->rb_fragments.rb_node); + rb_insert_color(&skb->rbnode, &q->rb_fragments); + + q->fragments_tail = skb; + q->last_run_head = skb; +} /* Given the OR values of all fragments, apply RFC 3168 5.3 requirements * Value : 0xff if frame should be dropped. @@ -122,6 +178,28 @@ static void inet_frag_destroy_rcu(struct rcu_head *head) kmem_cache_free(f->frags_cachep, q); } +unsigned int inet_frag_rbtree_purge(struct rb_root *root) +{ + struct rb_node *p = rb_first(root); + unsigned int sum = 0; + + while (p) { + struct sk_buff *skb = rb_entry(p, struct sk_buff, rbnode); + + p = rb_next(p); + rb_erase(&skb->rbnode, root); + while (skb) { + struct sk_buff *next = FRAG_CB(skb)->next_frag; + + sum += skb->truesize; + kfree_skb(skb); + skb = next; + } + } + return sum; +} +EXPORT_SYMBOL(inet_frag_rbtree_purge); + void inet_frag_destroy(struct inet_frag_queue *q) { struct sk_buff *fp; @@ -223,3 +301,218 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, void *key) return fq; } EXPORT_SYMBOL(inet_frag_find); + +int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb, + int offset, int end) +{ + struct sk_buff *last = q->fragments_tail; + + /* RFC5722, Section 4, amended by Errata ID : 3089 + * When reassembling an IPv6 datagram, if + * one or more its constituent fragments is determined to be an + * overlapping fragment, the entire datagram (and any constituent + * fragments) MUST be silently discarded. + * + * Duplicates, however, should be ignored (i.e. skb dropped, but the + * queue/fragments kept for later reassembly). + */ + if (!last) + fragrun_create(q, skb); /* First fragment. */ + else if (last->ip_defrag_offset + last->len < end) { + /* This is the common case: skb goes to the end. */ + /* Detect and discard overlaps. */ + if (offset < last->ip_defrag_offset + last->len) + return IPFRAG_OVERLAP; + if (offset == last->ip_defrag_offset + last->len) + fragrun_append_to_last(q, skb); + else + fragrun_create(q, skb); + } else { + /* Binary search. Note that skb can become the first fragment, + * but not the last (covered above). + */ + struct rb_node **rbn, *parent; + + rbn = &q->rb_fragments.rb_node; + do { + struct sk_buff *curr; + int curr_run_end; + + parent = *rbn; + curr = rb_to_skb(parent); + curr_run_end = curr->ip_defrag_offset + + FRAG_CB(curr)->frag_run_len; + if (end <= curr->ip_defrag_offset) + rbn = &parent->rb_left; + else if (offset >= curr_run_end) + rbn = &parent->rb_right; + else if (offset >= curr->ip_defrag_offset && + end <= curr_run_end) + return IPFRAG_DUP; + else + return IPFRAG_OVERLAP; + } while (*rbn); + /* Here we have parent properly set, and rbn pointing to + * one of its NULL left/right children. Insert skb. + */ + fragcb_clear(skb); + rb_link_node(&skb->rbnode, parent, rbn); + rb_insert_color(&skb->rbnode, &q->rb_fragments); + } + + skb->ip_defrag_offset = offset; + + return IPFRAG_OK; +} +EXPORT_SYMBOL(inet_frag_queue_insert); + +void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb, + struct sk_buff *parent) +{ + struct sk_buff *fp, *head = skb_rb_first(&q->rb_fragments); + struct sk_buff **nextp; + int delta; + + if (head != skb) { + fp = skb_clone(skb, GFP_ATOMIC); + if (!fp) + return NULL; + FRAG_CB(fp)->next_frag = FRAG_CB(skb)->next_frag; + if (RB_EMPTY_NODE(&skb->rbnode)) + FRAG_CB(parent)->next_frag = fp; + else + rb_replace_node(&skb->rbnode, &fp->rbnode, + &q->rb_fragments); + if (q->fragments_tail == skb) + q->fragments_tail = fp; + skb_morph(skb, head); + FRAG_CB(skb)->next_frag = FRAG_CB(head)->next_frag; + rb_replace_node(&head->rbnode, &skb->rbnode, + &q->rb_fragments); + consume_skb(head); + head = skb; + } + WARN_ON(head->ip_defrag_offset != 0); + + delta = -head->truesize; + + /* Head of list must not be cloned. */ + if (skb_unclone(head, GFP_ATOMIC)) + return NULL; + + delta += head->truesize; + if (delta) + add_frag_mem_limit(q->net, delta); + + /* If the first fragment is fragmented itself, we split + * it to two chunks: the first with data and paged part + * and the second, holding only fragments. + */ + if (skb_has_frag_list(head)) { + struct sk_buff *clone; + int i, plen = 0; + + clone = alloc_skb(0, GFP_ATOMIC); + if (!clone) + return NULL; + skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; + skb_frag_list_init(head); + for (i = 0; i < skb_shinfo(head)->nr_frags; i++) + plen += skb_frag_size(&skb_shinfo(head)->frags[i]); + clone->data_len = head->data_len - plen; + clone->len = clone->data_len; + head->truesize += clone->truesize; + clone->csum = 0; + clone->ip_summed = head->ip_summed; + add_frag_mem_limit(q->net, clone->truesize); + skb_shinfo(head)->frag_list = clone; + nextp = &clone->next; + } else { + nextp = &skb_shinfo(head)->frag_list; + } + + return nextp; +} +EXPORT_SYMBOL(inet_frag_reasm_prepare); + +void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head, + void *reasm_data) +{ + struct sk_buff **nextp = (struct sk_buff **)reasm_data; + struct rb_node *rbn; + struct sk_buff *fp; + + skb_push(head, head->data - skb_network_header(head)); + + /* Traverse the tree in order, to build frag_list. */ + fp = FRAG_CB(head)->next_frag; + rbn = rb_next(&head->rbnode); + rb_erase(&head->rbnode, &q->rb_fragments); + while (rbn || fp) { + /* fp points to the next sk_buff in the current run; + * rbn points to the next run. + */ + /* Go through the current run. */ + while (fp) { + *nextp = fp; + nextp = &fp->next; + fp->prev = NULL; + memset(&fp->rbnode, 0, sizeof(fp->rbnode)); + fp->sk = NULL; + head->data_len += fp->len; + head->len += fp->len; + if (head->ip_summed != fp->ip_summed) + head->ip_summed = CHECKSUM_NONE; + else if (head->ip_summed == CHECKSUM_COMPLETE) + head->csum = csum_add(head->csum, fp->csum); + head->truesize += fp->truesize; + fp = FRAG_CB(fp)->next_frag; + } + /* Move to the next run. */ + if (rbn) { + struct rb_node *rbnext = rb_next(rbn); + + fp = rb_to_skb(rbn); + rb_erase(rbn, &q->rb_fragments); + rbn = rbnext; + } + } + sub_frag_mem_limit(q->net, head->truesize); + + *nextp = NULL; + head->next = NULL; + head->prev = NULL; + head->tstamp = q->stamp; +} +EXPORT_SYMBOL(inet_frag_reasm_finish); + +struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q) +{ + struct sk_buff *head; + + if (q->fragments) { + head = q->fragments; + q->fragments = head->next; + } else { + struct sk_buff *skb; + + head = skb_rb_first(&q->rb_fragments); + if (!head) + return NULL; + skb = FRAG_CB(head)->next_frag; + if (skb) + rb_replace_node(&head->rbnode, &skb->rbnode, + &q->rb_fragments); + else + rb_erase(&head->rbnode, &q->rb_fragments); + memset(&head->rbnode, 0, sizeof(head->rbnode)); + barrier(); + } + if (head == q->fragments_tail) + q->fragments_tail = NULL; + + sub_frag_mem_limit(q->net, head->truesize); + + return head; +} +EXPORT_SYMBOL(inet_frag_pull_head); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index d95b32af4a0e3f552405c9e61cc372729834160c..5a1d39e32196e9b822cd8592ea6a6914c4da3908 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -57,57 +57,6 @@ */ static const char ip_frag_cache_name[] = "ip4-frags"; -/* Use skb->cb to track consecutive/adjacent fragments coming at - * the end of the queue. Nodes in the rb-tree queue will - * contain "runs" of one or more adjacent fragments. - * - * Invariants: - * - next_frag is NULL at the tail of a "run"; - * - the head of a "run" has the sum of all fragment lengths in frag_run_len. - */ -struct ipfrag_skb_cb { - struct inet_skb_parm h; - struct sk_buff *next_frag; - int frag_run_len; -}; - -#define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb)) - -static void ip4_frag_init_run(struct sk_buff *skb) -{ - BUILD_BUG_ON(sizeof(struct ipfrag_skb_cb) > sizeof(skb->cb)); - - FRAG_CB(skb)->next_frag = NULL; - FRAG_CB(skb)->frag_run_len = skb->len; -} - -/* Append skb to the last "run". */ -static void ip4_frag_append_to_last_run(struct inet_frag_queue *q, - struct sk_buff *skb) -{ - RB_CLEAR_NODE(&skb->rbnode); - FRAG_CB(skb)->next_frag = NULL; - - FRAG_CB(q->last_run_head)->frag_run_len += skb->len; - FRAG_CB(q->fragments_tail)->next_frag = skb; - q->fragments_tail = skb; -} - -/* Create a new "run" with the skb. */ -static void ip4_frag_create_run(struct inet_frag_queue *q, struct sk_buff *skb) -{ - if (q->last_run_head) - rb_link_node(&skb->rbnode, &q->last_run_head->rbnode, - &q->last_run_head->rbnode.rb_right); - else - rb_link_node(&skb->rbnode, NULL, &q->rb_fragments.rb_node); - rb_insert_color(&skb->rbnode, &q->rb_fragments); - - ip4_frag_init_run(skb); - q->fragments_tail = skb; - q->last_run_head = skb; -} - /* Describe an entry in the "incomplete datagrams" queue. */ struct ipq { struct inet_frag_queue q; @@ -212,27 +161,9 @@ static void ip_expire(struct timer_list *t) * pull the head out of the tree in order to be able to * deal with head->dev. */ - if (qp->q.fragments) { - head = qp->q.fragments; - qp->q.fragments = head->next; - } else { - head = skb_rb_first(&qp->q.rb_fragments); - if (!head) - goto out; - if (FRAG_CB(head)->next_frag) - rb_replace_node(&head->rbnode, - &FRAG_CB(head)->next_frag->rbnode, - &qp->q.rb_fragments); - else - rb_erase(&head->rbnode, &qp->q.rb_fragments); - memset(&head->rbnode, 0, sizeof(head->rbnode)); - barrier(); - } - if (head == qp->q.fragments_tail) - qp->q.fragments_tail = NULL; - - sub_frag_mem_limit(qp->q.net, head->truesize); - + head = inet_frag_pull_head(&qp->q); + if (!head) + goto out; head->dev = dev_get_by_index_rcu(net, qp->iif); if (!head->dev) goto out; @@ -345,12 +276,10 @@ static int ip_frag_reinit(struct ipq *qp) static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) { struct net *net = container_of(qp->q.net, struct net, ipv4.frags); - struct rb_node **rbn, *parent; - struct sk_buff *skb1, *prev_tail; - int ihl, end, skb1_run_end; + int ihl, end, flags, offset; + struct sk_buff *prev_tail; struct net_device *dev; unsigned int fragsize; - int flags, offset; int err = -ENOENT; u8 ecn; @@ -382,7 +311,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) */ if (end < qp->q.len || ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) - goto err; + goto discard_qp; qp->q.flags |= INET_FRAG_LAST_IN; qp->q.len = end; } else { @@ -394,82 +323,33 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) if (end > qp->q.len) { /* Some bits beyond end -> corruption. */ if (qp->q.flags & INET_FRAG_LAST_IN) - goto err; + goto discard_qp; qp->q.len = end; } } if (end == offset) - goto err; + goto discard_qp; err = -ENOMEM; if (!pskb_pull(skb, skb_network_offset(skb) + ihl)) - goto err; + goto discard_qp; err = pskb_trim_rcsum(skb, end - offset); if (err) - goto err; + goto discard_qp; /* Note : skb->rbnode and skb->dev share the same location. */ dev = skb->dev; /* Makes sure compiler wont do silly aliasing games */ barrier(); - /* RFC5722, Section 4, amended by Errata ID : 3089 - * When reassembling an IPv6 datagram, if - * one or more its constituent fragments is determined to be an - * overlapping fragment, the entire datagram (and any constituent - * fragments) MUST be silently discarded. - * - * We do the same here for IPv4 (and increment an snmp counter) but - * we do not want to drop the whole queue in response to a duplicate - * fragment. - */ - - err = -EINVAL; - /* Find out where to put this fragment. */ prev_tail = qp->q.fragments_tail; - if (!prev_tail) - ip4_frag_create_run(&qp->q, skb); /* First fragment. */ - else if (prev_tail->ip_defrag_offset + prev_tail->len < end) { - /* This is the common case: skb goes to the end. */ - /* Detect and discard overlaps. */ - if (offset < prev_tail->ip_defrag_offset + prev_tail->len) - goto discard_qp; - if (offset == prev_tail->ip_defrag_offset + prev_tail->len) - ip4_frag_append_to_last_run(&qp->q, skb); - else - ip4_frag_create_run(&qp->q, skb); - } else { - /* Binary search. Note that skb can become the first fragment, - * but not the last (covered above). - */ - rbn = &qp->q.rb_fragments.rb_node; - do { - parent = *rbn; - skb1 = rb_to_skb(parent); - skb1_run_end = skb1->ip_defrag_offset + - FRAG_CB(skb1)->frag_run_len; - if (end <= skb1->ip_defrag_offset) - rbn = &parent->rb_left; - else if (offset >= skb1_run_end) - rbn = &parent->rb_right; - else if (offset >= skb1->ip_defrag_offset && - end <= skb1_run_end) - goto err; /* No new data, potential duplicate */ - else - goto discard_qp; /* Found an overlap */ - } while (*rbn); - /* Here we have parent properly set, and rbn pointing to - * one of its NULL left/right children. Insert skb. - */ - ip4_frag_init_run(skb); - rb_link_node(&skb->rbnode, parent, rbn); - rb_insert_color(&skb->rbnode, &qp->q.rb_fragments); - } + err = inet_frag_queue_insert(&qp->q, skb, offset, end); + if (err) + goto insert_error; if (dev) qp->iif = dev->ifindex; - skb->ip_defrag_offset = offset; qp->q.stamp = skb->tstamp; qp->q.meat += skb->len; @@ -494,15 +374,24 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) skb->_skb_refdst = 0UL; err = ip_frag_reasm(qp, skb, prev_tail, dev); skb->_skb_refdst = orefdst; + if (err) + inet_frag_kill(&qp->q); return err; } skb_dst_drop(skb); return -EINPROGRESS; +insert_error: + if (err == IPFRAG_DUP) { + kfree_skb(skb); + return -EINVAL; + } + err = -EINVAL; + __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS); discard_qp: inet_frag_kill(&qp->q); - __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS); + __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); err: kfree_skb(skb); return err; @@ -514,13 +403,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb, { struct net *net = container_of(qp->q.net, struct net, ipv4.frags); struct iphdr *iph; - struct sk_buff *fp, *head = skb_rb_first(&qp->q.rb_fragments); - struct sk_buff **nextp; /* To build frag_list. */ - struct rb_node *rbn; - int len; - int ihlen; - int delta; - int err; + void *reasm_data; + int len, err; u8 ecn; ipq_kill(qp); @@ -530,117 +414,23 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb, err = -EINVAL; goto out_fail; } - /* Make the one we just received the head. */ - if (head != skb) { - fp = skb_clone(skb, GFP_ATOMIC); - if (!fp) - goto out_nomem; - FRAG_CB(fp)->next_frag = FRAG_CB(skb)->next_frag; - if (RB_EMPTY_NODE(&skb->rbnode)) - FRAG_CB(prev_tail)->next_frag = fp; - else - rb_replace_node(&skb->rbnode, &fp->rbnode, - &qp->q.rb_fragments); - if (qp->q.fragments_tail == skb) - qp->q.fragments_tail = fp; - skb_morph(skb, head); - FRAG_CB(skb)->next_frag = FRAG_CB(head)->next_frag; - rb_replace_node(&head->rbnode, &skb->rbnode, - &qp->q.rb_fragments); - consume_skb(head); - head = skb; - } - WARN_ON(head->ip_defrag_offset != 0); - - /* Allocate a new buffer for the datagram. */ - ihlen = ip_hdrlen(head); - len = ihlen + qp->q.len; + /* Make the one we just received the head. */ + reasm_data = inet_frag_reasm_prepare(&qp->q, skb, prev_tail); + if (!reasm_data) + goto out_nomem; + len = ip_hdrlen(skb) + qp->q.len; err = -E2BIG; if (len > 65535) goto out_oversize; - delta = - head->truesize; - - /* Head of list must not be cloned. */ - if (skb_unclone(head, GFP_ATOMIC)) - goto out_nomem; - - delta += head->truesize; - if (delta) - add_frag_mem_limit(qp->q.net, delta); - - /* If the first fragment is fragmented itself, we split - * it to two chunks: the first with data and paged part - * and the second, holding only fragments. */ - if (skb_has_frag_list(head)) { - struct sk_buff *clone; - int i, plen = 0; - - clone = alloc_skb(0, GFP_ATOMIC); - if (!clone) - goto out_nomem; - skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_frag_list_init(head); - for (i = 0; i < skb_shinfo(head)->nr_frags; i++) - plen += skb_frag_size(&skb_shinfo(head)->frags[i]); - clone->len = clone->data_len = head->data_len - plen; - head->truesize += clone->truesize; - clone->csum = 0; - clone->ip_summed = head->ip_summed; - add_frag_mem_limit(qp->q.net, clone->truesize); - skb_shinfo(head)->frag_list = clone; - nextp = &clone->next; - } else { - nextp = &skb_shinfo(head)->frag_list; - } + inet_frag_reasm_finish(&qp->q, skb, reasm_data); - skb_push(head, head->data - skb_network_header(head)); + skb->dev = dev; + IPCB(skb)->frag_max_size = max(qp->max_df_size, qp->q.max_size); - /* Traverse the tree in order, to build frag_list. */ - fp = FRAG_CB(head)->next_frag; - rbn = rb_next(&head->rbnode); - rb_erase(&head->rbnode, &qp->q.rb_fragments); - while (rbn || fp) { - /* fp points to the next sk_buff in the current run; - * rbn points to the next run. - */ - /* Go through the current run. */ - while (fp) { - *nextp = fp; - nextp = &fp->next; - fp->prev = NULL; - memset(&fp->rbnode, 0, sizeof(fp->rbnode)); - fp->sk = NULL; - head->data_len += fp->len; - head->len += fp->len; - if (head->ip_summed != fp->ip_summed) - head->ip_summed = CHECKSUM_NONE; - else if (head->ip_summed == CHECKSUM_COMPLETE) - head->csum = csum_add(head->csum, fp->csum); - head->truesize += fp->truesize; - fp = FRAG_CB(fp)->next_frag; - } - /* Move to the next run. */ - if (rbn) { - struct rb_node *rbnext = rb_next(rbn); - - fp = rb_to_skb(rbn); - rb_erase(rbn, &qp->q.rb_fragments); - rbn = rbnext; - } - } - sub_frag_mem_limit(qp->q.net, head->truesize); - - *nextp = NULL; - head->next = NULL; - head->prev = NULL; - head->dev = dev; - head->tstamp = qp->q.stamp; - IPCB(head)->frag_max_size = max(qp->max_df_size, qp->q.max_size); - - iph = ip_hdr(head); + iph = ip_hdr(skb); iph->tot_len = htons(len); iph->tos |= ecn; @@ -653,7 +443,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb, * from one very small df-fragment and one large non-df frag. */ if (qp->max_df_size == qp->q.max_size) { - IPCB(head)->flags |= IPSKB_FRAG_PMTU; + IPCB(skb)->flags |= IPSKB_FRAG_PMTU; iph->frag_off = htons(IP_DF); } else { iph->frag_off = 0; @@ -751,28 +541,6 @@ struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user) } EXPORT_SYMBOL(ip_check_defrag); -unsigned int inet_frag_rbtree_purge(struct rb_root *root) -{ - struct rb_node *p = rb_first(root); - unsigned int sum = 0; - - while (p) { - struct sk_buff *skb = rb_entry(p, struct sk_buff, rbnode); - - p = rb_next(p); - rb_erase(&skb->rbnode, root); - while (skb) { - struct sk_buff *next = FRAG_CB(skb)->next_frag; - - sum += skb->truesize; - kfree_skb(skb); - skb = next; - } - } - return sum; -} -EXPORT_SYMBOL(inet_frag_rbtree_purge); - #ifdef CONFIG_SYSCTL static int dist_min; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 880ef557c224046102e5b418ab4f2384954c428d..e87bf5fa9d074cd5a618e18a25c2dbcc9b4429f9 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -258,11 +258,10 @@ int ip_local_deliver(struct sk_buff *skb) ip_local_deliver_finish); } -static inline bool ip_rcv_options(struct sk_buff *skb) +static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) { struct ip_options *opt; const struct iphdr *iph; - struct net_device *dev = skb->dev; /* It looks as overkill, because not all IP options require packet mangling. @@ -298,7 +297,7 @@ static inline bool ip_rcv_options(struct sk_buff *skb) } } - if (ip_options_rcv_srr(skb)) + if (ip_options_rcv_srr(skb, dev)) goto drop; } @@ -361,7 +360,7 @@ static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) } #endif - if (iph->ihl > 5 && ip_rcv_options(skb)) + if (iph->ihl > 5 && ip_rcv_options(skb, dev)) goto drop; rt = skb_rtable(skb); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 32a35043c9f590314b7fa354d5e948b59e665214..3db31bb9df50622f8c9ae961f4eabc566d1cb74a 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -612,7 +612,7 @@ void ip_forward_options(struct sk_buff *skb) } } -int ip_options_rcv_srr(struct sk_buff *skb) +int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev) { struct ip_options *opt = &(IPCB(skb)->opt); int srrspace, srrptr; @@ -647,7 +647,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) orefdst = skb->_skb_refdst; skb_dst_set(skb, NULL); - err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); + err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, dev); rt2 = skb_rtable(skb); if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { skb_dst_drop(skb); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a6b403a2f791d74f655cb9e80f74598b750d91c8..546e1c42d76cbd89766e2bc986bb68025b11c79b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -518,6 +518,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->pkt_type = from->pkt_type; to->priority = from->priority; to->protocol = from->protocol; + to->skb_iif = from->skb_iif; skb_dst_drop(to); skb_dst_copy(to, from); to->dev = from->dev; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a1bf87711bfaa077584dd98c30eed88f45d24417..6a7e187dd0a9df355bef5de2e9565845cfdc685f 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1192,11 +1192,39 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) return dst; } +static void ipv4_send_dest_unreach(struct sk_buff *skb) +{ + struct ip_options opt; + int res; + + /* Recompile ip options since IPCB may not be valid anymore. + * Also check we have a reasonable ipv4 header. + */ + if (!pskb_network_may_pull(skb, sizeof(struct iphdr)) || + ip_hdr(skb)->version != 4 || ip_hdr(skb)->ihl < 5) + return; + + memset(&opt, 0, sizeof(opt)); + if (ip_hdr(skb)->ihl > 5) { + if (!pskb_network_may_pull(skb, ip_hdr(skb)->ihl * 4)) + return; + opt.optlen = ip_hdr(skb)->ihl * 4 - sizeof(struct iphdr); + + rcu_read_lock(); + res = __ip_options_compile(dev_net(skb->dev), &opt, skb, NULL); + rcu_read_unlock(); + + if (res) + return; + } + __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, &opt); +} + static void ipv4_link_failure(struct sk_buff *skb) { struct rtable *rt; - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); + ipv4_send_dest_unreach(skb); rt = skb_rtable(skb); if (rt) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 4c47a47c66bd3dfad64099de217278d78db1abea..47addbedef697f3095c543b7801cd01b3beeb31c 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -49,6 +49,7 @@ static int tcp_delack_seg_min = TCP_DELACK_MIN; static int tcp_delack_seg_max = 60; static int tcp_use_userconfig_min; static int tcp_use_userconfig_max = 1; +static int one_day_secs = 24 * 3600; /* obsolete */ static int sysctl_tcp_low_latency __read_mostly; @@ -571,7 +572,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_min_rtt_wlen, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one_day_secs }, { .procname = "tcp_low_latency", diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 8b637f9f23a232a137f4a7f2d685a599cc063c1b..f0de9fb92f0d31160487ea933505913df86ce4a9 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -66,11 +66,6 @@ static unsigned int dctcp_alpha_on_init __read_mostly = DCTCP_MAX_ALPHA; module_param(dctcp_alpha_on_init, uint, 0644); MODULE_PARM_DESC(dctcp_alpha_on_init, "parameter for initial alpha value"); -static unsigned int dctcp_clamp_alpha_on_loss __read_mostly; -module_param(dctcp_clamp_alpha_on_loss, uint, 0644); -MODULE_PARM_DESC(dctcp_clamp_alpha_on_loss, - "parameter for clamping alpha on loss"); - static struct tcp_congestion_ops dctcp_reno; static void dctcp_reset(const struct tcp_sock *tp, struct dctcp *ca) @@ -211,21 +206,23 @@ static void dctcp_update_alpha(struct sock *sk, u32 flags) } } -static void dctcp_state(struct sock *sk, u8 new_state) +static void dctcp_react_to_loss(struct sock *sk) { - if (dctcp_clamp_alpha_on_loss && new_state == TCP_CA_Loss) { - struct dctcp *ca = inet_csk_ca(sk); + struct dctcp *ca = inet_csk_ca(sk); + struct tcp_sock *tp = tcp_sk(sk); - /* If this extension is enabled, we clamp dctcp_alpha to - * max on packet loss; the motivation is that dctcp_alpha - * is an indicator to the extend of congestion and packet - * loss is an indicator of extreme congestion; setting - * this in practice turned out to be beneficial, and - * effectively assumes total congestion which reduces the - * window by half. - */ - ca->dctcp_alpha = DCTCP_MAX_ALPHA; - } + ca->loss_cwnd = tp->snd_cwnd; + tp->snd_ssthresh = max(tp->snd_cwnd >> 1U, 2U); +} + +static void dctcp_state(struct sock *sk, u8 new_state) +{ + if (new_state == TCP_CA_Recovery && + new_state != inet_csk(sk)->icsk_ca_state) + dctcp_react_to_loss(sk); + /* We handle RTO in dctcp_cwnd_event to ensure that we perform only + * one loss-adjustment per RTT. + */ } static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) @@ -237,6 +234,9 @@ static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) case CA_EVENT_ECN_NO_CE: dctcp_ce_state_1_to_0(sk); break; + case CA_EVENT_LOSS: + dctcp_react_to_loss(sk); + break; default: /* Don't care for the rest. */ break; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fe8e9dd1e5e0aa84db51b8ab9c6f1ec56185d1cc..75648417a549156f9e6213dfa30ed653a93d6195 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -390,11 +390,12 @@ static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb) static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); + int room; + + room = min_t(int, tp->window_clamp, tcp_space(sk)) - tp->rcv_ssthresh; /* Check #1 */ - if (tp->rcv_ssthresh < tp->window_clamp && - (int)tp->rcv_ssthresh < tcp_space(sk) && - !tcp_under_memory_pressure(sk)) { + if (room > 0 && !tcp_under_memory_pressure(sk)) { int incr; /* Check #2. Increase window, if skb with such overhead @@ -407,8 +408,7 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) if (incr) { incr = max_t(int, incr, 2 * skb->len); - tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, - tp->window_clamp); + tp->rcv_ssthresh += min(room, incr); inet_csk(sk)->icsk_ack.quick |= 1; } } diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 15535ee327c5780e80feb050c2ab4e0d1cc3e99c..6fa2bc236d9e427a753801835affb05c2e610d72 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -94,15 +94,21 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) return fl; } +static void fl_free_rcu(struct rcu_head *head) +{ + struct ip6_flowlabel *fl = container_of(head, struct ip6_flowlabel, rcu); + + if (fl->share == IPV6_FL_S_PROCESS) + put_pid(fl->owner.pid); + kfree(fl->opt); + kfree(fl); +} + static void fl_free(struct ip6_flowlabel *fl) { - if (fl) { - if (fl->share == IPV6_FL_S_PROCESS) - put_pid(fl->owner.pid); - kfree(fl->opt); - kfree_rcu(fl, rcu); - } + if (fl) + call_rcu(&fl->rcu, fl_free_rcu); } static void fl_release(struct ip6_flowlabel *fl) @@ -634,9 +640,9 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) if (fl1->share == IPV6_FL_S_EXCL || fl1->share != fl->share || ((fl1->share == IPV6_FL_S_PROCESS) && - (fl1->owner.pid == fl->owner.pid)) || + (fl1->owner.pid != fl->owner.pid)) || ((fl1->share == IPV6_FL_S_USER) && - uid_eq(fl1->owner.uid, fl->owner.uid))) + !uid_eq(fl1->owner.uid, fl->owner.uid))) goto release; err = -ENOMEM; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 645842de3815a44ec1ee43bd3adb7bf232eca4ed..94ba38fd154d1baa3cf6d5c5a955dbce89a16d17 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -611,7 +611,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, inet6_sk(skb->sk) : NULL; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; - unsigned int mtu, hlen, left, len; + unsigned int mtu, hlen, left, len, nexthdr_offset; int hroom, troom; __be32 frag_id; int ptr, offset = 0, err = 0; @@ -622,6 +622,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, goto fail; hlen = err; nexthdr = *prevhdr; + nexthdr_offset = prevhdr - skb_network_header(skb); mtu = ip6_skb_dst_mtu(skb); @@ -656,6 +657,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, (err = skb_checksum_help(skb))) goto fail; + prevhdr = skb_network_header(skb) + nexthdr_offset; hroom = LL_RESERVED_SPACE(rt->dst.dev); if (skb_has_frag_list(skb)) { unsigned int first_len = skb_pagelen(skb); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 1812c2a748ff44632bde612bc0b5f7288376b430..f71c7915ff0e015ca06c8c0c98e1eec211496c8e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -633,7 +633,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, IPPROTO_IPIP, RT_TOS(eiph->tos), 0); if (IS_ERR(rt) || - rt->dst.dev->type != ARPHRD_TUNNEL) { + rt->dst.dev->type != ARPHRD_TUNNEL6) { if (!IS_ERR(rt)) ip_rt_put(rt); goto out; @@ -643,7 +643,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || - skb_dst(skb2)->dev->type != ARPHRD_TUNNEL) + skb_dst(skb2)->dev->type != ARPHRD_TUNNEL6) goto out; } diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index eb72275ba3101d3bd2f17c32d4a6f8d56bba8c5e..cb1b4772dac0a8bfd4013491aee00d858f2acb54 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -33,9 +33,8 @@ #include #include -#include +#include -#include #include #include #include @@ -52,14 +51,6 @@ static const char nf_frags_cache_name[] = "nf-frags"; -struct nf_ct_frag6_skb_cb -{ - struct inet6_skb_parm h; - int offset; -}; - -#define NFCT_FRAG6_CB(skb) ((struct nf_ct_frag6_skb_cb *)((skb)->cb)) - static struct inet_frags nf_frags; #ifdef CONFIG_SYSCTL @@ -145,6 +136,9 @@ static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net) } #endif +static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb, + struct sk_buff *prev_tail, struct net_device *dev); + static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) { return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); @@ -159,7 +153,7 @@ static void nf_ct_frag6_expire(struct timer_list *t) fq = container_of(frag, struct frag_queue, q); net = container_of(fq->q.net, struct net, nf_frag.frags); - ip6_expire_frag_queue(net, fq); + ip6frag_expire_frag_queue(net, fq); } /* Creation primitives. */ @@ -186,9 +180,10 @@ static struct frag_queue *fq_find(struct net *net, __be32 id, u32 user, static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, const struct frag_hdr *fhdr, int nhoff) { - struct sk_buff *prev, *next; unsigned int payload_len; - int offset, end; + struct net_device *dev; + struct sk_buff *prev; + int offset, end, err; u8 ecn; if (fq->q.flags & INET_FRAG_COMPLETE) { @@ -263,55 +258,19 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, goto err; } - /* Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? - */ + /* Note : skb->rbnode and skb->dev share the same location. */ + dev = skb->dev; + /* Makes sure compiler wont do silly aliasing games */ + barrier(); + prev = fq->q.fragments_tail; - if (!prev || NFCT_FRAG6_CB(prev)->offset < offset) { - next = NULL; - goto found; - } - prev = NULL; - for (next = fq->q.fragments; next != NULL; next = next->next) { - if (NFCT_FRAG6_CB(next)->offset >= offset) - break; /* bingo! */ - prev = next; - } + err = inet_frag_queue_insert(&fq->q, skb, offset, end); + if (err) + goto insert_error; -found: - /* RFC5722, Section 4: - * When reassembling an IPv6 datagram, if - * one or more its constituent fragments is determined to be an - * overlapping fragment, the entire datagram (and any constituent - * fragments, including those not yet received) MUST be silently - * discarded. - */ + if (dev) + fq->iif = dev->ifindex; - /* Check for overlap with preceding fragment. */ - if (prev && - (NFCT_FRAG6_CB(prev)->offset + prev->len) > offset) - goto discard_fq; - - /* Look for overlap with succeeding segment. */ - if (next && NFCT_FRAG6_CB(next)->offset < end) - goto discard_fq; - - NFCT_FRAG6_CB(skb)->offset = offset; - - /* Insert this fragment in the chain of fragments. */ - skb->next = next; - if (!next) - fq->q.fragments_tail = skb; - if (prev) - prev->next = skb; - else - fq->q.fragments = skb; - - if (skb->dev) { - fq->iif = skb->dev->ifindex; - skb->dev = NULL; - } fq->q.stamp = skb->tstamp; fq->q.meat += skb->len; fq->ecn |= ecn; @@ -327,11 +286,25 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, fq->q.flags |= INET_FRAG_FIRST_IN; } - return 0; + if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + fq->q.meat == fq->q.len) { + unsigned long orefdst = skb->_skb_refdst; -discard_fq: + skb->_skb_refdst = 0UL; + err = nf_ct_frag6_reasm(fq, skb, prev, dev); + skb->_skb_refdst = orefdst; + return err; + } + + skb_dst_drop(skb); + return -EINPROGRESS; + +insert_error: + if (err == IPFRAG_DUP) + goto err; inet_frag_kill(&fq->q); err: + skb_dst_drop(skb); return -EINVAL; } @@ -341,147 +314,67 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, * It is called with locked fq, and caller must check that * queue is eligible for reassembly i.e. it is not COMPLETE, * the last and the first frames arrived and all the bits are here. - * - * returns true if *prev skb has been transformed into the reassembled - * skb, false otherwise. */ -static bool -nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *prev, struct net_device *dev) +static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb, + struct sk_buff *prev_tail, struct net_device *dev) { - struct sk_buff *fp, *head = fq->q.fragments; - int payload_len, delta; + void *reasm_data; + int payload_len; u8 ecn; inet_frag_kill(&fq->q); - WARN_ON(head == NULL); - WARN_ON(NFCT_FRAG6_CB(head)->offset != 0); - ecn = ip_frag_ecn_table[fq->ecn]; if (unlikely(ecn == 0xff)) - return false; + goto err; + + reasm_data = inet_frag_reasm_prepare(&fq->q, skb, prev_tail); + if (!reasm_data) + goto err; - /* Unfragmented part is taken from the first segment. */ - payload_len = ((head->data - skb_network_header(head)) - + payload_len = ((skb->data - skb_network_header(skb)) - sizeof(struct ipv6hdr) + fq->q.len - sizeof(struct frag_hdr)); if (payload_len > IPV6_MAXPLEN) { net_dbg_ratelimited("nf_ct_frag6_reasm: payload len = %d\n", payload_len); - return false; - } - - delta = - head->truesize; - - /* Head of list must not be cloned. */ - if (skb_unclone(head, GFP_ATOMIC)) - return false; - - delta += head->truesize; - if (delta) - add_frag_mem_limit(fq->q.net, delta); - - /* If the first fragment is fragmented itself, we split - * it to two chunks: the first with data and paged part - * and the second, holding only fragments. */ - if (skb_has_frag_list(head)) { - struct sk_buff *clone; - int i, plen = 0; - - clone = alloc_skb(0, GFP_ATOMIC); - if (clone == NULL) - return false; - - clone->next = head->next; - head->next = clone; - skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_frag_list_init(head); - for (i = 0; i < skb_shinfo(head)->nr_frags; i++) - plen += skb_frag_size(&skb_shinfo(head)->frags[i]); - clone->len = clone->data_len = head->data_len - plen; - head->data_len -= clone->len; - head->len -= clone->len; - clone->csum = 0; - clone->ip_summed = head->ip_summed; - - add_frag_mem_limit(fq->q.net, clone->truesize); - } - - /* morph head into last received skb: prev. - * - * This allows callers of ipv6 conntrack defrag to continue - * to use the last skb(frag) passed into the reasm engine. - * The last skb frag 'silently' turns into the full reassembled skb. - * - * Since prev is also part of q->fragments we have to clone it first. - */ - if (head != prev) { - struct sk_buff *iter; - - fp = skb_clone(prev, GFP_ATOMIC); - if (!fp) - return false; - - fp->next = prev->next; - - iter = head; - while (iter) { - if (iter->next == prev) { - iter->next = fp; - break; - } - iter = iter->next; - } - - skb_morph(prev, head); - prev->next = head->next; - consume_skb(head); - head = prev; + goto err; } /* We have to remove fragment header from datagram and to relocate * header in order to calculate ICV correctly. */ - skb_network_header(head)[fq->nhoffset] = skb_transport_header(head)[0]; - memmove(head->head + sizeof(struct frag_hdr), head->head, - (head->data - head->head) - sizeof(struct frag_hdr)); - head->mac_header += sizeof(struct frag_hdr); - head->network_header += sizeof(struct frag_hdr); - - skb_shinfo(head)->frag_list = head->next; - skb_reset_transport_header(head); - skb_push(head, head->data - skb_network_header(head)); - - for (fp = head->next; fp; fp = fp->next) { - head->data_len += fp->len; - head->len += fp->len; - if (head->ip_summed != fp->ip_summed) - head->ip_summed = CHECKSUM_NONE; - else if (head->ip_summed == CHECKSUM_COMPLETE) - head->csum = csum_add(head->csum, fp->csum); - head->truesize += fp->truesize; - fp->sk = NULL; - } - sub_frag_mem_limit(fq->q.net, head->truesize); + skb_network_header(skb)[fq->nhoffset] = skb_transport_header(skb)[0]; + memmove(skb->head + sizeof(struct frag_hdr), skb->head, + (skb->data - skb->head) - sizeof(struct frag_hdr)); + skb->mac_header += sizeof(struct frag_hdr); + skb->network_header += sizeof(struct frag_hdr); + + skb_reset_transport_header(skb); + + inet_frag_reasm_finish(&fq->q, skb, reasm_data); - head->ignore_df = 1; - head->next = NULL; - head->dev = dev; - head->tstamp = fq->q.stamp; - ipv6_hdr(head)->payload_len = htons(payload_len); - ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn); - IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size; + skb->ignore_df = 1; + skb->dev = dev; + ipv6_hdr(skb)->payload_len = htons(payload_len); + ipv6_change_dsfield(ipv6_hdr(skb), 0xff, ecn); + IP6CB(skb)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size; /* Yes, and fold redundant checksum back. 8) */ - if (head->ip_summed == CHECKSUM_COMPLETE) - head->csum = csum_partial(skb_network_header(head), - skb_network_header_len(head), - head->csum); + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->csum = csum_partial(skb_network_header(skb), + skb_network_header_len(skb), + skb->csum); fq->q.fragments = NULL; fq->q.rb_fragments = RB_ROOT; fq->q.fragments_tail = NULL; + fq->q.last_run_head = NULL; - return true; + return 0; + +err: + inet_frag_kill(&fq->q); + return -EINVAL; } /* @@ -550,7 +443,6 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) { u16 savethdr = skb->transport_header; - struct net_device *dev = skb->dev; int fhoff, nhoff, ret; struct frag_hdr *fhdr; struct frag_queue *fq; @@ -584,24 +476,17 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) spin_lock_bh(&fq->q.lock); ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff); - if (ret < 0) { - if (ret == -EPROTO) { - skb->transport_header = savethdr; - ret = 0; - } - goto out_unlock; + if (ret == -EPROTO) { + skb->transport_header = savethdr; + ret = 0; } /* after queue has assumed skb ownership, only 0 or -EINPROGRESS * must be returned. */ - ret = -EINPROGRESS; - if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && - fq->q.meat == fq->q.len && - nf_ct_frag6_reasm(fq, skb, dev)) - ret = 0; + if (ret) + ret = -EINPROGRESS; -out_unlock: spin_unlock_bh(&fq->q.lock); inet_frag_put(&fq->q); return ret; @@ -637,16 +522,24 @@ static struct pernet_operations nf_ct_net_ops = { .exit = nf_ct_net_exit, }; +static const struct rhashtable_params nfct_rhash_params = { + .head_offset = offsetof(struct inet_frag_queue, node), + .hashfn = ip6frag_key_hashfn, + .obj_hashfn = ip6frag_obj_hashfn, + .obj_cmpfn = ip6frag_obj_cmpfn, + .automatic_shrinking = true, +}; + int nf_ct_frag6_init(void) { int ret = 0; - nf_frags.constructor = ip6_frag_init; + nf_frags.constructor = ip6frag_init; nf_frags.destructor = NULL; nf_frags.qsize = sizeof(struct frag_queue); nf_frags.frag_expire = nf_ct_frag6_expire; nf_frags.frags_cache_name = nf_frags_cache_name; - nf_frags.rhash_params = ip6_rhash_params; + nf_frags.rhash_params = nfct_rhash_params; ret = inet_frags_init(&nf_frags); if (ret) goto out; diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index b326da59257f60396cda3daddfd643a3cec262a5..123bfb13a5d1488f30a1b05181998a06d1c9ecc8 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c @@ -14,8 +14,7 @@ #include #include #include -#include -#include +#include #include #include diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 535aa6217c2cf6784134d026ff5a1b27d9244117..fe797b29ca89d802058735eb51fa2769e2976597 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -57,18 +57,11 @@ #include #include #include -#include +#include #include static const char ip6_frag_cache_name[] = "ip6-frags"; -struct ip6frag_skb_cb { - struct inet6_skb_parm h; - int offset; -}; - -#define FRAG6_CB(skb) ((struct ip6frag_skb_cb *)((skb)->cb)) - static u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) { return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); @@ -76,63 +69,8 @@ static u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) static struct inet_frags ip6_frags; -static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, - struct net_device *dev); - -void ip6_frag_init(struct inet_frag_queue *q, const void *a) -{ - struct frag_queue *fq = container_of(q, struct frag_queue, q); - const struct frag_v6_compare_key *key = a; - - q->key.v6 = *key; - fq->ecn = 0; -} -EXPORT_SYMBOL(ip6_frag_init); - -void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq) -{ - struct net_device *dev = NULL; - struct sk_buff *head; - - rcu_read_lock(); - spin_lock(&fq->q.lock); - - if (fq->q.flags & INET_FRAG_COMPLETE) - goto out; - - inet_frag_kill(&fq->q); - - dev = dev_get_by_index_rcu(net, fq->iif); - if (!dev) - goto out; - - __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); - __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); - - /* Don't send error if the first segment did not arrive. */ - head = fq->q.fragments; - if (!(fq->q.flags & INET_FRAG_FIRST_IN) || !head) - goto out; - - /* But use as source device on which LAST ARRIVED - * segment was received. And do not use fq->dev - * pointer directly, device might already disappeared. - */ - head->dev = dev; - skb_get(head); - spin_unlock(&fq->q.lock); - - icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); - kfree_skb(head); - goto out_rcu_unlock; - -out: - spin_unlock(&fq->q.lock); -out_rcu_unlock: - rcu_read_unlock(); - inet_frag_put(&fq->q); -} -EXPORT_SYMBOL(ip6_expire_frag_queue); +static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb, + struct sk_buff *prev_tail, struct net_device *dev); static void ip6_frag_expire(struct timer_list *t) { @@ -143,7 +81,7 @@ static void ip6_frag_expire(struct timer_list *t) fq = container_of(frag, struct frag_queue, q); net = container_of(fq->q.net, struct net, ipv6.frags); - ip6_expire_frag_queue(net, fq); + ip6frag_expire_frag_queue(net, fq); } static struct frag_queue * @@ -170,27 +108,29 @@ fq_find(struct net *net, __be32 id, const struct ipv6hdr *hdr, int iif) } static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr, int nhoff) + struct frag_hdr *fhdr, int nhoff, + u32 *prob_offset) { - struct sk_buff *prev, *next; - struct net_device *dev; - int offset, end, fragsize; struct net *net = dev_net(skb_dst(skb)->dev); + int offset, end, fragsize; + struct sk_buff *prev_tail; + struct net_device *dev; + int err = -ENOENT; u8 ecn; if (fq->q.flags & INET_FRAG_COMPLETE) goto err; + err = -EINVAL; offset = ntohs(fhdr->frag_off) & ~0x7; end = offset + (ntohs(ipv6_hdr(skb)->payload_len) - ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); if ((unsigned int)end > IPV6_MAXPLEN) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - ((u8 *)&fhdr->frag_off - - skb_network_header(skb))); + *prob_offset = (u8 *)&fhdr->frag_off - skb_network_header(skb); + /* note that if prob_offset is set, the skb is freed elsewhere, + * we do not free it here. + */ return -1; } @@ -210,7 +150,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, */ if (end < fq->q.len || ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) - goto err; + goto discard_fq; fq->q.flags |= INET_FRAG_LAST_IN; fq->q.len = end; } else { @@ -221,79 +161,42 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, /* RFC2460 says always send parameter problem in * this case. -DaveM */ - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - offsetof(struct ipv6hdr, payload_len)); + *prob_offset = offsetof(struct ipv6hdr, payload_len); return -1; } if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ if (fq->q.flags & INET_FRAG_LAST_IN) - goto err; + goto discard_fq; fq->q.len = end; } } if (end == offset) - goto err; + goto discard_fq; + err = -ENOMEM; /* Point into the IP datagram 'data' part. */ if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) - goto err; - - if (pskb_trim_rcsum(skb, end - offset)) - goto err; - - /* Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? - */ - prev = fq->q.fragments_tail; - if (!prev || FRAG6_CB(prev)->offset < offset) { - next = NULL; - goto found; - } - prev = NULL; - for (next = fq->q.fragments; next != NULL; next = next->next) { - if (FRAG6_CB(next)->offset >= offset) - break; /* bingo! */ - prev = next; - } - -found: - /* RFC5722, Section 4, amended by Errata ID : 3089 - * When reassembling an IPv6 datagram, if - * one or more its constituent fragments is determined to be an - * overlapping fragment, the entire datagram (and any constituent - * fragments) MUST be silently discarded. - */ - - /* Check for overlap with preceding fragment. */ - if (prev && - (FRAG6_CB(prev)->offset + prev->len) > offset) goto discard_fq; - /* Look for overlap with succeeding segment. */ - if (next && FRAG6_CB(next)->offset < end) + err = pskb_trim_rcsum(skb, end - offset); + if (err) goto discard_fq; - FRAG6_CB(skb)->offset = offset; + /* Note : skb->rbnode and skb->dev share the same location. */ + dev = skb->dev; + /* Makes sure compiler wont do silly aliasing games */ + barrier(); - /* Insert this fragment in the chain of fragments. */ - skb->next = next; - if (!next) - fq->q.fragments_tail = skb; - if (prev) - prev->next = skb; - else - fq->q.fragments = skb; + prev_tail = fq->q.fragments_tail; + err = inet_frag_queue_insert(&fq->q, skb, offset, end); + if (err) + goto insert_error; - dev = skb->dev; - if (dev) { + if (dev) fq->iif = dev->ifindex; - skb->dev = NULL; - } + fq->q.stamp = skb->tstamp; fq->q.meat += skb->len; fq->ecn |= ecn; @@ -313,44 +216,48 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && fq->q.meat == fq->q.len) { - int res; unsigned long orefdst = skb->_skb_refdst; skb->_skb_refdst = 0UL; - res = ip6_frag_reasm(fq, prev, dev); + err = ip6_frag_reasm(fq, skb, prev_tail, dev); skb->_skb_refdst = orefdst; - return res; + return err; } skb_dst_drop(skb); - return -1; + return -EINPROGRESS; +insert_error: + if (err == IPFRAG_DUP) { + kfree_skb(skb); + return -EINVAL; + } + err = -EINVAL; + __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_REASM_OVERLAPS); discard_fq: inet_frag_kill(&fq->q); -err: __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); +err: kfree_skb(skb); - return -1; + return err; } /* * Check if this packet is complete. - * Returns NULL on failure by any reason, and pointer - * to current nexthdr field in reassembled frame. * * It is called with locked fq, and caller must check that * queue is eligible for reassembly i.e. it is not COMPLETE, * the last and the first frames arrived and all the bits are here. */ -static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, - struct net_device *dev) +static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb, + struct sk_buff *prev_tail, struct net_device *dev) { struct net *net = container_of(fq->q.net, struct net, ipv6.frags); - struct sk_buff *fp, *head = fq->q.fragments; - int payload_len, delta; unsigned int nhoff; - int sum_truesize; + void *reasm_data; + int payload_len; u8 ecn; inet_frag_kill(&fq->q); @@ -359,120 +266,40 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, if (unlikely(ecn == 0xff)) goto out_fail; - /* Make the one we just received the head. */ - if (prev) { - head = prev->next; - fp = skb_clone(head, GFP_ATOMIC); - - if (!fp) - goto out_oom; - - fp->next = head->next; - if (!fp->next) - fq->q.fragments_tail = fp; - prev->next = fp; - - skb_morph(head, fq->q.fragments); - head->next = fq->q.fragments->next; - - consume_skb(fq->q.fragments); - fq->q.fragments = head; - } - - WARN_ON(head == NULL); - WARN_ON(FRAG6_CB(head)->offset != 0); + reasm_data = inet_frag_reasm_prepare(&fq->q, skb, prev_tail); + if (!reasm_data) + goto out_oom; - /* Unfragmented part is taken from the first segment. */ - payload_len = ((head->data - skb_network_header(head)) - + payload_len = ((skb->data - skb_network_header(skb)) - sizeof(struct ipv6hdr) + fq->q.len - sizeof(struct frag_hdr)); if (payload_len > IPV6_MAXPLEN) goto out_oversize; - delta = - head->truesize; - - /* Head of list must not be cloned. */ - if (skb_unclone(head, GFP_ATOMIC)) - goto out_oom; - - delta += head->truesize; - if (delta) - add_frag_mem_limit(fq->q.net, delta); - - /* If the first fragment is fragmented itself, we split - * it to two chunks: the first with data and paged part - * and the second, holding only fragments. */ - if (skb_has_frag_list(head)) { - struct sk_buff *clone; - int i, plen = 0; - - clone = alloc_skb(0, GFP_ATOMIC); - if (!clone) - goto out_oom; - clone->next = head->next; - head->next = clone; - skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_frag_list_init(head); - for (i = 0; i < skb_shinfo(head)->nr_frags; i++) - plen += skb_frag_size(&skb_shinfo(head)->frags[i]); - clone->len = clone->data_len = head->data_len - plen; - head->data_len -= clone->len; - head->len -= clone->len; - clone->csum = 0; - clone->ip_summed = head->ip_summed; - add_frag_mem_limit(fq->q.net, clone->truesize); - } - /* We have to remove fragment header from datagram and to relocate * header in order to calculate ICV correctly. */ nhoff = fq->nhoffset; - skb_network_header(head)[nhoff] = skb_transport_header(head)[0]; - memmove(head->head + sizeof(struct frag_hdr), head->head, - (head->data - head->head) - sizeof(struct frag_hdr)); - if (skb_mac_header_was_set(head)) - head->mac_header += sizeof(struct frag_hdr); - head->network_header += sizeof(struct frag_hdr); - - skb_reset_transport_header(head); - skb_push(head, head->data - skb_network_header(head)); - - sum_truesize = head->truesize; - for (fp = head->next; fp;) { - bool headstolen; - int delta; - struct sk_buff *next = fp->next; - - sum_truesize += fp->truesize; - if (head->ip_summed != fp->ip_summed) - head->ip_summed = CHECKSUM_NONE; - else if (head->ip_summed == CHECKSUM_COMPLETE) - head->csum = csum_add(head->csum, fp->csum); - - if (skb_try_coalesce(head, fp, &headstolen, &delta)) { - kfree_skb_partial(fp, headstolen); - } else { - if (!skb_shinfo(head)->frag_list) - skb_shinfo(head)->frag_list = fp; - head->data_len += fp->len; - head->len += fp->len; - head->truesize += fp->truesize; - } - fp = next; - } - sub_frag_mem_limit(fq->q.net, sum_truesize); + skb_network_header(skb)[nhoff] = skb_transport_header(skb)[0]; + memmove(skb->head + sizeof(struct frag_hdr), skb->head, + (skb->data - skb->head) - sizeof(struct frag_hdr)); + if (skb_mac_header_was_set(skb)) + skb->mac_header += sizeof(struct frag_hdr); + skb->network_header += sizeof(struct frag_hdr); + + skb_reset_transport_header(skb); - head->next = NULL; - head->dev = dev; - head->tstamp = fq->q.stamp; - ipv6_hdr(head)->payload_len = htons(payload_len); - ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn); - IP6CB(head)->nhoff = nhoff; - IP6CB(head)->flags |= IP6SKB_FRAGMENTED; - IP6CB(head)->frag_max_size = fq->q.max_size; + inet_frag_reasm_finish(&fq->q, skb, reasm_data); + + skb->dev = dev; + ipv6_hdr(skb)->payload_len = htons(payload_len); + ipv6_change_dsfield(ipv6_hdr(skb), 0xff, ecn); + IP6CB(skb)->nhoff = nhoff; + IP6CB(skb)->flags |= IP6SKB_FRAGMENTED; + IP6CB(skb)->frag_max_size = fq->q.max_size; /* Yes, and fold redundant checksum back. 8) */ - skb_postpush_rcsum(head, skb_network_header(head), - skb_network_header_len(head)); + skb_postpush_rcsum(skb, skb_network_header(skb), + skb_network_header_len(skb)); rcu_read_lock(); __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); @@ -480,6 +307,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, fq->q.fragments = NULL; fq->q.rb_fragments = RB_ROOT; fq->q.fragments_tail = NULL; + fq->q.last_run_head = NULL; return 1; out_oversize: @@ -491,6 +319,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, rcu_read_lock(); __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); rcu_read_unlock(); + inet_frag_kill(&fq->q); return -1; } @@ -532,15 +361,23 @@ static int ipv6_frag_rcv(struct sk_buff *skb) iif = skb->dev ? skb->dev->ifindex : 0; fq = fq_find(net, fhdr->identification, hdr, iif); if (fq) { + u32 prob_offset = 0; int ret; spin_lock(&fq->q.lock); fq->iif = iif; - ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff); + ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff, + &prob_offset); spin_unlock(&fq->q.lock); inet_frag_put(&fq->q); + if (prob_offset) { + __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_INHDRERRORS); + /* icmpv6_param_prob() calls kfree_skb(skb) */ + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, prob_offset); + } return ret; } @@ -708,42 +545,19 @@ static struct pernet_operations ip6_frags_ops = { .exit = ipv6_frags_exit_net, }; -static u32 ip6_key_hashfn(const void *data, u32 len, u32 seed) -{ - return jhash2(data, - sizeof(struct frag_v6_compare_key) / sizeof(u32), seed); -} - -static u32 ip6_obj_hashfn(const void *data, u32 len, u32 seed) -{ - const struct inet_frag_queue *fq = data; - - return jhash2((const u32 *)&fq->key.v6, - sizeof(struct frag_v6_compare_key) / sizeof(u32), seed); -} - -static int ip6_obj_cmpfn(struct rhashtable_compare_arg *arg, const void *ptr) -{ - const struct frag_v6_compare_key *key = arg->key; - const struct inet_frag_queue *fq = ptr; - - return !!memcmp(&fq->key, key, sizeof(*key)); -} - -const struct rhashtable_params ip6_rhash_params = { +static const struct rhashtable_params ip6_rhash_params = { .head_offset = offsetof(struct inet_frag_queue, node), - .hashfn = ip6_key_hashfn, - .obj_hashfn = ip6_obj_hashfn, - .obj_cmpfn = ip6_obj_cmpfn, + .hashfn = ip6frag_key_hashfn, + .obj_hashfn = ip6frag_obj_hashfn, + .obj_cmpfn = ip6frag_obj_cmpfn, .automatic_shrinking = true, }; -EXPORT_SYMBOL(ip6_rhash_params); int __init ipv6_frag_init(void) { int ret; - ip6_frags.constructor = ip6_frag_init; + ip6_frags.constructor = ip6frag_init; ip6_frags.destructor = NULL; ip6_frags.qsize = sizeof(struct frag_queue); ip6_frags.frag_expire = ip6_frag_expire; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e231907252442aa92d7d4ff47ca4118f1bc59c8c..f7d080d1cf8e8628f2f5651319ff4c485f406be5 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -661,6 +661,10 @@ static int ipip6_rcv(struct sk_buff *skb) !net_eq(tunnel->net, dev_net(tunnel->dev)))) goto out; + /* skb can be uncloned in iptunnel_pull_header, so + * old iph is no longer valid + */ + iph = (const struct iphdr *)skb_mac_header(skb); err = IP_ECN_decapsulate(iph, skb); if (unlikely(err)) { if (log_ecn_error) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 9bf9974049185641dbd92839a4bdb6dfe9aceaea..7b4f3f86586177aff6f667db01681338b2171ae6 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -2059,14 +2059,14 @@ static int __init kcm_init(void) if (err) goto fail; - err = sock_register(&kcm_family_ops); - if (err) - goto sock_register_fail; - err = register_pernet_device(&kcm_net_ops); if (err) goto net_ops_fail; + err = sock_register(&kcm_family_ops); + if (err) + goto sock_register_fail; + err = kcm_proc_init(); if (err) goto proc_init_fail; @@ -2074,12 +2074,12 @@ static int __init kcm_init(void) return 0; proc_init_fail: - unregister_pernet_device(&kcm_net_ops); - -net_ops_fail: sock_unregister(PF_KCM); sock_register_fail: + unregister_pernet_device(&kcm_net_ops); + +net_ops_fail: proto_unregister(&kcm_proto); fail: @@ -2095,8 +2095,8 @@ static int __init kcm_init(void) static void __exit kcm_exit(void) { kcm_proc_exit(); - unregister_pernet_device(&kcm_net_ops); sock_unregister(PF_KCM); + unregister_pernet_device(&kcm_net_ops); proto_unregister(&kcm_proto); destroy_workqueue(kcm_wq); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4d82fe7d627c26f69b9d97c7b9e7f8aa1f2ed8f9..284276b3e0b4c371b04a4321b2efab84c7841a93 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1164,6 +1164,9 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif); + if (local->in_reconfig) + return; + if (!check_sdata_in_driver(sdata)) return; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 56dd5ce6274fc11ef96bf461aed1eecf25a4b794..6d7608b88f662e3c6253526a15cdc2e52e97ae7d 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -889,12 +889,13 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, { struct ip_vs_dest *dest; unsigned int atype, i; - int ret = 0; EnterFunction(2); #ifdef CONFIG_IP_VS_IPV6 if (udest->af == AF_INET6) { + int ret; + atype = ipv6_addr_type(&udest->addr.in6); if ((!(atype & IPV6_ADDR_UNICAST) || atype & IPV6_ADDR_LINKLOCAL) && diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c index d83a4ec5900d4a21dc39f74e8ba8a28a8b74a91e..6f3205de887f94f30647d5a67a769ed245f02ac9 100644 --- a/net/netfilter/nft_set_rbtree.c +++ b/net/netfilter/nft_set_rbtree.c @@ -224,10 +224,6 @@ static void *nft_rbtree_deactivate(const struct net *net, else if (d > 0) parent = parent->rb_right; else { - if (!nft_set_elem_active(&rbe->ext, genmask)) { - parent = parent->rb_left; - continue; - } if (nft_rbtree_interval_end(rbe) && !nft_rbtree_interval_end(this)) { parent = parent->rb_left; @@ -236,6 +232,9 @@ static void *nft_rbtree_deactivate(const struct net *net, nft_rbtree_interval_end(this)) { parent = parent->rb_right; continue; + } else if (!nft_set_elem_active(&rbe->ext, genmask)) { + parent = parent->rb_left; + continue; } nft_rbtree_flush(net, set, rbe); return rbe; diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c index 891f4e7e8ea7f507eebf1a22fa5dd818fc3ab49c..db18c0177b0f9caed3faf4b40ee4864a47fde25a 100644 --- a/net/netfilter/xt_cgroup.c +++ b/net/netfilter/xt_cgroup.c @@ -66,6 +66,38 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par) return 0; } +static int cgroup_mt_check_v2(const struct xt_mtchk_param *par) +{ + struct xt_cgroup_info_v2 *info = par->matchinfo; + struct cgroup *cgrp; + + if ((info->invert_path & ~1) || (info->invert_classid & ~1)) + return -EINVAL; + + if (!info->has_path && !info->has_classid) { + pr_info("xt_cgroup: no path or classid specified\n"); + return -EINVAL; + } + + if (info->has_path && info->has_classid) { + pr_info_ratelimited("path and classid specified\n"); + return -EINVAL; + } + + info->priv = NULL; + if (info->has_path) { + cgrp = cgroup_get_from_path(info->path); + if (IS_ERR(cgrp)) { + pr_info_ratelimited("invalid path, errno=%ld\n", + PTR_ERR(cgrp)); + return -EINVAL; + } + info->priv = cgrp; + } + + return 0; +} + static bool cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) { @@ -95,6 +127,24 @@ static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) info->invert_classid; } +static bool cgroup_mt_v2(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_cgroup_info_v2 *info = par->matchinfo; + struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; + struct cgroup *ancestor = info->priv; + struct sock *sk = skb->sk; + + if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk))) + return false; + + if (ancestor) + return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ + info->invert_path; + else + return (info->classid == sock_cgroup_classid(skcd)) ^ + info->invert_classid; +} + static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) { struct xt_cgroup_info_v1 *info = par->matchinfo; @@ -103,6 +153,14 @@ static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) cgroup_put(info->priv); } +static void cgroup_mt_destroy_v2(const struct xt_mtdtor_param *par) +{ + struct xt_cgroup_info_v2 *info = par->matchinfo; + + if (info->priv) + cgroup_put(info->priv); +} + static struct xt_match cgroup_mt_reg[] __read_mostly = { { .name = "cgroup", @@ -130,6 +188,20 @@ static struct xt_match cgroup_mt_reg[] __read_mostly = { (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN), }, + { + .name = "cgroup", + .revision = 2, + .family = NFPROTO_UNSPEC, + .checkentry = cgroup_mt_check_v2, + .match = cgroup_mt_v2, + .matchsize = sizeof(struct xt_cgroup_info_v2), + .usersize = offsetof(struct xt_cgroup_info_v2, priv), + .destroy = cgroup_mt_destroy_v2, + .me = THIS_MODULE, + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING) | + (1 << NF_INET_LOCAL_IN), + }, }; static int __init cgroup_mt_init(void) diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 285f8797c26a2b019cd10374051c70892f90d39a..0171b27a2b81bd83009bf22190c4744e8afab4fe 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef CONFIG_NF_NAT_NEEDED #include diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index e687b89dafe676cfd49648dbb683359140d7ffb8..f5deae2ccb79258fbe26f6a908db87b891b81858 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1967,14 +1967,14 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, struct sw_flow_actions *acts; int new_acts_size; - int req_size = NLA_ALIGN(attr_len); + size_t req_size = NLA_ALIGN(attr_len); int next_offset = offsetof(struct sw_flow_actions, actions) + (*sfa)->actions_len; if (req_size <= (ksize(*sfa) - next_offset)) goto out; - new_acts_size = ksize(*sfa) * 2; + new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2); if (new_acts_size > MAX_ACTIONS_BUFSIZE) { if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ec19e4559793a5c7ca0ecb7e17a65bb548f48a92..8b4e92175b5be620cd8c2b0b0a3335301af3cb8c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2641,8 +2641,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) void *ph; DECLARE_SOCKADDR(struct sockaddr_ll *, saddr, msg->msg_name); bool need_wait = !(msg->msg_flags & MSG_DONTWAIT); + unsigned char *addr = NULL; int tp_len, size_max; - unsigned char *addr; void *data; int len_sum = 0; int status = TP_STATUS_AVAILABLE; @@ -2653,7 +2653,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) if (likely(saddr == NULL)) { dev = packet_cached_dev_get(po); proto = po->num; - addr = NULL; } else { err = -EINVAL; if (msg->msg_namelen < sizeof(struct sockaddr_ll)) @@ -2663,10 +2662,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_halen ? saddr->sll_addr : NULL; dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); - if (addr && dev && saddr->sll_halen < dev->addr_len) - goto out_put; + if (po->sk.sk_socket->type == SOCK_DGRAM) { + if (dev && msg->msg_namelen < dev->addr_len + + offsetof(struct sockaddr_ll, sll_addr)) + goto out_put; + addr = saddr->sll_addr; + } } err = -ENXIO; @@ -2838,7 +2840,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) struct sk_buff *skb; struct net_device *dev; __be16 proto; - unsigned char *addr; + unsigned char *addr = NULL; int err, reserve = 0; struct sockcm_cookie sockc; struct virtio_net_hdr vnet_hdr = { 0 }; @@ -2855,7 +2857,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) if (likely(saddr == NULL)) { dev = packet_cached_dev_get(po); proto = po->num; - addr = NULL; } else { err = -EINVAL; if (msg->msg_namelen < sizeof(struct sockaddr_ll)) @@ -2863,10 +2864,13 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_halen ? saddr->sll_addr : NULL; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); - if (addr && dev && saddr->sll_halen < dev->addr_len) - goto out_unlock; + if (sock->type == SOCK_DGRAM) { + if (dev && msg->msg_namelen < dev->addr_len + + offsetof(struct sockaddr_ll, sll_addr)) + goto out_unlock; + addr = saddr->sll_addr; + } } err = -ENXIO; diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig index c4d5503684fa4604c7f2b76a0219d85f27835c25..be1c32e10f1852b7730652473d192279edbbca39 100644 --- a/net/qrtr/Kconfig +++ b/net/qrtr/Kconfig @@ -14,6 +14,17 @@ config QRTR if QRTR +config QRTR_NODE_ID + int "QRTR Local Node ID" + default 1 + ---help--- + This option is used to configure the QRTR Node ID for the local + processor. The node ID published to other nodes within the system. + This value can be overridden by the name service application. This + option is for configurations where Node ID needs to be customized + but the name service application is not priveleged enough to use + netlink sockets. + config QRTR_SMD tristate "SMD IPC Router channels" depends on RPMSG || (COMPILE_TEST && RPMSG=n) @@ -40,4 +51,13 @@ config QRTR_FIFO Say Y here to support FIFO based ipcrouter channels. FIFO Transport Layer enables IPC Router communication between two virtual machines. +config QRTR_MHI_DEV + tristate "MHI Device IPC Router channels" + depends on MSM_MHI_DEV || (COMPILE_TEST && MSM_MHI_DEV=n) + ---help--- + Say Y here to support MHI base ipcrouter channels for device + endpoint mode. MHI is the transport used for external modem + connections. This driver enables QRTR to run on the modem device + side. + endif # QRTR diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile index 57164b1c32aa4913505589d42e470ea97a34ba95..174741c03c4e2c93c95e1618d03f75c51b79a51c 100644 --- a/net/qrtr/Makefile +++ b/net/qrtr/Makefile @@ -11,3 +11,6 @@ qrtr-usb-y := usb.o obj-$(CONFIG_QRTR_FIFO) += qrtr-fifo.o qrtr-fifo-y := fifo.o + +obj-$(CONFIG_QRTR_MHI_DEV) += qrtr-mhi-dev.o +qrtr-mhi-dev-y := mhi_dev.o diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index dbc0d1efaadfb88bd28114576ddd58dea0d91a83..54aeefae1ddcc63b6519cc10d86e9c6b3b24a5d8 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -25,6 +25,7 @@ struct qrtr_mhi_dev { struct device *dev; spinlock_t ul_lock; /* lock to protect ul_pkts */ struct list_head ul_pkts; + atomic_t in_reset; }; struct qrtr_mhi_pkt { @@ -68,14 +69,33 @@ static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev, { struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); struct qrtr_mhi_pkt *pkt; + unsigned long flags; - spin_lock_bh(&qdev->ul_lock); + spin_lock_irqsave(&qdev->ul_lock, flags); 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); + spin_unlock_irqrestore(&qdev->ul_lock, flags); +} + +/* fatal error */ +static void qcom_mhi_qrtr_status_callback(struct mhi_device *mhi_dev, + enum MHI_CB mhi_cb) +{ + struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); + struct qrtr_mhi_pkt *pkt; + unsigned long flags; + + if (mhi_cb != MHI_CB_FATAL_ERROR) + return; + + atomic_inc(&qdev->in_reset); + spin_lock_irqsave(&qdev->ul_lock, flags); + list_for_each_entry(pkt, &qdev->ul_pkts, node) + complete_all(&pkt->done); + spin_unlock_irqrestore(&qdev->ul_lock, flags); } /* from qrtr to mhi */ @@ -118,10 +138,12 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb) sock_hold(skb->sk); rc = wait_for_completion_interruptible_timeout(&pkt->done, HZ * 5); - if (rc > 0) - rc = 0; + if (atomic_read(&qdev->in_reset)) + rc = -ECONNRESET; else if (rc == 0) rc = -ETIMEDOUT; + else if (rc > 0) + rc = 0; kref_put(&pkt->refcount, qrtr_mhi_pkt_release); return rc; @@ -142,6 +164,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, qdev->mhi_dev = mhi_dev; qdev->dev = &mhi_dev->dev; qdev->ep.xmit = qcom_mhi_qrtr_send; + atomic_set(&qdev->in_reset, 0); rc = of_property_read_u32(mhi_dev->dev.of_node, "qcom,net-id", &net_id); if (rc < 0) @@ -152,12 +175,11 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, INIT_LIST_HEAD(&qdev->ul_pkts); spin_lock_init(&qdev->ul_lock); + dev_set_drvdata(&mhi_dev->dev, qdev); rc = qrtr_endpoint_register(&qdev->ep, net_id, rt); if (rc) return rc; - dev_set_drvdata(&mhi_dev->dev, qdev); - dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n"); return 0; @@ -181,6 +203,7 @@ static struct mhi_driver qcom_mhi_qrtr_driver = { .remove = qcom_mhi_qrtr_remove, .dl_xfer_cb = qcom_mhi_qrtr_dl_callback, .ul_xfer_cb = qcom_mhi_qrtr_ul_callback, + .status_cb = qcom_mhi_qrtr_status_callback, .id_table = qcom_mhi_qrtr_mhi_match, .driver = { .name = "qcom_mhi_qrtr", diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..a838c2b61a0fb3c6a02a54d1239c0defa075067b --- /dev/null +++ b/net/qrtr/mhi_dev.c @@ -0,0 +1,252 @@ +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This 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 "qrtr.h" + +#define QRTR_MAX_PKT_SIZE SZ_32K + +/* MHI DEV Enums are defined from Host perspective */ +#define QRTR_MHI_DEV_OUT MHI_CLIENT_IPCR_IN +#define QRTR_MHI_DEV_IN MHI_CLIENT_IPCR_OUT + +/** + * struct qrtr_mhi_dev_ep - qrtr mhi device endpoint + * @ep: endpoint + * @dev: device from platform bus + * @out: channel handle from mhi dev + * @out_tre: complete when channel is ready to send + * @out_lock: hold when resetting completion variable + * @in: channel handle from mhi dev + * @buf_in: buffer to hold incoming data + * @net_id: subnet id used by qrtr core + * @rt: realtime option used by qrtr core + */ +struct qrtr_mhi_dev_ep { + struct qrtr_endpoint ep; + struct device *dev; + struct mhi_dev_client *out; + struct completion out_tre; + struct mutex out_lock; /* for out critical sections */ + struct mhi_dev_client *in; + void *buf_in; + + u32 net_id; + bool rt; +}; + +static struct qrtr_mhi_dev_ep *qrtr_mhi_device_endpoint; + +static int qrtr_mhi_dev_send(struct qrtr_endpoint *ep, struct sk_buff *skb) +{ + struct qrtr_mhi_dev_ep *qep; + struct mhi_req req = { 0 }; + int rc; + + qep = container_of(ep, struct qrtr_mhi_dev_ep, ep); + rc = skb_linearize(skb); + if (rc) { + kfree_skb(skb); + return rc; + } + + req.chan = QRTR_MHI_DEV_OUT; + req.client = qep->out; + req.mode = DMA_SYNC; + req.buf = skb->data; + req.len = skb->len; + + do { + wait_for_completion(&qep->out_tre); + + mutex_lock(&qep->out_lock); + rc = mhi_dev_write_channel(&req); + if (rc == 0) + reinit_completion(&qep->out_tre); + mutex_unlock(&qep->out_lock); + } while (!rc); + + if (rc != skb->len) { + dev_err(qep->dev, "send failed rc:%d len:%d\n", rc, skb->len); + kfree_skb(skb); + return rc; + } + + consume_skb(skb); + return 0; +} + +static void qrtr_mhi_dev_read(struct qrtr_mhi_dev_ep *qep) +{ + struct mhi_req req = { 0 }; + int rc; + int bytes_read; + + req.chan = QRTR_MHI_DEV_IN; + req.client = qep->in; + req.mode = DMA_SYNC; + req.buf = qep->buf_in; + req.len = QRTR_MAX_PKT_SIZE; + + do { + bytes_read = mhi_dev_read_channel(&req); + if (bytes_read < 0) { + dev_err(qep->dev, "failed to read channel %d\n", + bytes_read); + return; + } + + rc = qrtr_endpoint_post(&qep->ep, req.buf, req.transfer_len); + if (rc == -EINVAL) + dev_err(qep->dev, "invalid ipcrouter packet\n"); + } while (bytes_read > 0); +} + +static void qrtr_mhi_dev_event_cb(struct mhi_dev_client_cb_reason *reason) +{ + struct qrtr_mhi_dev_ep *qep; + + qep = qrtr_mhi_device_endpoint; + if (!qep) + return; + + if (reason->reason == MHI_DEV_TRE_AVAILABLE) { + pr_debug("TRE available event for chan %d\n", reason->ch_id); + if (reason->ch_id == QRTR_MHI_DEV_IN) { + qrtr_mhi_dev_read(qep); + } else { + mutex_lock(&qep->out_lock); + complete_all(&qep->out_tre); + mutex_unlock(&qep->out_lock); + } + } +} + +static int qrtr_mhi_dev_open_channels(struct qrtr_mhi_dev_ep *qep) +{ + int rc; + + /* write channel */ + rc = mhi_dev_open_channel(QRTR_MHI_DEV_IN, &qep->in, + qrtr_mhi_dev_event_cb); + if (rc < 0) + return rc; + + /* read channel */ + rc = mhi_dev_open_channel(QRTR_MHI_DEV_OUT, &qep->out, + qrtr_mhi_dev_event_cb); + if (rc < 0) { + mhi_dev_close_channel(qep->in); + return rc; + } + return 0; +} + +static void qrtr_mhi_dev_close_channels(struct qrtr_mhi_dev_ep *qep) +{ + int rc; + + rc = mhi_dev_close_channel(qep->in); + if (rc < 0) + dev_err(qep->dev, "failed to close in channel %d\n", rc); + + rc = mhi_dev_close_channel(qep->out); + if (rc < 0) + dev_err(qep->dev, "failed to close out channel %d\n", rc); +} + +static void qrtr_mhi_dev_state_cb(struct mhi_dev_client_cb_data *cb_data) +{ + struct qrtr_mhi_dev_ep *qep; + int rc; + + if (!cb_data || !cb_data->user_data) + return; + qep = cb_data->user_data; + + switch (cb_data->ctrl_info) { + case MHI_STATE_CONNECTED: + rc = qrtr_mhi_dev_open_channels(qep); + if (rc) { + dev_err(qep->dev, "open failed %d", rc); + return; + } + + rc = qrtr_endpoint_register(&qep->ep, qep->net_id, qep->rt); + if (rc) { + dev_err(qep->dev, "register failed %d", rc); + qrtr_mhi_dev_close_channels(qep); + } + break; + case MHI_STATE_DISCONNECTED: + qrtr_endpoint_unregister(&qep->ep); + qrtr_mhi_dev_close_channels(qep); + break; + default: + break; + } +} + +static int qrtr_mhi_dev_probe(struct platform_device *pdev) +{ + struct qrtr_mhi_dev_ep *qep; + struct device_node *node; + int rc; + + qep = devm_kzalloc(&pdev->dev, sizeof(*qep), GFP_KERNEL); + if (!qep) + return -ENOMEM; + qep->dev = &pdev->dev; + + node = pdev->dev.of_node; + rc = of_property_read_u32(node, "qcom,net-id", &qep->net_id); + if (rc < 0) + qep->net_id = QRTR_EP_NET_ID_AUTO; + qep->rt = of_property_read_bool(node, "qcom,low-latency"); + + qep->buf_in = devm_kzalloc(&pdev->dev, QRTR_MAX_PKT_SIZE, GFP_KERNEL); + if (!qep->buf_in) + return -ENOMEM; + + qrtr_mhi_device_endpoint = qep; + + mutex_init(&qep->out_lock); + init_completion(&qep->out_tre); + qep->ep.xmit = qrtr_mhi_dev_send; + rc = mhi_register_state_cb(qrtr_mhi_dev_state_cb, qep, + QRTR_MHI_DEV_IN); + if (rc) + return rc; + + return 0; +} + +static const struct of_device_id qrtr_mhi_dev_match_table[] = { + { .compatible = "qcom,qrtr-mhi-dev"}, + {}, +}; + +static struct platform_driver qrtr_mhi_dev_driver = { + .probe = qrtr_mhi_dev_probe, + .driver = { + .name = "qrtr_mhi_dev", + .of_match_table = qrtr_mhi_dev_match_table, + }, +}; +module_platform_driver(qrtr_mhi_dev_driver); + +MODULE_DESCRIPTION("QTI IPC-Router MHI device interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 2d940d7a2d75ac1a7e5493e193be659632a811fd..e3cbe33a043a43d86c1dcb983ec7e012bd1ba74d 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -122,7 +122,7 @@ static inline struct qrtr_sock *qrtr_sk(struct sock *sk) return container_of(sk, struct qrtr_sock, sk); } -static unsigned int qrtr_local_nid = 1; +static unsigned int qrtr_local_nid = CONFIG_QRTR_NODE_ID; /* for node ids */ static RADIX_TREE(qrtr_nodes, GFP_KERNEL); @@ -151,6 +151,7 @@ static DEFINE_MUTEX(qrtr_port_lock); * @kworker: worker thread for recv work * @task: task to run the worker thread * @read_data: scheduled work for recv work + * @say_hello: scheduled work for initiating hello * @ws: wakeupsource avoid system suspend * @ilc: ipc logging context reference */ @@ -161,6 +162,7 @@ struct qrtr_node { unsigned int nid; unsigned int net_id; atomic_t hello_sent; + atomic_t hello_rcvd; struct radix_tree_root qrtr_tx_flow; struct wait_queue_head resume_tx; @@ -172,6 +174,7 @@ struct qrtr_node { struct kthread_worker kworker; struct task_struct *task; struct kthread_work read_data; + struct kthread_work say_hello; struct wakeup_source *ws; @@ -516,6 +519,10 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, kfree_skb(skb); return rc; } + if (atomic_read(&node->hello_sent) && type == QRTR_TYPE_HELLO) { + kfree_skb(skb); + return 0; + } /* If sk is null, this is a forwarded packet and should not wait */ if (!skb->sk) { @@ -870,12 +877,38 @@ static void qrtr_fwd_pkt(struct sk_buff *skb, struct qrtr_cb *cb) struct qrtr_node *node; node = qrtr_node_lookup(cb->dst_node); - if (!node) + if (!node) { + kfree_skb(skb); return; + } qrtr_node_enqueue(node, skb, cb->type, &from, &to, 0); qrtr_node_release(node); } + +static void qrtr_sock_queue_skb(struct qrtr_node *node, struct sk_buff *skb, + struct qrtr_sock *ipc) +{ + struct qrtr_cb *cb = (struct qrtr_cb *)skb->cb; + int rc; + + /* Don't queue HELLO if control port already received */ + if (cb->type == QRTR_TYPE_HELLO) { + if (atomic_read(&node->hello_rcvd)) { + kfree_skb(skb); + return; + } + atomic_inc(&node->hello_rcvd); + } + + rc = sock_queue_rcv_skb(&ipc->sk, skb); + if (rc) { + pr_err("%s: qrtr pkt dropped flow[%d] rc[%d]\n", + __func__, cb->confirm_rx, rc); + kfree_skb(skb); + } +} + /* Handle and route a received packet. * * This will auto-reply with resume-tx packet as necessary. @@ -918,18 +951,40 @@ static void qrtr_node_rx_work(struct kthread_work *work) if (!ipc) { kfree_skb(skb); } else { - if (sock_queue_rcv_skb(&ipc->sk, skb)) { - pr_err("%s qrtr pkt dropped flow[%d]\n", - __func__, cb->confirm_rx); - kfree_skb(skb); - } - + qrtr_sock_queue_skb(node, skb, ipc); qrtr_port_put(ipc); } } } } +static void qrtr_hello_work(struct kthread_work *work) +{ + struct sockaddr_qrtr from = {AF_QIPCRTR, 0, QRTR_PORT_CTRL}; + struct sockaddr_qrtr to = {AF_QIPCRTR, 0, QRTR_PORT_CTRL}; + struct qrtr_ctrl_pkt *pkt; + struct qrtr_node *node; + struct qrtr_sock *ctrl; + struct sk_buff *skb; + + ctrl = qrtr_port_lookup(QRTR_PORT_CTRL); + if (!ctrl) + return; + + skb = qrtr_alloc_ctrl_packet(&pkt); + if (!skb) { + qrtr_port_put(ctrl); + return; + } + + node = container_of(work, struct qrtr_node, say_hello); + pkt->cmd = cpu_to_le32(QRTR_TYPE_HELLO); + from.sq_node = qrtr_local_nid; + to.sq_node = node->nid; + qrtr_node_enqueue(node, skb, QRTR_TYPE_HELLO, &from, &to, 0); + qrtr_port_put(ctrl); +} + /** * qrtr_endpoint_register() - register a new endpoint * @ep: endpoint to register @@ -958,8 +1013,10 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, node->nid = QRTR_EP_NID_AUTO; node->ep = ep; atomic_set(&node->hello_sent, 0); + atomic_set(&node->hello_rcvd, 0); kthread_init_work(&node->read_data, qrtr_node_rx_work); + kthread_init_work(&node->say_hello, qrtr_hello_work); kthread_init_worker(&node->kworker); node->task = kthread_run(kthread_worker_fn, &node->kworker, "qrtr_rx"); if (IS_ERR(node->task)) { @@ -981,6 +1038,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, up_write(&qrtr_node_lock); ep->node = node; + kthread_queue_work(&node->kworker, &node->say_hello); return 0; } EXPORT_SYMBOL_GPL(qrtr_endpoint_register); @@ -1262,6 +1320,17 @@ static int __qrtr_bind(struct socket *sock, qrtr_reset_ports(); mutex_unlock(&qrtr_port_lock); + if (port == QRTR_PORT_CTRL) { + struct qrtr_node *node; + + down_write(&qrtr_node_lock); + list_for_each_entry(node, &qrtr_all_epts, item) { + atomic_set(&node->hello_sent, 0); + atomic_set(&node->hello_rcvd, 0); + } + up_write(&qrtr_node_lock); + } + /* unbind previous, if any */ if (!zapped) qrtr_port_remove(ipc); @@ -1361,7 +1430,7 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, down_read(&qrtr_node_lock); list_for_each_entry(node, &qrtr_all_epts, item) { - if (node->nid == QRTR_EP_NID_AUTO) + if (node->nid == QRTR_EP_NID_AUTO && type != QRTR_TYPE_HELLO) continue; skbn = skb_clone(skb, GFP_KERNEL); if (!skbn) diff --git a/net/qrtr/usb.c b/net/qrtr/usb.c index 93566e39552312400d683e04e5fdd299534efa4d..d475b3125eb0e13ae94132e128081fb2c1c6047d 100644 --- a/net/qrtr/usb.c +++ b/net/qrtr/usb.c @@ -302,6 +302,7 @@ static const struct usb_device_id qcom_usb_qrtr_ids[] = { { USB_DEVICE_INTERFACE_NUMBER(QRTR_VENDOR_ID, 0x90ef, 3) }, { USB_DEVICE_INTERFACE_NUMBER(QRTR_VENDOR_ID, 0x90f0, 3) }, { USB_DEVICE_INTERFACE_NUMBER(QRTR_VENDOR_ID, 0x90f3, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(QRTR_VENDOR_ID, 0x90fd, 1) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, qcom_usb_qrtr_ids); diff --git a/net/rds/ib_fmr.c b/net/rds/ib_fmr.c index 86ef907067bb084e01ac4f8d5f00d0c17f40ac55..353b59d3bd44363728e296d6ee51f75b80f7208d 100644 --- a/net/rds/ib_fmr.c +++ b/net/rds/ib_fmr.c @@ -44,6 +44,17 @@ struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev, int npages) else pool = rds_ibdev->mr_1m_pool; + if (atomic_read(&pool->dirty_count) >= pool->max_items / 10) + queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10); + + /* Switch pools if one of the pool is reaching upper limit */ + if (atomic_read(&pool->dirty_count) >= pool->max_items * 9 / 10) { + if (pool->pool_type == RDS_IB_MR_8K_POOL) + pool = rds_ibdev->mr_1m_pool; + else + pool = rds_ibdev->mr_8k_pool; + } + ibmr = rds_ib_try_reuse_ibmr(pool); if (ibmr) return ibmr; diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 9a3c54e659e9e08430ba4649df65ccfbaea6d939..fe5d2e8a95d93a9eebb0d1ffe1797a6fd1da9842 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -442,9 +442,6 @@ struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *pool) struct rds_ib_mr *ibmr = NULL; int iter = 0; - if (atomic_read(&pool->dirty_count) >= pool->max_items_soft / 10) - queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10); - while (1) { ibmr = rds_ib_reuse_mr(pool); if (ibmr) diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 2a08bf75d008e8ec2f8e550a94d5f2a0d5c850bd..82e9ffecd90e39659a81ed5aa99988de49dc7b16 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -530,7 +530,7 @@ static void rds_tcp_kill_sock(struct net *net) list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) { struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); - if (net != c_net || !tc->t_sock) + if (net != c_net) continue; if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn)) { list_move_tail(&tc->t_tcp_node, &tmp_list); diff --git a/net/rmnet_usb/rmnet_usb.c b/net/rmnet_usb/rmnet_usb.c index 9e978eb9d499f2eceb48046e5445ea446812a4d2..e77c0ad52ad08647f196a23422bdc2d6c3c83c86 100644 --- a/net/rmnet_usb/rmnet_usb.c +++ b/net/rmnet_usb/rmnet_usb.c @@ -428,6 +428,14 @@ static const struct usb_device_id rmnet_usb_ids[] = { USB_DEVICE_INTERFACE_NUMBER(RMNET_VENDOR_ID, 0x90F3, 1), .driver_info = (unsigned long)&rmnet_usb_info, }, + { + USB_DEVICE_INTERFACE_NUMBER(RMNET_VENDOR_ID, 0x90FD, 2), + .driver_info = (unsigned long)&rmnet_usb_info, + }, + { + USB_DEVICE_INTERFACE_NUMBER(RMNET_VENDOR_ID, 0x90FD, 3), + .driver_info = (unsigned long)&rmnet_usb_info, + }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, rmnet_usb_ids); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 4a9729257023676565a0ff8c140ef56823b6d374..6a5c4992cf618a9b646e78dc621244214d2bccc7 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -318,9 +318,11 @@ void rose_destroy_socket(struct sock *); /* * Handler for deferred kills. */ -static void rose_destroy_timer(unsigned long data) +static void rose_destroy_timer(struct timer_list *t) { - rose_destroy_socket((struct sock *)data); + struct sock *sk = from_timer(sk, t, sk_timer); + + rose_destroy_socket(sk); } /* @@ -353,8 +355,7 @@ void rose_destroy_socket(struct sock *sk) if (sk_has_allocations(sk)) { /* Defer: outstanding buffers */ - setup_timer(&sk->sk_timer, rose_destroy_timer, - (unsigned long)sk); + timer_setup(&sk->sk_timer, rose_destroy_timer, 0); sk->sk_timer.expires = jiffies + 10 * HZ; add_timer(&sk->sk_timer); } else @@ -538,8 +539,8 @@ static int rose_create(struct net *net, struct socket *sock, int protocol, sock->ops = &rose_proto_ops; sk->sk_protocol = protocol; - init_timer(&rose->timer); - init_timer(&rose->idletimer); + timer_setup(&rose->timer, NULL, 0); + timer_setup(&rose->idletimer, NULL, 0); rose->t1 = msecs_to_jiffies(sysctl_rose_call_request_timeout); rose->t2 = msecs_to_jiffies(sysctl_rose_reset_request_timeout); @@ -582,8 +583,8 @@ static struct sock *rose_make_new(struct sock *osk) sk->sk_state = TCP_ESTABLISHED; sock_copy_flags(sk, osk); - init_timer(&rose->timer); - init_timer(&rose->idletimer); + timer_setup(&rose->timer, NULL, 0); + timer_setup(&rose->idletimer, NULL, 0); orose = rose_sk(osk); rose->t1 = orose->t1; diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c index c76638cc2cd533764bb78cef7f8bc24fb9312c3c..cda4c6678ef16708c185b220f24647ee308f9a93 100644 --- a/net/rose/rose_link.c +++ b/net/rose/rose_link.c @@ -27,8 +27,8 @@ #include #include -static void rose_ftimer_expiry(unsigned long); -static void rose_t0timer_expiry(unsigned long); +static void rose_ftimer_expiry(struct timer_list *); +static void rose_t0timer_expiry(struct timer_list *); static void rose_transmit_restart_confirmation(struct rose_neigh *neigh); static void rose_transmit_restart_request(struct rose_neigh *neigh); @@ -37,8 +37,7 @@ void rose_start_ftimer(struct rose_neigh *neigh) { del_timer(&neigh->ftimer); - neigh->ftimer.data = (unsigned long)neigh; - neigh->ftimer.function = &rose_ftimer_expiry; + neigh->ftimer.function = (TIMER_FUNC_TYPE)rose_ftimer_expiry; neigh->ftimer.expires = jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout); @@ -49,8 +48,7 @@ static void rose_start_t0timer(struct rose_neigh *neigh) { del_timer(&neigh->t0timer); - neigh->t0timer.data = (unsigned long)neigh; - neigh->t0timer.function = &rose_t0timer_expiry; + neigh->t0timer.function = (TIMER_FUNC_TYPE)rose_t0timer_expiry; neigh->t0timer.expires = jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout); @@ -77,13 +75,13 @@ static int rose_t0timer_running(struct rose_neigh *neigh) return timer_pending(&neigh->t0timer); } -static void rose_ftimer_expiry(unsigned long param) +static void rose_ftimer_expiry(struct timer_list *t) { } -static void rose_t0timer_expiry(unsigned long param) +static void rose_t0timer_expiry(struct timer_list *t) { - struct rose_neigh *neigh = (struct rose_neigh *)param; + struct rose_neigh *neigh = from_timer(neigh, t, t0timer); rose_transmit_restart_request(neigh); diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c index 344456206b70bfbfdfdac7a342687687db4cb0c8..094a6621f8e803ae41101899ef02f080d91ac0f3 100644 --- a/net/rose/rose_loopback.c +++ b/net/rose/rose_loopback.c @@ -16,15 +16,17 @@ #include static struct sk_buff_head loopback_queue; +#define ROSE_LOOPBACK_LIMIT 1000 static struct timer_list loopback_timer; static void rose_set_loopback_timer(void); +static void rose_loopback_timer(struct timer_list *unused); void rose_loopback_init(void) { skb_queue_head_init(&loopback_queue); - init_timer(&loopback_timer); + timer_setup(&loopback_timer, rose_loopback_timer, 0); } static int rose_loopback_running(void) @@ -34,36 +36,30 @@ static int rose_loopback_running(void) int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh) { - struct sk_buff *skbn; + struct sk_buff *skbn = NULL; - skbn = skb_clone(skb, GFP_ATOMIC); + if (skb_queue_len(&loopback_queue) < ROSE_LOOPBACK_LIMIT) + skbn = skb_clone(skb, GFP_ATOMIC); - kfree_skb(skb); - - if (skbn != NULL) { + if (skbn) { + consume_skb(skb); skb_queue_tail(&loopback_queue, skbn); if (!rose_loopback_running()) rose_set_loopback_timer(); + } else { + kfree_skb(skb); } return 1; } -static void rose_loopback_timer(unsigned long); - static void rose_set_loopback_timer(void) { - del_timer(&loopback_timer); - - loopback_timer.data = 0; - loopback_timer.function = &rose_loopback_timer; - loopback_timer.expires = jiffies + 10; - - add_timer(&loopback_timer); + mod_timer(&loopback_timer, jiffies + 10); } -static void rose_loopback_timer(unsigned long param) +static void rose_loopback_timer(struct timer_list *unused) { struct sk_buff *skb; struct net_device *dev; @@ -71,8 +67,12 @@ static void rose_loopback_timer(unsigned long param) struct sock *sk; unsigned short frametype; unsigned int lci_i, lci_o; + int count; - while ((skb = skb_dequeue(&loopback_queue)) != NULL) { + for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) { + skb = skb_dequeue(&loopback_queue); + if (!skb) + return; if (skb->len < ROSE_MIN_LEN) { kfree_skb(skb); continue; @@ -109,6 +109,8 @@ static void rose_loopback_timer(unsigned long param) kfree_skb(skb); } } + if (!skb_queue_empty(&loopback_queue)) + mod_timer(&loopback_timer, jiffies + 1); } void __exit rose_loopback_clear(void) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 2741abec7ee795ba097609604b406e7c725387ac..d94d6110bb1ca10d1a2740e4161c59d272392b38 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -104,8 +104,8 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, skb_queue_head_init(&rose_neigh->queue); - init_timer(&rose_neigh->ftimer); - init_timer(&rose_neigh->t0timer); + timer_setup(&rose_neigh->ftimer, NULL, 0); + timer_setup(&rose_neigh->t0timer, NULL, 0); if (rose_route->ndigis != 0) { rose_neigh->digipeat = @@ -390,8 +390,8 @@ void rose_add_loopback_neigh(void) skb_queue_head_init(&sn->queue); - init_timer(&sn->ftimer); - init_timer(&sn->t0timer); + timer_setup(&sn->ftimer, NULL, 0); + timer_setup(&sn->t0timer, NULL, 0); spin_lock_bh(&rose_neigh_list_lock); sn->next = rose_neigh_list; diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c index bc5469d6d9cb5cdf6e7995e3ee605f97d2dd2616..3b89d66f15bbe30e20a430fcb613373165de87cb 100644 --- a/net/rose/rose_timer.c +++ b/net/rose/rose_timer.c @@ -29,8 +29,8 @@ #include static void rose_heartbeat_expiry(unsigned long); -static void rose_timer_expiry(unsigned long); -static void rose_idletimer_expiry(unsigned long); +static void rose_timer_expiry(struct timer_list *); +static void rose_idletimer_expiry(struct timer_list *); void rose_start_heartbeat(struct sock *sk) { @@ -49,8 +49,7 @@ void rose_start_t1timer(struct sock *sk) del_timer(&rose->timer); - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; + rose->timer.function = (TIMER_FUNC_TYPE)rose_timer_expiry; rose->timer.expires = jiffies + rose->t1; add_timer(&rose->timer); @@ -62,8 +61,7 @@ void rose_start_t2timer(struct sock *sk) del_timer(&rose->timer); - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; + rose->timer.function = (TIMER_FUNC_TYPE)rose_timer_expiry; rose->timer.expires = jiffies + rose->t2; add_timer(&rose->timer); @@ -75,8 +73,7 @@ void rose_start_t3timer(struct sock *sk) del_timer(&rose->timer); - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; + rose->timer.function = (TIMER_FUNC_TYPE)rose_timer_expiry; rose->timer.expires = jiffies + rose->t3; add_timer(&rose->timer); @@ -88,8 +85,7 @@ void rose_start_hbtimer(struct sock *sk) del_timer(&rose->timer); - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; + rose->timer.function = (TIMER_FUNC_TYPE)rose_timer_expiry; rose->timer.expires = jiffies + rose->hb; add_timer(&rose->timer); @@ -102,8 +98,7 @@ void rose_start_idletimer(struct sock *sk) del_timer(&rose->idletimer); if (rose->idle > 0) { - rose->idletimer.data = (unsigned long)sk; - rose->idletimer.function = &rose_idletimer_expiry; + rose->idletimer.function = (TIMER_FUNC_TYPE)rose_idletimer_expiry; rose->idletimer.expires = jiffies + rose->idle; add_timer(&rose->idletimer); @@ -163,10 +158,10 @@ static void rose_heartbeat_expiry(unsigned long param) bh_unlock_sock(sk); } -static void rose_timer_expiry(unsigned long param) +static void rose_timer_expiry(struct timer_list *t) { - struct sock *sk = (struct sock *)param; - struct rose_sock *rose = rose_sk(sk); + struct rose_sock *rose = from_timer(rose, t, timer); + struct sock *sk = &rose->sock; bh_lock_sock(sk); switch (rose->state) { @@ -192,9 +187,10 @@ static void rose_timer_expiry(unsigned long param) bh_unlock_sock(sk); } -static void rose_idletimer_expiry(unsigned long param) +static void rose_idletimer_expiry(struct timer_list *t) { - struct sock *sk = (struct sock *)param; + struct rose_sock *rose = from_timer(rose, t, idletimer); + struct sock *sk = &rose->sock; bh_lock_sock(sk); rose_clear_queues(sk); diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 8a5a42e8ec230a481f99a1e28fa4649e22ca886c..ddaa471a26076f9cdddba51eaa3d576e31187ff8 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -684,27 +684,27 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet) _enter(""); - if (list_empty(&rxnet->calls)) - return; + if (!list_empty(&rxnet->calls)) { + write_lock(&rxnet->call_lock); - write_lock(&rxnet->call_lock); + while (!list_empty(&rxnet->calls)) { + call = list_entry(rxnet->calls.next, + struct rxrpc_call, link); + _debug("Zapping call %p", call); - while (!list_empty(&rxnet->calls)) { - call = list_entry(rxnet->calls.next, struct rxrpc_call, link); - _debug("Zapping call %p", call); + rxrpc_see_call(call); + list_del_init(&call->link); - rxrpc_see_call(call); - list_del_init(&call->link); + pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n", + call, atomic_read(&call->usage), + rxrpc_call_states[call->state], + call->flags, call->events); - pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n", - call, atomic_read(&call->usage), - rxrpc_call_states[call->state], - call->flags, call->events); + write_unlock(&rxnet->call_lock); + cond_resched(); + write_lock(&rxnet->call_lock); + } write_unlock(&rxnet->call_lock); - cond_resched(); - write_lock(&rxnet->call_lock); } - - write_unlock(&rxnet->call_lock); } diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index a859b55d789918074d29778d159a254a93f04748..64fd1e9818a68c9029b5dc32bfb8d80179b1c7cd 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -45,6 +45,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, struct tc_sample *parm; struct tcf_sample *s; bool exists = false; + u32 rate; int ret; if (!nla) @@ -73,10 +74,17 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, if (!ovr) return -EEXIST; } - s = to_sample(*a); + rate = nla_get_u32(tb[TCA_SAMPLE_RATE]); + if (!rate) { + tcf_idr_release(*a, bind); + return -EINVAL; + } + + s = to_sample(*a); s->tcf_action = parm->action; s->rate = nla_get_u32(tb[TCA_SAMPLE_RATE]); + s->rate = rate; s->psample_group_num = nla_get_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]); psample_group = psample_group_get(net, s->psample_group_num); if (!psample_group) { diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c index 6499aecfbfc43389965f13b638a4ec7b6bcb8d5b..d8fd152779c8d451bfaa0b028f3e3a94b723731d 100644 --- a/net/sched/cls_matchall.c +++ b/net/sched/cls_matchall.c @@ -125,6 +125,11 @@ static void mall_destroy(struct tcf_proto *tp) static void *mall_get(struct tcf_proto *tp, u32 handle) { + struct cls_mall_head *head = rtnl_dereference(tp->root); + + if (head && head->handle == handle) + return head; + return NULL; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index cbb04d66f564c2ae383a28d1a5319ffdaa1fce31..a7529aca2ac82782590533ffad5c5705186ad978 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -605,6 +605,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) { /* No address mapping for V4 sockets */ + memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero)); return sizeof(struct sockaddr_in); } diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index e2d9a4b49c9c98061a1c5b358b65ce5285f68de8..fb857cf09ecdade14c58510bc703923f15b25bd0 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1092,32 +1092,6 @@ static void sctp_cmd_send_msg(struct sctp_association *asoc, } -/* Sent the next ASCONF packet currently stored in the association. - * This happens after the ASCONF_ACK was succeffully processed. - */ -static void sctp_cmd_send_asconf(struct sctp_association *asoc) -{ - struct net *net = sock_net(asoc->base.sk); - - /* Send the next asconf chunk from the addip chunk - * queue. - */ - if (!list_empty(&asoc->addip_chunk_list)) { - struct list_head *entry = asoc->addip_chunk_list.next; - struct sctp_chunk *asconf = list_entry(entry, - struct sctp_chunk, list); - list_del_init(entry); - - /* Hold the chunk until an ASCONF_ACK is received. */ - sctp_chunk_hold(asconf); - if (sctp_primitive_ASCONF(net, asoc, asconf)) - sctp_chunk_free(asconf); - else - asoc->addip_last_asconf = asconf; - } -} - - /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -1763,9 +1737,6 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, } sctp_cmd_send_msg(asoc, cmd->obj.msg, gfp); break; - case SCTP_CMD_SEND_NEXT_ASCONF: - sctp_cmd_send_asconf(asoc); - break; case SCTP_CMD_PURGE_ASCONF_QUEUE: sctp_asconf_queue_teardown(asoc); break; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 01b078172306a59e66e28883327942548c1baaf9..a2e058127ef7a77b29afb9a6a7578c7ce670b06b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3756,6 +3756,29 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net, return SCTP_DISPOSITION_CONSUME; } +static enum sctp_disposition sctp_send_next_asconf( + struct net *net, + const struct sctp_endpoint *ep, + struct sctp_association *asoc, + const union sctp_subtype type, + struct sctp_cmd_seq *commands) +{ + struct sctp_chunk *asconf; + struct list_head *entry; + + if (list_empty(&asoc->addip_chunk_list)) + return SCTP_DISPOSITION_CONSUME; + + entry = asoc->addip_chunk_list.next; + asconf = list_entry(entry, struct sctp_chunk, list); + + list_del_init(entry); + sctp_chunk_hold(asconf); + asoc->addip_last_asconf = asconf; + + return sctp_sf_do_prm_asconf(net, ep, asoc, type, asconf, commands); +} + /* * ADDIP Section 4.3 General rules for address manipulation * When building TLV parameters for the ASCONF Chunk that will add or @@ -3847,14 +3870,10 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net, SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); if (!sctp_process_asconf_ack((struct sctp_association *)asoc, - asconf_ack)) { - /* Successfully processed ASCONF_ACK. We can - * release the next asconf if we have one. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF, - SCTP_NULL()); - return SCTP_DISPOSITION_CONSUME; - } + asconf_ack)) + return sctp_send_next_asconf(net, ep, + (struct sctp_association *)asoc, + type, commands); abort = sctp_make_abort(asoc, asconf_ack, sizeof(struct sctp_errhdr)); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index f2cf4edf219bd128802ea18d110fee63eeb950e0..475b453dc7ae169c9a3eff22c27e77d52f4c7ef8 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -54,6 +54,7 @@ static void cache_init(struct cache_head *h, struct cache_detail *detail) h->last_refresh = now; } +static inline int cache_is_valid(struct cache_head *h); static void cache_fresh_locked(struct cache_head *head, time_t expiry, struct cache_detail *detail); static void cache_fresh_unlocked(struct cache_head *head, @@ -100,6 +101,8 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, if (cache_is_expired(detail, tmp)) { hlist_del_init(&tmp->cache_list); detail->entries --; + if (cache_is_valid(tmp) == -EAGAIN) + set_bit(CACHE_NEGATIVE, &tmp->flags); cache_fresh_locked(tmp, 0, detail); freeme = tmp; break; diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 73895daf89431e79db6ad7e4d3c41e9ec2b273bc..aa75bc8b158f802ca854c25f624ee68e7c8d5e6c 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -262,8 +262,14 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, if (msg->rep_type) tipc_tlv_init(msg->rep, msg->rep_type); - if (cmd->header) - (*cmd->header)(msg); + if (cmd->header) { + err = (*cmd->header)(msg); + if (err) { + kfree_skb(msg->rep); + msg->rep = NULL; + return err; + } + } arg = nlmsg_new(0, GFP_KERNEL); if (!arg) { @@ -388,7 +394,12 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, if (!bearer) return -EMSGSIZE; - len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); + len = TLV_GET_DATA_LEN(msg->req); + len -= offsetof(struct tipc_bearer_config, name); + if (len <= 0) + return -EINVAL; + + len = min_t(int, len, TIPC_MAX_BEARER_NAME); if (!string_is_valid(b->name, len)) return -EINVAL; @@ -757,7 +768,12 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, lc = (struct tipc_link_config *)TLV_DATA(msg->req); - len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); + len = TLV_GET_DATA_LEN(msg->req); + len -= offsetof(struct tipc_link_config, name); + if (len <= 0) + return -EINVAL; + + len = min_t(int, len, TIPC_MAX_LINK_NAME); if (!string_is_valid(lc->name, len)) return -EINVAL; diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index edba7ab975639fc08c4257d0393391477979b1aa..40a8731c663bd2b946b886df04d5381fb7425f33 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -662,6 +662,8 @@ static int virtio_transport_reset(struct vsock_sock *vsk, */ static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt) { + const struct virtio_transport *t; + struct virtio_vsock_pkt *reply; struct virtio_vsock_pkt_info info = { .op = VIRTIO_VSOCK_OP_RST, .type = le16_to_cpu(pkt->hdr.type), @@ -672,15 +674,21 @@ static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt) if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) return 0; - pkt = virtio_transport_alloc_pkt(&info, 0, - le64_to_cpu(pkt->hdr.dst_cid), - le32_to_cpu(pkt->hdr.dst_port), - le64_to_cpu(pkt->hdr.src_cid), - le32_to_cpu(pkt->hdr.src_port)); - if (!pkt) + reply = virtio_transport_alloc_pkt(&info, 0, + le64_to_cpu(pkt->hdr.dst_cid), + le32_to_cpu(pkt->hdr.dst_port), + le64_to_cpu(pkt->hdr.src_cid), + le32_to_cpu(pkt->hdr.src_port)); + if (!reply) return -ENOMEM; - return virtio_transport_get_ops()->send_pkt(pkt); + t = virtio_transport_get_ops(); + if (!t) { + virtio_transport_free_pkt(reply); + return -ENOTCONN; + } + + return t->send_pkt(reply); } static void virtio_transport_wait_close(struct sock *sk, long timeout) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5f4d37ac3c4569f8103d9b921dc497466b04685a..504928f31c132f282dc04957579b1254d972f3e0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11023,9 +11023,6 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) if (err) return err; - if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] || - !tb[NL80211_REKEY_DATA_KCK]) - return -EINVAL; if (!tb[NL80211_REKEY_DATA_KEK] || !tb[NL80211_REKEY_DATA_REPLAY_CTR] || (!wiphy_ext_feature_isset(&rdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) && diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 1f2f528b7f23328caa95f3193901542491cb3fcd..ae30702c1f152e451ae18e22235f48b17bf0b577 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -196,9 +196,7 @@ cc-ldoption = $(call try-run,\ # ld-option # Usage: LDFLAGS += $(call ld-option, -X) -ld-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -x c /dev/null -c -o "$$TMPO"; \ - $(LD) $(LDFLAGS) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) +ld-option = $(call try-run, $(LD) $(LDFLAGS) $(1) -v,$(1),$(2)) # ar-option # Usage: KBUILD_ARFLAGS := $(call ar-option,D) diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c index d58de1dc5360dacf90fce2c177e3fb6c3ed8c83e..510049a7bd1d353bd750d84a012b4fa50e94ccad 100644 --- a/scripts/kconfig/lxdialog/inputbox.c +++ b/scripts/kconfig/lxdialog/inputbox.c @@ -126,7 +126,8 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width case KEY_DOWN: break; case KEY_BACKSPACE: - case 127: + case 8: /* ^H */ + case 127: /* ^? */ if (pos) { wattrset(dialog, dlg.inputbox.atr); if (input_x == 0) { diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 0031147798153bdd06aa5c1f3d6f2015298b5b5d..e8e1944fa09b062195fbcc2720db31f6c3cee380 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -1048,7 +1048,7 @@ static int do_match(int key, struct match_state *state, int *ans) state->match_direction = FIND_NEXT_MATCH_UP; *ans = get_mext_match(state->pattern, state->match_direction); - } else if (key == KEY_BACKSPACE || key == 127) { + } else if (key == KEY_BACKSPACE || key == 8 || key == 127) { state->pattern[strlen(state->pattern)-1] = '\0'; adj_match_dir(&state->match_direction); } else diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index a64b1c31253e13b918fefe509e1cccf5b4ac248d..0b63357f1d33901f8c1d83a8b7bd8caaffaa3b89 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -439,7 +439,8 @@ int dialog_inputbox(WINDOW *main_window, case KEY_F(F_EXIT): case KEY_F(F_BACK): break; - case 127: + case 8: /* ^H */ + case 127: /* ^? */ case KEY_BACKSPACE: if (cursor_position > 0) { memmove(&result[cursor_position-1], diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 29d6699d5a06c1eddb52e9aa4175766297754e4c..55b4c0dc2b935e9327258b642b5b1ef4db1d3003 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -47,49 +47,9 @@ typedef struct { struct devtable { const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; - void *function; + int (*do_entry)(const char *filename, void *symval, char *alias); }; -#define ___cat(a,b) a ## b -#define __cat(a,b) ___cat(a,b) - -/* we need some special handling for this host tool running eventually on - * Darwin. The Mach-O section handling is a bit different than ELF section - * handling. The differnces in detail are: - * a) we have segments which have sections - * b) we need a API call to get the respective section symbols */ -#if defined(__MACH__) -#include - -#define INIT_SECTION(name) do { \ - unsigned long name ## _len; \ - char *__cat(pstart_,name) = getsectdata("__TEXT", \ - #name, &__cat(name,_len)); \ - char *__cat(pstop_,name) = __cat(pstart_,name) + \ - __cat(name, _len); \ - __cat(__start_,name) = (void *)__cat(pstart_,name); \ - __cat(__stop_,name) = (void *)__cat(pstop_,name); \ - } while (0) -#define SECTION(name) __attribute__((section("__TEXT, " #name))) - -struct devtable **__start___devtable, **__stop___devtable; -#else -#define INIT_SECTION(name) /* no-op for ELF */ -#define SECTION(name) __attribute__((section(#name))) - -/* We construct a table of pointers in an ELF section (pointers generally - * go unpadded by gcc). ld creates boundary syms for us. */ -extern struct devtable *__start___devtable[], *__stop___devtable[]; -#endif /* __MACH__ */ - -#if !defined(__used) -# if __GNUC__ == 3 && __GNUC_MINOR__ < 3 -# define __used __attribute__((__unused__)) -# else -# define __used __attribute__((__used__)) -# endif -#endif - /* Define a variable f that holds the value of field f of struct devid * based at address m. */ @@ -102,16 +62,6 @@ extern struct devtable *__start___devtable[], *__stop___devtable[]; #define DEF_FIELD_ADDR(m, devid, f) \ typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) -/* Add a table entry. We test function type matches while we're here. */ -#define ADD_TO_DEVTABLE(device_id, type, function) \ - static struct devtable __cat(devtable,__LINE__) = { \ - device_id + 0*sizeof((function)((const char *)NULL, \ - (void *)NULL, \ - (char *)NULL)), \ - SIZE_##type, (function) }; \ - static struct devtable *SECTION(__devtable) __used \ - __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) - #define ADD(str, sep, cond, field) \ do { \ strcat(str, sep); \ @@ -431,7 +381,6 @@ static int do_hid_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry); /* Looks like: ieee1394:venNmoNspNverN */ static int do_ieee1394_entry(const char *filename, @@ -456,7 +405,6 @@ static int do_ieee1394_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry); /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ static int do_pci_entry(const char *filename, @@ -500,7 +448,6 @@ static int do_pci_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry); /* looks like: "ccw:tNmNdtNdmN" */ static int do_ccw_entry(const char *filename, @@ -524,7 +471,6 @@ static int do_ccw_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry); /* looks like: "ap:tN" */ static int do_ap_entry(const char *filename, @@ -535,7 +481,6 @@ static int do_ap_entry(const char *filename, sprintf(alias, "ap:t%02X*", dev_type); return 1; } -ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry); /* looks like: "css:tN" */ static int do_css_entry(const char *filename, @@ -546,7 +491,6 @@ static int do_css_entry(const char *filename, sprintf(alias, "css:t%01X", type); return 1; } -ADD_TO_DEVTABLE("css", css_device_id, do_css_entry); /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, @@ -566,7 +510,6 @@ static int do_serio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); /* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or * "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if) @@ -604,7 +547,6 @@ static int do_acpi_entry(const char *filename, } return 1; } -ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); /* looks like: "pnp:dD" */ static void do_pnp_device_entry(void *symval, unsigned long size, @@ -725,7 +667,6 @@ static int do_pcmcia_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); static int do_vio_entry(const char *filename, void *symval, char *alias) @@ -745,7 +686,6 @@ static int do_vio_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -818,7 +758,6 @@ static int do_input_entry(const char *filename, void *symval, do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); return 1; } -ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); static int do_eisa_entry(const char *filename, void *symval, char *alias) @@ -830,7 +769,6 @@ static int do_eisa_entry(const char *filename, void *symval, strcat(alias, "*"); return 1; } -ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry); /* Looks like: parisc:tNhvNrevNsvN */ static int do_parisc_entry(const char *filename, void *symval, @@ -850,7 +788,6 @@ static int do_parisc_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry); /* Looks like: sdio:cNvNdN. */ static int do_sdio_entry(const char *filename, @@ -867,7 +804,6 @@ static int do_sdio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry); /* Looks like: ssb:vNidNrevN. */ static int do_ssb_entry(const char *filename, @@ -884,7 +820,6 @@ static int do_ssb_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); /* Looks like: bcma:mNidNrevNclN. */ static int do_bcma_entry(const char *filename, @@ -903,7 +838,6 @@ static int do_bcma_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry); /* Looks like: virtio:dNvN */ static int do_virtio_entry(const char *filename, void *symval, @@ -919,7 +853,6 @@ static int do_virtio_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); /* * Looks like: vmbus:guid @@ -942,7 +875,6 @@ static int do_vmbus_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); /* Looks like: i2c:S */ static int do_i2c_entry(const char *filename, void *symval, @@ -953,7 +885,6 @@ static int do_i2c_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry); /* Looks like: spi:S */ static int do_spi_entry(const char *filename, void *symval, @@ -964,7 +895,6 @@ static int do_spi_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry); static const struct dmifield { const char *prefix; @@ -1019,7 +949,6 @@ static int do_dmi_entry(const char *filename, void *symval, strcat(alias, ":"); return 1; } -ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry); static int do_platform_entry(const char *filename, void *symval, char *alias) @@ -1028,7 +957,6 @@ static int do_platform_entry(const char *filename, sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry); static int do_mdio_entry(const char *filename, void *symval, char *alias) @@ -1053,7 +981,6 @@ static int do_mdio_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry); /* Looks like: zorro:iN. */ static int do_zorro_entry(const char *filename, void *symval, @@ -1064,7 +991,6 @@ static int do_zorro_entry(const char *filename, void *symval, ADD(alias, "i", id != ZORRO_WILDCARD, id); return 1; } -ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry); /* looks like: "pnp:dD" */ static int do_isapnp_entry(const char *filename, @@ -1080,7 +1006,6 @@ static int do_isapnp_entry(const char *filename, (function >> 12) & 0x0f, (function >> 8) & 0x0f); return 1; } -ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); /* Looks like: "ipack:fNvNdN". */ static int do_ipack_entry(const char *filename, @@ -1096,7 +1021,6 @@ static int do_ipack_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); /* * Append a match expression for a single masked hex digit. @@ -1167,7 +1091,6 @@ static int do_amba_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); /* * looks like: "mipscdmm:tN" @@ -1183,7 +1106,6 @@ static int do_mips_cdmm_entry(const char *filename, sprintf(alias, "mipscdmm:t%02X*", type); return 1; } -ADD_TO_DEVTABLE("mipscdmm", mips_cdmm_device_id, do_mips_cdmm_entry); /* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* * All fields are numbers. It would be nicer to use strings for vendor @@ -1208,7 +1130,6 @@ static int do_x86cpu_entry(const char *filename, void *symval, sprintf(alias + strlen(alias), "%04X*", feature); return 1; } -ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); /* LOOKS like cpu:type:*:feature:*FEAT* */ static int do_cpu_entry(const char *filename, void *symval, char *alias) @@ -1218,7 +1139,6 @@ static int do_cpu_entry(const char *filename, void *symval, char *alias) sprintf(alias, "cpu:type:*:feature:*%04X*", feature); return 1; } -ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); /* Looks like: mei:S:uuid:N:* */ static int do_mei_entry(const char *filename, void *symval, @@ -1237,7 +1157,6 @@ static int do_mei_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); /* Looks like: rapidio:vNdNavNadN */ static int do_rio_entry(const char *filename, @@ -1257,7 +1176,6 @@ static int do_rio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); /* Looks like: ulpi:vNpN */ static int do_ulpi_entry(const char *filename, void *symval, @@ -1270,7 +1188,6 @@ static int do_ulpi_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("ulpi", ulpi_device_id, do_ulpi_entry); /* Looks like: hdaudio:vNrNaN */ static int do_hda_entry(const char *filename, void *symval, char *alias) @@ -1287,7 +1204,6 @@ static int do_hda_entry(const char *filename, void *symval, char *alias) add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry); /* Looks like: fsl-mc:vNdN */ static int do_fsl_mc_entry(const char *filename, void *symval, @@ -1299,7 +1215,6 @@ static int do_fsl_mc_entry(const char *filename, void *symval, sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); return 1; } -ADD_TO_DEVTABLE("fslmc", fsl_mc_device_id, do_fsl_mc_entry); /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) @@ -1313,12 +1228,11 @@ static bool sym_is(const char *name, unsigned namelen, const char *symbol) static void do_table(void *symval, unsigned long size, unsigned long id_size, const char *device_id, - void *function, + int (*do_entry)(const char *filename, void *symval, char *alias), struct module *mod) { unsigned int i; char alias[500]; - int (*do_entry)(const char *, void *entry, char *alias) = function; device_id_check(mod->name, device_id, size, id_size, symval); /* Leave last one: it's the terminator. */ @@ -1332,6 +1246,44 @@ static void do_table(void *symval, unsigned long size, } } +static const struct devtable devtable[] = { + {"hid", SIZE_hid_device_id, do_hid_entry}, + {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry}, + {"pci", SIZE_pci_device_id, do_pci_entry}, + {"ccw", SIZE_ccw_device_id, do_ccw_entry}, + {"ap", SIZE_ap_device_id, do_ap_entry}, + {"css", SIZE_css_device_id, do_css_entry}, + {"serio", SIZE_serio_device_id, do_serio_entry}, + {"acpi", SIZE_acpi_device_id, do_acpi_entry}, + {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry}, + {"vio", SIZE_vio_device_id, do_vio_entry}, + {"input", SIZE_input_device_id, do_input_entry}, + {"eisa", SIZE_eisa_device_id, do_eisa_entry}, + {"parisc", SIZE_parisc_device_id, do_parisc_entry}, + {"sdio", SIZE_sdio_device_id, do_sdio_entry}, + {"ssb", SIZE_ssb_device_id, do_ssb_entry}, + {"bcma", SIZE_bcma_device_id, do_bcma_entry}, + {"virtio", SIZE_virtio_device_id, do_virtio_entry}, + {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry}, + {"i2c", SIZE_i2c_device_id, do_i2c_entry}, + {"spi", SIZE_spi_device_id, do_spi_entry}, + {"dmi", SIZE_dmi_system_id, do_dmi_entry}, + {"platform", SIZE_platform_device_id, do_platform_entry}, + {"mdio", SIZE_mdio_device_id, do_mdio_entry}, + {"zorro", SIZE_zorro_device_id, do_zorro_entry}, + {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry}, + {"ipack", SIZE_ipack_device_id, do_ipack_entry}, + {"amba", SIZE_amba_id, do_amba_entry}, + {"mipscdmm", SIZE_mips_cdmm_device_id, do_mips_cdmm_entry}, + {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, + {"cpu", SIZE_cpu_feature, do_cpu_entry}, + {"mei", SIZE_mei_cl_device_id, do_mei_entry}, + {"rapidio", SIZE_rio_device_id, do_rio_entry}, + {"ulpi", SIZE_ulpi_device_id, do_ulpi_entry}, + {"hdaudio", SIZE_hda_device_id, do_hda_entry}, + {"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry}, +}; + /* Create MODULE_ALIAS() statements. * At this time, we cannot write the actual output C source yet, * so we write into the mod->dev_table_buf buffer. */ @@ -1386,13 +1338,14 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, else if (sym_is(name, namelen, "pnp_card")) do_pnp_card_entries(symval, sym->st_size, mod); else { - struct devtable **p; - INIT_SECTION(__devtable); + int i; + + for (i = 0; i < ARRAY_SIZE(devtable); i++) { + const struct devtable *p = &devtable[i]; - for (p = __start___devtable; p < __stop___devtable; p++) { - if (sym_is(name, namelen, (*p)->device_id)) { - do_table(symval, sym->st_size, (*p)->id_size, - (*p)->device_id, (*p)->function, mod); + if (sym_is(name, namelen, p->device_id)) { + do_table(symval, sym->st_size, p->id_size, + p->device_id, p->do_entry, mod); break; } } diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c index fa48fabcb33047b380b1a8a601917ffdde623766..3cc4893d98cc5f53af13c2c524e770fa3c3fd9de 100644 --- a/scripts/selinux/genheaders/genheaders.c +++ b/scripts/selinux/genheaders/genheaders.c @@ -9,7 +9,6 @@ #include #include #include -#include struct security_class_mapping { const char *name; diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index ffe8179f5d41b38e43c475037c5ad0ab49c3a00d..c29fa4a6228d6f59f9346721d4569cb15002b3c6 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c @@ -32,7 +32,6 @@ #include #include #include -#include static void usage(char *name) { diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 5ef7e524056326d045c657a91a8f7fb40f9daac1..ea014df894285e87fe2fc5d9f2f5b1dfdcc29603 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -569,7 +569,7 @@ static int propagate_exception(struct dev_cgroup *devcg_root, devcg->behavior == DEVCG_DEFAULT_ALLOW) { rc = dev_exception_add(devcg, ex); if (rc) - break; + return rc; } else { /* * in the other possible cases: diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3ae81130c70aebb3c1da8984e256807d090cee4d..af030ff4786c17bf3c19f1041075bc893e078340 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -472,16 +472,10 @@ static int may_context_mount_inode_relabel(u32 sid, return rc; } -static int selinux_is_sblabel_mnt(struct super_block *sb) +static int selinux_is_genfs_special_handling(struct super_block *sb) { - struct superblock_security_struct *sbsec = sb->s_security; - - return sbsec->behavior == SECURITY_FS_USE_XATTR || - sbsec->behavior == SECURITY_FS_USE_TRANS || - sbsec->behavior == SECURITY_FS_USE_TASK || - sbsec->behavior == SECURITY_FS_USE_NATIVE || - /* Special handling. Genfs but also in-core setxattr handler */ - !strcmp(sb->s_type->name, "sysfs") || + /* Special handling. Genfs but also in-core setxattr handler */ + return !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore") || !strcmp(sb->s_type->name, "debugfs") || !strcmp(sb->s_type->name, "tracefs") || @@ -491,6 +485,34 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) !strcmp(sb->s_type->name, "cgroup2"))); } +static int selinux_is_sblabel_mnt(struct super_block *sb) +{ + struct superblock_security_struct *sbsec = sb->s_security; + + /* + * IMPORTANT: Double-check logic in this function when adding a new + * SECURITY_FS_USE_* definition! + */ + BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7); + + switch (sbsec->behavior) { + case SECURITY_FS_USE_XATTR: + case SECURITY_FS_USE_TRANS: + case SECURITY_FS_USE_TASK: + case SECURITY_FS_USE_NATIVE: + return 1; + + case SECURITY_FS_USE_GENFS: + return selinux_is_genfs_special_handling(sb); + + /* Never allow relabeling on context mounts */ + case SECURITY_FS_USE_MNTPOINT: + case SECURITY_FS_USE_NONE: + default: + return 0; + } +} + static int sb_finish_set_opts(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index acdee7795297f3b8e5c8a53403ceea3a1124ee4e..5ae315ab060be09fac474ef71f18c33463391ba6 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include +#include #define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \ "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append", "map" diff --git a/sound/core/info.c b/sound/core/info.c index 3939661d8419f16079e2c9f81a1c7f5e21e29992..f895fa3303b72d1f710c8755d85f5359693bafc9 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -819,7 +819,12 @@ void snd_info_free_entry(struct snd_info_entry * entry) list_for_each_entry_safe(p, n, &entry->children, list) snd_info_free_entry(p); - list_del(&entry->list); + p = entry->parent; + if (p) { + mutex_lock(&p->access); + list_del(&entry->list); + mutex_unlock(&p->access); + } kfree(entry->name); if (entry->private_free) entry->private_free(entry); diff --git a/sound/core/init.c b/sound/core/init.c index bd8100ff8994beb90bec3ead879ec2754be46d0d..752b6f5857ad51b725c64bd0c42ad1a922d238c0 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -512,14 +512,7 @@ int snd_card_disconnect(struct snd_card *card) card->shutdown = 1; spin_unlock(&card->files_lock); - /* phase 1: disable fops (user space) operations for ALSA API */ - mutex_lock(&snd_card_mutex); - snd_cards[card->number] = NULL; - clear_bit(card->number, snd_cards_lock); - mutex_unlock(&snd_card_mutex); - - /* phase 2: replace file->f_op with special dummy operations */ - + /* replace file->f_op with special dummy operations */ spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { /* it's critical part, use endless loop */ @@ -535,7 +528,7 @@ int snd_card_disconnect(struct snd_card *card) } spin_unlock(&card->files_lock); - /* phase 3: notify all connected devices about disconnection */ + /* notify all connected devices about disconnection */ /* at this point, they cannot respond to any calls except release() */ #if IS_ENABLED(CONFIG_SND_MIXER_OSS) @@ -551,6 +544,13 @@ int snd_card_disconnect(struct snd_card *card) device_del(&card->card_dev); card->registered = false; } + + /* disable fops (user space) operations for ALSA API */ + mutex_lock(&snd_card_mutex); + snd_cards[card->number] = NULL; + clear_bit(card->number, snd_cards_lock); + mutex_unlock(&snd_card_mutex); + #ifdef CONFIG_PM wake_up(&card->power_sleep); #endif diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 350c33ec82b3f06a481a36d97e3a22e111e85e8c..3bcd7a2f039451863bb23f800224fb9ce6a74486 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1249,7 +1249,7 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client, /* fill the info fields */ if (client_info->name[0]) - strlcpy(client->name, client_info->name, sizeof(client->name)); + strscpy(client->name, client_info->name, sizeof(client->name)); client->filter = client_info->filter; client->event_lost = client_info->event_lost; @@ -1527,7 +1527,7 @@ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg) /* set queue name */ if (!info->name[0]) snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue); - strlcpy(q->name, info->name, sizeof(q->name)); + strscpy(q->name, info->name, sizeof(q->name)); snd_use_lock_free(&q->use_lock); return 0; @@ -1589,7 +1589,7 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client, queuefree(q); return -EPERM; } - strlcpy(q->name, info->name, sizeof(q->name)); + strscpy(q->name, info->name, sizeof(q->name)); queuefree(q); return 0; diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h index eaef435e0528da8c8112bf5ccfed99d7b634dc54..abf6c23a721c97f277af51d87beadc9b39a59737 100644 --- a/sound/drivers/opl3/opl3_voice.h +++ b/sound/drivers/opl3/opl3_voice.h @@ -41,7 +41,7 @@ void snd_opl3_timer_func(unsigned long data); /* Prototypes for opl3_drums.c */ void snd_opl3_load_drums(struct snd_opl3 *opl3); -void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int on_off, int vel, struct snd_midi_channel *chan); +void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int vel, int on_off, struct snd_midi_channel *chan); /* Prototypes for opl3_oss.c */ #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index d77dcba276b544b750c452b622981c6c7a0ff585..1eb8b61a185be87ae95212bcccd7417919b1befc 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -111,6 +111,10 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) /* block the 0x388 port to avoid PnP conflicts */ acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); + if (!acard->fm_res) { + err = -EBUSY; + goto _err; + } if (port[dev] != SNDRV_AUTO_PORT) { if ((err = snd_sbdsp_create(card, port[dev], irq[dev], diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index d68f99e076a879def2241365e0dd78b3aeaa5611..e1f0bcd45c3783efece93c10ad74e21ed2a57dc0 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1953,6 +1953,11 @@ static int snd_echo_create(struct snd_card *card, } chip->dsp_registers = (volatile u32 __iomem *) ioremap_nocache(chip->dsp_registers_phys, sz); + if (!chip->dsp_registers) { + dev_err(chip->card->dev, "ioremap failed\n"); + snd_echo_free(chip); + return -ENOMEM; + } if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9637d0bbdeb5f7ca6e3973e5b0faefd1746da440..f44d08fe20fc57fd1bf47808addc330e5c9b6762 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5294,6 +5294,8 @@ static void alc274_fixup_bind_dacs(struct hda_codec *codec, return; spec->gen.preferred_dacs = preferred_pairs; + spec->gen.auto_mute_via_amp = 1; + codec->power_save_node = 0; } static void alc_fixup_disable_mic_vref(struct hda_codec *codec, @@ -6743,6 +6745,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60140}, {0x14, 0x90170150}, {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x40000000}, + {0x14, 0x90170110}, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -6853,6 +6861,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC256_STANDARD_PINS), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, {0x14, 0x90170110}, {0x1b, 0x90a70130}, @@ -6979,6 +6991,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_STANDARD_PINS, {0x13, 0x90a60140}), + SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, ALC295_STANDARD_PINS, {0x17, 0x21014020}, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 06f92571eba4622a89ae808911fd0b510ec2eed2..16dd1f61a7212488aa9af02c5aee147b8dbe9774 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -84,6 +84,7 @@ struct aic3x_priv { struct list_head list; int master; int gpio_reset; + bool reset_inverted; int power; #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 @@ -1355,7 +1356,8 @@ static int aic3x_regulator_event(struct notifier_block *nb, * of the supplies was disabled */ if (gpio_is_valid(aic3x->gpio_reset)) - gpio_set_value(aic3x->gpio_reset, 0); + gpio_set_value(aic3x->gpio_reset, + aic3x->reset_inverted); regcache_mark_dirty(aic3x->regmap); } @@ -1377,7 +1379,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) if (gpio_is_valid(aic3x->gpio_reset)) { udelay(1); - gpio_set_value(aic3x->gpio_reset, 1); + gpio_set_value(aic3x->gpio_reset, + !aic3x->reset_inverted); } /* Sync reg_cache with the hardware */ @@ -1810,6 +1813,9 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, else aic3x->gpio_reset = -1; + aic3x->reset_inverted = + of_property_read_bool(np, "reset-inverted"); + if (of_property_read_u32_array(np, "ai3x-gpio-func", ai3x_setup->gpio_func, 2) >= 0) { aic3x->setup = ai3x_setup; @@ -1846,7 +1852,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); if (ret != 0) goto err; - gpio_direction_output(aic3x->gpio_reset, 0); + gpio_direction_output(aic3x->gpio_reset, + aic3x->reset_inverted); } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) @@ -1894,7 +1901,7 @@ static int aic3x_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); if (gpio_is_valid(aic3x->gpio_reset) && !aic3x_is_shared_reset(aic3x)) { - gpio_set_value(aic3x->gpio_reset, 0); + gpio_set_value(aic3x->gpio_reset, aic3x->reset_inverted); gpio_free(aic3x->gpio_reset); } return 0; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index a23d6a821ff3a900e4c795f19979aad633b017ae..6152ae24772b1726ddfa8294398d649bb7054641 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -58,6 +58,8 @@ struct fsl_esai { u32 fifo_depth; u32 slot_width; u32 slots; + u32 tx_mask; + u32 rx_mask; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -358,21 +360,13 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); - esai_priv->slot_width = slot_width; esai_priv->slots = slots; + esai_priv->tx_mask = tx_mask; + esai_priv->rx_mask = rx_mask; return 0; } @@ -593,6 +587,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); + u32 mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -605,15 +600,38 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, for (i = 0; tx && i < channels; i++) regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); + /* + * When set the TE/RE in the end of enablement flow, there + * will be channel swap issue for multi data line case. + * In order to workaround this issue, we switch the bit + * enablement sequence to below sequence + * 1) clear the xSMB & xSMA: which is done in probe and + * stop state. + * 2) set TE/RE + * 3) set xSMB + * 4) set xSMA: xSMA is the last one in this flow, which + * will trigger esai to start. + */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); + mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); + break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, 0); /* Disable and reset FIFO */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), @@ -903,6 +921,15 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } + esai_priv->tx_mask = 0xFFFFFFFF; + esai_priv->rx_mask = 0xFFFFFFFF; + + /* Clear the TSMA, TSMB, RSMA, RSMB */ + regmap_write(esai_priv->regmap, REG_ESAI_TSMA, 0); + regmap_write(esai_priv->regmap, REG_ESAI_TSMB, 0); + regmap_write(esai_priv->regmap, REG_ESAI_RSMA, 0); + regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0); + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component, &fsl_esai_dai, 1); if (ret) { diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 90d43961389977f470a5c870d8678cdbd60a1cfe..48b4286100d4ea26581d9c812bdb554a849511c5 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -873,7 +873,6 @@ static int stm32_sai_sub_dais_init(struct platform_device *pdev, if (!sai->cpu_dai_drv) return -ENOMEM; - sai->cpu_dai_drv->name = dev_name(&pdev->dev); if (STM_SAI_IS_PLAYBACK(sai)) { memcpy(sai->cpu_dai_drv, &stm32_sai_playback_dai, sizeof(stm32_sai_playback_dai)); @@ -883,6 +882,7 @@ static int stm32_sai_sub_dais_init(struct platform_device *pdev, sizeof(stm32_sai_capture_dai)); sai->cpu_dai_drv->capture.stream_name = sai->cpu_dai_drv->name; } + sai->cpu_dai_drv->name = dev_name(&pdev->dev); return 0; } diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 167aebf8276e5014d7bd61ebe7ebff0ea5ec922d..b223de3defc4f4a17059549bf34680acfb161643 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -344,12 +344,16 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, { struct usb_device *usbdev = line6->usbdev; int ret; - unsigned char len; + unsigned char *len; unsigned count; if (address > 0xffff || datalen > 0xff) return -EINVAL; + len = kmalloc(sizeof(*len), GFP_KERNEL); + if (!len) + return -ENOMEM; + /* query the serial number: */ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, @@ -358,7 +362,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, if (ret < 0) { dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); - return ret; + goto exit; } /* Wait for data length. We'll get 0xff until length arrives. */ @@ -368,28 +372,29 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0012, 0x0000, &len, 1, + 0x0012, 0x0000, len, 1, LINE6_TIMEOUT * HZ); if (ret < 0) { dev_err(line6->ifcdev, "receive length failed (error %d)\n", ret); - return ret; + goto exit; } - if (len != 0xff) + if (*len != 0xff) break; } - if (len == 0xff) { + ret = -EIO; + if (*len == 0xff) { dev_err(line6->ifcdev, "read failed after %d retries\n", count); - return -EIO; - } else if (len != datalen) { + goto exit; + } else if (*len != datalen) { /* should be equal or something went wrong */ dev_err(line6->ifcdev, "length mismatch (expected %d, got %d)\n", - (int)datalen, (int)len); - return -EIO; + (int)datalen, (int)*len); + goto exit; } /* receive the result: */ @@ -398,12 +403,12 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT * HZ); - if (ret < 0) { + if (ret < 0) dev_err(line6->ifcdev, "read failed (error %d)\n", ret); - return ret; - } - return 0; +exit: + kfree(len); + return ret; } EXPORT_SYMBOL_GPL(line6_read_data); @@ -415,12 +420,16 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, { struct usb_device *usbdev = line6->usbdev; int ret; - unsigned char status; + unsigned char *status; int count; if (address > 0xffff || datalen > 0xffff) return -EINVAL; + status = kmalloc(sizeof(*status), GFP_KERNEL); + if (!status) + return -ENOMEM; + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x0022, address, data, datalen, @@ -429,7 +438,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, if (ret < 0) { dev_err(line6->ifcdev, "write request failed (error %d)\n", ret); - return ret; + goto exit; } for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { @@ -440,28 +449,29 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x0012, 0x0000, - &status, 1, LINE6_TIMEOUT * HZ); + status, 1, LINE6_TIMEOUT * HZ); if (ret < 0) { dev_err(line6->ifcdev, "receiving status failed (error %d)\n", ret); - return ret; + goto exit; } - if (status != 0xff) + if (*status != 0xff) break; } - if (status == 0xff) { + if (*status == 0xff) { dev_err(line6->ifcdev, "write failed after %d retries\n", count); - return -EIO; - } else if (status != 0) { + ret = -EIO; + } else if (*status != 0) { dev_err(line6->ifcdev, "write failed (error %d)\n", ret); - return -EIO; + ret = -EIO; } - - return 0; +exit: + kfree(status); + return ret; } EXPORT_SYMBOL_GPL(line6_write_data); diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 451007c2774344be753e38fd6863b03eaa284955..ee6a68c6e1c1ba0e950942a2c482bd02b1759fb5 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -224,28 +224,32 @@ static void podhd_startup_start_workqueue(unsigned long data) static int podhd_dev_start(struct usb_line6_podhd *pod) { int ret; - u8 init_bytes[8]; + u8 *init_bytes; int i; struct usb_device *usbdev = pod->line6.usbdev; + init_bytes = kmalloc(8, GFP_KERNEL); + if (!init_bytes) + return -ENOMEM; + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x11, 0, NULL, 0, LINE6_TIMEOUT * HZ); if (ret < 0) { dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret); - return ret; + goto exit; } /* NOTE: looks like some kind of ping message */ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x11, 0x0, - &init_bytes, 3, LINE6_TIMEOUT * HZ); + init_bytes, 3, LINE6_TIMEOUT * HZ); if (ret < 0) { dev_err(pod->line6.ifcdev, "receive length failed (error %d)\n", ret); - return ret; + goto exit; } pod->firmware_version = @@ -254,7 +258,7 @@ static int podhd_dev_start(struct usb_line6_podhd *pod) for (i = 0; i <= 16; i++) { ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8); if (ret < 0) - return ret; + goto exit; } ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), @@ -262,10 +266,9 @@ static int podhd_dev_start(struct usb_line6_podhd *pod) USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT, 1, 0, NULL, 0, LINE6_TIMEOUT * HZ); - if (ret < 0) - return ret; - - return 0; +exit: + kfree(init_bytes); + return ret; } static void podhd_startup_workqueue(struct work_struct *work) diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index ba7975c0d03d90e31674dbfb2a333d37343f0d96..4bdedfa87487a880c14c5fffa71252b412107638 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -365,15 +365,20 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport) /* Setup Toneport device. */ -static void toneport_setup(struct usb_line6_toneport *toneport) +static int toneport_setup(struct usb_line6_toneport *toneport) { - int ticks; + int *ticks; struct usb_line6 *line6 = &toneport->line6; struct usb_device *usbdev = line6->usbdev; + ticks = kmalloc(sizeof(*ticks), GFP_KERNEL); + if (!ticks) + return -ENOMEM; + /* sync time on device with host: */ - ticks = (int)get_seconds(); - line6_write_data(line6, 0x80c6, &ticks, 4); + *ticks = (int)get_seconds(); + line6_write_data(line6, 0x80c6, ticks, 4); + kfree(ticks); /* enable device: */ toneport_send_cmd(usbdev, 0x0301, 0x0000); @@ -388,6 +393,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport) toneport_update_led(toneport); mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); + return 0; } /* @@ -451,7 +457,9 @@ static int toneport_init(struct usb_line6 *line6, return err; } - toneport_setup(toneport); + err = toneport_setup(toneport); + if (err) + return err; /* register audio system: */ return snd_card_register(line6->card); @@ -463,7 +471,11 @@ static int toneport_init(struct usb_line6 *line6, */ static int toneport_reset_resume(struct usb_interface *interface) { - toneport_setup(usb_get_intfdata(interface)); + int err; + + err = toneport_setup(usb_get_intfdata(interface)); + if (err) + return err; return line6_resume(interface); } #endif diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 7bb404eb7bce26cf7eca883b5646b340157de7df..307ebcf78b1577c2eaa8063785d5eeb7529c8fd4 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -1156,17 +1156,17 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, response: if (!req_msg->enable && ret != -EINVAL) { + mutex_lock(&chip->dev_lock); if (info_idx >= 0) { - mutex_lock(&chip->dev_lock); info = &uadev[pcm_card_num].info[info_idx]; uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info); uaudio_dbg("release resources: intf# %d card# %d\n", subs->interface, pcm_card_num); - mutex_unlock(&chip->dev_lock); } if (atomic_read(&uadev[pcm_card_num].in_use)) kref_put(&uadev[pcm_card_num].kref, uaudio_dev_release); + mutex_unlock(&chip->dev_lock); } resp.usb_token = req_msg->usb_token; diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h index acc704bd3998cf9bb592a240232addca209d7f34..0b0ef3abc966e98c806bf7148d1d3f66fa096102 100644 --- a/tools/include/linux/bitops.h +++ b/tools/include/linux/bitops.h @@ -3,8 +3,6 @@ #define _TOOLS_LINUX_BITOPS_H_ #include -#include - #ifndef __WORDSIZE #define __WORDSIZE (__SIZEOF_LONG__ * 8) #endif @@ -12,10 +10,9 @@ #ifndef BITS_PER_LONG # define BITS_PER_LONG __WORDSIZE #endif +#include +#include -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define BITS_PER_BYTE 8 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) diff --git a/tools/include/linux/bits.h b/tools/include/linux/bits.h new file mode 100644 index 0000000000000000000000000000000000000000..2b7b532c1d51d6352a524fd827f9fd776f690f78 --- /dev/null +++ b/tools/include/linux/bits.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_BITS_H +#define __LINUX_BITS_H +#include + +#define BIT(nr) (1UL << (nr)) +#define BIT_ULL(nr) (1ULL << (nr)) +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) +#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) +#define BITS_PER_BYTE 8 + +/* + * Create a contiguous bitmask starting at bit position @l and ending at + * position @h. For example + * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. + */ +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + +#define GENMASK_ULL(h, l) \ + (((~0ULL) - (1ULL << (l)) + 1) & \ + (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) + +#endif /* __LINUX_BITS_H */ diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 5b4fff3adc4be4ca66a30a9e8b85b55e1a472f4a..782a8966b7211270983a9972b9aa333eecb160d9 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -114,7 +114,7 @@ Given a $HOME/.perfconfig like this: [report] # Defaults - sort-order = comm,dso,symbol + sort_order = comm,dso,symbol percent-limit = 0 queue-size = 0 children = true diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3103a33c13a841f72e38c790adb7bf111f26b7d7..133eb79493211ed5fb318b397da921ac84b0c718 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1345,8 +1345,9 @@ int cmd_top(int argc, const char **argv) goto out_delete_evlist; symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); - if (symbol__init(NULL) < 0) - return -1; + status = symbol__init(NULL); + if (status < 0) + goto out_delete_evlist; sort__setup_elide(stdout); diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 50cd6228f50637def472cf75ce37ed9bba759a10..df1dbee8d98db028e0bcf6025a8c440f265f7a67 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -11,6 +11,7 @@ include/uapi/linux/sched.h include/uapi/linux/stat.h include/uapi/linux/vhost.h include/uapi/sound/asound.h +include/linux/bits.h include/linux/hash.h include/uapi/linux/hw_breakpoint.h arch/x86/include/asm/disabled-features.h diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index d0406116c9057dd237aba97b7cf3669576ab826f..926a8e1b5e9472b205e8fb9801fae906b4012502 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -85,5 +85,6 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) ret = -1; + perf_evsel__delete(evsel); return ret; } diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 01f0706995a9737c4bf7ff9012228f6bda8d11fa..9acc1e80b93673c018f81296314f6c4e7363ca70 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -19,7 +19,7 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) const char *p; const char **other; double val; - int ret; + int i, ret; struct parse_ctx ctx; int num_other; @@ -56,6 +56,9 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ")); TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO")); TEST_ASSERT_VAL("find other", other[3] == NULL); + + for (i = 0; i < num_other; i++) + free((void *)other[i]); free((void *)other); return 0; diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index c531e6deb104799d733f47fbee405b5dca4b861c..493ecb61154026b0ee777feef5043681aa784973 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -45,7 +45,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int if (IS_ERR(evsel)) { tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); pr_debug("%s\n", errbuf); - goto out_thread_map_delete; + goto out_cpu_map_delete; } if (perf_evsel__open(evsel, cpus, threads) < 0) { @@ -119,6 +119,8 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int perf_evsel__close_fd(evsel); out_evsel_delete: perf_evsel__delete(evsel); +out_cpu_map_delete: + cpu_map__put(cpus); out_thread_map_delete: thread_map__put(threads); return err; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 7f8553630c4d9f37d252aa480eed903d25112f80..69910deab6e053ab924b36bb6579104b81ae3939 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -185,6 +185,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) return bf; } +/* The caller is responsible to free the returned buffer. */ char *build_id_cache__origname(const char *sbuild_id) { char *linkname; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 4b893c622236294b7934db7b88c057c3a41788cd..a0c9ff27c7bf2770f1243a0f0728ee9f5a2c6ec6 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -628,11 +628,10 @@ static int collect_config(const char *var, const char *value, } ret = set_value(item, value); - return ret; out_free: free(key); - return -1; + return ret; } int perf_config_set__collect(struct perf_config_set *set, const char *file_name, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 44c2f62b47a31853b4309b3580087e02b7ded155..0cf6f537f980f867df099252b2d1e87d05e57cfd 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1229,6 +1229,7 @@ void perf_evsel__exit(struct perf_evsel *evsel) { assert(list_empty(&evsel->node)); assert(evsel->evlist == NULL); + perf_evsel__free_counts(evsel); perf_evsel__free_fd(evsel); perf_evsel__free_id(evsel); perf_evsel__free_config_terms(evsel); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 5d420209505eb03aa6ab17d189f4fcb6cf60e237..5b8bc1fd943d679c5da54df8269af5f038ebbe96 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1040,8 +1040,10 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, iter->evsel, al, max_stack_depth); - if (err) + if (err) { + map__put(alm); return err; + } err = iter->ops->prepare_entry(iter, al); if (err) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d0b92d374ba908964a9dfc9a10183ca10769078a..29e2bb304168c1cf35c86febe0c7161167e9ddbd 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2109,6 +2109,7 @@ static bool is_event_supported(u8 type, unsigned config) perf_evsel__delete(evsel); } + thread_map__put(tmap); return ret; } @@ -2179,6 +2180,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob, printf(" %-50s [%s]\n", buf, "SDT event"); free(buf); } + free(path); } else printf(" %-50s [%s]\n", nd->s, "SDT event"); if (nd2) { diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 7a1b20ec52164d155bbc5f06d0f15c2cb604e57b..d1b2348db0f98ccbf13b982e1b2a1b41aa5df2e3 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -4588,6 +4588,9 @@ int fork_it(char **argv) signal(SIGQUIT, SIG_IGN); if (waitpid(child_pid, &status, 0) == -1) err(status, "waitpid"); + + if (WIFEXITED(status)) + status = WEXITSTATUS(status); } /* * n.b. fork_it() does not check for errors from for_all_cpus() diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index a0591d06c61bfcd5929936af8269f7513bc5e7b5..913539aea645040e087602e6103031f4b90e7700 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1860,6 +1860,7 @@ static struct bpf_test tests[] = { }, .result = REJECT, .errstr = "invalid stack off=-79992 size=8", + .errstr_unpriv = "R1 stack pointer arithmetic goes out of range", }, { "PTR_TO_STACK store/load - out of bounds high", @@ -2243,6 +2244,8 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "R1 stack pointer arithmetic goes out of range", }, { "unpriv: cmp of stack pointer", @@ -7013,6 +7016,7 @@ static struct bpf_test tests[] = { }, .fixup_map1 = { 3 }, .errstr = "pointer offset 1073741822", + .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range", .result = REJECT }, { @@ -7034,6 +7038,7 @@ static struct bpf_test tests[] = { }, .fixup_map1 = { 3 }, .errstr = "pointer offset -1073741822", + .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range", .result = REJECT }, { @@ -7203,6 +7208,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN() }, .errstr = "fp pointer offset 1073741822", + .errstr_unpriv = "R1 stack pointer arithmetic goes out of range", .result = REJECT }, { diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index ed8c9d360c0f8e80cf65b564728db0bec52af168..4225d462701d08bb4b09c3f63fd6309641541cc2 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -150,7 +150,7 @@ static int get_nports(struct udev_device *hc_device) static int vhci_hcd_filter(const struct dirent *dirent) { - return strcmp(dirent->d_name, "vhci_hcd") >= 0; + return !strncmp(dirent->d_name, "vhci_hcd.", 9); } static int get_ncontrollers(void) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index d72b8481f2500ca470a8e3eb935589ff29dc4926..dc06f5e40041b0de981690634e6764af14f21384 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -704,8 +704,9 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; u64 indirect_ptr, type = GITS_BASER_TYPE(baser); int esz = GITS_BASER_ENTRY_SIZE(baser); - int index; + int index, idx; gfn_t gfn; + bool ret; switch (type) { case GITS_BASER_TYPE_DEVICE: @@ -732,7 +733,8 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, if (eaddr) *eaddr = addr; - return kvm_is_visible_gfn(its->dev->kvm, gfn); + + goto out; } /* calculate and check the index into the 1st level */ @@ -766,7 +768,12 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, if (eaddr) *eaddr = indirect_ptr; - return kvm_is_visible_gfn(its->dev->kvm, gfn); + +out: + idx = srcu_read_lock(&its->dev->kvm->srcu); + ret = kvm_is_visible_gfn(its->dev->kvm, gfn); + srcu_read_unlock(&its->dev->kvm->srcu, idx); + return ret; } static int vgic_its_alloc_collection(struct vgic_its *its,