diff options
author | Mohit Sharma <smohit@codeaurora.org> | 2019-09-02 16:58:34 +0530 |
---|---|---|
committer | Mohit Sharma <smohit@codeaurora.org> | 2019-09-02 16:58:49 +0530 |
commit | 845c507fbf9cc1951916f568cb184ded98481b03 (patch) | |
tree | 77313fc1e5fb39b0d29568a9eea12f8e83cec5e9 | |
parent | 18b0267621bda4b3823ecad8f146d17ea42e4713 (diff) | |
parent | 76eabecf9f42c0e4ec3c74e66c64627708787437 (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.txt | 2 | ||||
-rw-r--r-- | arch/arm64/boot/dts/qcom/msm-arm-smmu-trinket.dtsi | 5 | ||||
-rw-r--r-- | arch/arm64/boot/dts/qcom/trinket-gpu.dtsi | 1 | ||||
-rw-r--r-- | arch/arm64/boot/dts/qcom/trinket.dtsi | 24 | ||||
-rw-r--r-- | arch/arm64/include/asm/io.h | 10 | ||||
-rw-r--r-- | drivers/char/adsprpc.c | 51 | ||||
-rw-r--r-- | drivers/gpu/msm/kgsl_iommu.c | 24 | ||||
-rw-r--r-- | drivers/gpu/msm/kgsl_iommu.h | 4 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu-debug.c | 57 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu-debug.h | 47 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu-v3.c | 10 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu.c | 367 | ||||
-rw-r--r-- | drivers/iommu/dma-mapping-fast.c | 1 | ||||
-rw-r--r-- | drivers/iommu/io-pgtable.c | 1 | ||||
-rw-r--r-- | drivers/iommu/ipmmu-vmsa.c | 10 | ||||
-rw-r--r-- | drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 4 | ||||
-rw-r--r-- | drivers/misc/qseecom.c | 30 | ||||
-rw-r--r-- | drivers/power/supply/qcom/qpnp-qg.c | 6 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion.c | 5 |
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; |