[PATCH 9/9] ARM64: DT: add iommu for msm8916
Signed-off-by: Rob Clark--- arch/arm64/boot/dts/qcom/msm8916.dtsi | 57 +++ 1 file changed, 57 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 7bcf4cd..8aeec6f 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -705,6 +705,59 @@ #thermal-sensor-cells = <1>; }; + apps_iommu: iommu@1ef { + #address-cells = <1>; + #size-cells = <1>; + #iommu-cells = <1>; + compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1"; + ranges = <0 0x1e2 0x4>; + reg = <0x1ef 0x3000>; + clocks = < GCC_SMMU_CFG_CLK>, +< GCC_APSS_TCU_CLK>; + clock-names = "iface", "bus"; + qcom,iommu-secure-id = <17>; + + // mdp_0: + iommu-ctx@4000 { + compatible = "qcom,msm-iommu-v1-ns"; + reg = <0x4000 0x1000>; + interrupts = ; + }; + + // venus_ns: + iommu-ctx@5000 { + compatible = "qcom,msm-iommu-v1-sec"; + reg = <0x5000 0x1000>; + interrupts = ; + }; + }; + + gpu_iommu: iommu@1f08000 { + #address-cells = <1>; + #size-cells = <1>; + #iommu-cells = <1>; + compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1"; + ranges = <0 0x1f08000 0x1>; + clocks = < GCC_SMMU_CFG_CLK>, +< GCC_GFX_TCU_CLK>; + clock-names = "iface", "bus"; + qcom,iommu-secure-id = <18>; + + // gfx3d_user: + iommu-ctx@1000 { + compatible = "qcom,msm-iommu-v1-ns"; + reg = <0x1000 0x1000>; + interrupts = ; + }; + + // gfx3d_priv: + iommu-ctx@2000 { + compatible = "qcom,msm-iommu-v1-ns"; + reg = <0x2000 0x1000>; + interrupts = ; + }; + }; + gpu@01c0 { compatible = "qcom,adreno-306.0", "qcom,adreno"; reg = <0x01c0 0x2>; @@ -726,6 +779,7 @@ < GCC_BIMC_GPU_CLK>, < GFX3D_CLK_SRC>; power-domains = < OXILI_GDSC>; + iommus = <_iommu 1>, <_iommu 2>; }; mdss: mdss@1a0 { @@ -769,6 +823,8 @@ "core_clk", "vsync_clk"; + iommus = <_iommu 4>; + ports { #address-cells = <1>; #size-cells = <0>; @@ -1207,6 +1263,7 @@ < GCC_VENUS0_AHB_CLK>, < GCC_VENUS0_AXI_CLK>; clock-names = "core", "iface", "bus"; + iommus = <_iommu 5>; memory-region = <_mem>; status = "okay"; -- 2.9.3 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 8/9] ARM64: DT: add video codec devicetree node
From: Stanimir VarbanovSigned-off-by: Stanimir Varbanov Signed-off-by: Rob Clark --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 28 1 file changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index b0daf39..7bcf4cd 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -88,6 +88,13 @@ no-map; }; + venus_mem: venus@8990 { + compatible = "shared-dma-pool"; + reg = <0x0 0x8990 0x0 0x80>; + alignment = <0x1000>; + no-map; + }; + mba_mem: mba@8ea0 { no-map; reg = <0 0x8ea0 0 0x10>; @@ -1190,6 +1197,27 @@ }; }; }; + + venus: video-codec@1d0 { + compatible = "qcom,msm8916-venus"; + reg = <0x01d0 0xff000>; + interrupts = ; + power-domains = < VENUS_GDSC>; + clocks = < GCC_VENUS0_VCODEC0_CLK>, +< GCC_VENUS0_AHB_CLK>, +< GCC_VENUS0_AXI_CLK>; + clock-names = "core", "iface", "bus"; + memory-region = <_mem>; + status = "okay"; + + video-decoder { + compatible = "venus-decoder"; + }; + + video-encoder { + compatible = "venus-encoder"; + }; + }; }; smd { -- 2.9.3 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 7/9] ARM64: DT: add gpu for msm8916
Signed-off-by: Rob Clark--- arch/arm64/boot/dts/qcom/msm8916.dtsi | 23 +++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 68a8e67..b0daf39 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -698,6 +698,29 @@ #thermal-sensor-cells = <1>; }; + gpu@01c0 { + compatible = "qcom,adreno-306.0", "qcom,adreno"; + reg = <0x01c0 0x2>; + reg-names = "kgsl_3d0_reg_memory"; + interrupts = <0 33 0>; + interrupt-names = "kgsl_3d0_irq"; + clock-names = + "core", + "iface", + "mem", + "mem_iface", + "alt_mem_iface", + "gfx3d_clk"; + clocks = + < GCC_OXILI_GFX3D_CLK>, + < GCC_OXILI_AHB_CLK>, + < GCC_OXILI_GMEM_CLK>, + < GCC_BIMC_GFX_CLK>, + < GCC_BIMC_GPU_CLK>, + < GFX3D_CLK_SRC>; + power-domains = < OXILI_GDSC>; + }; + mdss: mdss@1a0 { compatible = "qcom,mdss"; reg = <0x1a0 0x1000>, -- 2.9.3 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 5/9] iommu: add qcom_iommu
An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible). Signed-off-by: Rob ClarkSigned-off-by: Stanimir Varbanov --- drivers/iommu/Kconfig | 10 + drivers/iommu/Makefile| 1 + drivers/iommu/arm-smmu-regs.h | 2 + drivers/iommu/qcom_iommu.c| 818 ++ 4 files changed, 831 insertions(+) create mode 100644 drivers/iommu/qcom_iommu.c diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 37e204f..400a404 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -359,4 +359,14 @@ config MTK_IOMMU_V1 if unsure, say N here. +config QCOM_IOMMU + bool "Qualcomm IOMMU Support" + depends on ARM || ARM64 + depends on ARCH_QCOM || COMPILE_TEST + select IOMMU_API + select IOMMU_IO_PGTABLE_LPAE + select ARM_DMA_USE_IOMMU + help + Support for IOMMU on certain Qualcomm SoCs. + endif # IOMMU_SUPPORT diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 195f7b9..b910aea 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o obj-$(CONFIG_S390_IOMMU) += s390-iommu.o +obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h index 632240f..e643164 100644 --- a/drivers/iommu/arm-smmu-regs.h +++ b/drivers/iommu/arm-smmu-regs.h @@ -174,6 +174,8 @@ enum arm_smmu_s2cr_privcfg { #define ARM_SMMU_CB_S1_TLBIVAL 0x620 #define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 #define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 +#define ARM_SMMU_CB_TLBSYNC0x7f0 +#define ARM_SMMU_CB_TLBSTATUS 0x7f4 #define ARM_SMMU_CB_ATS1PR 0x800 #define ARM_SMMU_CB_ATSR 0x8f0 diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c new file mode 100644 index 000..6b7adbf --- /dev/null +++ b/drivers/iommu/qcom_iommu.c @@ -0,0 +1,818 @@ +/* + * IOMMU API for QCOM secure IOMMUs. Somewhat based on arm-smmu.c + * + * 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 + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2013 ARM Limited + * Copyright (C) 2017 Red Hat + */ + +#define pr_fmt(fmt) "qcom-iommu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "io-pgtable.h" +#include "arm-smmu-regs.h" + +#define SMMU_INTR_SEL_NS 0x2000 + +struct qcom_iommu_dev { + /* IOMMU core code handle */ + struct iommu_device iommu; + struct device *dev; + struct clk *iface_clk; + struct clk *bus_clk; + void __iomem*local_base; + u32 sec_id; + struct list_head context_list; /* list of qcom_iommu_context */ +}; + +struct qcom_iommu_ctx { + struct device *dev; + void __iomem*base; + unsigned int irq; + bool secure_init; + u32 asid; /* asid and ctx bank # are 1:1 */ + struct iommu_group *group; + struct list_head node; /* head in qcom_iommu_device::context_list */ +}; + +struct qcom_iommu_domain { + struct io_pgtable_ops *pgtbl_ops; + spinlock_t pgtbl_lock; + struct mutex init_mutex; /* Protects iommu pointer */ + struct iommu_domain domain; + struct qcom_iommu_dev *iommu; +}; + +static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom) +{ + return container_of(dom, struct qcom_iommu_domain, domain); +} + +static const struct iommu_ops qcom_iommu_ops; + +static struct qcom_iommu_dev * __to_iommu(struct iommu_fwspec *fwspec) +{ + if (WARN_ON(!fwspec || fwspec->ops != _iommu_ops)) + return NULL; + return fwspec->iommu_priv;
[PATCH 6/9] iommu: qcom: initialize secure page table
From: Stanimir VarbanovThis basically gets the secure page table size, allocates memory for secure pagetables and passes the physical address to the trusted zone. Signed-off-by: Stanimir Varbanov Signed-off-by: Rob Clark --- drivers/iommu/qcom_iommu.c | 64 ++ 1 file changed, 64 insertions(+) diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index 6b7adbf..743a628 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -608,6 +608,51 @@ static void qcom_iommu_disable_clocks(struct qcom_iommu_dev *qcom_iommu) clk_disable_unprepare(qcom_iommu->iface_clk); } +static int qcom_iommu_sec_ptbl_init(struct device *dev) +{ + size_t psize = 0; + unsigned int spare = 0; + void *cpu_addr; + dma_addr_t paddr; + unsigned long attrs; + static bool allocated = false; + int ret; + + if (allocated) + return 0; + + ret = qcom_scm_iommu_secure_ptbl_size(spare, ); + if (ret) { + dev_err(dev, "failed to get iommu secure pgtable size (%d)\n", + ret); + return ret; + } + + dev_info(dev, "iommu sec: pgtable size: %zu\n", psize); + + attrs = DMA_ATTR_NO_KERNEL_MAPPING; + + cpu_addr = dma_alloc_attrs(dev, psize, , GFP_KERNEL, attrs); + if (!cpu_addr) { + dev_err(dev, "failed to allocate %zu bytes for pgtable\n", + psize); + return -ENOMEM; + } + + ret = qcom_scm_iommu_secure_ptbl_init(paddr, psize, spare); + if (ret) { + dev_err(dev, "failed to init iommu pgtable (%d)\n", ret); + goto free_mem; + } + + allocated = true; + return 0; + +free_mem: + dma_free_attrs(dev, psize, cpu_addr, paddr, attrs); + return ret; +} + static int qcom_iommu_ctx_probe(struct platform_device *pdev) { struct qcom_iommu_ctx *ctx; @@ -688,6 +733,17 @@ static struct platform_driver qcom_iommu_ctx_driver = { }; module_platform_driver(qcom_iommu_ctx_driver); +static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu) +{ + struct device_node *child; + + for_each_child_of_node(qcom_iommu->dev->of_node, child) + if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec")) + return true; + + return false; +} + static int qcom_iommu_device_probe(struct platform_device *pdev) { struct qcom_iommu_dev *qcom_iommu; @@ -724,6 +780,14 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) return -ENODEV; } + if (qcom_iommu_has_secure_context(qcom_iommu)) { + ret = qcom_iommu_sec_ptbl_init(dev); + if (ret) { + dev_err(dev, "cannot init secure pg table(%d)\n", ret); + return ret; + } + } + platform_set_drvdata(pdev, qcom_iommu); /* register context bank devices, which are child nodes: */ -- 2.9.3 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 4/9] iommu: arm-smmu: split out register defines
I want to re-use some of these for qcom_iommu, which has (roughly) the same context-bank registers. Signed-off-by: Rob Clark--- drivers/iommu/arm-smmu-regs.h | 225 ++ drivers/iommu/arm-smmu.c | 200 + 2 files changed, 226 insertions(+), 199 deletions(-) create mode 100644 drivers/iommu/arm-smmu-regs.h diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h new file mode 100644 index 000..632240f --- /dev/null +++ b/drivers/iommu/arm-smmu-regs.h @@ -0,0 +1,225 @@ +/* + * IOMMU API for ARM architected SMMU implementations. + * + * 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 + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2013 ARM Limited + * + * Author: Will Deacon + */ + +#ifndef _ARM_SMMU_REGS_H +#define _ARM_SMMU_REGS_H + + +/* Configuration registers */ +#define ARM_SMMU_GR0_sCR0 0x0 +#define sCR0_CLIENTPD (1 << 0) +#define sCR0_GFRE (1 << 1) +#define sCR0_GFIE (1 << 2) +#define sCR0_EXIDENABLE(1 << 3) +#define sCR0_GCFGFRE (1 << 4) +#define sCR0_GCFGFIE (1 << 5) +#define sCR0_USFCFG(1 << 10) +#define sCR0_VMIDPNE (1 << 11) +#define sCR0_PTM (1 << 12) +#define sCR0_FB(1 << 13) +#define sCR0_VMID16EN (1 << 31) +#define sCR0_BSU_SHIFT 14 +#define sCR0_BSU_MASK 0x3 + +/* Auxiliary Configuration register */ +#define ARM_SMMU_GR0_sACR 0x10 + +/* Identification registers */ +#define ARM_SMMU_GR0_ID0 0x20 +#define ARM_SMMU_GR0_ID1 0x24 +#define ARM_SMMU_GR0_ID2 0x28 +#define ARM_SMMU_GR0_ID3 0x2c +#define ARM_SMMU_GR0_ID4 0x30 +#define ARM_SMMU_GR0_ID5 0x34 +#define ARM_SMMU_GR0_ID6 0x38 +#define ARM_SMMU_GR0_ID7 0x3c +#define ARM_SMMU_GR0_sGFSR 0x48 +#define ARM_SMMU_GR0_sGFSYNR0 0x50 +#define ARM_SMMU_GR0_sGFSYNR1 0x54 +#define ARM_SMMU_GR0_sGFSYNR2 0x58 + +#define ID0_S1TS (1 << 30) +#define ID0_S2TS (1 << 29) +#define ID0_NTS(1 << 28) +#define ID0_SMS(1 << 27) +#define ID0_ATOSNS (1 << 26) +#define ID0_PTFS_NO_AARCH32(1 << 25) +#define ID0_PTFS_NO_AARCH32S (1 << 24) +#define ID0_CTTW (1 << 14) +#define ID0_NUMIRPT_SHIFT 16 +#define ID0_NUMIRPT_MASK 0xff +#define ID0_NUMSIDB_SHIFT 9 +#define ID0_NUMSIDB_MASK 0xf +#define ID0_EXIDS (1 << 8) +#define ID0_NUMSMRG_SHIFT 0 +#define ID0_NUMSMRG_MASK 0xff + +#define ID1_PAGESIZE (1 << 31) +#define ID1_NUMPAGENDXB_SHIFT 28 +#define ID1_NUMPAGENDXB_MASK 7 +#define ID1_NUMS2CB_SHIFT 16 +#define ID1_NUMS2CB_MASK 0xff +#define ID1_NUMCB_SHIFT0 +#define ID1_NUMCB_MASK 0xff + +#define ID2_OAS_SHIFT 4 +#define ID2_OAS_MASK 0xf +#define ID2_IAS_SHIFT 0 +#define ID2_IAS_MASK 0xf +#define ID2_UBS_SHIFT 8 +#define ID2_UBS_MASK 0xf +#define ID2_PTFS_4K(1 << 12) +#define ID2_PTFS_16K (1 << 13) +#define ID2_PTFS_64K (1 << 14) +#define ID2_VMID16 (1 << 15) + +#define ID7_MAJOR_SHIFT4 +#define ID7_MAJOR_MASK 0xf + +/* Global TLB invalidation */ +#define ARM_SMMU_GR0_TLBIVMID 0x64 +#define ARM_SMMU_GR0_TLBIALLNSNH 0x68 +#define ARM_SMMU_GR0_TLBIALLH 0x6c +#define ARM_SMMU_GR0_sTLBGSYNC 0x70 +#define ARM_SMMU_GR0_sTLBGSTATUS 0x74 +#define sTLBGSTATUS_GSACTIVE (1 << 0) +#define TLB_LOOP_TIMEOUT 100 /* 1s! */ + +/* Stream mapping registers */ +#define ARM_SMMU_GR0_SMR(n)(0x800 + ((n) << 2)) +#define SMR_VALID (1 << 31) +#define SMR_MASK_SHIFT
[PATCH 2/9] firmware: qcom_scm: add two scm calls for iommu secure page table
From: Stanimir VarbanovThose two new SCM calls are needed from qcom-iommu driver in order to initialize secure iommu page table. Signed-off-by: Stanimir Varbanov Signed-off-by: Rob Clark --- drivers/firmware/qcom_scm-32.c | 12 drivers/firmware/qcom_scm-64.c | 42 ++ drivers/firmware/qcom_scm.c| 12 drivers/firmware/qcom_scm.h| 6 ++ include/linux/qcom_scm.h | 4 5 files changed, 76 insertions(+) diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 722e65a..93e3b96 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -584,3 +584,15 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, { return -ENODEV; } + +int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, + size_t *size) +{ + return -ENODEV; +} + +int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, + u32 spare) +{ + return -ENODEV; +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index 550e3a3..6e6d561 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -397,3 +397,45 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) return ret ? : res.a1; } + +int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, + size_t *size) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = spare; + desc.arginfo = QCOM_SCM_ARGS(1); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, , ); + + if (size) + *size = res.a1; + + return ret ? : res.a2; +} + +int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, + u32 spare) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = addr; + desc.args[1] = size; + desc.args[2] = spare; + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, +QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_SCM_IOMMU_SECURE_PTBL_INIT, , ); + + /* the pg table has been initialized already, ignore the error */ + if (ret == -EPERM) + ret = 0; + + return ret; +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index ae1f473..bb16510 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -321,6 +321,18 @@ int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) } EXPORT_SYMBOL(qcom_scm_restore_sec_cfg); +int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) +{ + return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size); +} +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size); + +int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) +{ + return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare); +} +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); + /** * qcom_scm_is_available() - Checks if SCM is available */ diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 31fc732..9bea691 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -89,5 +89,11 @@ static inline int qcom_scm_remap_error(int err) #define QCOM_SCM_RESTORE_SEC_CFG 2 extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare); +#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE3 +#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT4 +extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, +size_t *size); +extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, +u32 size, u32 spare); #endif diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 22017f5d..e538047 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -41,6 +41,8 @@ extern void qcom_scm_cpu_power_down(u32 flags); extern u32 qcom_scm_get_version(void); extern int qcom_scm_set_remote_state(u32 state, u32 id); extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare); +extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size); +extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare); #else static inline int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) @@ -69,5 +71,7 @@ static inline u32 qcom_scm_get_version(void) { return 0; } static inline u32
[PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2)
An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible). There are a couple vaguely unrelated patches to add venus and gpu dt nodes, so that we have something to wire up the iommu to. These patches apply on top of some in-flight patches to support IOMMU probe deferral. You can find full branch on top of linux-next here: git://people.freedesktop.org/~robclark/linux next-20170307-db410c-qcom-smmu-3-venus or github if you prefer: https://github.com/freedreno/kernel-msm/commits/next-20170307-db410c-qcom-smmu-3-venus Compared to previous patchset, there have been some (mostly binding related) cleanups. Also fixed some other-config related build issues that kbuild robot spotted. Rob Clark (6): firmware/qcom: add qcom_scm_restore_sec_cfg() Docs: dt: document qcom iommu bindings iommu: arm-smmu: split out register defines iommu: add qcom_iommu ARM64: DT: add gpu for msm8916 ARM64: DT: add iommu for msm8916 Stanimir Varbanov (3): firmware: qcom_scm: add two scm calls for iommu secure page table iommu: qcom: initialize secure page table ARM64: DT: add video codec devicetree node .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++ arch/arm64/boot/dts/qcom/msm8916.dtsi | 108 +++ drivers/firmware/qcom_scm-32.c | 18 + drivers/firmware/qcom_scm-64.c | 58 ++ drivers/firmware/qcom_scm.c| 18 + drivers/firmware/qcom_scm.h| 11 + drivers/iommu/Kconfig | 10 + drivers/iommu/Makefile | 1 + drivers/iommu/arm-smmu-regs.h | 227 ++ drivers/iommu/arm-smmu.c | 200 + drivers/iommu/qcom_iommu.c | 882 + include/linux/qcom_scm.h | 6 + 12 files changed, 1453 insertions(+), 199 deletions(-) create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt create mode 100644 drivers/iommu/arm-smmu-regs.h create mode 100644 drivers/iommu/qcom_iommu.c -- 2.9.3 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/9] firmware/qcom: add qcom_scm_restore_sec_cfg()
Signed-off-by: Rob Clark--- drivers/firmware/qcom_scm-32.c | 6 ++ drivers/firmware/qcom_scm-64.c | 16 drivers/firmware/qcom_scm.c| 6 ++ drivers/firmware/qcom_scm.h| 5 + include/linux/qcom_scm.h | 2 ++ 5 files changed, 35 insertions(+) diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 8ad226c..722e65a 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -578,3 +578,9 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) return ret ? : le32_to_cpu(scm_ret); } + +int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, + u32 spare) +{ + return -ENODEV; +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index c933259..550e3a3 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -381,3 +381,19 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) return ret ? : res.a1; } + +int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = device_id; + desc.args[1] = spare; + desc.arginfo = QCOM_SCM_ARGS(2); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG, + , ); + + return ret ? : res.a1; +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d987bcc..ae1f473 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -315,6 +315,12 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = { .deassert = qcom_scm_pas_reset_deassert, }; +int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) +{ + return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare); +} +EXPORT_SYMBOL(qcom_scm_restore_sec_cfg); + /** * qcom_scm_is_available() - Checks if SCM is available */ diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 6a0f154..31fc732 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -85,4 +85,9 @@ static inline int qcom_scm_remap_error(int err) return -EINVAL; } +#define QCOM_SCM_SVC_MP0xc +#define QCOM_SCM_RESTORE_SEC_CFG 2 +extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, + u32 spare); + #endif diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index d32f6f1..22017f5d 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -40,6 +40,7 @@ extern int qcom_scm_pas_shutdown(u32 peripheral); extern void qcom_scm_cpu_power_down(u32 flags); extern u32 qcom_scm_get_version(void); extern int qcom_scm_set_remote_state(u32 state, u32 id); +extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare); #else static inline int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) @@ -67,5 +68,6 @@ static inline void qcom_scm_cpu_power_down(u32 flags) {} static inline u32 qcom_scm_get_version(void) { return 0; } static inline u32 qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; } +static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; } #endif #endif -- 2.9.3 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
RE: [RFC PATCH] iommu/dma: check pci host bridge dma_mask for IOVA allocation
My responses inline: -Original Message- From: Robin Murphy [mailto:robin.mur...@arm.com] Sent: Tuesday, March 14, 2017 4:27 PM To: Oza Pawandeep; Joerg Roedel Cc: iommu@lists.linux-foundation.org; linux-ker...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; bcm-kernel-feedback-l...@broadcom.com; a...@arndb.de; Nikita Yushchenko Subject: Re: [RFC PATCH] iommu/dma: check pci host bridge dma_mask for IOVA allocation On 14/03/17 08:48, Oza Pawandeep wrote: > It is possible that PCI device supports 64-bit DMA addressing, and > thus it's driver sets device's dma_mask to DMA_BIT_MASK(64), however > PCI host bridge may have limitations on the inbound transaction > addressing. As an example, consider NVME SSD device connected to > iproc-PCIe controller. Aw heck, not another one :( > Currently, the IOMMU DMA ops only considers PCI device dma_mask when > allocating an IOVA. This is particularly problematic on > ARM/ARM64 SOCs where the IOMMU (i.e. SMMU) translates IOVA to PA for > in-bound transactions only after PCI Host has forwarded these > transactions on SOC IO bus. This means on such ARM/ARM64 SOCs the IOVA > of in-bound transactions has to honor the addressing restrictions of > the PCI Host. Depending on whether this most closely matches the R-Car situation[1] or the X-Gene situation[2], this may not address the real problem at all (if the non-IOMMU case is also affected). Either way it also fails to help non-PCI devices which can face the exact same problem. I am not fully aware of R-car and X-gene situation, but for iproc based SOCs, our pcie host floats addresses in higher order dma_mask is set. > This patch tries to solve above described IOVA allocation problem by: > 1. Adding iommu_get_dma_mask() to get dma_mask of any device 2. For > PCI device, iommu_get_dma_mask() compare dma_mask of PCI device and > corresponding PCI Host dma_mask (if set). > 3. Use iommu_get_dma_mask() in IOMMU DMA ops implementation instead of > dma_get_mask() Sorry, but NAK to this approach - not only is the implementation rather ugly, and incomplete as above, but the fact that it starts with a clear description of the underlying problem and then goes on to bodge around it down the line instead of actually fixing it is the kicker. :) that is why this is RFC patch, and I had something similar in mind to go and poke around which you have provided.. [1] and [3]. Let me try this on our platform, and see if that solves the issue. I've got a simple arm64 patch for proper DMA mask inheritance based on the various discussions at [1] which I will try to clean up and send out for 4.12 if nobody else sends anything soon, but it does depend on getting [3] merged first to avoid regressing certain platforms. Robin. [1]:http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1306545.ht ml [2]:http://www.spinics.net/lists/arm-kernel/msg552422.html [3]:http://www.spinics.net/lists/arm-kernel/msg566947.html > Signed-off-by: Oza Pawandeep> Reviewed-by: Anup Patel > Reviewed-by: Scott Branden > --- > drivers/iommu/dma-iommu.c | 44 > > 1 file changed, 40 insertions(+), 4 deletions(-) > > diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c > index 48d36ce..e93e536 100644 > --- a/drivers/iommu/dma-iommu.c > +++ b/drivers/iommu/dma-iommu.c > @@ -108,6 +108,42 @@ int iommu_get_dma_cookie(struct iommu_domain > *domain) } EXPORT_SYMBOL(iommu_get_dma_cookie); > > +static u64 __iommu_dma_mask(struct device *dev, bool is_coherent) { > +#ifdef CONFIG_PCI > + u64 pci_hb_dma_mask; > + > + if (dev_is_pci(dev)) { > + struct pci_dev *pdev = to_pci_dev(dev); > + struct pci_host_bridge *br = pci_find_host_bridge(pdev->bus); > + > + if ((!is_coherent) && !(br->dev.dma_mask)) > + goto default_dev_dma_mask; > + > + /* pci host bridge dma-mask. */ > + pci_hb_dma_mask = (!is_coherent) ? *br->dev.dma_mask : > +br->dev.coherent_dma_mask; > + > + if (pci_hb_dma_mask && ((pci_hb_dma_mask) < (*dev->dma_mask))) > + return pci_hb_dma_mask; > + } > +default_dev_dma_mask: > +#endif > + return (!is_coherent) ? dma_get_mask(dev) : > + dev->coherent_dma_mask; > +} > + > +static u64 __iommu_dma_get_coherent_mask(struct device *dev) { > + return __iommu_dma_mask(dev, true); > +} > + > +static u64 __iommu_dma_get_mask(struct device *dev) { > + return __iommu_dma_mask(dev, false); } > + > + > /** > * iommu_get_msi_cookie - Acquire just MSI remapping resources > * @domain: IOMMU domain to prepare > @@ -461,7 +497,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, > if (!pages) > return NULL; > > - iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); > + iova =
Re: [RFC PATCH] iommu/dma: check pci host bridge dma_mask for IOVA allocation
On 14/03/17 08:48, Oza Pawandeep wrote: > It is possible that PCI device supports 64-bit DMA addressing, > and thus it's driver sets device's dma_mask to DMA_BIT_MASK(64), > however PCI host bridge may have limitations on the inbound > transaction addressing. As an example, consider NVME SSD device > connected to iproc-PCIe controller. Aw heck, not another one :( > Currently, the IOMMU DMA ops only considers PCI device dma_mask > when allocating an IOVA. This is particularly problematic on > ARM/ARM64 SOCs where the IOMMU (i.e. SMMU) translates IOVA to > PA for in-bound transactions only after PCI Host has forwarded > these transactions on SOC IO bus. This means on such ARM/ARM64 > SOCs the IOVA of in-bound transactions has to honor the addressing > restrictions of the PCI Host. Depending on whether this most closely matches the R-Car situation[1] or the X-Gene situation[2], this may not address the real problem at all (if the non-IOMMU case is also affected). Either way it also fails to help non-PCI devices which can face the exact same problem. > This patch tries to solve above described IOVA allocation > problem by: > 1. Adding iommu_get_dma_mask() to get dma_mask of any device > 2. For PCI device, iommu_get_dma_mask() compare dma_mask of > PCI device and corresponding PCI Host dma_mask (if set). > 3. Use iommu_get_dma_mask() in IOMMU DMA ops implementation > instead of dma_get_mask() Sorry, but NAK to this approach - not only is the implementation rather ugly, and incomplete as above, but the fact that it starts with a clear description of the underlying problem and then goes on to bodge around it down the line instead of actually fixing it is the kicker. I've got a simple arm64 patch for proper DMA mask inheritance based on the various discussions at [1] which I will try to clean up and send out for 4.12 if nobody else sends anything soon, but it does depend on getting [3] merged first to avoid regressing certain platforms. Robin. [1]:http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1306545.html [2]:http://www.spinics.net/lists/arm-kernel/msg552422.html [3]:http://www.spinics.net/lists/arm-kernel/msg566947.html > Signed-off-by: Oza Pawandeep> Reviewed-by: Anup Patel > Reviewed-by: Scott Branden > --- > drivers/iommu/dma-iommu.c | 44 > 1 file changed, 40 insertions(+), 4 deletions(-) > > diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c > index 48d36ce..e93e536 100644 > --- a/drivers/iommu/dma-iommu.c > +++ b/drivers/iommu/dma-iommu.c > @@ -108,6 +108,42 @@ int iommu_get_dma_cookie(struct iommu_domain *domain) > } > EXPORT_SYMBOL(iommu_get_dma_cookie); > > +static u64 __iommu_dma_mask(struct device *dev, bool is_coherent) > +{ > +#ifdef CONFIG_PCI > + u64 pci_hb_dma_mask; > + > + if (dev_is_pci(dev)) { > + struct pci_dev *pdev = to_pci_dev(dev); > + struct pci_host_bridge *br = pci_find_host_bridge(pdev->bus); > + > + if ((!is_coherent) && !(br->dev.dma_mask)) > + goto default_dev_dma_mask; > + > + /* pci host bridge dma-mask. */ > + pci_hb_dma_mask = (!is_coherent) ? *br->dev.dma_mask : > +br->dev.coherent_dma_mask; > + > + if (pci_hb_dma_mask && ((pci_hb_dma_mask) < (*dev->dma_mask))) > + return pci_hb_dma_mask; > + } > +default_dev_dma_mask: > +#endif > + return (!is_coherent) ? dma_get_mask(dev) : > + dev->coherent_dma_mask; > +} > + > +static u64 __iommu_dma_get_coherent_mask(struct device *dev) > +{ > + return __iommu_dma_mask(dev, true); > +} > + > +static u64 __iommu_dma_get_mask(struct device *dev) > +{ > + return __iommu_dma_mask(dev, false); > +} > + > + > /** > * iommu_get_msi_cookie - Acquire just MSI remapping resources > * @domain: IOMMU domain to prepare > @@ -461,7 +497,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t > size, gfp_t gfp, > if (!pages) > return NULL; > > - iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); > + iova = __alloc_iova(domain, size, __iommu_dma_get_coherent_mask(dev), > dev); > if (!iova) > goto out_free_pages; > > @@ -532,7 +568,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, > phys_addr_t phys, > struct iova_domain *iovad = cookie_iovad(domain); > size_t iova_off = iova_offset(iovad, phys); > size_t len = iova_align(iovad, size + iova_off); > - struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev), dev); > + struct iova *iova = __alloc_iova(domain, len, > __iommu_dma_get_mask(dev), dev); > > if (!iova) > return DMA_ERROR_CODE; > @@ -690,7 +726,7 @@ int iommu_dma_map_sg(struct device *dev, struct > scatterlist *sg, > prev = s; > } > > -
[RFC PATCH] iommu/dma: check pci host bridge dma_mask for IOVA allocation
It is possible that PCI device supports 64-bit DMA addressing, and thus it's driver sets device's dma_mask to DMA_BIT_MASK(64), however PCI host bridge may have limitations on the inbound transaction addressing. As an example, consider NVME SSD device connected to iproc-PCIe controller. Currently, the IOMMU DMA ops only considers PCI device dma_mask when allocating an IOVA. This is particularly problematic on ARM/ARM64 SOCs where the IOMMU (i.e. SMMU) translates IOVA to PA for in-bound transactions only after PCI Host has forwarded these transactions on SOC IO bus. This means on such ARM/ARM64 SOCs the IOVA of in-bound transactions has to honor the addressing restrictions of the PCI Host. This patch tries to solve above described IOVA allocation problem by: 1. Adding iommu_get_dma_mask() to get dma_mask of any device 2. For PCI device, iommu_get_dma_mask() compare dma_mask of PCI device and corresponding PCI Host dma_mask (if set). 3. Use iommu_get_dma_mask() in IOMMU DMA ops implementation instead of dma_get_mask() Signed-off-by: Oza PawandeepReviewed-by: Anup Patel Reviewed-by: Scott Branden --- drivers/iommu/dma-iommu.c | 44 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 48d36ce..e93e536 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -108,6 +108,42 @@ int iommu_get_dma_cookie(struct iommu_domain *domain) } EXPORT_SYMBOL(iommu_get_dma_cookie); +static u64 __iommu_dma_mask(struct device *dev, bool is_coherent) +{ +#ifdef CONFIG_PCI + u64 pci_hb_dma_mask; + + if (dev_is_pci(dev)) { + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_host_bridge *br = pci_find_host_bridge(pdev->bus); + + if ((!is_coherent) && !(br->dev.dma_mask)) + goto default_dev_dma_mask; + + /* pci host bridge dma-mask. */ + pci_hb_dma_mask = (!is_coherent) ? *br->dev.dma_mask : + br->dev.coherent_dma_mask; + + if (pci_hb_dma_mask && ((pci_hb_dma_mask) < (*dev->dma_mask))) + return pci_hb_dma_mask; + } +default_dev_dma_mask: +#endif + return (!is_coherent) ? dma_get_mask(dev) : + dev->coherent_dma_mask; +} + +static u64 __iommu_dma_get_coherent_mask(struct device *dev) +{ + return __iommu_dma_mask(dev, true); +} + +static u64 __iommu_dma_get_mask(struct device *dev) +{ + return __iommu_dma_mask(dev, false); +} + + /** * iommu_get_msi_cookie - Acquire just MSI remapping resources * @domain: IOMMU domain to prepare @@ -461,7 +497,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, if (!pages) return NULL; - iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); + iova = __alloc_iova(domain, size, __iommu_dma_get_coherent_mask(dev), dev); if (!iova) goto out_free_pages; @@ -532,7 +568,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, struct iova_domain *iovad = cookie_iovad(domain); size_t iova_off = iova_offset(iovad, phys); size_t len = iova_align(iovad, size + iova_off); - struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev), dev); + struct iova *iova = __alloc_iova(domain, len, __iommu_dma_get_mask(dev), dev); if (!iova) return DMA_ERROR_CODE; @@ -690,7 +726,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, prev = s; } - iova = __alloc_iova(domain, iova_len, dma_get_mask(dev), dev); + iova = __alloc_iova(domain, iova_len, __iommu_dma_get_mask(dev), dev); if (!iova) goto out_restore_sg; @@ -760,7 +796,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, msi_page->phys = msi_addr; if (iovad) { - iova = __alloc_iova(domain, size, dma_get_mask(dev), dev); + iova = __alloc_iova(domain, size, __iommu_dma_get_mask(dev), dev); if (!iova) goto out_free_page; msi_page->iova = iova_dma_addr(iovad, iova); -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu