aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohit Sharma <smohit@codeaurora.org>2019-09-02 16:58:34 +0530
committerMohit Sharma <smohit@codeaurora.org>2019-09-02 16:58:49 +0530
commit845c507fbf9cc1951916f568cb184ded98481b03 (patch)
tree77313fc1e5fb39b0d29568a9eea12f8e83cec5e9
parent18b0267621bda4b3823ecad8f146d17ea42e4713 (diff)
parent76eabecf9f42c0e4ec3c74e66c64627708787437 (diff)
Merge commit '76eabecf9f42c0e4ec3c74e66c64627708787437' into HEADLA.UM.7.11.r1-03500-NICOBAR.0
Change-Id: I1f4772c7aa9b40fa0c50027ec86d5d0946ab29ec Signed-off-by: Mohit Sharma <smohit@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/gpu/adreno-iommu.txt2
-rw-r--r--arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi5
-rw-r--r--arch/arm64/boot/dts/qcom/trinket-gpu.dtsi1
-rw-r--r--arch/arm64/boot/dts/qcom/trinket.dtsi24
-rw-r--r--arch/arm64/include/asm/io.h10
-rw-r--r--drivers/char/adsprpc.c51
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c24
-rw-r--r--drivers/gpu/msm/kgsl_iommu.h4
-rw-r--r--drivers/iommu/arm-smmu-debug.c57
-rw-r--r--drivers/iommu/arm-smmu-debug.h47
-rw-r--r--drivers/iommu/arm-smmu-v3.c10
-rw-r--r--drivers/iommu/arm-smmu.c367
-rw-r--r--drivers/iommu/dma-mapping-fast.c1
-rw-r--r--drivers/iommu/io-pgtable.c1
-rw-r--r--drivers/iommu/ipmmu-vmsa.c10
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c4
-rw-r--r--drivers/misc/qseecom.c30
-rw-r--r--drivers/power/supply/qcom/qpnp-qg.c6
-rw-r--r--drivers/staging/android/ion/ion.c5
19 files changed, 589 insertions, 70 deletions
diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
index c679fe670ce5..df29ef5d26a1 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -36,6 +36,8 @@ Optional properties:
for secure buffer allocation
- qcom,secure_align_mask: A mask for determining how secure buffers need to
be aligned
+- qcom,unmap_fast : A boolean specifying if iommu unmap fast is supported on
+ this target.
- List of sub nodes, one for each of the translation context banks supported.
The driver uses the names of these nodes to determine how they are used,
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi
index 685ff615f8bd..f9cb196a2c2f 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi
@@ -56,6 +56,7 @@
<0x59c2200 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x0 0x400>;
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
};
};
@@ -154,6 +155,7 @@
<0xc782200 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x0 0x400>;
+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
qcom,msm-bus,name = "apps_smmu";
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,active-only;
@@ -179,6 +181,7 @@
<0xc782208 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x400 0x400>;
+ interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc>;
qcom,msm-bus,name = "apps_smmu";
@@ -206,6 +209,7 @@
<0xc782210 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0x800 0x400>;
+ interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc>;
qcom,msm-bus,name = "apps_smmu";
@@ -233,6 +237,7 @@
<0xc782218 0x8>;
reg-names = "base", "status-reg";
qcom,stream-id-range = <0xc00 0x400>;
+ interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_turing_mmu_tbu0_gdsc>;
qcom,msm-bus,name = "apps_smmu";
diff --git a/arch/arm64/boot/dts/qcom/trinket-gpu.dtsi b/arch/arm64/boot/dts/qcom/trinket-gpu.dtsi
index 382f052e48e5..54ab510871ea 100644
--- a/arch/arm64/boot/dts/qcom/trinket-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/trinket-gpu.dtsi
@@ -261,6 +261,7 @@
"alt_mem_iface_clk", "smmu_vote";
qcom,retention;
+ qcom,unmap_fast;
qcom,hyp_secure_alloc;
gfx3d_user: gfx3d_user {
diff --git a/arch/arm64/boot/dts/qcom/trinket.dtsi b/arch/arm64/boot/dts/qcom/trinket.dtsi
index 1ed2f299dd75..7174b55e2378 100644
--- a/arch/arm64/boot/dts/qcom/trinket.dtsi
+++ b/arch/arm64/boot/dts/qcom/trinket.dtsi
@@ -87,7 +87,7 @@
};
L1_TLB_0: l1-tlb {
- qcom,dump-size = <0x2800>;
+ qcom,dump-size = <0x2000>;
};
};
@@ -115,7 +115,7 @@
};
L1_TLB_1: l1-tlb {
- qcom,dump-size = <0x2800>;
+ qcom,dump-size = <0x2000>;
};
};
@@ -143,7 +143,7 @@
};
L1_TLB_2: l1-tlb {
- qcom,dump-size = <0x2800>;
+ qcom,dump-size = <0x2000>;
};
};
@@ -171,7 +171,7 @@
};
L1_TLB_3: l1-tlb {
- qcom,dump-size = <0x2800>;
+ qcom,dump-size = <0x2000>;
};
};
@@ -1437,35 +1437,35 @@
};
qcom,l1_tlb_dump0 {
qcom,dump-node = <&L1_TLB_0>;
- qcom,dump-id = <0x20>;
+ qcom,dump-id = <0x120>;
};
qcom,l1_tlb_dump1 {
qcom,dump-node = <&L1_TLB_1>;
- qcom,dump-id = <0x21>;
+ qcom,dump-id = <0x121>;
};
qcom,l1_tlb_dump2 {
qcom,dump-node = <&L1_TLB_2>;
- qcom,dump-id = <0x22>;
+ qcom,dump-id = <0x122>;
};
qcom,l1_tlb_dump3 {
qcom,dump-node = <&L1_TLB_3>;
- qcom,dump-id = <0x23>;
+ qcom,dump-id = <0x123>;
};
qcom,l1_tlb_dump100 {
qcom,dump-node = <&L1_TLB_100>;
- qcom,dump-id = <0x24>;
+ qcom,dump-id = <0x124>;
};
qcom,l1_tlb_dump101 {
qcom,dump-node = <&L1_TLB_101>;
- qcom,dump-id = <0x25>;
+ qcom,dump-id = <0x125>;
};
qcom,l1_tlb_dump102 {
qcom,dump-node = <&L1_TLB_102>;
- qcom,dump-id = <0x26>;
+ qcom,dump-id = <0x126>;
};
qcom,l1_tlb_dump103 {
qcom,dump-node = <&L1_TLB_103>;
- qcom,dump-id = <0x27>;
+ qcom,dump-id = <0x127>;
};
};
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index d87b9ebac9db..52c78d77d472 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -107,10 +107,11 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr)
#define __raw_write_logged(v, a, _t) ({ \
int _ret; \
- void *_addr = (void *)(a); \
+ volatile void __iomem *_a = (a); \
+ void *_addr = (void __force *)(_a); \
_ret = uncached_logk(LOGK_WRITEL, _addr); \
ETB_WAYPOINT; \
- __raw_write##_t##_no_log((v), _addr); \
+ __raw_write##_t##_no_log((v), _a); \
if (_ret) \
LOG_BARRIER; \
})
@@ -122,11 +123,12 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr)
#define __raw_read_logged(a, _l, _t) ({ \
_t __a; \
- void *_addr = (void *)(a); \
+ const volatile void __iomem *_a = (a); \
+ void *_addr = (void __force *)(_a); \
int _ret; \
_ret = uncached_logk(LOGK_READL, _addr); \
ETB_WAYPOINT; \
- __a = __raw_read##_l##_no_log(_addr); \
+ __a = __raw_read##_l##_no_log(_a); \
if (_ret) \
LOG_BARRIER; \
__a; \
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index c57bd0390187..cbefe9118ed3 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -377,7 +377,7 @@ struct fastrpc_file {
int pd;
char *spdname;
int file_close;
- int dsp_process_init;
+ int dsp_proc_init;
struct fastrpc_apps *apps;
struct hlist_head perf;
struct dentry *debugfs_file;
@@ -1899,12 +1899,13 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode,
}
}
- VERIFY(err, fl->sctx != NULL);
- if (err)
- goto bail;
- VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS);
- if (err)
+ VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS && fl->sctx != NULL);
+ if (err) {
+ pr_err("adsprpc: ERROR: %s: user application %s domain is not set\n",
+ __func__, current->comm);
+ err = -EBADR;
goto bail;
+ }
if (!kernel) {
VERIFY(err, 0 == context_restore_interrupted(fl, inv,
@@ -2240,7 +2241,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
err = -ENOTTY;
goto bail;
}
- fl->dsp_process_init = 1;
+ fl->dsp_proc_init = 1;
bail:
kfree(proc_name);
if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC))
@@ -2300,7 +2301,7 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl)
ioctl.crc = NULL;
VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl,
FASTRPC_MODE_PARALLEL, 1, &ioctl)));
- if (err && fl->dsp_process_init)
+ if (err && fl->dsp_proc_init)
pr_err("adsprpc: %s: releasing DSP process failed for %s, returned 0x%x",
__func__, current->comm, err);
bail:
@@ -2591,6 +2592,13 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
struct fastrpc_buf *rbuf = NULL, *free = NULL;
struct hlist_node *n;
+ VERIFY(err, fl->dsp_proc_init == 1);
+ if (err) {
+ pr_err("adsprpc: ERROR: %s: user application %s trying to unmap without initialization\n",
+ __func__, current->comm);
+ err = -EBADR;
+ goto bail;
+ }
mutex_lock(&fl->internal_map_mutex);
spin_lock(&fl->hlock);
@@ -2646,6 +2654,13 @@ static int fastrpc_internal_munmap_fd(struct fastrpc_file *fl,
VERIFY(err, (fl && ud));
if (err)
goto bail;
+ VERIFY(err, fl->dsp_proc_init == 1);
+ if (err) {
+ pr_err("adsprpc: ERROR: %s: user application %s trying to unmap without initialization\n",
+ __func__, current->comm);
+ err = -EBADR;
+ goto bail;
+ }
mutex_lock(&fl->map_mutex);
if (fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) {
pr_err("adsprpc: mapping not found to unmap fd 0x%x, va 0x%llx, len 0x%x\n",
@@ -2672,6 +2687,13 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
uintptr_t raddr = 0;
int err = 0;
+ VERIFY(err, fl->dsp_proc_init == 1);
+ if (err) {
+ pr_err("adsprpc: ERROR: %s: user application %s trying to map without initialization\n",
+ __func__, current->comm);
+ err = -EBADR;
+ goto bail;
+ }
mutex_lock(&fl->internal_map_mutex);
if (ud->flags == ADSP_MMAP_ADD_PAGES) {
if (ud->vaddrin) {
@@ -3202,13 +3224,14 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
int cid, err = 0;
- VERIFY(err, fl && fl->sctx);
- if (err)
+ VERIFY(err, fl && fl->sctx && fl->cid >= 0 && fl->cid < NUM_CHANNELS);
+ if (err) {
+ pr_err("adsprpc: ERROR: %s: user application %s domain is not set\n",
+ __func__, current->comm);
+ err = -EBADR;
return err;
+ }
cid = fl->cid;
- VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
- if (err)
- return err;
mutex_lock(&me->channel[cid].rpmsg_mutex);
VERIFY(err, NULL != me->channel[cid].rpdev);
@@ -3305,7 +3328,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
fl->debugfs_file = debugfs_file;
memset(&fl->perf, 0, sizeof(fl->perf));
fl->qos_request = 0;
- fl->dsp_process_init = 0;
+ fl->dsp_proc_init = 0;
filp->private_data = fl;
mutex_init(&fl->internal_map_mutex);
mutex_init(&fl->map_mutex);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 927406ebfa65..4afbd3de988b 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -405,11 +405,19 @@ static int _iommu_unmap_sync_pc(struct kgsl_pagetable *pt,
uint64_t addr, uint64_t size)
{
struct kgsl_iommu_pt *iommu_pt = pt->priv;
+ struct kgsl_iommu *iommu = _IOMMU_PRIV(pt->mmu);
size_t unmapped = 0;
_iommu_sync_mmu_pc(true);
- unmapped = iommu_unmap(iommu_pt->domain, addr, size);
+ /*
+ * Take iommu unmap fast path if CX GDSC is in OFF state.
+ */
+ if (iommu->vddcx_regulator &&
+ (!regulator_is_enabled(iommu->vddcx_regulator)))
+ unmapped = iommu_unmap_fast(iommu_pt->domain, addr, size);
+ else
+ unmapped = iommu_unmap(iommu_pt->domain, addr, size);
_iommu_sync_mmu_pc(false);
@@ -2679,6 +2687,7 @@ static int _kgsl_iommu_probe(struct kgsl_device *device,
u32 reg_val[2];
int i = 0;
struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct device_node *child;
struct platform_device *pdev = of_find_device_by_node(node);
@@ -2725,6 +2734,19 @@ static int _kgsl_iommu_probe(struct kgsl_device *device,
device->mmu.features |= kgsl_iommu_features[i].bit;
}
+ /*
+ * Try to preserve the SMMU regulator if HW can support
+ * unmap fast path.
+ */
+ if (of_property_read_bool(node, "qcom,unmap_fast")) {
+ for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
+ if (!strcmp(pwr->regulators[i].name, "vddcx")) {
+ iommu->vddcx_regulator =
+ pwr->regulators[i].reg;
+ }
+ }
+ }
+
if (of_property_read_u32(node, "qcom,micro-mmu-control",
&iommu->micro_mmu_ctrl))
iommu->micro_mmu_ctrl = UINT_MAX;
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index a96f34b808ec..844aeec104f6 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -126,6 +126,7 @@ struct kgsl_iommu_context {
* @setstate: Scratch GPU memory for IOMMU operations
* @clk_enable_count: The ref count of clock enable calls
* @clks: Array of pointers to IOMMU clocks
+ * @vddcx_regulator: Handle to IOMMU regulator
* @micro_mmu_ctrl: GPU register offset of this glob al register
* @smmu_info: smmu info used in a5xx preemption
* @protect: register protection settings for the iommu.
@@ -140,6 +141,7 @@ struct kgsl_iommu {
struct kgsl_memdesc setstate;
atomic_t clk_enable_count;
struct clk *clks[KGSL_IOMMU_MAX_CLKS];
+ struct regulator *vddcx_regulator;
unsigned int micro_mmu_ctrl;
struct kgsl_memdesc smmu_info;
unsigned int version;
diff --git a/drivers/iommu/arm-smmu-debug.c b/drivers/iommu/arm-smmu-debug.c
index fde0710be8e2..ad0fbf0c98c6 100644
--- a/drivers/iommu/arm-smmu-debug.c
+++ b/drivers/iommu/arm-smmu-debug.c
@@ -231,3 +231,60 @@ void arm_smmu_debug_dump_tcu_testbus(struct device *dev, void __iomem *base,
arm_smmu_debug_tcu_testbus_select(base, tcu_base,
CLK_TESTBUS, READ, 0));
}
+
+void arm_smmu_debug_set_tnx_tcr_cntl(void __iomem *tbu_base, u64 val)
+{
+ writel_relaxed(val, tbu_base + ARM_SMMU_TNX_TCR_CNTL);
+}
+
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl(void __iomem *tbu_base)
+{
+ return readl_relaxed(tbu_base + ARM_SMMU_TNX_TCR_CNTL);
+}
+
+void arm_smmu_debug_set_mask_and_match(void __iomem *tbu_base, u64 sel,
+ u64 mask, u64 match)
+{
+ writeq_relaxed(mask, tbu_base + ARM_SMMU_CAPTURE1_MASK(sel));
+ writeq_relaxed(match, tbu_base + ARM_SMMU_CAPTURE1_MATCH(sel));
+}
+
+void arm_smmu_debug_get_mask_and_match(void __iomem *tbu_base, u64 *mask,
+ u64 *match)
+{
+ int i;
+
+ for (i = 0; i < NO_OF_MASK_AND_MATCH; ++i) {
+ mask[i] = readq_relaxed(tbu_base +
+ ARM_SMMU_CAPTURE1_MASK(i+1));
+ match[i] = readq_relaxed(tbu_base +
+ ARM_SMMU_CAPTURE1_MATCH(i+1));
+ }
+}
+
+void arm_smmu_debug_get_capture_snapshot(void __iomem *tbu_base,
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT])
+{
+ int valid, i, j;
+
+ valid = readl_relaxed(tbu_base + APPS_SMMU_TNX_TCR_CNTL_2);
+
+ for (i = 0; i < NO_OF_CAPTURE_POINTS ; ++i) {
+ if (valid & (1 << i))
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j)
+ snapshot[i][j] = readq_relaxed(tbu_base +
+ ARM_SMMU_CAPTURE_SNAPSHOT(i, j));
+ else
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j)
+ snapshot[i][j] = 0xdededede;
+ }
+}
+
+void arm_smmu_debug_clear_intr_and_validbits(void __iomem *tbu_base)
+{
+ int val = 0;
+
+ val |= INTR_CLR;
+ val |= RESET_VALID;
+ writel_relaxed(val, tbu_base + ARM_SMMU_TNX_TCR_CNTL);
+}
diff --git a/drivers/iommu/arm-smmu-debug.h b/drivers/iommu/arm-smmu-debug.h
index 6b7843a54892..399cab64c8bc 100644
--- a/drivers/iommu/arm-smmu-debug.h
+++ b/drivers/iommu/arm-smmu-debug.h
@@ -55,6 +55,18 @@ enum testbus_ops {
TESTBUS_OUTPUT,
};
+#define ARM_SMMU_TNX_TCR_CNTL 0x130
+#define ARM_SMMU_CAPTURE1_MASK(i) (0x100 + (0x8)*(i-1))
+#define ARM_SMMU_CAPTURE1_MATCH(i) (0x118 + (0x8)*(i-1))
+#define ARM_SMMU_CAPTURE_SNAPSHOT(i, j) ((0x138 + (0x10)*i) + j*0x8)
+#define APPS_SMMU_TNX_TCR_CNTL_2 0x178
+
+#define NO_OF_MASK_AND_MATCH 0x3
+#define NO_OF_CAPTURE_POINTS 0x4
+#define REGS_PER_CAPTURE_POINT 0x2
+#define INTR_CLR (1 << 0)
+#define RESET_VALID (1 << 7)
+
#ifdef CONFIG_ARM_SMMU
u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
@@ -71,7 +83,16 @@ void arm_smmu_debug_dump_tbu_testbus(struct device *dev, void __iomem *tbu_base,
u32 testbus_version);
void arm_smmu_debug_dump_tcu_testbus(struct device *dev, void __iomem *base,
void __iomem *tcu_base, int tcu_testbus_sel);
-
+void arm_smmu_debug_set_tnx_tcr_cntl(void __iomem *tbu_base, u64 val);
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl(void __iomem *tbu_base);
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl_2(void __iomem *tbu_base);
+void arm_smmu_debug_set_mask_and_match(void __iomem *tbu_base, u64 sel,
+ u64 mask, u64 match);
+void arm_smmu_debug_get_mask_and_match(void __iomem *tbu_base,
+ u64 *mask, u64 *match);
+void arm_smmu_debug_get_capture_snapshot(void __iomem *tbu_base,
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT]);
+void arm_smmu_debug_clear_intr_and_validbits(void __iomem *tbu_base);
#else
static inline u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
void __iomem *tcu_base, u32 testbus_version, bool write,
@@ -100,4 +121,28 @@ static inline void arm_smmu_debug_dump_tcu_testbus(struct device *dev,
int tcu_testbus_sel)
{
}
+void arm_smmu_debug_set_tnx_tcr_cntl(void __iomem *tbu_base, u64 val)
+{
+}
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl(void __iomem *tbu_base)
+{
+}
+unsigned long arm_smmu_debug_get_tnx_tcr_cntl_2(void __iomem *tbu_base)
+{
+}
+void arm_smmu_debug_set_mask_and_match(void __iomem *tbu_base, u64 sel,
+ u64 mask, u64 match)
+{
+}
+void arm_smmu_debug_get_mask_and_match(void __iomem *tbu_base,
+ u64 *mask, u64 *match)
+{
+}
+void arm_smmu_debug_get_capture_snapshot(void __iomem *tbu_base,
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT])
+{
+}
+void arm_smmu_debug_clear_intr_and_validbits(void __iomem *tbu_base)
+{
+}
#endif
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 56135f4525ca..1f24df6aed4d 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1753,6 +1753,14 @@ arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
return ops->unmap(ops, iova, size);
}
+static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
+{
+ struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+
+ if (smmu)
+ __arm_smmu_tlb_sync(smmu);
+}
+
static phys_addr_t
arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
{
@@ -1973,6 +1981,8 @@ static struct iommu_ops arm_smmu_ops = {
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
.map_sg = default_iommu_map_sg,
+ .flush_iotlb_all = arm_smmu_iotlb_sync,
+ .iotlb_sync = arm_smmu_iotlb_sync,
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
.remove_device = arm_smmu_remove_device,
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index aca5232c5fac..e870b6496dc4 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -353,6 +353,7 @@ static int tbu_testbus_sel = TBU_TESTBUS_SEL_ALL;
static int tcu_testbus_sel = TCU_TESTBUS_SEL_ALL;
static struct dentry *debugfs_testbus_dir;
static DEFINE_SPINLOCK(testbus_lock);
+static struct dentry *debugfs_capturebus_dir;
module_param_named(tcu_testbus_sel, tcu_testbus_sel, int, 0644);
module_param_named(tbu_testbus_sel, tbu_testbus_sel, int, 0644);
@@ -374,7 +375,7 @@ struct arm_smmu_domain {
struct arm_smmu_device *smmu;
struct device *dev;
struct io_pgtable_ops *pgtbl_ops;
-
+ const struct iommu_gather_ops *tlb_ops;
struct arm_smmu_cfg cfg;
enum arm_smmu_domain_stage stage;
struct mutex init_mutex; /* Protects smmu pointer */
@@ -430,6 +431,7 @@ struct qsmmuv500_tbu_device {
/* Protects halt count */
spinlock_t halt_lock;
u32 halt_count;
+ unsigned int *irqs;
};
static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0);
@@ -1244,21 +1246,44 @@ static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu)
spin_unlock_irqrestore(&smmu->global_sync_lock, flags);
}
+static void arm_smmu_tlb_inv_context_s1(void *cookie);
+
static void arm_smmu_tlb_sync_context(void *cookie)
{
struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct device *dev = smmu_domain->dev;
+ struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
void __iomem *base = ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
unsigned long flags;
+ size_t ret;
+ bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
+ ktime_t cur = ktime_get();
+
+ ret = arm_smmu_domain_power_on(&smmu_domain->domain,
+ smmu_domain->smmu);
+ if (ret)
+ return;
+
+ trace_tlbi_start(dev, 0);
+
+ if (!use_tlbiall)
+ writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
+ else
+ writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
spin_lock_irqsave(&smmu_domain->sync_lock, flags);
if (__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC,
base + ARM_SMMU_CB_TLBSTATUS, smmu_domain))
dev_err_ratelimited(smmu->dev,
- "TLB sync on cb%d failed for device %s\n",
- smmu_domain->cfg.cbndx,
- dev_name(smmu_domain->dev));
+ "TLB sync on cb%d failed for device %s\n",
+ smmu_domain->cfg.cbndx,
+ dev_name(smmu_domain->dev));
spin_unlock_irqrestore(&smmu_domain->sync_lock, flags);
+
+ trace_tlbi_end(dev, ktime_us_delta(ktime_get(), cur));
+
+ arm_smmu_domain_power_off(&smmu_domain->domain, smmu_domain->smmu);
}
static void arm_smmu_tlb_sync_vmid(void *cookie)
@@ -1270,23 +1295,7 @@ static void arm_smmu_tlb_sync_vmid(void *cookie)
static void arm_smmu_tlb_inv_context_s1(void *cookie)
{
- struct arm_smmu_domain *smmu_domain = cookie;
- struct device *dev = smmu_domain->dev;
- struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- struct arm_smmu_device *smmu = smmu_domain->smmu;
- void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx);
- bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
- ktime_t cur = ktime_get();
-
- trace_tlbi_start(dev, 0);
-
- if (!use_tlbiall)
- writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
- else
- writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
-
- arm_smmu_tlb_sync_context(cookie);
- trace_tlbi_end(dev, ktime_us_delta(ktime_get(), cur));
+ return;
}
static void arm_smmu_tlb_inv_context_s2(void *cookie)
@@ -1577,6 +1586,7 @@ static phys_addr_t arm_smmu_verify_fault(struct iommu_domain *domain,
phys = arm_smmu_iova_to_phys_hard(domain, iova);
smmu_domain->pgtbl_cfg.tlb->tlb_flush_all(smmu_domain);
+ smmu_domain->pgtbl_cfg.tlb->tlb_sync(smmu_domain);
phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
if (phys != phys_post_tlbiall) {
@@ -1992,7 +2002,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
enum io_pgtable_fmt fmt;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- const struct iommu_gather_ops *tlb_ops;
bool is_fast = smmu_domain->attributes & (1 << DOMAIN_ATTR_FAST);
unsigned long quirks = 0;
bool dynamic;
@@ -2092,7 +2101,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
ias = min(ias, 32UL);
oas = min(oas, 32UL);
}
- tlb_ops = &arm_smmu_s1_tlb_ops;
+ smmu_domain->tlb_ops = &arm_smmu_s1_tlb_ops;
break;
case ARM_SMMU_DOMAIN_NESTED:
/*
@@ -2112,9 +2121,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
oas = min(oas, 40UL);
}
if (smmu->version == ARM_SMMU_V2)
- tlb_ops = &arm_smmu_s2_tlb_ops_v2;
+ smmu_domain->tlb_ops = &arm_smmu_s2_tlb_ops_v2;
else
- tlb_ops = &arm_smmu_s2_tlb_ops_v1;
+ smmu_domain->tlb_ops = &arm_smmu_s2_tlb_ops_v1;
break;
default:
ret = -EINVAL;
@@ -2136,7 +2145,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
quirks |= IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE;
if (arm_smmu_is_slave_side_secure(smmu_domain))
- tlb_ops = &msm_smmu_gather_ops;
+ smmu_domain->tlb_ops = &msm_smmu_gather_ops;
ret = arm_smmu_alloc_cb(domain, smmu, dev);
if (ret < 0)
@@ -2152,7 +2161,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
.sec_id = smmu->sec_id,
.cbndx = cfg->cbndx,
},
- .tlb = tlb_ops,
+ .tlb = smmu_domain->tlb_ops,
.iommu_dev = smmu->dev,
};
fmt = ARM_MSM_SECURE;
@@ -2162,7 +2171,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
.pgsize_bitmap = smmu->pgsize_bitmap,
.ias = ias,
.oas = oas,
- .tlb = tlb_ops,
+ .tlb = smmu_domain->tlb_ops,
.iommu_dev = smmu->dev,
};
}
@@ -2617,6 +2626,7 @@ static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
/* Ensure there are no stale mappings for this context bank */
tlb->tlb_flush_all(smmu_domain);
+ tlb->tlb_sync(smmu_domain);
}
static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
@@ -2960,17 +2970,12 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
if (arm_smmu_is_slave_side_secure(smmu_domain))
return msm_secure_smmu_unmap(domain, iova, size);
- ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
- if (ret)
- return ret;
-
arm_smmu_secure_domain_lock(smmu_domain);
spin_lock_irqsave(&smmu_domain->cb_lock, flags);
ret = ops->unmap(ops, iova, size);
spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
- arm_smmu_domain_power_off(domain, smmu_domain->smmu);
/*
* While splitting up block mappings, we might allocate page table
* memory during unmap, so the vmids needs to be assigned to the
@@ -3116,6 +3121,14 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
return ret;
}
+static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+ if (smmu_domain->tlb_ops)
+ smmu_domain->tlb_ops->tlb_sync(smmu_domain);
+}
+
/*
* This function can sleep, and cannot be called from atomic context. Will
* power on register block if required. This restriction does not apply to the
@@ -3925,6 +3938,8 @@ static struct iommu_ops arm_smmu_ops = {
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
.map_sg = arm_smmu_map_sg,
+ .flush_iotlb_all = arm_smmu_iotlb_sync,
+ .iotlb_sync = arm_smmu_iotlb_sync,
.iova_to_phys = arm_smmu_iova_to_phys,
.iova_to_phys_hard = arm_smmu_iova_to_phys_hard,
.add_device = arm_smmu_add_device,
@@ -5980,6 +5995,260 @@ err:
return 0;
}
+static ssize_t arm_smmu_debug_capturebus_snapshot_read(struct file *file,
+ char __user *ubuf, size_t count, loff_t *offset)
+{
+ struct qsmmuv500_tbu_device *tbu = file->private_data;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT];
+ char buf[400];
+ ssize_t retval;
+ size_t buflen;
+ int buf_len = sizeof(buf);
+ int i, j;
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, buf_len);
+
+ arm_smmu_power_on(smmu->pwr);
+ arm_smmu_power_on(tbu->pwr);
+
+ arm_smmu_debug_get_capture_snapshot(tbu_base, snapshot);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+
+ for (i = 0; i < NO_OF_CAPTURE_POINTS ; ++i) {
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j) {
+ snprintf(buf + strlen(buf), buf_len - strlen(buf),
+ "Capture_%d_Snapshot_%d : 0x%0llx\n",
+ i+1, j+1, snapshot[i][j]);
+ }
+ }
+
+ buflen = min(count, strlen(buf));
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err_ratelimited("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1;
+ retval = buflen;
+ }
+
+ return retval;
+}
+static const struct file_operations arm_smmu_debug_capturebus_snapshot_fops = {
+ .open = simple_open,
+ .read = arm_smmu_debug_capturebus_snapshot_read,
+};
+
+static ssize_t arm_smmu_debug_capturebus_config_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *offset)
+{
+ struct qsmmuv500_tbu_device *tbu = file->private_data;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ char *comma1, *comma2;
+ char buf[100];
+ u64 sel, mask, match, val;
+
+ if (count >= 100) {
+ pr_err_ratelimited("Input too large\n");
+ goto invalid_format;
+ }
+
+ memset(buf, 0, 100);
+
+ if (copy_from_user(buf, ubuf, count)) {
+ pr_err_ratelimited("Couldn't copy from user\n");
+ return -EFAULT;
+ }
+
+ comma1 = strnchr(buf, count, ',');
+ if (!comma1)
+ goto invalid_format;
+
+ *comma1 = '\0';
+
+ if (kstrtou64(buf, 0, &sel))
+ goto invalid_format;
+
+ if (sel > 4) {
+ goto invalid_format;
+ } else if (sel == 4) {
+ if (kstrtou64(comma1 + 1, 0, &val))
+ goto invalid_format;
+ goto program_capturebus;
+ }
+
+ comma2 = strnchr(comma1 + 1, count, ',');
+ if (!comma2)
+ goto invalid_format;
+
+ /* split up the words */
+ *comma2 = '\0';
+
+ if (kstrtou64(comma1 + 1, 0, &mask))
+ goto invalid_format;
+
+ if (kstrtou64(comma2 + 1, 0, &match))
+ goto invalid_format;
+
+program_capturebus:
+ arm_smmu_power_on(smmu->pwr);
+ arm_smmu_power_on(tbu->pwr);
+
+ if (sel == 4)
+ arm_smmu_debug_set_tnx_tcr_cntl(tbu_base, val);
+ else
+ arm_smmu_debug_set_mask_and_match(tbu_base, sel, mask, match);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+ return count;
+
+invalid_format:
+ pr_err_ratelimited("Invalid format. Expected: <1/2/3,Mask,Match> (or) <4,TNX_TCR_CNTL>>\n");
+ return -EINVAL;
+}
+static ssize_t arm_smmu_debug_capturebus_config_read(struct file *file,
+ char __user *ubuf, size_t count, loff_t *offset)
+{
+ struct qsmmuv500_tbu_device *tbu = file->private_data;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ unsigned long val;
+ u64 mask[NO_OF_MASK_AND_MATCH], match[NO_OF_MASK_AND_MATCH];
+ char buf[400];
+ ssize_t retval;
+ size_t buflen;
+ int buf_len = sizeof(buf);
+ int i;
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, buf_len);
+
+ arm_smmu_power_on(smmu->pwr);
+ arm_smmu_power_on(tbu->pwr);
+
+ arm_smmu_debug_get_mask_and_match(tbu_base,
+ mask, match);
+ val = arm_smmu_debug_get_tnx_tcr_cntl(tbu_base);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+
+ for (i = 0; i < NO_OF_MASK_AND_MATCH; ++i) {
+ snprintf(buf + strlen(buf), buf_len - strlen(buf),
+ "Mask_%d : 0x%0llx\t", i+1, mask[i]);
+ snprintf(buf + strlen(buf), buf_len - strlen(buf),
+ "Match_%d : 0x%0llx\n", i+1, match[i]);
+ }
+ snprintf(buf + strlen(buf), buf_len - strlen(buf), "0x%0x\n", val);
+
+ buflen = min(count, strlen(buf));
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err_ratelimited("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1;
+ retval = buflen;
+ }
+
+ return retval;
+}
+
+static const struct file_operations arm_smmu_debug_capturebus_config_fops = {
+ .open = simple_open,
+ .write = arm_smmu_debug_capturebus_config_write,
+ .read = arm_smmu_debug_capturebus_config_read,
+};
+
+static int qsmmuv500_capturebus_init(struct qsmmuv500_tbu_device *tbu)
+{
+ struct dentry *capturebus_dir;
+
+ if (!debugfs_capturebus_dir) {
+ debugfs_capturebus_dir = debugfs_create_dir(
+ "capturebus", iommu_debugfs_top);
+ if (!debugfs_capturebus_dir) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus debugfs directory\n");
+ return -ENODEV;
+ }
+ }
+ capturebus_dir = debugfs_create_dir(dev_name(tbu->dev),
+ debugfs_capturebus_dir);
+ if (!capturebus_dir) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus/%s debugfs directory\n",
+ dev_name(tbu->dev));
+ goto err;
+ }
+
+ if (!debugfs_create_file("config", 0400, capturebus_dir, tbu,
+ &arm_smmu_debug_capturebus_config_fops)) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus/%s/config debugfs file\n",
+ dev_name(tbu->dev));
+ goto err_rmdir;
+ }
+
+ if (!debugfs_create_file("snapshot", 0400, capturebus_dir, tbu,
+ &arm_smmu_debug_capturebus_snapshot_fops)) {
+ pr_err_ratelimited("Couldn't create iommu/capturebus/%s/snapshot debugfs file\n",
+ dev_name(tbu->dev));
+ goto err_rmdir;
+ }
+ return 0;
+err_rmdir:
+ debugfs_remove_recursive(capturebus_dir);
+err:
+ return 0;
+}
+
+static irqreturn_t arm_smmu_debug_capture_bus_match(int irq, void *dev)
+{
+ struct qsmmuv500_tbu_device *tbu = dev;
+ struct arm_smmu_device *smmu = tbu->smmu;
+ void __iomem *tbu_base = tbu->base;
+ u64 mask[NO_OF_MASK_AND_MATCH], match[NO_OF_MASK_AND_MATCH];
+ u64 snapshot[NO_OF_CAPTURE_POINTS][REGS_PER_CAPTURE_POINT];
+ int i, j, val;
+
+ if (arm_smmu_power_on(smmu->pwr) || arm_smmu_power_on(tbu->pwr))
+ return IRQ_NONE;
+
+ val = arm_smmu_debug_get_tnx_tcr_cntl(tbu_base);
+ arm_smmu_debug_get_mask_and_match(tbu_base, mask, match);
+ arm_smmu_debug_get_capture_snapshot(tbu_base, snapshot);
+ arm_smmu_debug_clear_intr_and_validbits(tbu_base);
+
+ arm_smmu_power_off(tbu->pwr);
+ arm_smmu_power_off(smmu->pwr);
+
+ dev_info(tbu->dev, "TNX_TCR_CNTL : 0x%0llx\n", val);
+
+ for (i = 0; i < NO_OF_MASK_AND_MATCH; ++i) {
+ dev_info(tbu->dev,
+ "Mask_%d : 0x%0llx\n", i+1, mask[i]);
+ dev_info(tbu->dev,
+ "Match_%d : 0x%0llx\n", i+1, match[i]);
+ }
+
+ for (i = 0; i < NO_OF_CAPTURE_POINTS ; ++i) {
+ for (j = 0; j < REGS_PER_CAPTURE_POINT; ++j) {
+ dev_info(tbu->dev,
+ "Capture_%d_Snapshot_%d : 0x%0llx\n",
+ i+1, j+1, snapshot[i][j]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
{
struct resource *res;
@@ -6064,7 +6333,7 @@ static int qsmmuv500_tbu_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct qsmmuv500_tbu_device *tbu;
const __be32 *cell;
- int len;
+ int len, i, err, num_irqs = 0;
tbu = devm_kzalloc(dev, sizeof(*tbu), GFP_KERNEL);
if (!tbu)
@@ -6091,12 +6360,42 @@ static int qsmmuv500_tbu_probe(struct platform_device *pdev)
tbu->sid_start = of_read_number(cell, 1);
tbu->num_sids = of_read_number(cell + 1, 1);
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs)))
+ num_irqs++;
+
+ tbu->irqs = devm_kzalloc(dev, sizeof(*tbu->irqs) * num_irqs,
+ GFP_KERNEL);
+ if (!tbu->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < num_irqs; ++i) {
+ int irq = platform_get_irq(pdev, i);
+
+ if (irq < 0) {
+ dev_err(dev, "failed to get irq index %d\n", i);
+ return -ENODEV;
+ }
+ tbu->irqs[i] = irq;
+
+ err = devm_request_threaded_irq(tbu->dev, tbu->irqs[i],
+ NULL, arm_smmu_debug_capture_bus_match,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "capture bus", tbu);
+ if (err) {
+ dev_err(dev, "failed to request capture bus irq%d (%u)\n",
+ i, tbu->irqs[i]);
+ return err;
+ }
+ }
+
tbu->pwr = arm_smmu_init_power_resources(pdev);
if (IS_ERR(tbu->pwr))
return PTR_ERR(tbu->pwr);
dev_set_drvdata(dev, tbu);
+
qsmmuv500_tbu_testbus_init(tbu);
+ qsmmuv500_capturebus_init(tbu);
return 0;
}
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 23c721b072dc..85934458cd76 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -201,6 +201,7 @@ static dma_addr_t __fast_smmu_alloc_iova(struct dma_fast_smmu_mapping *mapping,
bool skip_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC);
iommu_tlbiall(mapping->domain);
+ iommu_tlb_sync(mapping->domain);
mapping->have_stale_tlbs = false;
av8l_fast_clear_stale_ptes(mapping->pgtbl_pmds, skip_sync);
}
diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
index 0e30cfb52ce8..631e31f9aa57 100644
--- a/drivers/iommu/io-pgtable.c
+++ b/drivers/iommu/io-pgtable.c
@@ -89,6 +89,7 @@ void free_io_pgtable_ops(struct io_pgtable_ops *ops)
iop = container_of(ops, struct io_pgtable, ops);
io_pgtable_tlb_flush_all(iop);
+ io_pgtable_tlb_sync(iop);
io_pgtable_init_table[iop->fmt]->free(iop);
}
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 777aff1f549f..78a9ca5300d0 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -621,6 +621,14 @@ static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova,
return domain->iop->unmap(domain->iop, iova, size);
}
+static void ipmmu_iotlb_sync(struct iommu_domain *io_domain)
+{
+ struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
+
+ if (domain->mmu)
+ ipmmu_tlb_flush_all(domain);
+}
+
static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
dma_addr_t iova)
{
@@ -878,6 +886,8 @@ static const struct iommu_ops ipmmu_ops = {
.detach_dev = ipmmu_detach_device,
.map = ipmmu_map,
.unmap = ipmmu_unmap,
+ .flush_iotlb_all = ipmmu_iotlb_sync,
+ .iotlb_sync = ipmmu_iotlb_sync,
.map_sg = default_iommu_map_sg,
.iova_to_phys = ipmmu_iova_to_phys,
.add_device = ipmmu_add_device_dma,
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 0ae7d0ac4186..88c5c88030dc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -3663,6 +3663,8 @@ STREAM_BUFF_END:
} else {
ioctl_cmd = VIDIOC_MSM_BUF_MNGR_IOCTL_CMD;
idx = MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX;
+ buff_mgr_info.index =
+ frame_info.output_buffer_info[0].index;
}
rc = msm_cpp_buffer_ops(cpp_dev, ioctl_cmd, idx,
&buff_mgr_info);
@@ -4376,6 +4378,8 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
memset(&k64_frame_info, 0, sizeof(k64_frame_info));
k64_frame_info.identity = k32_frame_info.identity;
k64_frame_info.frame_id = k32_frame_info.frame_id;
+ k64_frame_info.output_buffer_info[0].index =
+ k32_frame_info.output_buffer_info[0].index;
kp_ioctl.ioctl_ptr = (__force void __user *)&k64_frame_info;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 0d738018ff4f..7210a0613f2e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -3594,6 +3594,33 @@ int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req,
return 0;
}
+static int __boundary_checks_offset_64(struct qseecom_send_modfd_cmd_req *req,
+ struct qseecom_send_modfd_listener_resp *lstnr_resp,
+ struct qseecom_dev_handle *data, int i)
+{
+
+ if ((data->type != QSEECOM_LISTENER_SERVICE) &&
+ (req->ifd_data[i].fd > 0)) {
+ if ((req->cmd_req_len < sizeof(uint64_t)) ||
+ (req->ifd_data[i].cmd_buf_offset >
+ req->cmd_req_len - sizeof(uint64_t))) {
+ pr_err("Invalid offset (req len) 0x%x\n",
+ req->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
+ } else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
+ (lstnr_resp->ifd_data[i].fd > 0)) {
+ if ((lstnr_resp->resp_len < sizeof(uint64_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint64_t))) {
+ pr_err("Invalid offset (lstnr resp len) 0x%x\n",
+ lstnr_resp->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_dev_handle *data)
{
@@ -3937,7 +3964,8 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
if (sg_ptr->nents == 1) {
uint64_t *update_64bit;
- if (__boundary_checks_offset(req, lstnr_resp, data, i))
+ if (__boundary_checks_offset_64(req, lstnr_resp,
+ data, i))
goto err;
/* 64bit app uses 64bit address */
update_64bit = (uint64_t *) field;
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 98d43b33cf95..a6805e86c1f1 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -2358,6 +2358,12 @@ static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count,
struct qpnp_qg *chip = file->private_data;
unsigned long data_size = sizeof(chip->kdata);
+ if (count < data_size) {
+ pr_err("Invalid datasize %lu, expected lesser then %zu\n",
+ data_size, count);
+ return -EINVAL;
+ }
+
/* non-blocking access, return */
if (!chip->data_ready && (file->f_flags & O_NONBLOCK))
return 0;
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 9bf1b8f7f5cb..b6271a865762 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -3,7 +3,7 @@
* drivers/staging/android/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -577,7 +577,8 @@ static int ion_sgl_sync_range(struct device *dev, struct scatterlist *sgl,
break;
if (i > 0) {
- pr_warn("Partial cmo only supported with 1 segment\n"
+ pr_warn_ratelimited(
+ "Partial cmo only supported with 1 segment\n"
"is dma_set_max_seg_size being set on dev:%s\n",
dev_name(dev));
return -EINVAL;