summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/guest_shm.txt19
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi50
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi538
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts611
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi75
-rw-r--r--arch/arm64/Kconfig9
-rw-r--r--arch/arm64/configs/msm-auto-gvm-perf_defconfig286
-rw-r--r--arch/arm64/configs/msm-auto-gvm_defconfig316
-rw-r--r--arch/arm64/mm/dma-mapping.c24
-rw-r--r--drivers/clk/msm/clock-dummy.c7
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c2
-rw-r--r--drivers/iommu/arm-smmu.c2
-rw-r--r--drivers/iommu/dma-iommu.c10
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c112
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c4
-rw-r--r--drivers/soc/qcom/Kconfig2
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/hab/Kconfig7
-rw-r--r--drivers/soc/qcom/hab/Makefile14
-rw-r--r--drivers/soc/qcom/hab/hab.c726
-rw-r--r--drivers/soc/qcom/hab/hab.h415
-rw-r--r--drivers/soc/qcom/hab/hab_grantable.h29
-rw-r--r--drivers/soc/qcom/hab/hab_mem_linux.c451
-rw-r--r--drivers/soc/qcom/hab/hab_mimex.c394
-rw-r--r--drivers/soc/qcom/hab/hab_msg.c208
-rw-r--r--drivers/soc/qcom/hab/hab_open.c154
-rw-r--r--drivers/soc/qcom/hab/hab_pchan.c86
-rw-r--r--drivers/soc/qcom/hab/hab_pipe.c131
-rw-r--r--drivers/soc/qcom/hab/hab_pipe.h60
-rw-r--r--drivers/soc/qcom/hab/hab_qvm.c251
-rw-r--r--drivers/soc/qcom/hab/hab_qvm.h47
-rw-r--r--drivers/soc/qcom/hab/hab_vchan.c184
-rw-r--r--drivers/soc/qcom/hab/khab.c140
-rw-r--r--drivers/soc/qcom/hab/qvm_comm.c95
-rw-r--r--drivers/soc/qcom/scm_qcpe.c35
-rw-r--r--include/linux/dma-iommu.h1
-rw-r--r--include/linux/habmm.h38
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/habmm.h143
-rw-r--r--include/uapi/linux/msm_ipa.h56
-rw-r--r--sound/soc/msm/Kconfig4
43 files changed, 5696 insertions, 47 deletions
diff --git a/Documentation/devicetree/bindings/soc/qcom/guest_shm.txt b/Documentation/devicetree/bindings/soc/qcom/guest_shm.txt
new file mode 100644
index 000000000000..9491344c7b9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/guest_shm.txt
@@ -0,0 +1,19 @@
+QVM Guest Shared Memory
+
+guest_shm is a device that enables linux as a guest operating system
+to allocate shared memory between virtual machines and send notifications
+of updates to other virtual machines.
+
+Required properties:
+- compatible: Must be "qvm,guest_shm".
+- interrupt-parent: Parent interrupt controller.
+- interrupts: Should contain QVM interrupt.
+- reg: Physical address of the guest factory and length.
+
+Example:
+ qvm,guest_shm {
+ compatible = "qvm,guest_shm";
+ interrupt-parent = <&gic>;
+ interrupts = <6 4>;
+ reg = <0x1c050000 0x1000>;
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index e3bed3a961a3..bfaca0cf9adf 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -188,6 +188,7 @@ qcom Qualcomm Technologies, Inc
qemu QEMU, a generic and open source machine emulator and virtualizer
qi Qi Hardware
qnap QNAP Systems, Inc.
+qvm BlackBerry Ltd
radxa Radxa
raidsonic RaidSonic Technology GmbH
ralink Mediatek/Ralink Technology Corp.
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi
new file mode 100644
index 000000000000..fddffee703d1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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,msm-dai-mi2s {
+ dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active
+ &sec_mi2s_sd1_active>;
+ pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep
+ &sec_mi2s_sd1_sleep>;
+ };
+
+ dai_mi2s: qcom,msm-dai-q6-mi2s-tert {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_mi2s_active &tert_mi2s_sd0_active>;
+ pinctrl-1 = <&tert_mi2s_sleep &tert_mi2s_sd0_sleep>;
+ };
+
+ dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>;
+ pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_sd0_sleep>;
+ };
+ };
+
+ qcom,msm-dai-tdm-tert-rx {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_tdm_dout_active>;
+ pinctrl-1 = <&tert_tdm_dout_sleep>;
+ };
+
+ qcom,msm-dai-tdm-quat-rx {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_tdm_dout_active>;
+ pinctrl-1 = <&quat_tdm_dout_sleep>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi
new file mode 100644
index 000000000000..ce7741f75b24
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi
@@ -0,0 +1,538 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 {
+ tlmm: pinctrl@01010000 {
+ compatible = "qcom,msm8996-pinctrl";
+ reg = <0x01010000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ blsp1_uart2_active: blsp1_uart2_active {
+ mux {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_sleep: blsp1_uart2_sleep {
+ mux {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ usb_hub_reset_active: usb_hub_reset_active {
+ usb_hub_reset_active {
+ pins = "gpio103";
+ drive-strength = <8>; /* 8 mA */
+ bias-pull-up; /* pull up */
+ output-high;
+ };
+ };
+
+ usb_hub_reset_suspend: usb_hub_reset_suspend {
+ usb_hub_reset_suspend {
+ pins = "gpio103";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable= <0>; /* no pull */
+ };
+ };
+
+ i2c_6 {
+ i2c_6_active: i2c_6_active {
+ mux {
+ pins = "gpio27", "gpio28";
+ function = "blsp_i2c6";
+ };
+
+ config {
+ pins = "gpio27", "gpio28";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_6_sleep: i2c_6_sleep {
+ mux {
+ pins = "gpio27", "gpio28";
+ function = "blsp_i2c6";
+ };
+
+ config {
+ pins = "gpio27", "gpio28";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ i2c_8 {
+ i2c_8_active: i2c_8_active {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c8";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <4>;
+ bias-disable;
+ };
+ };
+
+ i2c_8_sleep: i2c_8_sleep {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c8";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <4>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ spi_9 {
+ spi_9_active: spi_9_active {
+ mux {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ function = "blsp_spi9";
+ };
+
+ config {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_9_sleep: spi_9_sleep {
+ mux {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ function = "blsp_spi9";
+ };
+
+ config {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ cnss_pins {
+ cnss_bootstrap_active: cnss_bootstrap_active {
+ mux {
+ pins = "gpio46";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio46";
+ drive-strength = <16>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+ cnss_bootstrap_sleep: cnss_bootstrap_sleep {
+ mux {
+ pins = "gpio46";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio46";
+ drive-strength = <2>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+ };
+
+ sec_mi2s {
+ sec_mi2s_sleep: sec_mi2s_sleep {
+ mux {
+ pins = "gpio80", "gpio81";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio80", "gpio81";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ sec_mi2s_active: sec_mi2s_active {
+ mux {
+ pins = "gpio80", "gpio81";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio80", "gpio81";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ sec_mi2s_sd0 {
+ sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio82";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio82";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ sec_mi2s_sd0_active: sec_mi2s_sd0_active {
+ mux {
+ pins = "gpio82";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio82";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ sec_mi2s_sd1 {
+ sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep {
+ mux {
+ pins = "gpio83";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio83";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ sec_mi2s_sd1_active: sec_mi2s_sd1_active {
+ mux {
+ pins = "gpio83";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio83";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ tert_mi2s {
+ tert_mi2s_sleep: tert_mi2s_sleep {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_mi2s_active: tert_mi2s_active {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ tert_mi2s_sd0 {
+ tert_mi2s_sd0_sleep: tert_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_mi2s_sd0_active: tert_mi2s_sd0_active {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_mi2s {
+ quat_mi2s_sleep: quat_mi2s_sleep {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_mi2s_active: quat_mi2s_active {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ quat_mi2s_sd0 {
+ quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_mi2s_sd0_active: quat_mi2s_sd0_active {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ tert_tdm {
+ tert_tdm_sleep: tert_tdm_sleep {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_tdm_active: tert_tdm_active {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ tert_tdm_din {
+ tert_tdm_din_sleep: tert_tdm_din_sleep {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_tdm_din_active: tert_tdm_din_active {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ tert_tdm_dout {
+ tert_tdm_dout_sleep: tert_tdm_dout_sleep {
+ mux {
+ pins = "gpio78";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio78";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_tdm_dout_active: tert_tdm_dout_active {
+ mux {
+ pins = "gpio78";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio78";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm {
+ quat_tdm_sleep: quat_tdm_sleep {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_tdm_active: quat_tdm_active {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ quat_tdm_din {
+ quat_tdm_din_sleep: quat_tdm_din_sleep {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_tdm_din_active: quat_tdm_din_active {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm_dout {
+ quat_tdm_dout_sleep: quat_tdm_dout_sleep {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_tdm_dout_active: quat_tdm_dout_active {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
index 5c0bbbccafea..e6d9f7b7d2f2 100644
--- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
@@ -13,12 +13,20 @@
/dts-v1/;
#include "skeleton64.dtsi"
+#include <dt-bindings/clock/msm-clocks-8996.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
model = "Qualcomm Technologies, Inc. MSM 8996";
compatible = "qcom,msm8996";
qcom,msm-id = <246 0x0>;
+ aliases {
+ spi9 = &spi_9;
+ i2c6 = &i2c_6;
+ i2c8 = &i2c_8;
+ };
+
soc: soc { };
psci {
@@ -53,14 +61,33 @@
reg = <0 0xc8000000 0 0x00400000>;
label = "ion_audio_mem";
};
+ modem_mem: modem_region@88800000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x88800000 0 0x6200000>;
+ };
+ peripheral_mem: peripheral_region@8ea00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x8ea00000 0 0x2b00000>;
+ };
+ adsp_mem: adsp_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x100000>;
+ size = <0 0x400000>;
+ };
};
};
#include "vplatform-lfv-ion.dtsi"
+#include "vplatform-lfv-smmu.dtsi"
&soc {
#address-cells = <1>;
#size-cells = <1>;
+ virtual-interrupt-parent = "gic";
ranges = <0 0 0 0xffffffff>;
compatible = "simple-bus";
@@ -125,11 +152,17 @@
asoc-codec = <&stub_codec>;
asoc-codec-names = "msm-stub-codec.1";
};
+ qcom,msm-adsp-loader {
+ status = "ok";
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
qcom,msm-audio-ion {
compatible = "qcom,msm-audio-ion";
+ qcom,smmu-version = <2>;
qcom,smmu-enabled;
- qcom,smmu-sid = <1>;
+ iommus = <&lpass_q6_smmu 1>;
};
pcm0: qcom,msm-pcm {
@@ -587,4 +620,580 @@
hostless: qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
};
+
+ qcom,msm-adsprpc-mem {
+ compatible = "qcom,msm-adsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
+ qcom,msm_fastrpc {
+ compatible = "qcom,msm-fastrpc-adsp";
+
+ qcom,msm_fastrpc_compute_cb1 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 8>;
+ };
+ qcom,msm_fastrpc_compute_cb2 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 9>;
+ };
+ qcom,msm_fastrpc_compute_cb3 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 10>;
+ };
+ qcom,msm_fastrpc_compute_cb4 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 11>;
+ };
+ qcom,msm_fastrpc_compute_cb5 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 12>;
+ };
+ qcom,msm_fastrpc_compute_cb6 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 5>;
+ };
+ qcom,msm_fastrpc_compute_cb7 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 6>;
+ };
+ qcom,msm_fastrpc_compute_cb8 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 7>;
+ };
+ };
+};
+
+#include "vplatform-lfv-msm8996-pinctrl.dtsi"
+#include "msm8996-smp2p.dtsi"
+
+&soc {
+ qcom,ipc-spinlock@740000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x740000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@86000000 {
+ compatible = "qcom,smem";
+ reg = <0x86000000 0x200000>,
+ <0x9820010 0x4>,
+ <0x7b4000 0x8>;
+ reg-names = "smem", "irq-reg-base",
+ "smem_targ_info_reg";
+ qcom,mpu-enabled;
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ interrupts = <0 449 1>;
+ label = "modem";
+ qcom,not-loadable;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0x1>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x100>;
+ interrupts = <0x0 0x9c 0x1>;
+ label = "adsp";
+ };
+ };
+
+ qcom,rmtfs_sharedmem@0 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x85e00000 0x00200000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
+ qcom,glink-smem-native-xprt-modem@86000000 {
+ compatible = "qcom,glink-smem-native-xprt";
+ reg = <0x86000000 0x200000>,
+ <0x9820010 0x4>;
+ reg-names = "smem", "irq-reg-base";
+ qcom,irq-mask = <0x8000>;
+ interrupts = <0 452 1>;
+ label = "mpss";
+ };
+
+ qcom,glink-smem-native-xprt-adsp@86000000 {
+ compatible = "qcom,glink-smem-native-xprt";
+ reg = <0x86000000 0x200000>,
+ <0x9820010 0x4>;
+ reg-names = "smem", "irq-reg-base";
+ qcom,irq-mask = <0x200>;
+ interrupts = <0 157 1>;
+ label = "lpass";
+ qcom,qos-config = <0x1b8>;
+ qcom,ramp-time = <0xaf>;
+ };
+
+ qcom,glink-qos-config-adsp {
+ compatible = "qcom,glink-qos-config";
+ qcom,flow-info = <0x3c 0x0 0x3c 0x0 0x3c 0x0 0x3c 0x0>;
+ qcom,mtu-size = <0x800>;
+ qcom,tput-stats-cycle = <0xa>;
+ linux,phandle = <0x1b8>;
+ phandle = <0x1b8>;
+ };
+
+ /* IPC router */
+ qcom,ipc_router {
+ compatible = "qcom,ipc_router";
+ qcom,node-id = <1>;
+ };
+
+ qcom,ipc_router_modem_xprt {
+ compatible = "qcom,ipc_router_glink_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "mpss";
+ qcom,glink-xprt = "smd_trans";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ qcom,ipc_router_q6_xprt {
+ compatible = "qcom,ipc_router_glink_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "lpass";
+ qcom,glink-xprt = "smd_trans";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ /* IPA including NDP-BAM */
+ ipa_hw: qcom,ipa@680000 {
+ compatible = "qcom,ipa";
+ reg = <0x680000 0x4effc>,
+ <0x684000 0x26934>;
+ reg-names = "ipa-base", "bam-base";
+ interrupts = <0 333 0>,
+ <0 432 0>;
+ interrupt-names = "ipa-irq", "bam-irq";
+ qcom,ipa-hw-ver = <5>; /* IPA core version = IPAv2.5 */
+ qcom,ipa-hw-mode = <0>;
+ qcom,ee = <0>;
+ qcom,use-ipa-tethering-bridge;
+ qcom,ipa-bam-remote-mode;
+ qcom,modem-cfg-emb-pipe-flt;
+ clocks = <&clock_gcc clk_ipa_clk>;
+ clock-names = "core_clk";
+ qcom,use-dma-zone;
+ qcom,msm-bus,name = "ipa";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <90 512 0 0>, <90 585 0 0>, /* No vote */
+ <90 512 80000 640000>, <90 585 80000 640000>, /* SVS */
+ <90 512 206000 960000>, <90 585 206000 960000>; /* PERF */
+ qcom,bus-vector-names = "MIN", "SVS", "PERF";
+ };
+
+ /* rmnet over IPA */
+ qcom,rmnet-ipa {
+ compatible = "qcom,rmnet-ipa";
+ qcom,rmnet-ipa-ssr;
+ qcom,ipa-loaduC;
+ qcom,ipa-advertise-sg-support;
+ };
+
+ /* SPS */
+ qcom,sps {
+ compatible = "qcom,msm_sps_4k";
+ qcom,device-type = <3>;
+ qcom,pipe-attr-ee;
+ };
+
+ clock_gcc: qcom,gcc@300000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_mmss: qcom,mmsscc@8c0000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_gpu: qcom,gpucc@8c0000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_debug: qcom,cc-debug@362000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_cpu: qcom,cpu-clock-8996@ {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pil_modem: qcom,mss@2080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x2080000 0x100>,
+ <0x0763000 0x008>,
+ <0x0765000 0x008>,
+ <0x0764000 0x008>,
+ <0x2180000 0x020>,
+ <0x038f008 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem",
+ "halt_nc", "rmb_base", "restart_reg";
+
+ clocks = <&clock_gcc clk_cxo_clk_src>,
+ <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+ <&clock_gcc clk_pnoc_clk>,
+ <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+ <&clock_gcc clk_gcc_boot_rom_ahb_clk>,
+ <&clock_gcc clk_gpll0_out_msscc>,
+ <&clock_gcc clk_gcc_mss_snoc_axi_clk>,
+ <&clock_gcc clk_gcc_mss_mnoc_bimc_axi_clk>,
+ <&clock_gcc clk_qdss_clk>;
+ clock-names = "xo", "iface_clk", "pnoc_clk", "bus_clk",
+ "mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk", "qdss_clk";
+ qcom,proxy-clock-names = "xo", "pnoc_clk", "qdss_clk";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk";
+
+ interrupts = <0 448 1>;
+ vdd_cx-supply = <&pm8994_s1_corner>;
+ vdd_cx-voltage = <7>;
+ vdd_mx-supply = <&pm8994_s2_corner>;
+ vdd_mx-uV = <6>;
+ vdd_pll-supply = <&pm8994_l12>;
+ qcom,vdd_pll = <1800000>;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,override-acc;
+ qcom,ahb-clk-vote;
+ qcom,pnoc-clk-vote;
+ qcom,qdsp6v56-1-5;
+ qcom,mx-spike-wa;
+ memory-region = <&modem_mem>;
+ qcom,mem-protect-id = <0xF>;
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+ qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ status = "ok";
+ };
+
+ pm8994_s1_corner: regulator-s1-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s1_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ pm8994_s1_floor_corner: regulator-s1-floor-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s1_floor_corner";
+ };
+
+ pm8994_s1_corner_ao: regulator-s1-corner-ao {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s1_corner_ao";
+ };
+
+ pm8994_s2_corner: regulator-s2-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s2_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ pm8994_s2_corner_ao: regulator-s2-corner-ao {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s2_corner_ao";
+ };
+
+ pm8994_l12: regulator-l12 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l12";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8994_l30: regulator-l30 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l30";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+
+ pm8994_l18_pin_ctrl: regulator-l18-pin-ctrl {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l18_pin_ctrl";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2700000>;
+ };
+
+ pm8994_l26_corner: regulator-l26-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l26_corner";
+ };
+
+ pm8994_l26_floor_corner: regulator-l26-floor-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l26_floor_corner";
+ };
+
+ pmi8994_boost_pin_ctrl: regulator-bst-pin-ctrl {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pmi8994_boost_pin_ctrl";
+ };
+
+ pm8994_s11: spm-regulator@3200 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s11";
+ };
+
+ pmi8994_s2: regulator@1700 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pmi8994_s2";
+ };
+
+ pm8994_s3: regulator-s3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s3";
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ };
+
+ pm8994_s4: regulator-s4 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s4";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+
+ pm8004_s2: regulator@1700 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8004_s2";
+ };
+
+ spi_eth_vreg: spi_eth_phy_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "ethernet_phy";
+ };
+
+ usb_otg_switch: usb-otg-switch {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "usb_otg_vreg";
+ };
+
+ rome_vreg: rome_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "rome_vreg";
+ };
+
+ wlan_en_vreg: wlan_en_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "wlan_en_vreg";
+ };
+
+ hl7509_en_vreg: hl7509_en_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "hl7509_en_vreg";
+ };
+
+ gdsc_mmagic_camss: qcom,gdsc@8c3c4c {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "gdsc_mmagic_camss";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ gdsc_hlos1_vote_lpass_adsp: qcom,gdsc@37d034 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "gdsc_hlos1_vote_lpass_adsp";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ spi_9: spi@75B7000 { /* BLSP2 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical";
+ reg = <0x075B7000 0x600>;
+ interrupt-names = "spi_irq";
+ interrupts = <0 103 0>;
+ spi-max-frequency = <19200000>;
+ qcom,infinite-mode = <0>;
+ qcom,ver-reg-exists;
+ qcom,master-id = <84>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_9_active>;
+ pinctrl-1 = <&spi_9_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup3_spi_apps_clk>;
+ };
+
+ i2c_6: i2c@757a000 { /* BLSP1 QUP6 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x757a000 0x1000>;
+ reg-names = "qup_phys_addr";
+ interrupt-names = "qup_irq";
+ interrupts = <0 100 0>;
+ qcom,disable-dma;
+ qcom,master-id = <86>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup6_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_6_active>;
+ pinctrl-1 = <&i2c_6_sleep>;
+ };
+
+ i2c_8: i2c@75b6000 { /* BLSP2 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x75b6000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 102 0>;
+ qcom,disable-dma;
+ qcom,master-id = <84>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup2_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_8_active>;
+ pinctrl-1 = <&i2c_8_sleep>;
+ };
+
+ blsp1_uart2: uart@07570000 { /* BLSP1 UART2 */
+ compatible = "qcom,msm-hsuart-v14";
+ reg = <0x07570000 0x1000>,
+ <0x7544000 0x2b000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ interrupts = <0 108 0>, <0 238 0>, <0 810 0>;
+ #address-cells = <0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <2>;
+ qcom,bam-rx-ep-pipe-index = <3>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart2_sleep>;
+ pinctrl-1 = <&blsp1_uart2_active>;
+
+ qcom,msm-bus,name = "buart2";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ };
+
+ qcom,lpass@9300000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x9300000 0x00100>;
+ interrupts = <0 162 1>;
+
+ vdd_cx-supply = <&pm8994_s1_corner>;
+ qcom,proxy-reg-names = "vdd_cx";
+ qcom,vdd_cx-uV-uA = <7 100000>;
+
+ clocks = <&clock_gcc clk_cxo_pil_lpass_clk>;
+ clock-names = "xo";
+ qcom,proxy-clock-names = "xo";
+
+ 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";
+ qcom,edge = "lpass";
+ memory-region = <&peripheral_mem>;
+
+ /* GPIO inputs from lpass */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>;
+
+ /* GPIO output to lpass */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+ };
+
+ qcom,cnss {
+ compatible = "qcom,cnss";
+ wlan-bootstrap-gpio = <&tlmm 46 0>;
+ vdd-wlan-en-supply = <&wlan_en_vreg>;
+ vdd-wlan-supply = <&rome_vreg>;
+ vdd-wlan-io-supply = <&pm8994_s4>;
+ vdd-wlan-xtal-supply = <&pm8994_l30>;
+ vdd-wlan-core-supply = <&pm8994_s3>;
+ wlan-ant-switch-supply = <&pm8994_l18_pin_ctrl>;
+ qcom,wlan-en-vreg-support;
+ qcom,notify-modem-status;
+ pinctrl-names = "bootstrap_active", "bootstrap_sleep";
+ pinctrl-0 = <&cnss_bootstrap_active>;
+ pinctrl-1 = <&cnss_bootstrap_sleep>;
+
+ qcom,msm-bus,name = "msm-cnss";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <45 512 0 0>,
+ /* Up to 200 Mbps */
+ <45 512 41421 1520000>,
+ /* Up to 400 Mbps */
+ <45 512 96650 1520000>,
+ /* Up to 800 Mbps */
+ <45 512 207108 14432000>;
+ };
};
+#include "vplatform-lfv-agave.dtsi"
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi
new file mode 100644
index 000000000000..65eaa0c5aef9
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi
@@ -0,0 +1,75 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "msm-arm-smmu.dtsi"
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&lpass_q6_smmu {
+ status = "ok";
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_hlos1_vote_lpass_adsp>;
+ clocks = <&clock_gcc clk_hlos1_vote_lpass_adsp_smmu_clk>;
+ clock-names = "lpass_q6_smmu_clocks";
+ #clock-cells = <1>;
+};
+
+&cpp_fd_smmu {
+ status = "ok";
+ qcom,register-save;
+ qcom,skip-init;
+ qcom,fatal-asf;
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_mmagic_camss>;
+ clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+ <&clock_mmss clk_mmss_mmagic_cfg_ahb_clk>,
+ <&clock_mmss clk_smmu_cpp_ahb_clk>,
+ <&clock_mmss clk_smmu_cpp_axi_clk>,
+ <&clock_mmss clk_mmagic_camss_axi_clk>;
+ clock-names = "mmagic_ahb_clk", "mmagic_cfg_ahb_clk",
+ "cpp_ahb_clk", "cpp_axi_clk",
+ "mmagic_camss_axi_clk";
+ #clock-cells = <1>;
+ qcom,bus-master-id = <MSM_BUS_MASTER_CPP>;
+};
+
+&soc {
+ iommu_test_device {
+ compatible = "iommu-debug-test";
+ /*
+ * 42 shouldn't be used by anyone on the cpp_fd_smmu. We just
+ * need _something_ here to get this node recognized by the
+ * SMMU driver. Our test uses ATOS, which doesn't use SIDs
+ * anyways, so using a dummy value is ok.
+ */
+ iommus = <&cpp_fd_smmu 42>;
+ };
+};
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 0c369a5d59f9..a4aaba570d44 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -247,6 +247,15 @@ config PGTABLE_LEVELS
default 3 if ARM64_16K_PAGES && ARM64_VA_BITS_47
default 4 if !ARM64_64K_PAGES && ARM64_VA_BITS_48
+config MSM_GVM_QUIN
+ bool "Enable virtualization Support for MSM kernel required for QUIN platform"
+ help
+ This enables support for MSM Kernel based virtual
+ machine for QUIN platform.
+ This helps to enable virtual driver support.
+ This should work on 64bit machine.
+ If you don't know what to do here, say N.
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/arm64/configs/msm-auto-gvm-perf_defconfig b/arch/arm64/configs/msm-auto-gvm-perf_defconfig
new file mode 100644
index 000000000000..2e551218af2d
--- /dev/null
+++ b/arch/arm64/configs/msm-auto-gvm-perf_defconfig
@@ -0,0 +1,286 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_NAMESPACES=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_REGULAR=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_PCI=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+CONFIG_COMPAT=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_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_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_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=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_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_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=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_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_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=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_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_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_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_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_CAN=y
+CONFIG_CAN_RH850=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SRAM=y
+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_DUMMY=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_PINCTRL_MSM8996=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_DRM=y
+# CONFIG_DRM_MSM is not set
+CONFIG_SOUND=y
+CONFIG_SND=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_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_SW_SYNC_USER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_COMMON_CLK_MSM=y
+CONFIG_MSM_CLK_CONTROLLER_V2=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+CONFIG_IPC_LOGGING=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/msm-auto-gvm_defconfig b/arch/arm64/configs/msm-auto-gvm_defconfig
new file mode 100644
index 000000000000..a6d36c314a4a
--- /dev/null
+++ b/arch/arm64/configs/msm-auto-gvm_defconfig
@@ -0,0 +1,316 @@
+CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_NAMESPACES=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_REGULAR=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_PCI=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+CONFIG_COMPAT=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_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_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_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=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_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_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=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_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_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=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_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_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_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_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_CAN=y
+CONFIG_CAN_RH850=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SRAM=y
+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_DUMMY=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=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_PINCTRL_MSM8996=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_DRM=y
+# CONFIG_DRM_MSM is not set
+CONFIG_SOUND=y
+CONFIG_SND=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_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_SW_SYNC_USER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_COMMON_CLK_MSM=y
+CONFIG_MSM_CLK_CONTROLLER_V2=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=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_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_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_ARM64_PTDUMP=y
+CONFIG_FREE_PAGES_RDONLY=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index a41178f8eeea..159c79612e63 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2012 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -49,17 +50,6 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
return prot;
}
-static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
- bool coherent)
-{
- if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
- prot |= IOMMU_NOEXEC;
- if (coherent)
- prot |= IOMMU_CACHE;
-
- return prot;
-}
-
static bool is_dma_coherent(struct device *dev, struct dma_attrs *attrs)
{
bool is_coherent;
@@ -930,7 +920,6 @@ static struct dma_map_ops iommu_dma_ops = {
.sync_single_for_device = __iommu_sync_single_for_device,
.sync_sg_for_cpu = __iommu_sync_sg_for_cpu,
.sync_sg_for_device = __iommu_sync_sg_for_device,
- .dma_supported = iommu_dma_supported,
.mapping_error = iommu_dma_mapping_error,
};
@@ -1145,6 +1134,17 @@ EXPORT_SYMBOL(arch_setup_dma_ops);
#ifdef CONFIG_ARM64_DMA_USE_IOMMU
+static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
+ bool coherent)
+{
+ if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
+ prot |= IOMMU_NOEXEC;
+ if (coherent)
+ prot |= IOMMU_CACHE;
+
+ return prot;
+}
+
/*
* Make an area consistent for devices.
* Note: Drivers should NOT use this function directly, as it will break
diff --git a/drivers/clk/msm/clock-dummy.c b/drivers/clk/msm/clock-dummy.c
index e5339b110cd6..caa6a6ab7565 100644
--- a/drivers/clk/msm/clock-dummy.c
+++ b/drivers/clk/msm/clock-dummy.c
@@ -64,12 +64,18 @@ struct clk dummy_clk = {
static void *dummy_clk_dt_parser(struct device *dev, struct device_node *np)
{
struct clk *c;
+ u32 rate;
+
c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
if (!c) {
dev_err(dev, "failed to map memory for %s\n", np->name);
return ERR_PTR(-ENOMEM);
}
c->ops = &clk_ops_dummy;
+
+ if (!of_property_read_u32(np, "clock-frequency", &rate))
+ c->rate = rate;
+
return msmclk_generic_clk_init(dev, np, c);
}
MSMCLK_PARSER(dummy_clk_dt_parser, "qcom,dummy-clk", 0);
@@ -82,6 +88,7 @@ static struct clk *of_dummy_get(struct of_phandle_args *clkspec,
static struct of_device_id msm_clock_dummy_match_table[] = {
{ .compatible = "qcom,dummycc" },
+ { .compatible = "fixed-clock" },
{}
};
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 34a32d79f22c..8d821e43afa5 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -69,7 +69,7 @@
*
* This is disabled by default.
*/
-static bool sdecustom = true;
+static bool sdecustom;
module_param(sdecustom, bool, 0400);
MODULE_PARM_DESC(sdecustom, "Enable customizations for sde clients");
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index ce18a512b76a..b30739de79e7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1728,7 +1728,7 @@ static void arm_smmu_pgtbl_unlock(struct arm_smmu_domain *smmu_domain,
static int arm_smmu_restore_sec_cfg(struct arm_smmu_device *smmu)
{
int ret;
- u64 scm_ret;
+ u64 scm_ret = 0;
if (!arm_smmu_is_static_cb(smmu))
return 0;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 347a3c17f73a..041c42fb511f 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -514,16 +514,6 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
__iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg));
}
-int iommu_dma_supported(struct device *dev, u64 mask)
-{
- /*
- * 'Special' IOMMUs which don't have the same addressing capability
- * as the CPU will have to wait until we have some way to query that
- * before they'll be able to use this framework.
- */
- return 1;
-}
-
int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
return dma_addr == DMA_ERROR_CODE;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index cb95f6e98956..4275e3d26157 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -83,6 +83,10 @@ const char *ipa_event_name[] = {
__stringify(IPA_QUOTA_REACH),
__stringify(IPA_SSR_BEFORE_SHUTDOWN),
__stringify(IPA_SSR_AFTER_POWERUP),
+ __stringify(ADD_VLAN_IFACE),
+ __stringify(DEL_VLAN_IFACE),
+ __stringify(ADD_L2TP_VLAN_MAPPING),
+ __stringify(DEL_L2TP_VLAN_MAPPING)
};
const char *ipa_hdr_l2_type_name[] = {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 2615db4e9755..425596483057 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -611,6 +611,90 @@ static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type)
return 0;
}
+static void ipa3_vlan_l2tp_msg_free_cb(void *buff, u32 len, u32 type)
+{
+ if (!buff) {
+ IPAERR("Null buffer\n");
+ return;
+ }
+
+ if (type != ADD_VLAN_IFACE &&
+ type != DEL_VLAN_IFACE &&
+ type != ADD_L2TP_VLAN_MAPPING &&
+ type != DEL_L2TP_VLAN_MAPPING) {
+ IPAERR("Wrong type given. buff %pK type %d\n", buff, type);
+ return;
+ }
+
+ kfree(buff);
+}
+
+static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type)
+{
+ int retval;
+ struct ipa_ioc_vlan_iface_info *vlan_info;
+ struct ipa_ioc_l2tp_vlan_mapping_info *mapping_info;
+ struct ipa_msg_meta msg_meta;
+
+ if (msg_type == ADD_VLAN_IFACE ||
+ msg_type == DEL_VLAN_IFACE) {
+ vlan_info = kzalloc(sizeof(struct ipa_ioc_vlan_iface_info),
+ GFP_KERNEL);
+ if (!vlan_info) {
+ IPAERR("no memory\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user((u8 *)vlan_info, (void __user *)usr_param,
+ sizeof(struct ipa_ioc_vlan_iface_info))) {
+ kfree(vlan_info);
+ return -EFAULT;
+ }
+
+ memset(&msg_meta, 0, sizeof(msg_meta));
+ msg_meta.msg_type = msg_type;
+ msg_meta.msg_len = sizeof(struct ipa_ioc_vlan_iface_info);
+ retval = ipa3_send_msg(&msg_meta, vlan_info,
+ ipa3_vlan_l2tp_msg_free_cb);
+ if (retval) {
+ IPAERR("ipa3_send_msg failed: %d\n", retval);
+ kfree(vlan_info);
+ return retval;
+ }
+ } else if (msg_type == ADD_L2TP_VLAN_MAPPING ||
+ msg_type == DEL_L2TP_VLAN_MAPPING) {
+ mapping_info = kzalloc(sizeof(struct
+ ipa_ioc_l2tp_vlan_mapping_info), GFP_KERNEL);
+ if (!mapping_info) {
+ IPAERR("no memory\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user((u8 *)mapping_info,
+ (void __user *)usr_param,
+ sizeof(struct ipa_ioc_l2tp_vlan_mapping_info))) {
+ kfree(mapping_info);
+ return -EFAULT;
+ }
+
+ memset(&msg_meta, 0, sizeof(msg_meta));
+ msg_meta.msg_type = msg_type;
+ msg_meta.msg_len = sizeof(struct
+ ipa_ioc_l2tp_vlan_mapping_info);
+ retval = ipa3_send_msg(&msg_meta, mapping_info,
+ ipa3_vlan_l2tp_msg_free_cb);
+ if (retval) {
+ IPAERR("ipa3_send_msg failed: %d\n", retval);
+ kfree(mapping_info);
+ return retval;
+ }
+ } else {
+ IPAERR("Unexpected event\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -1582,6 +1666,34 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
+ case IPA_IOC_ADD_VLAN_IFACE:
+ if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case IPA_IOC_DEL_VLAN_IFACE:
+ if (ipa3_send_vlan_l2tp_msg(arg, DEL_VLAN_IFACE)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case IPA_IOC_ADD_L2TP_VLAN_MAPPING:
+ if (ipa3_send_vlan_l2tp_msg(arg, ADD_L2TP_VLAN_MAPPING)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case IPA_IOC_DEL_L2TP_VLAN_MAPPING:
+ if (ipa3_send_vlan_l2tp_msg(arg, DEL_L2TP_VLAN_MAPPING)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
default: /* redundant, as cmd was checked against MAXNR */
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -ENOTTY;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index fbf84ab7d2d4..c7ab616cb5b8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -64,6 +64,10 @@ const char *ipa3_event_name[] = {
__stringify(IPA_QUOTA_REACH),
__stringify(IPA_SSR_BEFORE_SHUTDOWN),
__stringify(IPA_SSR_AFTER_POWERUP),
+ __stringify(ADD_VLAN_IFACE),
+ __stringify(DEL_VLAN_IFACE),
+ __stringify(ADD_L2TP_VLAN_MAPPING),
+ __stringify(DEL_L2TP_VLAN_MAPPING)
};
const char *ipa3_hdr_l2_type_name[] = {
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 907960cfa9d5..829876226689 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -1,6 +1,8 @@
#
# QCOM Soc drivers
#
+source "drivers/soc/qcom/hab/Kconfig"
+
config MSM_INRUSH_CURRENT_MITIGATION
bool "Inrush-current mitigation Driver"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0bf54bedd6ea..229b13a04819 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -107,3 +107,4 @@ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o
obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o
obj-$(CONFIG_MSM_CACHE_M4M_ERP64) += cache_m4m_erp64.o
+obj-$(CONFIG_MSM_HAB) += hab/
diff --git a/drivers/soc/qcom/hab/Kconfig b/drivers/soc/qcom/hab/Kconfig
new file mode 100644
index 000000000000..2e4f5114e29f
--- /dev/null
+++ b/drivers/soc/qcom/hab/Kconfig
@@ -0,0 +1,7 @@
+config MSM_HAB
+ bool "Enable Multimedia driver Hypervisor Abstraction Layer"
+ help
+ Multimedia driver hypervisor abstraction layer.
+ Required for drivers to use the HAB API to communicate with the host
+ OS.
+
diff --git a/drivers/soc/qcom/hab/Makefile b/drivers/soc/qcom/hab/Makefile
new file mode 100644
index 000000000000..83fc54d42202
--- /dev/null
+++ b/drivers/soc/qcom/hab/Makefile
@@ -0,0 +1,14 @@
+msm_hab-objs = \
+ khab.o \
+ hab.o \
+ hab_msg.o \
+ hab_vchan.o \
+ hab_pchan.o \
+ hab_open.o \
+ hab_mimex.o \
+ hab_mem_linux.o \
+ hab_pipe.o \
+ qvm_comm.o \
+ hab_qvm.o
+
+obj-$(CONFIG_MSM_HAB) += msm_hab.o
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c
new file mode 100644
index 000000000000..c6df36f5c0a2
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab.c
@@ -0,0 +1,726 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+
+#define HAB_DEVICE_CNSTR(__name__, __id__, __num__) { \
+ .name = __name__,\
+ .id = __id__,\
+ .pchannels = LIST_HEAD_INIT(hab_devices[__num__].pchannels),\
+ .pchan_lock = __MUTEX_INITIALIZER(hab_devices[__num__].pchan_lock),\
+ .openq_list = LIST_HEAD_INIT(hab_devices[__num__].openq_list),\
+ .openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\
+ }
+
+/* the following has to match habmm definitions, order does not matter */
+static struct hab_device hab_devices[] = {
+ HAB_DEVICE_CNSTR(DEVICE_AUD1_NAME, MM_AUD_1, 0),
+ HAB_DEVICE_CNSTR(DEVICE_AUD2_NAME, MM_AUD_2, 1),
+ HAB_DEVICE_CNSTR(DEVICE_AUD3_NAME, MM_AUD_3, 2),
+ HAB_DEVICE_CNSTR(DEVICE_AUD4_NAME, MM_AUD_4, 3),
+ HAB_DEVICE_CNSTR(DEVICE_CAM_NAME, MM_CAM, 4),
+ HAB_DEVICE_CNSTR(DEVICE_DISP1_NAME, MM_DISP_1, 5),
+ HAB_DEVICE_CNSTR(DEVICE_DISP2_NAME, MM_DISP_2, 6),
+ HAB_DEVICE_CNSTR(DEVICE_DISP3_NAME, MM_DISP_3, 7),
+ HAB_DEVICE_CNSTR(DEVICE_DISP4_NAME, MM_DISP_4, 8),
+ HAB_DEVICE_CNSTR(DEVICE_DISP5_NAME, MM_DISP_5, 9),
+ HAB_DEVICE_CNSTR(DEVICE_GFX_NAME, MM_GFX, 10),
+ HAB_DEVICE_CNSTR(DEVICE_VID_NAME, MM_VID, 11),
+ HAB_DEVICE_CNSTR(DEVICE_MISC_NAME, MM_MISC, 12),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE1_NAME, MM_QCPE_VM1, 13),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE2_NAME, MM_QCPE_VM2, 14),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE3_NAME, MM_QCPE_VM3, 15),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE4_NAME, MM_QCPE_VM4, 16)
+};
+
+struct hab_driver hab_driver = {
+ .ndevices = ARRAY_SIZE(hab_devices),
+ .devp = hab_devices,
+};
+
+struct uhab_context *hab_ctx_alloc(int kernel)
+{
+ struct uhab_context *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->closing = 0;
+ INIT_LIST_HEAD(&ctx->vchannels);
+ INIT_LIST_HEAD(&ctx->exp_whse);
+ INIT_LIST_HEAD(&ctx->imp_whse);
+
+ INIT_LIST_HEAD(&ctx->exp_rxq);
+ init_waitqueue_head(&ctx->exp_wq);
+ spin_lock_init(&ctx->expq_lock);
+
+ spin_lock_init(&ctx->imp_lock);
+ rwlock_init(&ctx->exp_lock);
+ rwlock_init(&ctx->ctx_lock);
+
+ kref_init(&ctx->refcount);
+ ctx->import_ctx = habmem_imp_hyp_open();
+ if (!ctx->import_ctx) {
+ kfree(ctx);
+ return NULL;
+ }
+ ctx->kernel = kernel;
+
+ return ctx;
+}
+
+void hab_ctx_free(struct kref *ref)
+{
+ struct uhab_context *ctx =
+ container_of(ref, struct uhab_context, refcount);
+ struct hab_export_ack_recvd *ack_recvd, *tmp;
+
+ habmem_imp_hyp_close(ctx->import_ctx, ctx->kernel);
+
+ list_for_each_entry_safe(ack_recvd, tmp, &ctx->exp_rxq, node) {
+ list_del(&ack_recvd->node);
+ kfree(ack_recvd);
+ }
+
+ kfree(ctx);
+}
+
+struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
+ struct uhab_context *ctx)
+{
+ struct virtual_channel *vchan;
+
+ read_lock(&ctx->ctx_lock);
+ list_for_each_entry(vchan, &ctx->vchannels, node) {
+ if (vcid == vchan->id) {
+ kref_get(&vchan->refcount);
+ read_unlock(&ctx->ctx_lock);
+ return vchan;
+ }
+ }
+ read_unlock(&ctx->ctx_lock);
+ return NULL;
+}
+
+static struct hab_device *find_hab_device(unsigned int mm_id)
+{
+ int i;
+
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ if (hab_driver.devp[i].id == HAB_MMID_GET_MAJOR(mm_id))
+ return &hab_driver.devp[i];
+ }
+
+ pr_err("find_hab_device failed: id=%d\n", mm_id);
+ return NULL;
+}
+/*
+ * open handshake in FE and BE
+
+ * frontend backend
+ * send(INIT) wait(INIT)
+ * wait(INIT_ACK) send(INIT_ACK)
+ * send(ACK) wait(ACK)
+
+ */
+struct virtual_channel *frontend_open(struct uhab_context *ctx,
+ unsigned int mm_id,
+ int dom_id)
+{
+ int ret, open_id = 0;
+ struct physical_channel *pchan = NULL;
+ struct hab_device *dev;
+ struct virtual_channel *vchan = NULL;
+ static atomic_t open_id_counter = ATOMIC_INIT(0);
+ struct hab_open_request request;
+ struct hab_open_request *recv_request;
+ int sub_id = HAB_MMID_GET_MINOR(mm_id);
+
+ dev = find_hab_device(mm_id);
+ if (dev == NULL) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pchan = hab_pchan_find_domid(dev, dom_id);
+ if (!pchan) {
+ pr_err("hab_pchan_find_domid failed: dom_id=%d\n", dom_id);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ vchan = hab_vchan_alloc(ctx, pchan);
+ if (!vchan) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Send Init sequence */
+ open_id = atomic_inc_return(&open_id_counter);
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT, pchan,
+ vchan->id, sub_id, open_id);
+ ret = hab_open_request_send(&request);
+ if (ret) {
+ pr_err("hab_open_request_send failed: %d\n", ret);
+ goto err;
+ }
+
+ /* Wait for Init-Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_ACK, pchan,
+ 0, sub_id, open_id);
+ ret = hab_open_listen(ctx, dev, &request, &recv_request, 0);
+ if (ret || !recv_request) {
+ pr_err("hab_open_listen failed: %d\n", ret);
+ goto err;
+ }
+
+ vchan->otherend_id = recv_request->vchan_id;
+ hab_open_request_free(recv_request);
+
+ /* Send Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_ACK, pchan,
+ 0, sub_id, open_id);
+ ret = hab_open_request_send(&request);
+ if (ret)
+ goto err;
+
+ hab_pchan_put(pchan);
+
+ return vchan;
+err:
+ if (vchan)
+ hab_vchan_put(vchan);
+ if (pchan)
+ hab_pchan_put(pchan);
+
+ return ERR_PTR(ret);
+}
+
+struct virtual_channel *backend_listen(struct uhab_context *ctx,
+ unsigned int mm_id)
+{
+ int ret;
+ int open_id;
+ int sub_id = HAB_MMID_GET_MINOR(mm_id);
+ struct physical_channel *pchan = NULL;
+ struct hab_device *dev;
+ struct virtual_channel *vchan = NULL;
+ struct hab_open_request request;
+ struct hab_open_request *recv_request;
+ uint32_t otherend_vchan_id;
+
+ dev = find_hab_device(mm_id);
+ if (dev == NULL) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ while (1) {
+ /* Wait for Init sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT,
+ NULL, 0, sub_id, 0);
+ ret = hab_open_listen(ctx, dev, &request, &recv_request, 0);
+ if (ret || !recv_request) {
+ pr_err("hab_open_listen failed: %d\n", ret);
+ goto err;
+ }
+
+ otherend_vchan_id = recv_request->vchan_id;
+ open_id = recv_request->open_id;
+ pchan = recv_request->pchan;
+ hab_pchan_get(pchan);
+ hab_open_request_free(recv_request);
+
+ vchan = hab_vchan_alloc(ctx, pchan);
+ if (!vchan) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ vchan->otherend_id = otherend_vchan_id;
+
+ /* Send Init-Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_ACK,
+ pchan, vchan->id, sub_id, open_id);
+ ret = hab_open_request_send(&request);
+ if (ret)
+ goto err;
+
+ /* Wait for Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_ACK,
+ pchan, 0, sub_id, open_id);
+ ret = hab_open_listen(ctx, dev, &request, &recv_request, HZ);
+
+ if (ret != -EAGAIN)
+ break;
+
+ hab_vchan_put(vchan);
+ vchan = NULL;
+ hab_pchan_put(pchan);
+ pchan = NULL;
+ }
+
+ if (ret || !recv_request) {
+ pr_err("backend_listen failed: %d\n", ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ hab_open_request_free(recv_request);
+ hab_pchan_put(pchan);
+ return vchan;
+err:
+ if (vchan)
+ hab_vchan_put(vchan);
+ if (pchan)
+ hab_pchan_put(pchan);
+ return ERR_PTR(ret);
+}
+
+long hab_vchan_send(struct uhab_context *ctx,
+ int vcid,
+ size_t sizebytes,
+ void *data,
+ unsigned int flags)
+{
+ struct virtual_channel *vchan;
+ int ret;
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+ int nonblocking_flag = flags & HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING;
+
+ if (sizebytes > HAB_MAX_MSG_SIZEBYTES) {
+ pr_err("Message too large, %lu bytes\n", sizebytes);
+ return -EINVAL;
+ }
+
+ vchan = hab_get_vchan_fromvcid(vcid, ctx);
+ if (!vchan || vchan->otherend_closed)
+ return -ENODEV;
+
+ HAB_HEADER_SET_SIZE(header, sizebytes);
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_MSG);
+ HAB_HEADER_SET_ID(header, vchan->otherend_id);
+
+ while (1) {
+ ret = physical_channel_send(vchan->pchan, &header, data);
+
+ if (vchan->otherend_closed || nonblocking_flag ||
+ ret != -EAGAIN)
+ break;
+
+ schedule();
+ }
+
+ hab_vchan_put(vchan);
+ return ret;
+}
+
+struct hab_message *hab_vchan_recv(struct uhab_context *ctx,
+ int vcid,
+ unsigned int flags)
+{
+ struct virtual_channel *vchan;
+ struct hab_message *message;
+ int ret = 0;
+ int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING;
+
+ vchan = hab_get_vchan_fromvcid(vcid, ctx);
+ if (!vchan || vchan->otherend_closed)
+ return ERR_PTR(-ENODEV);
+
+ if (nonblocking_flag) {
+ /*
+ * Try to pull data from the ring in this context instead of
+ * IRQ handler. Any available messages will be copied and queued
+ * internally, then fetched by hab_msg_dequeue()
+ */
+ physical_channel_rx_dispatch((unsigned long) vchan->pchan);
+ }
+
+ message = hab_msg_dequeue(vchan, !nonblocking_flag);
+ if (!message) {
+ if (nonblocking_flag)
+ ret = -EAGAIN;
+ else
+ ret = -EPIPE;
+ }
+
+ hab_vchan_put(vchan);
+ return ret ? ERR_PTR(ret) : message;
+}
+
+bool hab_is_loopback(void)
+{
+ return hab_driver.b_loopback;
+}
+
+int hab_vchan_open(struct uhab_context *ctx,
+ unsigned int mmid,
+ int32_t *vcid,
+ uint32_t flags)
+{
+ struct virtual_channel *vchan;
+
+ if (!vcid)
+ return -EINVAL;
+
+ if (hab_is_loopback()) {
+ if (!hab_driver.loopback_num) {
+ hab_driver.loopback_num = 1;
+ vchan = backend_listen(ctx, mmid);
+ } else {
+ hab_driver.loopback_num = 0;
+ vchan = frontend_open(ctx, mmid, LOOPBACK_DOM);
+ }
+ } else {
+ if (hab_driver.b_server_dom)
+ vchan = backend_listen(ctx, mmid);
+ else
+ vchan = frontend_open(ctx, mmid, 0);
+ }
+
+ if (IS_ERR(vchan))
+ return PTR_ERR(vchan);
+
+ write_lock(&ctx->ctx_lock);
+ list_add_tail(&vchan->node, &ctx->vchannels);
+ write_unlock(&ctx->ctx_lock);
+
+ *vcid = vchan->id;
+
+ return 0;
+}
+
+void hab_send_close_msg(struct virtual_channel *vchan)
+{
+ struct hab_header header;
+
+ if (vchan && !vchan->otherend_closed) {
+ HAB_HEADER_SET_SIZE(header, 0);
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_CLOSE);
+ HAB_HEADER_SET_ID(header, vchan->otherend_id);
+ physical_channel_send(vchan->pchan, &header, NULL);
+ }
+}
+
+static void hab_vchan_close_impl(struct kref *ref)
+{
+ struct virtual_channel *vchan =
+ container_of(ref, struct virtual_channel, usagecnt);
+
+ list_del(&vchan->node);
+ hab_vchan_stop_notify(vchan);
+ hab_vchan_put(vchan);
+}
+
+
+void hab_vchan_close(struct uhab_context *ctx, int32_t vcid)
+{
+ struct virtual_channel *vchan, *tmp;
+
+ if (!ctx)
+ return;
+
+ write_lock(&ctx->ctx_lock);
+ list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
+ if (vchan->id == vcid) {
+ kref_put(&vchan->usagecnt, hab_vchan_close_impl);
+ break;
+ }
+ }
+
+ write_unlock(&ctx->ctx_lock);
+}
+
+static int hab_open(struct inode *inodep, struct file *filep)
+{
+ int result = 0;
+ struct uhab_context *ctx;
+
+ ctx = hab_ctx_alloc(0);
+
+ if (!ctx) {
+ pr_err("hab_ctx_alloc failed\n");
+ filep->private_data = NULL;
+ return -ENOMEM;
+ }
+
+ filep->private_data = ctx;
+
+ return result;
+}
+
+static int hab_release(struct inode *inodep, struct file *filep)
+{
+ struct uhab_context *ctx = filep->private_data;
+ struct virtual_channel *vchan, *tmp;
+
+ if (!ctx)
+ return 0;
+
+ write_lock(&ctx->ctx_lock);
+
+ list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
+ list_del(&vchan->node);
+ hab_vchan_stop_notify(vchan);
+ hab_vchan_put(vchan);
+ }
+
+ write_unlock(&ctx->ctx_lock);
+
+ hab_ctx_put(ctx);
+ filep->private_data = NULL;
+
+ return 0;
+}
+
+static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ struct uhab_context *ctx = (struct uhab_context *)filep->private_data;
+ struct hab_open *open_param;
+ struct hab_close *close_param;
+ struct hab_recv *recv_param;
+ struct hab_send *send_param;
+ struct hab_message *msg;
+ void *send_data;
+ unsigned char data[256] = { 0 };
+ long ret = 0;
+
+ if (_IOC_SIZE(cmd) && (cmd & IOC_IN)) {
+ if (_IOC_SIZE(cmd) > sizeof(data))
+ return -EINVAL;
+
+ if (copy_from_user(data, (void __user *)arg, _IOC_SIZE(cmd))) {
+ pr_err("copy_from_user failed cmd=%x size=%d\n",
+ cmd, _IOC_SIZE(cmd));
+ return -EFAULT;
+ }
+ }
+
+ switch (cmd) {
+ case IOCTL_HAB_VC_OPEN:
+ open_param = (struct hab_open *)data;
+ ret = hab_vchan_open(ctx, open_param->mmid,
+ &open_param->vcid, open_param->flags);
+ break;
+ case IOCTL_HAB_VC_CLOSE:
+ close_param = (struct hab_close *)data;
+ hab_vchan_close(ctx, close_param->vcid);
+ break;
+ case IOCTL_HAB_SEND:
+ send_param = (struct hab_send *)data;
+ if (send_param->sizebytes > HAB_MAX_MSG_SIZEBYTES) {
+ ret = -EINVAL;
+ break;
+ }
+
+ send_data = kzalloc(send_param->sizebytes, GFP_TEMPORARY);
+ if (!send_data) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(send_data, (void __user *)send_param->data,
+ send_param->sizebytes)) {
+ ret = -EFAULT;
+ } else {
+ ret = hab_vchan_send(ctx, send_param->vcid,
+ send_param->sizebytes,
+ send_data,
+ send_param->flags);
+ }
+ kfree(send_data);
+ break;
+ case IOCTL_HAB_RECV:
+ recv_param = (struct hab_recv *)data;
+ if (!recv_param->data) {
+ ret = -EINVAL;
+ break;
+ }
+
+ msg = hab_vchan_recv(ctx, recv_param->vcid, recv_param->flags);
+
+ if (IS_ERR(msg)) {
+ recv_param->sizebytes = 0;
+ ret = PTR_ERR(msg);
+ break;
+ }
+
+ if (recv_param->sizebytes < msg->sizebytes) {
+ recv_param->sizebytes = 0;
+ ret = -EINVAL;
+ } else if (copy_to_user((void __user *)recv_param->data,
+ msg->data,
+ msg->sizebytes)) {
+ pr_err("copy_to_user failed: vc=%x size=%d\n",
+ recv_param->vcid, (int)msg->sizebytes);
+ recv_param->sizebytes = 0;
+ ret = -EFAULT;
+ } else {
+ recv_param->sizebytes = msg->sizebytes;
+ }
+
+ hab_msg_free(msg);
+ break;
+ case IOCTL_HAB_VC_EXPORT:
+ ret = hab_mem_export(ctx, (struct hab_export *)data, 0);
+ break;
+ case IOCTL_HAB_VC_IMPORT:
+ ret = hab_mem_import(ctx, (struct hab_import *)data, 0);
+ break;
+ case IOCTL_HAB_VC_UNEXPORT:
+ ret = hab_mem_unexport(ctx, (struct hab_unexport *)data, 0);
+ break;
+ case IOCTL_HAB_VC_UNIMPORT:
+ ret = hab_mem_unimport(ctx, (struct hab_unimport *)data, 0);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ if (ret == 0 && _IOC_SIZE(cmd) && (cmd & IOC_OUT))
+ if (copy_to_user((void __user *) arg, data, _IOC_SIZE(cmd))) {
+ pr_err("copy_to_user failed: cmd=%x\n", cmd);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static const struct file_operations hab_fops = {
+ .owner = THIS_MODULE,
+ .open = hab_open,
+ .release = hab_release,
+ .mmap = habmem_imp_hyp_mmap,
+ .unlocked_ioctl = hab_ioctl
+};
+
+/*
+ * These map sg functions are pass through because the memory backing the
+ * sg list is already accessible to the kernel as they come from a the
+ * dedicated shared vm pool
+ */
+
+static int hab_map_sg(struct device *dev, struct scatterlist *sgl,
+ int nelems, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ /* return nelems directly */
+ return nelems;
+}
+
+static void hab_unmap_sg(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ /*Do nothing */
+}
+
+static const struct dma_map_ops hab_dma_ops = {
+ .map_sg = hab_map_sg,
+ .unmap_sg = hab_unmap_sg,
+};
+
+static int __init hab_init(void)
+{
+ int result;
+ int i;
+ dev_t dev;
+ struct hab_device *device;
+
+ result = alloc_chrdev_region(&hab_driver.major, 0, 1, "hab");
+
+ if (result < 0) {
+ pr_err("alloc_chrdev_region failed: %d\n", result);
+ return result;
+ }
+
+ cdev_init(&hab_driver.cdev, &hab_fops);
+ hab_driver.cdev.owner = THIS_MODULE;
+ hab_driver.cdev.ops = &hab_fops;
+ dev = MKDEV(MAJOR(hab_driver.major), 0);
+
+ result = cdev_add(&hab_driver.cdev, dev, 1);
+
+ if (result < 0) {
+ unregister_chrdev_region(dev, 1);
+ pr_err("cdev_add failed: %d\n", result);
+ return result;
+ }
+
+ hab_driver.class = class_create(THIS_MODULE, "hab");
+
+ if (IS_ERR(hab_driver.class)) {
+ result = PTR_ERR(hab_driver.class);
+ pr_err("class_create failed: %d\n", result);
+ goto err;
+ }
+
+ hab_driver.dev = device_create(hab_driver.class, NULL,
+ dev, &hab_driver, "hab");
+
+ if (IS_ERR(hab_driver.dev)) {
+ result = PTR_ERR(hab_driver.dev);
+ pr_err("device_create failed: %d\n", result);
+ goto err;
+ }
+
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ device = &hab_driver.devp[i];
+ init_waitqueue_head(&device->openq);
+ }
+
+ hab_hypervisor_register();
+
+ hab_driver.kctx = hab_ctx_alloc(1);
+ if (!hab_driver.kctx) {
+ pr_err("hab_ctx_alloc failed");
+ result = -ENOMEM;
+ hab_hypervisor_unregister();
+ goto err;
+ }
+
+ set_dma_ops(hab_driver.dev, &hab_dma_ops);
+
+ return result;
+
+err:
+ if (!IS_ERR_OR_NULL(hab_driver.dev))
+ device_destroy(hab_driver.class, dev);
+ if (!IS_ERR_OR_NULL(hab_driver.class))
+ class_destroy(hab_driver.class);
+ cdev_del(&hab_driver.cdev);
+ unregister_chrdev_region(dev, 1);
+
+ return result;
+}
+
+static void __exit hab_exit(void)
+{
+ dev_t dev;
+
+ hab_hypervisor_unregister();
+ hab_ctx_put(hab_driver.kctx);
+ dev = MKDEV(MAJOR(hab_driver.major), 0);
+ device_destroy(hab_driver.class, dev);
+ class_destroy(hab_driver.class);
+ cdev_del(&hab_driver.cdev);
+ unregister_chrdev_region(dev, 1);
+}
+
+subsys_initcall(hab_init);
+module_exit(hab_exit);
+
+MODULE_DESCRIPTION("Hypervisor abstraction layer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h
new file mode 100644
index 000000000000..805e5b4a7008
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab.h
@@ -0,0 +1,415 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 __HAB_H
+#define __HAB_H
+
+#define pr_fmt(fmt) "hab: " fmt
+
+#include <linux/types.h>
+
+#include <linux/habmm.h>
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rbtree.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+
+enum hab_payload_type {
+ HAB_PAYLOAD_TYPE_MSG = 0x0,
+ HAB_PAYLOAD_TYPE_INIT,
+ HAB_PAYLOAD_TYPE_INIT_ACK,
+ HAB_PAYLOAD_TYPE_ACK,
+ HAB_PAYLOAD_TYPE_EXPORT,
+ HAB_PAYLOAD_TYPE_EXPORT_ACK,
+ HAB_PAYLOAD_TYPE_PROFILE,
+ HAB_PAYLOAD_TYPE_CLOSE,
+};
+#define LOOPBACK_DOM 0xFF
+
+/*
+ * Tuning required. If there are multiple clients, the aging of previous
+ * "request" might be discarded
+ */
+#define Q_AGE_THRESHOLD 1000000
+
+/* match the name to dtsi if for real HYP framework */
+#define DEVICE_AUD1_NAME "hab_aud1"
+#define DEVICE_AUD2_NAME "hab_aud2"
+#define DEVICE_AUD3_NAME "hab_aud3"
+#define DEVICE_AUD4_NAME "hab_aud4"
+#define DEVICE_CAM_NAME "hab_cam"
+#define DEVICE_DISP1_NAME "hab_disp1"
+#define DEVICE_DISP2_NAME "hab_disp2"
+#define DEVICE_DISP3_NAME "hab_disp3"
+#define DEVICE_DISP4_NAME "hab_disp4"
+#define DEVICE_DISP5_NAME "hab_disp5"
+#define DEVICE_GFX_NAME "hab_ogles"
+#define DEVICE_VID_NAME "hab_vid"
+#define DEVICE_MISC_NAME "hab_misc"
+#define DEVICE_QCPE1_NAME "hab_qcpe_vm1"
+#define DEVICE_QCPE2_NAME "hab_qcpe_vm2"
+#define DEVICE_QCPE3_NAME "hab_qcpe_vm3"
+#define DEVICE_QCPE4_NAME "hab_qcpe_vm4"
+
+/* "Size" of the HAB_HEADER_ID and HAB_VCID_ID must match */
+#define HAB_HEADER_SIZE_SHIFT 0
+#define HAB_HEADER_TYPE_SHIFT 16
+#define HAB_HEADER_ID_SHIFT 24
+#define HAB_HEADER_SIZE_MASK 0x0000FFFF
+#define HAB_HEADER_TYPE_MASK 0x00FF0000
+#define HAB_HEADER_ID_MASK 0xFF000000
+#define HAB_HEADER_INITIALIZER {0}
+
+#define HAB_MMID_GET_MAJOR(mmid) (mmid & 0xFFFF)
+#define HAB_MMID_GET_MINOR(mmid) ((mmid>>16) & 0xFF)
+
+#define HAB_VCID_ID_SHIFT 0
+#define HAB_VCID_DOMID_SHIFT 8
+#define HAB_VCID_MMID_SHIFT 16
+#define HAB_VCID_ID_MASK 0x000000FF
+#define HAB_VCID_DOMID_MASK 0x0000FF00
+#define HAB_VCID_MMID_MASK 0xFFFF0000
+#define HAB_VCID_GET_ID(vcid) \
+ (((vcid) & HAB_VCID_ID_MASK) >> HAB_VCID_ID_SHIFT)
+
+#define HAB_HEADER_SET_SIZE(header, size) \
+ ((header).info = (((header).info) & (~HAB_HEADER_SIZE_MASK)) | \
+ (((size) << HAB_HEADER_SIZE_SHIFT) & HAB_HEADER_SIZE_MASK))
+
+#define HAB_HEADER_SET_TYPE(header, type) \
+ ((header).info = (((header).info) & (~HAB_HEADER_TYPE_MASK)) | \
+ (((type) << HAB_HEADER_TYPE_SHIFT) & HAB_HEADER_TYPE_MASK))
+
+#define HAB_HEADER_SET_ID(header, id) \
+ ((header).info = (((header).info) & (~HAB_HEADER_ID_MASK)) | \
+ ((HAB_VCID_GET_ID(id) << HAB_HEADER_ID_SHIFT) \
+ & HAB_HEADER_ID_MASK))
+
+#define HAB_HEADER_GET_SIZE(header) \
+ ((((header).info) & HAB_HEADER_SIZE_MASK) >> HAB_HEADER_SIZE_SHIFT)
+
+#define HAB_HEADER_GET_TYPE(header) \
+ ((((header).info) & HAB_HEADER_TYPE_MASK) >> HAB_HEADER_TYPE_SHIFT)
+
+#define HAB_HEADER_GET_ID(header) \
+ (((((header).info) & HAB_HEADER_ID_MASK) >> \
+ (HAB_HEADER_ID_SHIFT - HAB_VCID_ID_SHIFT)) & HAB_VCID_ID_MASK)
+
+struct hab_header {
+ uint32_t info;
+};
+
+struct physical_channel {
+ struct kref refcount;
+ struct hab_device *habdev;
+ struct list_head node;
+ struct idr vchan_idr;
+ spinlock_t vid_lock;
+
+ struct idr expid_idr;
+ spinlock_t expid_lock;
+
+ void *hyp_data;
+ int dom_id;
+ int closed;
+
+ spinlock_t rxbuf_lock;
+};
+
+struct hab_open_send_data {
+ int vchan_id;
+ int sub_id;
+ int open_id;
+};
+
+struct hab_open_request {
+ int type;
+ struct physical_channel *pchan;
+ int vchan_id;
+ int sub_id;
+ int open_id;
+};
+
+struct hab_open_node {
+ struct hab_open_request request;
+ struct list_head node;
+ int age;
+};
+
+struct hab_export_ack {
+ uint32_t export_id;
+ int32_t vcid_local;
+ int32_t vcid_remote;
+};
+
+struct hab_export_ack_recvd {
+ struct hab_export_ack ack;
+ struct list_head node;
+ int age;
+};
+
+struct hab_message {
+ size_t sizebytes;
+ struct list_head node;
+ uint32_t data[];
+};
+
+struct hab_device {
+ const char *name;
+ unsigned int id;
+ struct list_head pchannels;
+ struct mutex pchan_lock;
+ struct list_head openq_list;
+ spinlock_t openlock;
+ wait_queue_head_t openq;
+};
+
+struct uhab_context {
+ struct kref refcount;
+ struct list_head vchannels;
+
+ struct list_head exp_whse;
+ uint32_t export_total;
+
+ wait_queue_head_t exp_wq;
+ struct list_head exp_rxq;
+ rwlock_t exp_lock;
+ spinlock_t expq_lock;
+
+ struct list_head imp_whse;
+ spinlock_t imp_lock;
+ uint32_t import_total;
+
+ void *import_ctx;
+
+ rwlock_t ctx_lock;
+ int closing;
+ int kernel;
+};
+
+struct hab_driver {
+ struct device *dev;
+ struct cdev cdev;
+ dev_t major;
+ struct class *class;
+ int irq;
+
+ int ndevices;
+ struct hab_device *devp;
+ struct uhab_context *kctx;
+ int b_server_dom;
+ int loopback_num;
+ int b_loopback;
+};
+
+struct virtual_channel {
+ struct work_struct work;
+ /*
+ * refcount is used to track the references from hab core to the virtual
+ * channel such as references from physical channels,
+ * i.e. references from the "other" side
+ */
+ struct kref refcount;
+ /*
+ * usagecnt is used to track the clients who are using this virtual
+ * channel such as local clients, client sowftware etc,
+ * i.e. references from "this" side
+ */
+ struct kref usagecnt;
+ struct physical_channel *pchan;
+ struct uhab_context *ctx;
+ struct list_head node;
+ struct list_head rx_list;
+ wait_queue_head_t rx_queue;
+ spinlock_t rx_lock;
+ int id;
+ int otherend_id;
+ int otherend_closed;
+};
+
+/*
+ * Struct shared between local and remote, contents are composed by exporter,
+ * the importer only writes to pdata and local (exporter) domID
+ */
+struct export_desc {
+ uint32_t export_id;
+ int readonly;
+ uint64_t import_index;
+
+ struct virtual_channel *vchan;
+
+ int32_t vcid_local;
+ int32_t vcid_remote;
+ int domid_local;
+ int domid_remote;
+
+ struct list_head node;
+ void *kva;
+ int payload_count;
+ unsigned char payload[1];
+};
+
+int hab_vchan_open(struct uhab_context *ctx,
+ unsigned int mmid, int32_t *vcid, uint32_t flags);
+void hab_vchan_close(struct uhab_context *ctx,
+ int32_t vcid);
+long hab_vchan_send(struct uhab_context *ctx,
+ int vcid,
+ size_t sizebytes,
+ void *data,
+ unsigned int flags);
+struct hab_message *hab_vchan_recv(struct uhab_context *ctx,
+ int vcid,
+ unsigned int flags);
+void hab_vchan_stop(struct virtual_channel *vchan);
+void hab_vchan_stop_notify(struct virtual_channel *vchan);
+
+int hab_mem_export(struct uhab_context *ctx,
+ struct hab_export *param, int kernel);
+int hab_mem_import(struct uhab_context *ctx,
+ struct hab_import *param, int kernel);
+int hab_mem_unexport(struct uhab_context *ctx,
+ struct hab_unexport *param, int kernel);
+int hab_mem_unimport(struct uhab_context *ctx,
+ struct hab_unimport *param, int kernel);
+
+void habmem_remove_export(struct export_desc *exp);
+
+/* memory hypervisor framework plugin I/F */
+void *habmm_hyp_allocate_grantable(int page_count,
+ uint32_t *sizebytes);
+
+int habmem_hyp_grant_user(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata);
+
+int habmem_hyp_grant(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata);
+
+int habmem_hyp_revoke(void *expdata, uint32_t count);
+
+void *habmem_imp_hyp_open(void);
+void habmem_imp_hyp_close(void *priv, int kernel);
+
+long habmem_imp_hyp_map(void *priv, void *impdata, uint32_t count,
+ uint32_t remotedom,
+ uint64_t *index,
+ void **pkva,
+ int kernel,
+ uint32_t userflags);
+
+long habmm_imp_hyp_unmap(void *priv, uint64_t index,
+ uint32_t count,
+ int kernel);
+
+int habmem_imp_hyp_mmap(struct file *flip, struct vm_area_struct *vma);
+
+
+
+void hab_msg_free(struct hab_message *message);
+struct hab_message *hab_msg_dequeue(struct virtual_channel *vchan,
+ int wait_flag);
+
+void hab_msg_recv(struct physical_channel *pchan,
+ struct hab_header *header);
+
+void hab_open_request_init(struct hab_open_request *request,
+ int type,
+ struct physical_channel *pchan,
+ int vchan_id,
+ int sub_id,
+ int open_id);
+int hab_open_request_send(struct hab_open_request *request);
+int hab_open_request_add(struct physical_channel *pchan,
+ struct hab_header *header);
+void hab_open_request_free(struct hab_open_request *request);
+int hab_open_listen(struct uhab_context *ctx,
+ struct hab_device *dev,
+ struct hab_open_request *listen,
+ struct hab_open_request **recv_request,
+ int ms_timeout);
+
+struct virtual_channel *hab_vchan_alloc(struct uhab_context *ctx,
+ struct physical_channel *pchan);
+struct virtual_channel *hab_vchan_get(struct physical_channel *pchan,
+ uint32_t vchan_id);
+void hab_vchan_put(struct virtual_channel *vchan);
+
+struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
+ struct uhab_context *ctx);
+struct physical_channel *hab_pchan_alloc(struct hab_device *habdev,
+ int otherend_id);
+struct physical_channel *hab_pchan_find_domid(struct hab_device *dev,
+ int dom_id);
+int hab_vchan_find_domid(struct virtual_channel *vchan);
+
+void hab_pchan_get(struct physical_channel *pchan);
+void hab_pchan_put(struct physical_channel *pchan);
+
+struct uhab_context *hab_ctx_alloc(int kernel);
+
+void hab_ctx_free(struct kref *ref);
+
+static inline void hab_ctx_get(struct uhab_context *ctx)
+{
+ if (ctx)
+ kref_get(&ctx->refcount);
+}
+
+static inline void hab_ctx_put(struct uhab_context *ctx)
+{
+ if (ctx)
+ kref_put(&ctx->refcount, hab_ctx_free);
+}
+
+void hab_send_close_msg(struct virtual_channel *vchan);
+int hab_hypervisor_register(void);
+void hab_hypervisor_unregister(void);
+
+int physical_channel_read(struct physical_channel *pchan,
+ void *payload,
+ size_t read_size);
+
+int physical_channel_send(struct physical_channel *pchan,
+ struct hab_header *header,
+ void *payload);
+
+void physical_channel_rx_dispatch(unsigned long physical_channel);
+
+int loopback_pchan_create(char *dev_name);
+
+bool hab_is_loopback(void);
+
+/* Global singleton HAB instance */
+extern struct hab_driver hab_driver;
+
+#endif /* __HAB_H */
diff --git a/drivers/soc/qcom/hab/hab_grantable.h b/drivers/soc/qcom/hab/hab_grantable.h
new file mode 100644
index 000000000000..8a3f9721a89a
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_grantable.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 __HAB_GRANTABLE_H
+#define __HAB_GRANTABLE_H
+
+/* Grantable should be common between exporter and importer */
+struct grantable {
+ unsigned long pfn;
+};
+
+struct compressed_pfns {
+ unsigned long first_pfn;
+ int nregions;
+ struct region {
+ int size;
+ int space;
+ } region[];
+};
+#endif /* __HAB_GRANTABLE_H */
diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c
new file mode 100644
index 000000000000..ab4b9d0885cb
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_mem_linux.c
@@ -0,0 +1,451 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+#include <linux/fdtable.h>
+#include <linux/dma-buf.h>
+#include "hab_grantable.h"
+
+
+struct pages_list {
+ struct list_head list;
+ struct page **pages;
+ long npages;
+ uint64_t index; /* for mmap first call */
+ int kernel;
+ void *kva;
+ void *uva;
+ int refcntk;
+ int refcntu;
+ uint32_t userflags;
+ struct file *filp_owner;
+ struct file *filp_mapper;
+};
+
+struct importer_context {
+ int cnt; /* pages allocated for local file */
+ struct list_head imp_list;
+ struct file *filp;
+};
+
+void *habmm_hyp_allocate_grantable(int page_count,
+ uint32_t *sizebytes)
+{
+ if (!sizebytes || !page_count)
+ return NULL;
+
+ *sizebytes = page_count * sizeof(struct grantable);
+ return vmalloc(*sizebytes);
+}
+
+static int match_file(const void *p, struct file *file, unsigned int fd)
+{
+ /*
+ * We must return fd + 1 because iterate_fd stops searching on
+ * non-zero return, but 0 is a valid fd.
+ */
+ return (p == file) ? (fd + 1) : 0;
+}
+
+
+static int habmem_get_dma_pages(unsigned long address,
+ int page_count,
+ struct page **pages)
+{
+ struct vm_area_struct *vma;
+ struct dma_buf *dmabuf = NULL;
+ unsigned long offset;
+ unsigned long page_offset;
+ struct scatterlist *s;
+ struct sg_table *sg_table = NULL;
+ struct dma_buf_attachment *attach = NULL;
+ struct page *page;
+ int i, j, rc = 0;
+ int fd;
+
+ vma = find_vma(current->mm, address);
+ if (!vma || !vma->vm_file)
+ goto err;
+
+ /* Look for the fd that matches this the vma file */
+ fd = iterate_fd(current->files, 0, match_file, vma->vm_file);
+ if (fd == 0) {
+ pr_err("iterate_fd failed\n");
+ goto err;
+ }
+
+ offset = address - vma->vm_start;
+ page_offset = offset/PAGE_SIZE;
+
+ dmabuf = dma_buf_get(fd - 1);
+
+ attach = dma_buf_attach(dmabuf, hab_driver.dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ pr_err("dma_buf_attach failed\n");
+ goto err;
+ }
+
+ sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
+
+ if (IS_ERR_OR_NULL(sg_table)) {
+ pr_err("dma_buf_map_attachment failed\n");
+ goto err;
+ }
+
+ for_each_sg(sg_table->sgl, s, sg_table->nents, i) {
+ page = sg_page(s);
+
+ for (j = page_offset; j < (s->length >> PAGE_SHIFT); j++) {
+ pages[rc] = nth_page(page, j);
+ rc++;
+ if (rc >= page_count)
+ break;
+ }
+ if (rc >= page_count)
+ break;
+
+ if (page_offset > (s->length >> PAGE_SHIFT)) {
+ /* carry-over the remaining offset to next s list */
+ page_offset = page_offset-(s->length >> PAGE_SHIFT);
+ } else {
+ /*
+ * the page_offset is within this s list
+ * there is no more offset for the next s list
+ */
+ page_offset = 0;
+ }
+
+ }
+
+err:
+ if (!IS_ERR_OR_NULL(sg_table))
+ dma_buf_unmap_attachment(attach, sg_table, DMA_TO_DEVICE);
+ if (!IS_ERR_OR_NULL(attach))
+ dma_buf_detach(dmabuf, attach);
+ if (!IS_ERR_OR_NULL(dmabuf))
+ dma_buf_put(dmabuf);
+ return rc;
+}
+
+int habmem_hyp_grant_user(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata)
+{
+ int i, ret = 0;
+ struct grantable *item = (struct grantable *)ppdata;
+ struct page **pages;
+
+ pages = vmalloc(page_count * sizeof(struct page *));
+ if (!pages)
+ return -ENOMEM;
+
+ down_read(&current->mm->mmap_sem);
+
+ if (HABMM_EXP_MEM_TYPE_DMA & flags) {
+ ret = habmem_get_dma_pages(address,
+ page_count,
+ pages);
+ } else {
+ ret = get_user_pages(current, current->mm,
+ address,
+ page_count,
+ 1,
+ 1,
+ pages,
+ NULL);
+ }
+
+ if (ret > 0) {
+ for (i = 0; i < page_count; i++)
+ item[i].pfn = page_to_pfn(pages[i]);
+ } else {
+ pr_err("get %d user pages failed: %d\n", page_count, ret);
+ }
+
+ vfree(pages);
+ up_read(&current->mm->mmap_sem);
+ return ret;
+}
+/*
+ * exporter - grant & revoke
+ * generate shareable page list based on CPU friendly virtual "address".
+ * The result as an array is stored in ppdata to return to caller
+ * page size 4KB is assumed
+ */
+int habmem_hyp_grant(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata)
+{
+ int i;
+ struct grantable *item;
+ void *kva = (void *)(uintptr_t)address;
+ int is_vmalloc = is_vmalloc_addr(kva);
+
+ item = (struct grantable *)ppdata;
+
+ for (i = 0; i < page_count; i++) {
+ kva = (void *)(uintptr_t)(address + i*PAGE_SIZE);
+ if (is_vmalloc)
+ item[i].pfn = page_to_pfn(vmalloc_to_page(kva));
+ else
+ item[i].pfn = page_to_pfn(virt_to_page(kva));
+ }
+
+ return 0;
+}
+
+int habmem_hyp_revoke(void *expdata, uint32_t count)
+{
+ return 0;
+}
+
+void *habmem_imp_hyp_open(void)
+{
+ struct importer_context *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ INIT_LIST_HEAD(&priv->imp_list);
+
+ return priv;
+}
+
+void habmem_imp_hyp_close(void *imp_ctx, int kernel)
+{
+ struct importer_context *priv = imp_ctx;
+ struct pages_list *pglist, *pglist_tmp;
+
+ if (!priv)
+ return;
+
+ list_for_each_entry_safe(pglist, pglist_tmp, &priv->imp_list, list) {
+ if (kernel && pglist->kva)
+ vunmap(pglist->kva);
+
+ list_del(&pglist->list);
+ priv->cnt--;
+
+ vfree(pglist->pages);
+ kfree(pglist);
+ }
+
+ kfree(priv);
+}
+
+/*
+ * setup pages, be ready for the following mmap call
+ * index is output to refer to this imported buffer described by the import data
+ */
+long habmem_imp_hyp_map(void *imp_ctx,
+ void *impdata,
+ uint32_t count,
+ uint32_t remotedom,
+ uint64_t *index,
+ void **pkva,
+ int kernel,
+ uint32_t userflags)
+{
+ struct page **pages;
+ struct compressed_pfns *pfn_table = impdata;
+ struct pages_list *pglist;
+ struct importer_context *priv = imp_ctx;
+ unsigned long pfn;
+ int i, j, k = 0;
+
+ if (!pfn_table || !priv)
+ return -EINVAL;
+
+ pages = vmalloc(count * sizeof(struct page *));
+ if (!pages)
+ return -ENOMEM;
+
+ pglist = kzalloc(sizeof(*pglist), GFP_KERNEL);
+ if (!pglist) {
+ vfree(pages);
+ return -ENOMEM;
+ }
+
+ pfn = pfn_table->first_pfn;
+ for (i = 0; i < pfn_table->nregions; i++) {
+ for (j = 0; j < pfn_table->region[i].size; j++) {
+ pages[k] = pfn_to_page(pfn+j);
+ k++;
+ }
+ pfn += pfn_table->region[i].size + pfn_table->region[i].space;
+ }
+
+ pglist->pages = pages;
+ pglist->npages = count;
+ pglist->kernel = kernel;
+ pglist->index = page_to_phys(pages[0]) >> PAGE_SHIFT;
+ pglist->refcntk = pglist->refcntu = 0;
+ pglist->userflags = userflags;
+
+ *index = pglist->index << PAGE_SHIFT;
+
+ if (kernel) {
+ pgprot_t prot = PAGE_KERNEL;
+
+ if (!(userflags & HABMM_IMPORT_FLAGS_CACHED))
+ prot = pgprot_writecombine(prot);
+
+ pglist->kva = vmap(pglist->pages, pglist->npages, VM_MAP, prot);
+ if (pglist->kva == NULL) {
+ vfree(pages);
+ kfree(pglist);
+ pr_err("%ld pages vmap failed\n", pglist->npages);
+ return -ENOMEM;
+ }
+
+ pglist->uva = NULL;
+ pglist->refcntk++;
+ *pkva = pglist->kva;
+ *index = (uint64_t)((uintptr_t)pglist->kva);
+ } else {
+ pglist->kva = NULL;
+ }
+
+ list_add_tail(&pglist->list, &priv->imp_list);
+ priv->cnt++;
+
+ return 0;
+}
+
+/* the input index is PHY address shifted for uhab, and kva for khab */
+long habmm_imp_hyp_unmap(void *imp_ctx,
+ uint64_t index,
+ uint32_t count,
+ int kernel)
+{
+ struct importer_context *priv = imp_ctx;
+ struct pages_list *pglist;
+ int found = 0;
+ uint64_t pg_index = index >> PAGE_SHIFT;
+
+ list_for_each_entry(pglist, &priv->imp_list, list) {
+ if (kernel) {
+ if (pglist->kva == (void *)((uintptr_t)index))
+ found = 1;
+ } else {
+ if (pglist->index == pg_index)
+ found = 1;
+ }
+
+ if (found) {
+ list_del(&pglist->list);
+ priv->cnt--;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("failed to find export id on index %llx\n", index);
+ return -EINVAL;
+ }
+
+ if (kernel)
+ if (pglist->kva)
+ vunmap(pglist->kva);
+
+ vfree(pglist->pages);
+ kfree(pglist);
+
+ return 0;
+}
+
+static int hab_map_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct page *page;
+ struct pages_list *pglist;
+
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* PHY address */
+ unsigned long fault_offset =
+ (unsigned long)vmf->virtual_address - vma->vm_start + offset;
+ unsigned long fault_index = fault_offset>>PAGE_SHIFT;
+ int page_idx;
+
+ if (vma == NULL)
+ return VM_FAULT_SIGBUS;
+
+ pglist = vma->vm_private_data;
+
+ page_idx = fault_index - pglist->index;
+ if (page_idx < 0 || page_idx >= pglist->npages) {
+ pr_err("Out of page array. page_idx %d, pg cnt %ld",
+ page_idx, pglist->npages);
+ return VM_FAULT_SIGBUS;
+ }
+
+ page = pglist->pages[page_idx];
+ get_page(page);
+ vmf->page = page;
+ return 0;
+}
+
+static void hab_map_open(struct vm_area_struct *vma)
+{
+}
+
+static void hab_map_close(struct vm_area_struct *vma)
+{
+}
+
+static const struct vm_operations_struct habmem_vm_ops = {
+
+ .fault = hab_map_fault,
+ .open = hab_map_open,
+ .close = hab_map_close,
+};
+
+int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct uhab_context *ctx = (struct uhab_context *) filp->private_data;
+ struct importer_context *imp_ctx = ctx->import_ctx;
+ long length = vma->vm_end - vma->vm_start;
+ struct pages_list *pglist;
+ int bfound = 0;
+
+ list_for_each_entry(pglist, &imp_ctx->imp_list, list) {
+ if (pglist->index == vma->vm_pgoff) {
+ bfound = 1;
+ break;
+ }
+ }
+
+ if (!bfound) {
+ pr_err("Failed to find pglist vm_pgoff: %d\n", vma->vm_pgoff);
+ return -EINVAL;
+ }
+
+ if (length > pglist->npages * PAGE_SIZE) {
+ pr_err("Error vma length %ld not matching page list %ld\n",
+ length, pglist->npages * PAGE_SIZE);
+ return -EINVAL;
+ }
+
+ vma->vm_ops = &habmem_vm_ops;
+
+ vma->vm_private_data = pglist;
+
+ if (!(pglist->userflags & HABMM_IMPORT_FLAGS_CACHED))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ return 0;
+}
diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c
new file mode 100644
index 000000000000..aaef9aa9f414
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_mimex.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+#include "hab_grantable.h"
+
+/*
+ * use physical channel to send export parcel
+
+ * local remote
+ * send(export) --> IRQ store to export warehouse
+ * wait(export ack) <-- send(export ack)
+
+ * the actual data consists the following 3 parts listed in order
+ * 1. header (uint32_t) vcid|type|size
+ * 2. export parcel (full struct)
+ * 3. full contents in export->pdata
+ */
+
+
+static int hab_export_ack_find(struct uhab_context *ctx,
+ struct hab_export_ack *expect_ack)
+{
+ int ret = 0;
+ struct hab_export_ack_recvd *ack_recvd;
+
+ spin_lock_bh(&ctx->expq_lock);
+
+ list_for_each_entry(ack_recvd, &ctx->exp_rxq, node) {
+ if (ack_recvd->ack.export_id == expect_ack->export_id &&
+ ack_recvd->ack.vcid_local == expect_ack->vcid_local &&
+ ack_recvd->ack.vcid_remote == expect_ack->vcid_remote) {
+ list_del(&ack_recvd->node);
+ kfree(ack_recvd);
+ ret = 1;
+ break;
+ }
+ ack_recvd->age++;
+ if (ack_recvd->age > Q_AGE_THRESHOLD) {
+ list_del(&ack_recvd->node);
+ kfree(ack_recvd);
+ }
+ }
+
+ spin_unlock_bh(&ctx->expq_lock);
+
+ return ret;
+}
+
+static int hab_export_ack_wait(struct uhab_context *ctx,
+ struct hab_export_ack *expect_ack)
+{
+ int ret;
+
+ ret = wait_event_interruptible_timeout(ctx->exp_wq,
+ hab_export_ack_find(ctx, expect_ack),
+ HZ);
+ if (!ret || (ret == -ERESTARTSYS))
+ ret = -EAGAIN;
+ else if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/*
+ * Get id from free list first. if not available, new id is generated.
+ * Once generated it will not be erased
+ * assumptions: no handshake or memory map/unmap in this helper function
+ */
+static struct export_desc *habmem_add_export(struct virtual_channel *vchan,
+ int sizebytes,
+ uint32_t flags)
+{
+ struct uhab_context *ctx;
+ struct export_desc *exp;
+
+ if (!vchan || !sizebytes)
+ return NULL;
+
+ exp = vmalloc(sizebytes);
+ if (!exp)
+ return NULL;
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&vchan->pchan->expid_lock);
+ exp->export_id =
+ idr_alloc(&vchan->pchan->expid_idr, exp, 1, 0, GFP_NOWAIT);
+ spin_unlock(&vchan->pchan->expid_lock);
+ idr_preload_end();
+
+ exp->readonly = flags;
+ exp->vchan = vchan;
+ exp->vcid_local = vchan->id;
+ exp->vcid_remote = vchan->otherend_id;
+ exp->domid_local = -1; /* dom id, provided on the importer */
+ exp->domid_remote = vchan->pchan->dom_id;
+
+ ctx = vchan->ctx;
+ write_lock(&ctx->exp_lock);
+ ctx->export_total++;
+ list_add_tail(&exp->node, &ctx->exp_whse);
+ write_unlock(&ctx->exp_lock);
+
+ return exp;
+}
+
+void habmem_remove_export(struct export_desc *exp)
+{
+ struct physical_channel *pchan;
+ struct uhab_context *ctx;
+
+ if (!exp || !exp->vchan || !exp->vchan->ctx || !exp->vchan->pchan)
+ return;
+
+ ctx = exp->vchan->ctx;
+ ctx->export_total--;
+
+ pchan = exp->vchan->pchan;
+
+ spin_lock(&pchan->expid_lock);
+ idr_remove(&pchan->expid_idr, exp->export_id);
+ spin_unlock(&pchan->expid_lock);
+
+ vfree(exp);
+}
+
+static int compress_pfns(void **pfns, int npages, unsigned int *data_size)
+{
+ int i, j = 0;
+ struct grantable *item = (struct grantable *)*pfns;
+ int region_size = 1;
+ struct compressed_pfns *new_table =
+ vmalloc(sizeof(struct compressed_pfns) +
+ npages * sizeof(struct region));
+
+ if (!new_table)
+ return -ENOMEM;
+
+ new_table->first_pfn = item[0].pfn;
+ for (i = 1; i < npages; i++) {
+ if (item[i].pfn-1 == item[i-1].pfn) {
+ region_size++;
+ } else {
+ new_table->region[j].size = region_size;
+ new_table->region[j].space = item[i].pfn -
+ item[i-1].pfn - 1;
+ j++;
+ region_size = 1;
+ }
+ }
+ new_table->region[j].size = region_size;
+ new_table->region[j].space = 0;
+ new_table->nregions = j+1;
+ vfree(*pfns);
+
+ *data_size = sizeof(struct compressed_pfns) +
+ sizeof(struct region)*new_table->nregions;
+ *pfns = new_table;
+ return 0;
+}
+
+/*
+ * store the parcel to the warehouse, then send the parcel to remote side
+ * both exporter composed export descriptor and the grantrefids are sent
+ * as one msg to the importer side
+ */
+static int habmem_export_vchan(struct uhab_context *ctx,
+ struct virtual_channel *vchan,
+ void *pdata,
+ int payload_size,
+ int nunits,
+ uint32_t flags,
+ uint32_t *export_id) {
+ int ret;
+ struct export_desc *exp;
+ uint32_t sizebytes = sizeof(*exp) + payload_size;
+ struct hab_export_ack expected_ack = {0};
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+
+ exp = habmem_add_export(vchan, sizebytes, flags);
+ if (!exp)
+ return -ENOMEM;
+
+ /* append the pdata to the export descriptor */
+ exp->payload_count = nunits;
+ memcpy(exp->payload, pdata, payload_size);
+
+ HAB_HEADER_SET_SIZE(header, sizebytes);
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_EXPORT);
+ HAB_HEADER_SET_ID(header, vchan->otherend_id);
+ ret = physical_channel_send(vchan->pchan, &header, exp);
+
+ if (ret != 0) {
+ pr_err("failed to export payload to the remote %d\n", ret);
+ return ret;
+ }
+
+ expected_ack.export_id = exp->export_id;
+ expected_ack.vcid_local = exp->vcid_local;
+ expected_ack.vcid_remote = exp->vcid_remote;
+ ret = hab_export_ack_wait(ctx, &expected_ack);
+
+ *export_id = exp->export_id;
+
+ return ret;
+}
+
+int hab_mem_export(struct uhab_context *ctx,
+ struct hab_export *param,
+ int kernel)
+{
+ int ret = 0;
+ void *pdata_exp = NULL;
+ unsigned int pdata_size = 0;
+ uint32_t export_id = 0;
+ struct virtual_channel *vchan;
+ int page_count;
+
+ if (!ctx || !param || param->sizebytes > HAB_MAX_EXPORT_SIZE)
+ return -EINVAL;
+
+ vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
+ if (!vchan || !vchan->pchan) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ page_count = param->sizebytes/PAGE_SIZE;
+ pdata_exp = habmm_hyp_allocate_grantable(page_count, &pdata_size);
+ if (!pdata_exp) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (kernel) {
+ ret = habmem_hyp_grant((unsigned long)param->buffer,
+ page_count,
+ param->flags,
+ vchan->pchan->dom_id,
+ pdata_exp);
+ } else {
+ ret = habmem_hyp_grant_user((unsigned long)param->buffer,
+ page_count,
+ param->flags,
+ vchan->pchan->dom_id,
+ pdata_exp);
+ }
+ if (ret < 0) {
+ pr_err("habmem_hyp_grant failed size=%d ret=%d\n",
+ pdata_size, ret);
+ goto err;
+ }
+
+ compress_pfns(&pdata_exp, page_count, &pdata_size);
+
+ ret = habmem_export_vchan(ctx,
+ vchan,
+ pdata_exp,
+ pdata_size,
+ page_count,
+ param->flags,
+ &export_id);
+
+ param->exportid = export_id;
+err:
+ vfree(pdata_exp);
+ if (vchan)
+ hab_vchan_put(vchan);
+ return ret;
+}
+
+int hab_mem_unexport(struct uhab_context *ctx,
+ struct hab_unexport *param,
+ int kernel)
+{
+ int ret = 0, found = 0;
+ struct export_desc *exp, *tmp;
+
+ if (!ctx || !param)
+ return -EINVAL;
+
+ write_lock(&ctx->exp_lock);
+ list_for_each_entry_safe(exp, tmp, &ctx->exp_whse, node) {
+ if ((param->exportid == exp->export_id) &&
+ (param->vcid == exp->vcid_local)) {
+ list_del(&exp->node);
+ found = 1;
+ break;
+ }
+ }
+ write_unlock(&ctx->exp_lock);
+
+ if (!found)
+ return -EINVAL;
+
+ ret = habmem_hyp_revoke(exp->payload, exp->payload_count);
+
+ habmem_remove_export(exp);
+ return ret;
+}
+
+int hab_mem_import(struct uhab_context *ctx,
+ struct hab_import *param,
+ int kernel)
+{
+ int ret = 0, found = 0;
+ struct export_desc *exp = NULL;
+
+ if (!ctx || !param)
+ return -EINVAL;
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry(exp, &ctx->imp_whse, node) {
+ if ((exp->export_id == param->exportid) &&
+ (param->vcid == exp->vcid_remote)) {
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+
+ if (!found) {
+ pr_err("Fail to get export descriptor from export id %d\n",
+ param->exportid);
+ ret = -ENODEV;
+ return ret;
+ }
+
+ ret = habmem_imp_hyp_map(ctx->import_ctx,
+ exp->payload,
+ exp->payload_count,
+ exp->domid_local,
+ &exp->import_index,
+ &exp->kva,
+ kernel,
+ param->flags);
+ if (ret) {
+ pr_err("Import fail ret:%d pcnt:%d rem:%d 1st_ref:0x%X\n",
+ ret, exp->payload_count,
+ exp->domid_local, *((uint32_t *)exp->payload));
+ return ret;
+ }
+
+ param->index = exp->import_index;
+ param->kva = (uint64_t)exp->kva;
+
+ return ret;
+}
+
+int hab_mem_unimport(struct uhab_context *ctx,
+ struct hab_unimport *param,
+ int kernel)
+{
+ int ret = 0, found = 0;
+ struct export_desc *exp = NULL, *exp_tmp;
+
+ if (!ctx || !param)
+ return -EINVAL;
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) {
+ if ((exp->export_id == param->exportid) &&
+ (param->vcid == exp->vcid_remote)) {
+ list_del(&exp->node);
+ ctx->import_total--;
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+
+ if (!found)
+ ret = -EINVAL;
+ else {
+ ret = habmm_imp_hyp_unmap(ctx->import_ctx,
+ exp->import_index,
+ exp->payload_count,
+ kernel);
+
+ param->kva = (uint64_t)exp->kva;
+ kfree(exp);
+ }
+
+ return ret;
+}
diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c
new file mode 100644
index 000000000000..f08cc83fe9fc
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_msg.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+
+static int hab_rx_queue_empty(struct virtual_channel *vchan)
+{
+ int ret;
+
+ spin_lock_bh(&vchan->rx_lock);
+ ret = list_empty(&vchan->rx_list);
+ spin_unlock_bh(&vchan->rx_lock);
+ return ret;
+}
+
+static struct hab_message*
+hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes)
+{
+ struct hab_message *message;
+
+ message = kzalloc(sizeof(*message) + sizebytes, GFP_ATOMIC);
+ if (!message)
+ return NULL;
+
+ message->sizebytes =
+ physical_channel_read(pchan, message->data, sizebytes);
+
+ return message;
+}
+
+void hab_msg_free(struct hab_message *message)
+{
+ kfree(message);
+}
+
+struct hab_message *
+hab_msg_dequeue(struct virtual_channel *vchan, int wait_flag)
+{
+ struct hab_message *message = NULL;
+ int ret = 0;
+
+ if (wait_flag) {
+ if (hab_rx_queue_empty(vchan))
+ ret = wait_event_interruptible(vchan->rx_queue,
+ !hab_rx_queue_empty(vchan) ||
+ vchan->otherend_closed);
+ }
+
+ if (!ret && !vchan->otherend_closed) {
+ spin_lock_bh(&vchan->rx_lock);
+ if (!list_empty(&vchan->rx_list)) {
+ message = list_first_entry(&vchan->rx_list,
+ struct hab_message, node);
+ list_del(&message->node);
+ }
+ spin_unlock_bh(&vchan->rx_lock);
+ }
+
+ return message;
+}
+
+static void hab_msg_queue(struct virtual_channel *vchan,
+ struct hab_message *message)
+{
+ spin_lock_bh(&vchan->rx_lock);
+ list_add_tail(&message->node, &vchan->rx_list);
+ spin_unlock_bh(&vchan->rx_lock);
+
+ wake_up_interruptible(&vchan->rx_queue);
+}
+
+static int hab_export_enqueue(struct virtual_channel *vchan,
+ struct export_desc *exp)
+{
+ struct uhab_context *ctx = vchan->ctx;
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_add_tail(&exp->node, &ctx->imp_whse);
+ ctx->import_total++;
+ spin_unlock_bh(&ctx->imp_lock);
+
+ return 0;
+}
+
+static int hab_send_export_ack(struct physical_channel *pchan,
+ struct export_desc *exp)
+{
+ struct hab_export_ack exp_ack = {
+ .export_id = exp->export_id,
+ .vcid_local = exp->vcid_local,
+ .vcid_remote = exp->vcid_remote
+ };
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+
+ HAB_HEADER_SET_SIZE(header, sizeof(exp_ack));
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_EXPORT_ACK);
+ HAB_HEADER_SET_ID(header, exp->vcid_local);
+ return physical_channel_send(pchan, &header, &exp_ack);
+}
+
+static int hab_receive_create_export_ack(struct physical_channel *pchan,
+ struct uhab_context *ctx)
+{
+ struct hab_export_ack_recvd *ack_recvd =
+ kzalloc(sizeof(*ack_recvd), GFP_ATOMIC);
+
+ if (!ack_recvd)
+ return -ENOMEM;
+
+ if (physical_channel_read(pchan,
+ &ack_recvd->ack,
+ sizeof(ack_recvd->ack)) != sizeof(ack_recvd->ack))
+ return -EIO;
+
+ spin_lock_bh(&ctx->expq_lock);
+ list_add_tail(&ack_recvd->node, &ctx->exp_rxq);
+ spin_unlock_bh(&ctx->expq_lock);
+
+ return 0;
+}
+
+void hab_msg_recv(struct physical_channel *pchan,
+ struct hab_header *header)
+{
+ int ret;
+ struct hab_message *message;
+ struct hab_device *dev = pchan->habdev;
+ size_t sizebytes = HAB_HEADER_GET_SIZE(*header);
+ uint32_t payload_type = HAB_HEADER_GET_TYPE(*header);
+ uint32_t vchan_id = HAB_HEADER_GET_ID(*header);
+ struct virtual_channel *vchan = NULL;
+ struct export_desc *exp_desc;
+
+ /* get the local virtual channel if it isn't an open message */
+ if (payload_type != HAB_PAYLOAD_TYPE_INIT &&
+ payload_type != HAB_PAYLOAD_TYPE_INIT_ACK &&
+ payload_type != HAB_PAYLOAD_TYPE_ACK) {
+ vchan = hab_vchan_get(pchan, vchan_id);
+ if (!vchan) {
+ return;
+ } else if (vchan->otherend_closed) {
+ hab_vchan_put(vchan);
+ return;
+ }
+ }
+
+ switch (payload_type) {
+ case HAB_PAYLOAD_TYPE_MSG:
+ message = hab_msg_alloc(pchan, sizebytes);
+ if (!message)
+ break;
+
+ hab_msg_queue(vchan, message);
+ break;
+
+ case HAB_PAYLOAD_TYPE_INIT:
+ case HAB_PAYLOAD_TYPE_INIT_ACK:
+ case HAB_PAYLOAD_TYPE_ACK:
+ ret = hab_open_request_add(pchan, header);
+ if (ret)
+ break;
+ wake_up_interruptible(&dev->openq);
+ break;
+
+ case HAB_PAYLOAD_TYPE_EXPORT:
+ exp_desc = kzalloc(sizebytes, GFP_ATOMIC);
+ if (!exp_desc)
+ break;
+
+ if (physical_channel_read(pchan, exp_desc, sizebytes) !=
+ sizebytes) {
+ vfree(exp_desc);
+ break;
+ }
+
+ exp_desc->domid_local = pchan->dom_id;
+
+ hab_export_enqueue(vchan, exp_desc);
+ hab_send_export_ack(pchan, exp_desc);
+ break;
+
+ case HAB_PAYLOAD_TYPE_EXPORT_ACK:
+ ret = hab_receive_create_export_ack(pchan, vchan->ctx);
+ if (ret)
+ break;
+
+ wake_up_interruptible(&vchan->ctx->exp_wq);
+ break;
+
+ case HAB_PAYLOAD_TYPE_CLOSE:
+ hab_vchan_stop(vchan);
+ break;
+
+ default:
+ break;
+ }
+ if (vchan)
+ hab_vchan_put(vchan);
+}
diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c
new file mode 100644
index 000000000000..66468aa43afd
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_open.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+
+void hab_open_request_init(struct hab_open_request *request,
+ int type,
+ struct physical_channel *pchan,
+ int vchan_id,
+ int sub_id,
+ int open_id)
+{
+ request->type = type;
+ request->pchan = pchan;
+ request->vchan_id = vchan_id;
+ request->sub_id = sub_id;
+ request->open_id = open_id;
+}
+
+int hab_open_request_send(struct hab_open_request *request)
+{
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+ struct hab_open_send_data data;
+
+ HAB_HEADER_SET_SIZE(header, sizeof(struct hab_open_send_data));
+ HAB_HEADER_SET_TYPE(header, request->type);
+
+ data.vchan_id = request->vchan_id;
+ data.open_id = request->open_id;
+ data.sub_id = request->sub_id;
+
+ return physical_channel_send(request->pchan, &header, &data);
+}
+
+int hab_open_request_add(struct physical_channel *pchan,
+ struct hab_header *header)
+{
+ struct hab_open_node *node;
+ struct hab_device *dev = pchan->habdev;
+ struct hab_open_send_data data;
+ struct hab_open_request *request;
+
+ node = kzalloc(sizeof(*node), GFP_ATOMIC);
+ if (!node)
+ return -ENOMEM;
+
+ if (physical_channel_read(pchan, &data, HAB_HEADER_GET_SIZE(*header)) !=
+ HAB_HEADER_GET_SIZE(*header))
+ return -EIO;
+
+ request = &node->request;
+ request->type = HAB_HEADER_GET_TYPE(*header);
+ request->pchan = pchan;
+ request->vchan_id = data.vchan_id;
+ request->sub_id = data.sub_id;
+ request->open_id = data.open_id;
+ node->age = 0;
+ hab_pchan_get(pchan);
+
+ spin_lock_bh(&dev->openlock);
+ list_add_tail(&node->node, &dev->openq_list);
+ spin_unlock_bh(&dev->openlock);
+
+ return 0;
+}
+
+static int hab_open_request_find(struct uhab_context *ctx,
+ struct hab_device *dev,
+ struct hab_open_request *listen,
+ struct hab_open_request **recv_request)
+{
+ struct hab_open_node *node, *tmp;
+ struct hab_open_request *request;
+ int ret = 0;
+
+ if (ctx->closing ||
+ (listen->pchan && listen->pchan->closed)) {
+ *recv_request = NULL;
+ return 1;
+ }
+
+ spin_lock_bh(&dev->openlock);
+ if (list_empty(&dev->openq_list))
+ goto done;
+
+ list_for_each_entry_safe(node, tmp, &dev->openq_list, node) {
+ request = (struct hab_open_request *)node;
+ if (request->type == listen->type &&
+ (request->sub_id == listen->sub_id) &&
+ (!listen->open_id ||
+ request->open_id == listen->open_id) &&
+ (!listen->pchan ||
+ request->pchan == listen->pchan)) {
+ list_del(&node->node);
+ *recv_request = request;
+ ret = 1;
+ break;
+ }
+ node->age++;
+ if (node->age > Q_AGE_THRESHOLD) {
+ list_del(&node->node);
+ hab_open_request_free(request);
+ }
+ }
+
+done:
+ spin_unlock_bh(&dev->openlock);
+ return ret;
+}
+
+void hab_open_request_free(struct hab_open_request *request)
+{
+ if (request) {
+ hab_pchan_put(request->pchan);
+ kfree(request);
+ }
+}
+
+int hab_open_listen(struct uhab_context *ctx,
+ struct hab_device *dev,
+ struct hab_open_request *listen,
+ struct hab_open_request **recv_request,
+ int ms_timeout)
+{
+ int ret = 0;
+
+ if (!ctx || !listen || !recv_request)
+ return -EINVAL;
+
+ *recv_request = NULL;
+ if (ms_timeout > 0) {
+ ret = wait_event_interruptible_timeout(dev->openq,
+ hab_open_request_find(ctx, dev, listen, recv_request),
+ ms_timeout);
+ if (!ret || (-ERESTARTSYS == ret))
+ ret = -EAGAIN;
+ else if (ret > 0)
+ ret = 0;
+ } else {
+ ret = wait_event_interruptible(dev->openq,
+ hab_open_request_find(ctx, dev, listen, recv_request));
+ }
+
+ return ret;
+}
diff --git a/drivers/soc/qcom/hab/hab_pchan.c b/drivers/soc/qcom/hab/hab_pchan.c
new file mode 100644
index 000000000000..1ad727f7d90f
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_pchan.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+
+struct physical_channel *
+hab_pchan_alloc(struct hab_device *habdev, int otherend_id)
+{
+ struct physical_channel *pchan = kzalloc(sizeof(*pchan), GFP_KERNEL);
+
+ if (!pchan)
+ return NULL;
+
+ idr_init(&pchan->vchan_idr);
+ spin_lock_init(&pchan->vid_lock);
+ idr_init(&pchan->expid_idr);
+ spin_lock_init(&pchan->expid_lock);
+ kref_init(&pchan->refcount);
+
+ pchan->habdev = habdev;
+ pchan->dom_id = otherend_id;
+ pchan->closed = 1;
+ pchan->hyp_data = NULL;
+
+ spin_lock_init(&pchan->rxbuf_lock);
+
+ mutex_lock(&habdev->pchan_lock);
+ list_add_tail(&pchan->node, &habdev->pchannels);
+ mutex_unlock(&habdev->pchan_lock);
+
+ return pchan;
+}
+
+static void hab_pchan_free(struct kref *ref)
+{
+ struct physical_channel *pchan =
+ container_of(ref, struct physical_channel, refcount);
+
+ mutex_lock(&pchan->habdev->pchan_lock);
+ list_del(&pchan->node);
+ mutex_unlock(&pchan->habdev->pchan_lock);
+ kfree(pchan->hyp_data);
+ kfree(pchan);
+}
+
+struct physical_channel *
+hab_pchan_find_domid(struct hab_device *dev, int dom_id)
+{
+ struct physical_channel *pchan;
+
+ mutex_lock(&dev->pchan_lock);
+ list_for_each_entry(pchan, &dev->pchannels, node)
+ if (pchan->dom_id == dom_id)
+ break;
+
+ if (pchan->dom_id != dom_id)
+ pchan = NULL;
+
+ if (pchan && !kref_get_unless_zero(&pchan->refcount))
+ pchan = NULL;
+
+ mutex_unlock(&dev->pchan_lock);
+
+ return pchan;
+}
+
+void hab_pchan_get(struct physical_channel *pchan)
+{
+ if (pchan)
+ kref_get(&pchan->refcount);
+}
+
+void hab_pchan_put(struct physical_channel *pchan)
+{
+ if (pchan)
+ kref_put(&pchan->refcount, hab_pchan_free);
+}
diff --git a/drivers/soc/qcom/hab/hab_pipe.c b/drivers/soc/qcom/hab/hab_pipe.c
new file mode 100644
index 000000000000..e757b6cb1f01
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_pipe.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+#include "hab_pipe.h"
+
+size_t hab_pipe_calc_required_bytes(uint32_t shared_buf_size)
+{
+ return sizeof(struct hab_pipe)
+ + (2 * (sizeof(struct hab_shared_buf) + shared_buf_size));
+}
+
+struct hab_pipe_endpoint *hab_pipe_init(struct hab_pipe *pipe,
+ uint32_t shared_buf_size, int top)
+{
+ struct hab_pipe_endpoint *ep = NULL;
+ struct hab_shared_buf *buf_a;
+ struct hab_shared_buf *buf_b;
+
+ if (!pipe)
+ return NULL;
+
+ buf_a = (struct hab_shared_buf *) pipe->buf_base;
+ buf_b = (struct hab_shared_buf *) (pipe->buf_base
+ + sizeof(struct hab_shared_buf) + shared_buf_size);
+
+ if (top) {
+ ep = &pipe->top;
+ memset(ep, 0, sizeof(*ep));
+ ep->tx_info.sh_buf = buf_a;
+ ep->rx_info.sh_buf = buf_b;
+ } else {
+ ep = &pipe->bottom;
+ memset(ep, 0, sizeof(*ep));
+ ep->tx_info.sh_buf = buf_b;
+ ep->rx_info.sh_buf = buf_a;
+ memset(ep->tx_info.sh_buf, 0, sizeof(struct hab_shared_buf));
+ memset(ep->rx_info.sh_buf, 0, sizeof(struct hab_shared_buf));
+ ep->tx_info.sh_buf->size = shared_buf_size;
+ ep->rx_info.sh_buf->size = shared_buf_size;
+
+ pipe->buf_a = buf_a;
+ pipe->buf_b = buf_b;
+ pipe->total_size =
+ hab_pipe_calc_required_bytes(shared_buf_size);
+ }
+ return ep;
+}
+
+uint32_t hab_pipe_write(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t num_bytes)
+{
+ struct hab_shared_buf *sh_buf = ep->tx_info.sh_buf;
+ uint32_t space =
+ (sh_buf->size - (ep->tx_info.wr_count - sh_buf->rd_count));
+ uint32_t count1, count2;
+
+ if (!p || num_bytes > space || num_bytes == 0)
+ return 0;
+
+ count1 = (num_bytes <= (sh_buf->size - ep->tx_info.index)) ? num_bytes :
+ (sh_buf->size - ep->tx_info.index);
+ count2 = num_bytes - count1;
+
+ if (count1 > 0) {
+ memcpy(&sh_buf->data[ep->tx_info.index], p, count1);
+ ep->tx_info.wr_count += count1;
+ ep->tx_info.index += count1;
+ if (ep->tx_info.index >= sh_buf->size)
+ ep->tx_info.index = 0;
+ }
+ if (count2 > 0) {/* handle buffer wrapping */
+ memcpy(&sh_buf->data[ep->tx_info.index], p + count1, count2);
+ ep->tx_info.wr_count += count2;
+ ep->tx_info.index += count2;
+ if (ep->tx_info.index >= sh_buf->size)
+ ep->tx_info.index = 0;
+ }
+ return num_bytes;
+}
+
+/* Updates the write index which is shared with the other VM */
+void hab_pipe_write_commit(struct hab_pipe_endpoint *ep)
+{
+ struct hab_shared_buf *sh_buf = ep->tx_info.sh_buf;
+
+ mb(); /* Must commit data before incrementing count */
+ sh_buf->wr_count = ep->tx_info.wr_count;
+}
+
+uint32_t hab_pipe_read(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t size)
+{
+ struct hab_shared_buf *sh_buf = ep->rx_info.sh_buf;
+ uint32_t avail = sh_buf->wr_count - sh_buf->rd_count;
+ uint32_t count1, count2, to_read;
+
+ if (!p || avail == 0 || size == 0)
+ return 0;
+
+ to_read = (avail < size) ? avail : size;
+ count1 = (to_read <= (sh_buf->size - ep->rx_info.index)) ? to_read :
+ (sh_buf->size - ep->rx_info.index);
+ count2 = to_read - count1;
+
+ if (count1 > 0) {
+ memcpy(p, &sh_buf->data[ep->rx_info.index], count1);
+ ep->rx_info.index += count1;
+ if (ep->rx_info.index >= sh_buf->size)
+ ep->rx_info.index = 0;
+ mb(); /*Must commit data before incremeting count*/
+ sh_buf->rd_count += count1;
+ }
+ if (count2 > 0) { /* handle buffer wrapping */
+ memcpy(p + count1, &sh_buf->data[ep->rx_info.index], count2);
+ ep->rx_info.index += count2;
+ mb(); /*Must commit data before incremeting count*/
+ sh_buf->rd_count += count2;
+ }
+
+ return to_read;
+}
diff --git a/drivers/soc/qcom/hab/hab_pipe.h b/drivers/soc/qcom/hab/hab_pipe.h
new file mode 100644
index 000000000000..6ffdbd133868
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_pipe.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 HAB_PIPE_H
+#define HAB_PIPE_H
+
+struct hab_shared_buf {
+ uint32_t rd_count;
+ uint32_t wr_count;
+ uint32_t size;
+ unsigned char data[];
+};
+
+struct hab_pipe_endpoint {
+ struct {
+ uint32_t wr_count;
+ uint32_t index;
+ struct hab_shared_buf *sh_buf;
+ } tx_info;
+ struct {
+ uint32_t index;
+ struct hab_shared_buf *sh_buf;
+ } rx_info;
+};
+
+struct hab_pipe {
+ struct hab_pipe_endpoint top;
+ struct hab_pipe_endpoint bottom;
+
+ /* For debugging only */
+ struct hab_shared_buf *buf_a; /* top TX, bottom RX */
+ struct hab_shared_buf *buf_b; /* top RX, bottom TX */
+ size_t total_size;
+
+ unsigned char buf_base[];
+};
+
+size_t hab_pipe_calc_required_bytes(uint32_t shared_buf_size);
+
+struct hab_pipe_endpoint *hab_pipe_init(struct hab_pipe *pipe,
+ uint32_t shared_buf_size, int top);
+
+uint32_t hab_pipe_write(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t num_bytes);
+
+void hab_pipe_write_commit(struct hab_pipe_endpoint *ep);
+
+uint32_t hab_pipe_read(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t size);
+
+#endif /* HAB_PIPE_H */
diff --git a/drivers/soc/qcom/hab/hab_qvm.c b/drivers/soc/qcom/hab/hab_qvm.c
new file mode 100644
index 000000000000..a37590f23c61
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_qvm.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+#include "hab_qvm.h"
+
+#include <linux/highmem.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#define DEFAULT_HAB_SHMEM_IRQ 7
+
+#define SHMEM_PHYSICAL_ADDR 0x1c050000
+
+static irqreturn_t shm_irq_handler(int irq, void *_pchan)
+{
+ irqreturn_t rc = IRQ_NONE;
+ struct physical_channel *pchan = _pchan;
+ struct qvm_channel *dev =
+ (struct qvm_channel *) (pchan ? pchan->hyp_data : NULL);
+
+ if (dev && dev->guest_ctrl) {
+ int status = dev->guest_ctrl->status;
+
+ if (status & dev->idx) {
+ rc = IRQ_HANDLED;
+ tasklet_schedule(&dev->task);
+ }
+ }
+ return rc;
+}
+
+static uint64_t get_guest_factory_paddr(struct qvm_channel *dev,
+ const char *name, uint32_t pages)
+{
+ int i;
+
+ dev->guest_factory = ioremap(SHMEM_PHYSICAL_ADDR, PAGE_SIZE);
+
+ if (!dev->guest_factory) {
+ pr_err("Couldn't map guest_factory\n");
+ return 0;
+ }
+
+ if (dev->guest_factory->signature != GUEST_SHM_SIGNATURE) {
+ pr_err("shmem factory signature incorrect: %ld != %lu\n",
+ GUEST_SHM_SIGNATURE, dev->guest_factory->signature);
+ iounmap(dev->guest_factory);
+ return 0;
+ }
+
+ dev->guest_intr = dev->guest_factory->vector;
+
+ /*
+ * Set the name field on the factory page to identify the shared memory
+ * region
+ */
+ for (i = 0; i < strlen(name) && i < GUEST_SHM_MAX_NAME - 1; i++)
+ dev->guest_factory->name[i] = name[i];
+ dev->guest_factory->name[i] = (char) 0;
+
+ guest_shm_create(dev->guest_factory, pages);
+
+ /* See if we successfully created/attached to the region. */
+ if (dev->guest_factory->status != GSS_OK) {
+ pr_err("create failed: %d\n", dev->guest_factory->status);
+ iounmap(dev->guest_factory);
+ return 0;
+ }
+
+ pr_debug("shm creation size %x\n", dev->guest_factory->size);
+
+ return dev->guest_factory->shmem;
+}
+
+static int create_dispatcher(struct physical_channel *pchan, int id)
+{
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+ int ret;
+
+ tasklet_init(&dev->task, physical_channel_rx_dispatch,
+ (unsigned long) pchan);
+
+ ret = request_irq(hab_driver.irq, shm_irq_handler, IRQF_SHARED,
+ hab_driver.devp[id].name, pchan);
+
+ if (ret)
+ pr_err("request_irq for %s failed: %d\n",
+ hab_driver.devp[id].name, ret);
+
+ return ret;
+}
+
+static struct physical_channel *habhyp_commdev_alloc(int id)
+{
+ struct qvm_channel *dev;
+ struct physical_channel *pchan = NULL;
+ int ret = 0, channel = 0;
+ char *shmdata;
+ uint32_t pipe_alloc_size =
+ hab_pipe_calc_required_bytes(PIPE_SHMEM_SIZE);
+ uint32_t pipe_alloc_pages =
+ (pipe_alloc_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ uint64_t paddr;
+ int temp;
+ int total_pages;
+ struct page **pages;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&dev->io_lock);
+
+ paddr = get_guest_factory_paddr(dev,
+ hab_driver.devp[id].name,
+ pipe_alloc_pages);
+
+ total_pages = dev->guest_factory->size + 1;
+ pages = kmalloc_array(total_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (temp = 0; temp < total_pages; temp++)
+ pages[temp] = pfn_to_page((paddr / PAGE_SIZE) + temp);
+
+ dev->guest_ctrl = vmap(pages, total_pages, VM_MAP, PAGE_KERNEL);
+ if (!dev->guest_ctrl) {
+ ret = -ENOMEM;
+ kfree(pages);
+ goto err;
+ }
+
+ shmdata = (char *)dev->guest_ctrl + PAGE_SIZE;
+ dev->idx = dev->guest_ctrl->idx;
+
+ kfree(pages);
+
+ dev->pipe = (struct hab_pipe *) shmdata;
+ dev->pipe_ep = hab_pipe_init(dev->pipe, PIPE_SHMEM_SIZE,
+ dev->be ? 0 : 1);
+
+ pchan = hab_pchan_alloc(&hab_driver.devp[id], dev->be);
+ if (!pchan) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pchan->closed = 0;
+ pchan->hyp_data = (void *)dev;
+
+ dev->channel = channel;
+
+ ret = create_dispatcher(pchan, id);
+ if (ret < 0)
+ goto err;
+
+ return pchan;
+
+err:
+ kfree(dev);
+
+ if (pchan)
+ hab_pchan_put(pchan);
+ pr_err("habhyp_commdev_alloc failed: %d\n", ret);
+ return ERR_PTR(ret);
+}
+
+int hab_hypervisor_register(void)
+{
+ int ret = 0, i;
+
+ hab_driver.b_server_dom = 0;
+
+ /*
+ * Can still attempt to instantiate more channels if one fails.
+ * Others can be retried later.
+ */
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ if (IS_ERR(habhyp_commdev_alloc(i)))
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
+void hab_hypervisor_unregister(void)
+{
+}
+
+static int hab_shmem_probe(struct platform_device *pdev)
+{
+ int irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0)
+ hab_driver.irq = irq;
+ else
+ hab_driver.irq = DEFAULT_HAB_SHMEM_IRQ;
+
+ return 0;
+}
+
+static int hab_shmem_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id hab_shmem_match_table[] = {
+ {.compatible = "qvm,guest_shm"},
+ {},
+};
+
+static struct platform_driver hab_shmem_driver = {
+ .probe = hab_shmem_probe,
+ .remove = hab_shmem_remove,
+ .driver = {
+ .name = "hab_shmem",
+ .of_match_table = of_match_ptr(hab_shmem_match_table),
+ },
+};
+
+static int __init hab_shmem_init(void)
+{
+ return platform_driver_register(&hab_shmem_driver);
+}
+
+static void __exit hab_shmem_exit(void)
+{
+ platform_driver_unregister(&hab_shmem_driver);
+}
+
+core_initcall(hab_shmem_init);
+module_exit(hab_shmem_exit);
+
+MODULE_DESCRIPTION("Hypervisor shared memory driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/hab/hab_qvm.h b/drivers/soc/qcom/hab/hab_qvm.h
new file mode 100644
index 000000000000..e94b82f87942
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_qvm.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 __HAB_QNX_H
+#define __HAB_QNX_H
+#include "hab.h"
+#include "hab_pipe.h"
+
+#include <guest_shm.h>
+#include <linux/stddef.h>
+
+#define PULSE_CODE_NOTIFY 0
+#define PULSE_CODE_INPUT 1
+
+struct qvm_channel {
+ int be;
+
+ struct hab_pipe *pipe;
+ struct hab_pipe_endpoint *pipe_ep;
+ spinlock_t io_lock;
+ struct tasklet_struct task;
+ struct guest_shm_factory *guest_factory;
+ struct guest_shm_control *guest_ctrl;
+ uint32_t idx;
+
+ int channel;
+ int coid;
+
+ unsigned int guest_intr;
+ unsigned int guest_iid;
+};
+
+/* Shared mem size in each direction for communication pipe */
+#define PIPE_SHMEM_SIZE (128 * 1024)
+
+void *qnx_hyp_rx_dispatch(void *data);
+
+#endif /* __HAB_QNX_H */
diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c
new file mode 100644
index 000000000000..75a3fad68ab5
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_vchan.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+
+struct virtual_channel *
+hab_vchan_alloc(struct uhab_context *ctx, struct physical_channel *pchan)
+{
+ int id;
+ struct virtual_channel *vchan;
+
+ if (!pchan || !ctx)
+ return NULL;
+
+ vchan = kzalloc(sizeof(*vchan), GFP_KERNEL);
+ if (!vchan)
+ return NULL;
+
+ /* This should be the first thing we do in this function */
+ idr_preload(GFP_KERNEL);
+ spin_lock_bh(&pchan->vid_lock);
+ id = idr_alloc(&pchan->vchan_idr, vchan, 1, 256, GFP_NOWAIT);
+ spin_unlock_bh(&pchan->vid_lock);
+ idr_preload_end();
+
+ if (id < 0) {
+ kfree(vchan);
+ return NULL;
+ }
+ mb(); /* id must be generated done before pchan_get */
+
+ hab_pchan_get(pchan);
+ vchan->pchan = pchan;
+ vchan->id = ((id << HAB_VCID_ID_SHIFT) & HAB_VCID_ID_MASK) |
+ ((pchan->habdev->id << HAB_VCID_MMID_SHIFT) &
+ HAB_VCID_MMID_MASK) |
+ ((pchan->dom_id << HAB_VCID_DOMID_SHIFT) &
+ HAB_VCID_DOMID_MASK);
+ spin_lock_init(&vchan->rx_lock);
+ INIT_LIST_HEAD(&vchan->rx_list);
+ init_waitqueue_head(&vchan->rx_queue);
+
+ kref_init(&vchan->refcount);
+ kref_init(&vchan->usagecnt);
+ vchan->otherend_closed = pchan->closed;
+
+ hab_ctx_get(ctx);
+ vchan->ctx = ctx;
+
+ return vchan;
+}
+
+static void
+hab_vchan_free(struct kref *ref)
+{
+ int found;
+ struct virtual_channel *vchan =
+ container_of(ref, struct virtual_channel, refcount);
+ struct hab_message *message, *msg_tmp;
+ struct export_desc *exp;
+ struct physical_channel *pchan = vchan->pchan;
+ struct uhab_context *ctx = vchan->ctx;
+
+ list_for_each_entry_safe(message, msg_tmp, &vchan->rx_list, node) {
+ list_del(&message->node);
+ hab_msg_free(message);
+ }
+
+ do {
+ found = 0;
+ write_lock(&ctx->exp_lock);
+ list_for_each_entry(exp, &ctx->exp_whse, node) {
+ if (exp->vcid_local == vchan->id) {
+ list_del(&exp->node);
+ found = 1;
+ break;
+ }
+ }
+ write_unlock(&ctx->exp_lock);
+ if (found) {
+ habmem_hyp_revoke(exp->payload, exp->payload_count);
+ habmem_remove_export(exp);
+ }
+ } while (found);
+
+ do {
+ found = 0;
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry(exp, &ctx->imp_whse, node) {
+ if (exp->vcid_remote == vchan->id) {
+ list_del(&exp->node);
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+ if (found) {
+ habmm_imp_hyp_unmap(ctx->import_ctx,
+ exp->import_index,
+ exp->payload_count,
+ ctx->kernel);
+ ctx->import_total--;
+ kfree(exp);
+ }
+ } while (found);
+
+ spin_lock_bh(&pchan->vid_lock);
+ idr_remove(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan->id));
+ spin_unlock_bh(&pchan->vid_lock);
+
+ hab_pchan_put(pchan);
+ hab_ctx_put(ctx);
+
+ kfree(vchan);
+}
+
+struct virtual_channel*
+hab_vchan_get(struct physical_channel *pchan, uint32_t vchan_id)
+{
+ struct virtual_channel *vchan;
+
+ spin_lock_bh(&pchan->vid_lock);
+ vchan = idr_find(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan_id));
+ if (vchan)
+ if (!kref_get_unless_zero(&vchan->refcount))
+ vchan = NULL;
+ spin_unlock_bh(&pchan->vid_lock);
+
+ return vchan;
+}
+
+void hab_vchan_stop(struct virtual_channel *vchan)
+{
+ if (vchan) {
+ vchan->otherend_closed = 1;
+ wake_up_interruptible(&vchan->rx_queue);
+ }
+}
+
+void hab_vchan_stop_notify(struct virtual_channel *vchan)
+{
+ hab_send_close_msg(vchan);
+ hab_vchan_stop(vchan);
+}
+
+
+int hab_vchan_find_domid(struct virtual_channel *vchan)
+{
+ return vchan ? vchan->pchan->dom_id : -1;
+}
+
+static void
+hab_vchan_free_deferred(struct work_struct *work)
+{
+ struct virtual_channel *vchan =
+ container_of(work, struct virtual_channel, work);
+
+ hab_vchan_free(&vchan->refcount);
+}
+
+static void
+hab_vchan_schedule_free(struct kref *ref)
+{
+ struct virtual_channel *vchan =
+ container_of(ref, struct virtual_channel, refcount);
+
+ INIT_WORK(&vchan->work, hab_vchan_free_deferred);
+ schedule_work(&vchan->work);
+}
+
+void hab_vchan_put(struct virtual_channel *vchan)
+{
+ if (vchan)
+ kref_put(&vchan->refcount, hab_vchan_schedule_free);
+}
diff --git a/drivers/soc/qcom/hab/khab.c b/drivers/soc/qcom/hab/khab.c
new file mode 100644
index 000000000000..f7499773ae42
--- /dev/null
+++ b/drivers/soc/qcom/hab/khab.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include "hab.h"
+
+int32_t habmm_socket_open(int32_t *handle, uint32_t mm_ip_id,
+ uint32_t timeout, uint32_t flags)
+{
+ return hab_vchan_open(hab_driver.kctx, mm_ip_id, handle, flags);
+}
+EXPORT_SYMBOL(habmm_socket_open);
+
+int32_t habmm_socket_close(int32_t handle)
+{
+ hab_vchan_close(hab_driver.kctx, handle);
+ return 0;
+}
+EXPORT_SYMBOL(habmm_socket_close);
+
+int32_t habmm_socket_send(int32_t handle, void *src_buff,
+ uint32_t size_bytes, uint32_t flags)
+{
+ struct hab_send param = {0};
+
+ param.vcid = handle;
+ param.data = (uint64_t)(uintptr_t)src_buff;
+ param.sizebytes = size_bytes;
+ param.flags = flags;
+
+ return hab_vchan_send(hab_driver.kctx, handle,
+ size_bytes, src_buff, flags);
+}
+EXPORT_SYMBOL(habmm_socket_send);
+
+int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes,
+ uint32_t timeout, uint32_t flags)
+{
+ int ret = 0;
+ struct hab_message *msg;
+
+ if (!size_bytes || !dst_buff)
+ return -EINVAL;
+
+ msg = hab_vchan_recv(hab_driver.kctx, handle, flags);
+
+ if (IS_ERR(msg)) {
+ *size_bytes = 0;
+ return PTR_ERR(msg);
+ }
+
+ if (*size_bytes < msg->sizebytes) {
+ *size_bytes = 0;
+ ret = -EINVAL;
+ } else {
+ memcpy(dst_buff, msg->data, msg->sizebytes);
+ *size_bytes = msg->sizebytes;
+ }
+
+ hab_msg_free(msg);
+ return ret;
+}
+EXPORT_SYMBOL(habmm_socket_recv);
+
+int32_t habmm_export(int32_t handle, void *buff_to_share, uint32_t size_bytes,
+ uint32_t *export_id, uint32_t flags)
+{
+ int ret;
+ struct hab_export param = {0};
+
+ if (!export_id)
+ return -EINVAL;
+
+ param.vcid = handle;
+ param.buffer = (uint64_t)(uintptr_t)buff_to_share;
+ param.sizebytes = size_bytes;
+
+ ret = hab_mem_export(hab_driver.kctx, &param, 1);
+
+ *export_id = param.exportid;
+ return ret;
+}
+EXPORT_SYMBOL(habmm_export);
+
+int32_t habmm_unexport(int32_t handle, uint32_t export_id, uint32_t flags)
+{
+ struct hab_unexport param = {0};
+
+ param.vcid = handle;
+ param.exportid = export_id;
+
+ return hab_mem_unexport(hab_driver.kctx, &param, 1);
+}
+EXPORT_SYMBOL(habmm_unexport);
+
+int32_t habmm_import(int32_t handle, void **buff_shared, uint32_t size_bytes,
+ uint32_t export_id, uint32_t flags)
+{
+ int ret;
+ struct hab_import param = {0};
+
+ if (!buff_shared)
+ return -EINVAL;
+
+ param.vcid = handle;
+ param.sizebytes = size_bytes;
+ param.exportid = export_id;
+ param.flags = flags;
+
+ ret = hab_mem_import(hab_driver.kctx, &param, 1);
+ if (!IS_ERR(ret))
+ *buff_shared = (void *)(uintptr_t)param.kva;
+
+ return ret;
+}
+EXPORT_SYMBOL(habmm_import);
+
+int32_t habmm_unimport(int32_t handle,
+ uint32_t export_id,
+ void *buff_shared,
+ uint32_t flags)
+{
+ struct hab_unimport param = {0};
+
+ param.vcid = handle;
+ param.exportid = export_id;
+ param.kva = (uint64_t)(uintptr_t)buff_shared;
+
+ return hab_mem_unimport(hab_driver.kctx, &param, 1);
+}
+EXPORT_SYMBOL(habmm_unimport);
diff --git a/drivers/soc/qcom/hab/qvm_comm.c b/drivers/soc/qcom/hab/qvm_comm.c
new file mode 100644
index 000000000000..20a631e13794
--- /dev/null
+++ b/drivers/soc/qcom/hab/qvm_comm.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 "hab.h"
+#include "hab_qvm.h"
+
+static inline void habhyp_notify(void *commdev)
+{
+ struct qvm_channel *dev = (struct qvm_channel *)commdev;
+
+ if (dev && dev->guest_ctrl)
+ dev->guest_ctrl->notify = ~0;
+}
+
+int physical_channel_read(struct physical_channel *pchan,
+ void *payload,
+ size_t read_size)
+{
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+
+ if (dev)
+ return hab_pipe_read(dev->pipe_ep, payload, read_size);
+ else
+ return 0;
+}
+
+int physical_channel_send(struct physical_channel *pchan,
+ struct hab_header *header,
+ void *payload)
+{
+ int sizebytes = HAB_HEADER_GET_SIZE(*header);
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+ int total_size = sizeof(*header) + sizebytes;
+
+ if (total_size > dev->pipe_ep->tx_info.sh_buf->size)
+ return -EINVAL; /* too much data for ring */
+
+ spin_lock_bh(&dev->io_lock);
+
+ 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);
+ return -EAGAIN; /* not enough free space */
+ }
+
+ if (hab_pipe_write(dev->pipe_ep,
+ (unsigned char *)header,
+ sizeof(*header)) != sizeof(*header)) {
+ spin_unlock_bh(&dev->io_lock);
+ return -EIO;
+ }
+
+ if (sizebytes) {
+ if (hab_pipe_write(dev->pipe_ep,
+ (unsigned char *)payload,
+ sizebytes) != sizebytes) {
+ spin_unlock_bh(&dev->io_lock);
+ return -EIO;
+ }
+ }
+
+ hab_pipe_write_commit(dev->pipe_ep);
+ spin_unlock_bh(&dev->io_lock);
+ habhyp_notify(dev);
+
+ return 0;
+}
+
+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;
+
+ spin_lock_bh(&pchan->rxbuf_lock);
+ while (1) {
+ if (hab_pipe_read(dev->pipe_ep,
+ (unsigned char *)&header,
+ sizeof(header)) != sizeof(header))
+ break; /* no data available */
+
+ hab_msg_recv(pchan, &header);
+ }
+ spin_unlock_bh(&pchan->rxbuf_lock);
+}
diff --git a/drivers/soc/qcom/scm_qcpe.c b/drivers/soc/qcom/scm_qcpe.c
index 1e369c73e34b..3f2b05a0ec9e 100644
--- a/drivers/soc/qcom/scm_qcpe.c
+++ b/drivers/soc/qcom/scm_qcpe.c
@@ -1027,55 +1027,56 @@ int scm_is_call_available(u32 svc_id, u32 cmd_id)
ret = scm_call(SCM_SVC_INFO, IS_CALL_AVAIL_CMD, &svc_cmd,
sizeof(svc_cmd), &ret_val, sizeof(ret_val));
- if (ret)
- return ret;
+ if (!ret && ret_val)
+ return 1;
+ else
+ return 0;
return ret_val;
}
desc.arginfo = SCM_ARGS(1);
desc.args[0] = SCM_SIP_FNID(svc_id, cmd_id);
+ desc.ret[0] = 0;
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, IS_CALL_AVAIL_CMD), &desc);
- if (ret)
- return ret;
-
- return desc.ret[0];
+ if (!ret && desc.ret[0])
+ return 1;
+ else
+ return 0;
}
EXPORT_SYMBOL(scm_is_call_available);
#define GET_FEAT_VERSION_CMD 3
-int scm_get_feat_version(u32 feat)
+int scm_get_feat_version(u32 feat, u64 *scm_ret)
{
struct scm_desc desc = {0};
int ret;
if (!is_scm_armv8()) {
if (scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) {
- u32 version;
-
- if (!scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat,
- sizeof(feat), &version, sizeof(version)))
- return version;
+ ret = scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD,
+ &feat, sizeof(feat), scm_ret, sizeof(*scm_ret));
+ return ret;
}
return 0;
}
ret = scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD);
if (ret <= 0)
- return 0;
+ return -EAGAIN;
desc.args[0] = feat;
desc.arginfo = SCM_ARGS(1);
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, GET_FEAT_VERSION_CMD),
&desc);
- if (!ret)
- return desc.ret[0];
- return 0;
+ *scm_ret = desc.ret[0];
+
+ return ret;
}
EXPORT_SYMBOL(scm_get_feat_version);
#define RESTORE_SEC_CFG 2
-int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret)
+int scm_restore_sec_cfg(u32 device_id, u32 spare, u64 *scm_ret)
{
struct scm_desc desc = {0};
int ret;
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index fc481037478a..f3422440c45f 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -59,7 +59,6 @@ void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs);
void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, struct dma_attrs *attrs);
-int iommu_dma_supported(struct device *dev, u64 mask);
int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
#else
diff --git a/include/linux/habmm.h b/include/linux/habmm.h
new file mode 100644
index 000000000000..4d3a81f536d9
--- /dev/null
+++ b/include/linux/habmm.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This 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 <uapi/linux/habmm.h>
+
+#ifndef _HABMM_H
+#define _HABMM_H
+
+int32_t habmm_socket_open(int32_t *handle, uint32_t mm_ip_id,
+ uint32_t timeout, uint32_t flags);
+int32_t habmm_socket_close(int32_t handle);
+int32_t habmm_socket_send(int32_t handle, void *src_buff, uint32_t size_bytes,
+ uint32_t flags);
+int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes,
+ uint32_t timeout, uint32_t flags);
+int32_t habmm_socket_sendto(int32_t handle, void *src_buff, uint32_t size_bytes,
+ int32_t remote_handle, uint32_t flags);
+int32_t habmm_socket_recvfrom(int32_t handle, void *dst_buff,
+ uint32_t *size_bytes, uint32_t timeout,
+ int32_t *remote_handle, uint32_t flags);
+int32_t habmm_export(int32_t handle, void *buff_to_share, uint32_t size_bytes,
+ uint32_t *export_id, uint32_t flags);
+int32_t habmm_unexport(int32_t handle, uint32_t export_id, uint32_t flags);
+int32_t habmm_import(int32_t handle, void **buff_shared, uint32_t size_bytes,
+ uint32_t export_id, uint32_t flags);
+int32_t habmm_unimport(int32_t handle, uint32_t export_id, void *buff_shared,
+ uint32_t flags);
+
+#endif
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 3d912dd57c08..b041334338f9 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -528,3 +528,4 @@ header-y += ipa_qmi_service_v01.h
header-y += rmnet_ipa_fd_ioctl.h
header-y += msm_ipa.h
header-y += smcinvoke.h
+header-y += habmm.h
diff --git a/include/uapi/linux/habmm.h b/include/uapi/linux/habmm.h
new file mode 100644
index 000000000000..902bd35ee474
--- /dev/null
+++ b/include/uapi/linux/habmm.h
@@ -0,0 +1,143 @@
+#ifndef HABMM_H
+#define HABMM_H
+
+#include <linux/types.h>
+
+struct hab_send {
+ __u64 data;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 flags;
+};
+
+struct hab_recv {
+ __u64 data;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 flags;
+};
+
+struct hab_open {
+ __s32 vcid;
+ __u32 mmid;
+ __u32 timeout;
+ __u32 flags;
+};
+
+struct hab_close {
+ __s32 vcid;
+ __u32 flags;
+};
+
+struct hab_export {
+ __u64 buffer;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 exportid;
+ __u32 flags;
+};
+
+struct hab_import {
+ __u64 index;
+ __u64 kva;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 exportid;
+ __u32 flags;
+};
+
+struct hab_unexport {
+ __s32 vcid;
+ __u32 exportid;
+ __u32 flags;
+};
+
+struct hab_unimport {
+ __s32 vcid;
+ __u32 exportid;
+ __u64 kva;
+ __u32 flags;
+};
+
+#define HAB_IOC_TYPE 0x0A
+#define HAB_MAX_MSG_SIZEBYTES 0x1000
+#define HAB_MAX_EXPORT_SIZE 0x8000000
+
+#define HAB_MMID_CREATE(major, minor) ((major&0xFFFF) | ((minor&0xFF)<<16))
+
+#define MM_AUD_START 100
+#define MM_AUD_1 101
+#define MM_AUD_2 102
+#define MM_AUD_3 103
+#define MM_AUD_4 104
+#define MM_AUD_END 105
+
+#define MM_CAM_START 200
+#define MM_CAM 201
+#define MM_CAM_END 202
+
+#define MM_DISP_START 300
+#define MM_DISP_1 301
+#define MM_DISP_2 302
+#define MM_DISP_3 303
+#define MM_DISP_4 304
+#define MM_DISP_5 305
+#define MM_DISP_END 306
+
+#define MM_GFX_START 400
+#define MM_GFX 401
+#define MM_GFX_END 402
+
+#define MM_VID_START 500
+#define MM_VID 501
+#define MM_VID_END 502
+
+#define MM_MISC_START 600
+#define MM_MISC 601
+#define MM_MISC_END 602
+
+#define MM_QCPE_START 700
+#define MM_QCPE_VM1 701
+#define MM_QCPE_VM2 702
+#define MM_QCPE_VM3 703
+#define MM_QCPE_VM4 704
+#define MM_QCPE_END 705
+#define MM_ID_MAX 706
+
+#define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE 0x00000000
+#define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_DOMU 0x00000001
+#define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_MULTI_DOMUS 0x00000002
+
+#define HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING 0x00000001
+
+#define HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING 0x00000001
+
+#define HABMM_EXP_MEM_TYPE_DMA 0x00000001
+
+#define HABMM_IMPORT_FLAGS_CACHED 0x00000001
+
+#define IOCTL_HAB_SEND \
+ _IOW(HAB_IOC_TYPE, 0x2, struct hab_send)
+
+#define IOCTL_HAB_RECV \
+ _IOWR(HAB_IOC_TYPE, 0x3, struct hab_recv)
+
+#define IOCTL_HAB_VC_OPEN \
+ _IOWR(HAB_IOC_TYPE, 0x4, struct hab_open)
+
+#define IOCTL_HAB_VC_CLOSE \
+ _IOW(HAB_IOC_TYPE, 0x5, struct hab_close)
+
+#define IOCTL_HAB_VC_EXPORT \
+ _IOWR(HAB_IOC_TYPE, 0x6, struct hab_export)
+
+#define IOCTL_HAB_VC_IMPORT \
+ _IOWR(HAB_IOC_TYPE, 0x7, struct hab_import)
+
+#define IOCTL_HAB_VC_UNEXPORT \
+ _IOW(HAB_IOC_TYPE, 0x8, struct hab_unexport)
+
+#define IOCTL_HAB_VC_UNIMPORT \
+ _IOW(HAB_IOC_TYPE, 0x9, struct hab_unimport)
+
+#endif /* HABMM_H */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 4d0b992d0ba6..322fb09b8614 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -91,7 +91,11 @@
#define IPA_IOCTL_ALLOC_IPV6CT_TABLE 49
#define IPA_IOCTL_DEL_NAT_TABLE 50
#define IPA_IOCTL_DEL_IPV6CT_TABLE 51
-#define IPA_IOCTL_MAX 52
+#define IPA_IOCTL_ADD_VLAN_IFACE 52
+#define IPA_IOCTL_DEL_VLAN_IFACE 53
+#define IPA_IOCTL_ADD_L2TP_VLAN_MAPPING 54
+#define IPA_IOCTL_DEL_L2TP_VLAN_MAPPING 55
+#define IPA_IOCTL_MAX 56
/**
* max size of the header to be inserted
@@ -435,7 +439,16 @@ enum ipa_ssr_event {
IPA_SSR_EVENT_MAX
};
-#define IPA_EVENT_MAX_NUM ((int)IPA_SSR_EVENT_MAX)
+enum ipa_vlan_l2tp_event {
+ ADD_VLAN_IFACE = IPA_SSR_EVENT_MAX,
+ DEL_VLAN_IFACE,
+ ADD_L2TP_VLAN_MAPPING,
+ DEL_L2TP_VLAN_MAPPING,
+ IPA_VLAN_L2TP_EVENT_MAX,
+};
+
+#define IPA_EVENT_MAX_NUM (IPA_VLAN_L2TP_EVENT_MAX)
+#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM)
/**
* enum ipa_rm_resource_name - IPA RM clients identification names
@@ -1448,6 +1461,30 @@ struct ipa_ioc_nat_pdn_entry {
};
/**
+ * struct ipa_ioc_vlan_iface_info - add vlan interface
+ * @name: interface name
+ * @vlan_id: VLAN ID
+ */
+struct ipa_ioc_vlan_iface_info {
+ char name[IPA_RESOURCE_NAME_MAX];
+ uint8_t vlan_id;
+};
+
+/**
+ * struct ipa_ioc_l2tp_vlan_mapping_info - l2tp->vlan mapping info
+ * @iptype: l2tp tunnel IP type
+ * @l2tp_iface_name: l2tp interface name
+ * @l2tp_session_id: l2tp session id
+ * @vlan_iface_name: vlan interface name
+ */
+struct ipa_ioc_l2tp_vlan_mapping_info {
+ enum ipa_ip_type iptype;
+ char l2tp_iface_name[IPA_RESOURCE_NAME_MAX];
+ uint8_t l2tp_session_id;
+ char vlan_iface_name[IPA_RESOURCE_NAME_MAX];
+};
+
+/**
* struct ipa_msg_meta - Format of the message meta-data.
* @msg_type: the type of the message
* @rsvd: reserved bits for future use.
@@ -1742,6 +1779,21 @@ enum ipacm_client_enum {
IPA_IOCTL_GET_HW_VERSION, \
enum ipa_hw_type *)
+#define IPA_IOC_ADD_VLAN_IFACE _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_ADD_VLAN_IFACE, \
+ struct ipa_ioc_vlan_iface_info *)
+
+#define IPA_IOC_DEL_VLAN_IFACE _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_DEL_VLAN_IFACE, \
+ struct ipa_ioc_vlan_iface_info *)
+
+#define IPA_IOC_ADD_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_ADD_L2TP_VLAN_MAPPING, \
+ struct ipa_ioc_l2tp_vlan_mapping_info *)
+
+#define IPA_IOC_DEL_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_DEL_L2TP_VLAN_MAPPING, \
+ struct ipa_ioc_l2tp_vlan_mapping_info *)
/*
* unique magic number of the Tethering bridge ioctls
*/
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index eb650d19a97c..629a9c3d91db 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -166,7 +166,7 @@ config SND_SOC_EXT_CODEC
config SND_SOC_MSM8996
tristate "SoC Machine driver for MSM8996 boards"
- depends on ARCH_MSM8996
+ depends on ARCH_MSM8996 || MSM_GVM_QUIN
select SND_SOC_COMPRESS
select SND_SOC_QDSP6V2
select SND_SOC_MSM_STUB
@@ -176,7 +176,7 @@ config SND_SOC_MSM8996
select MSM_QDSP6V2_CODECS
select SND_SOC_WCD9335
select SND_SOC_WSA881X
- select SND_SOC_MSM_HDMI_CODEC_RX
+ select SND_SOC_MSM_HDMI_CODEC_RX if ARCH_MSM8996
select DTS_SRS_TM
select QTI_PP
select QTI_PP_AUDIOSPHERE