From patchwork Tue Apr 22 13:14:29 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 28814 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qc0-f200.google.com (mail-qc0-f200.google.com [209.85.216.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 9C25D203AC for ; Tue, 22 Apr 2014 13:17:00 +0000 (UTC) Received: by mail-qc0-f200.google.com with SMTP id i17sf23773106qcy.3 for ; Tue, 22 Apr 2014 06:17:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:cc:subject:precedence:list-id:list-unsubscribe:list-post :list-help:list-subscribe:mime-version:sender:errors-to :x-original-sender:x-original-authentication-results:mailing-list :list-archive:content-type:content-transfer-encoding; bh=ZI0ohv9574/7lJIWP9Ve/WMUVTYCGc3qiX5AjkQ9FFI=; b=dEdqLp4lv+aCISfdVJ7/+NiTRkFsaAD/+z8LBNpI3IDOD1pgk0qXc22hY7yCgdc6AL n/R+c6zNYksvVQnItW6nQh3dzy47nrLhsp19oS6YKVf9xLs9/W/s2AUAktRM8YLtiqzk rsRyF8NHPb8RJX87CJh1BicWaxYSOZ4DUt1nLT7OfbkpZ0wj1HhOusRCkoKXum8lkDSK slvF0FhI5OfX7wk1zjGuH6T8ER8x1rYLREj2yM7ht6wJuqMpD/6riZn5Q6TTy70MnAyk TwKoYzFS7jzFq7dY8JFeQlXf0QSGS3gm10QzqpDHIaUKe/A7xgOxwy387P+BEFjKRh2N iQzQ== X-Gm-Message-State: ALoCoQkuHtTBR4pD+DJUUPyOJonb8kw6BKRUXFX+b/2My06JanFB3aGkWgxNNmQnEhv3aO/y5Myl X-Received: by 10.236.159.99 with SMTP id r63mr21780972yhk.7.1398172620360; Tue, 22 Apr 2014 06:17:00 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.88.229 with SMTP id t92ls92027qgd.9.gmail; Tue, 22 Apr 2014 06:17:00 -0700 (PDT) X-Received: by 10.52.22.74 with SMTP id b10mr18920vdf.87.1398172620118; Tue, 22 Apr 2014 06:17:00 -0700 (PDT) Received: from mail-vc0-f173.google.com (mail-vc0-f173.google.com [209.85.220.173]) by mx.google.com with ESMTPS id b5si6901468vej.83.2014.04.22.06.17.00 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 22 Apr 2014 06:17:00 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.173 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.173; Received: by mail-vc0-f173.google.com with SMTP id il7so2569234vcb.32 for ; Tue, 22 Apr 2014 06:17:00 -0700 (PDT) X-Received: by 10.58.161.101 with SMTP id xr5mr538271veb.36.1398172620000; Tue, 22 Apr 2014 06:17:00 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp23909vcb; Tue, 22 Apr 2014 06:16:59 -0700 (PDT) X-Received: by 10.220.95.2 with SMTP id b2mr36348vcn.61.1398172619604; Tue, 22 Apr 2014 06:16:59 -0700 (PDT) Received: from lists.xen.org (lists.xen.org. [50.57.142.19]) by mx.google.com with ESMTPS id kp12si6897687veb.12.2014.04.22.06.16.58 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Tue, 22 Apr 2014 06:16:59 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of xen-devel-bounces@lists.xen.org designates 50.57.142.19 as permitted sender) client-ip=50.57.142.19; Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WcaXl-0006HX-AC; Tue, 22 Apr 2014 13:15:25 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WcaXZ-0006AO-2B for xen-devel@lists.xenproject.org; Tue, 22 Apr 2014 13:15:13 +0000 Received: from [85.158.139.211:39459] by server-12.bemta-5.messagelabs.com id 1E/24-03824-06B66535; Tue, 22 Apr 2014 13:15:12 +0000 X-Env-Sender: julien.grall@linaro.org X-Msg-Ref: server-16.tower-206.messagelabs.com!1398172510!8742586!1 X-Originating-IP: [74.125.83.50] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 6.11.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 14695 invoked from network); 22 Apr 2014 13:15:11 -0000 Received: from mail-ee0-f50.google.com (HELO mail-ee0-f50.google.com) (74.125.83.50) by server-16.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 22 Apr 2014 13:15:11 -0000 Received: by mail-ee0-f50.google.com with SMTP id c13so4701462eek.9 for ; Tue, 22 Apr 2014 06:15:10 -0700 (PDT) X-Received: by 10.14.7.65 with SMTP id 41mr2228963eeo.100.1398172510858; Tue, 22 Apr 2014 06:15:10 -0700 (PDT) Received: from belegaer.uk.xensource.com ([185.25.64.249]) by mx.google.com with ESMTPSA id 45sm112969867eeh.9.2014.04.22.06.15.08 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Apr 2014 06:15:09 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xenproject.org Date: Tue, 22 Apr 2014 14:14:29 +0100 Message-Id: <1398172475-27873-16-git-send-email-julien.grall@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1398172475-27873-1-git-send-email-julien.grall@linaro.org> References: <1398172475-27873-1-git-send-email-julien.grall@linaro.org> Cc: ian.campbell@citrix.com, Julien Grall , tim@xen.org, stefano.stabellini@citrix.com, Jan Beulich , Xiantao Zhang Subject: [Xen-devel] [PATCH v4 15/21] xen/passthrough: Introduce IOMMU ARM architecture X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: julien.grall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.173 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Archive: This patch contains the architecture to use IOMMUs on ARM. There is no IOMMU drivers on this patch. In this implementation, IOMMU page table will be shared with the P2M. The code will run through the device tree and will initialize every IOMMU. It's possible to have multiple IOMMUs on the same platform, but they must be handled with the same driver. For now, there is no support for using multiple iommu drivers at runtime. Each new IOMMU drivers should contain: static const char * const myiommu_dt_compat[] __initconst = { /* list of device compatible with the drivers. Will be matched with * the "compatible" property on the device tree */ NULL, }; DT_DEVICE_START(myiommu, "MY IOMMU", DEVICE_IOMMU) .compatible = myiommu_compatible, .init = myiommu_init, DT_DEVICE_END Signed-off-by: Julien Grall Cc: Xiantao Zhang Cc: Jan Beulich --- Changes in v4: - Rebase on latest Xen (hwdom series was pushed) - Return directly iommu_dt_domain_init in arch_iommu_domain_init - Rename hvm_iommu field into iommu - Implement arch_iommu_check_hwdom_reqs Changes in v3: - Call iommu_dt_domain_{init,destroy} function in arch code Changes in v2: - Fix typoes in commit message - Remove useless comment in arch/arm/setup.c - Update copyright date to 2014 - Move iommu_dom0_init earlier - Call iommu_assign_dt_device in map_device when the device is protected by an IOMMU --- xen/arch/arm/Rules.mk | 1 + xen/arch/arm/domain.c | 7 ++++ xen/arch/arm/domain_build.c | 21 ++++++++-- xen/arch/arm/p2m.c | 4 ++ xen/arch/arm/setup.c | 2 + xen/drivers/passthrough/Makefile | 1 + xen/drivers/passthrough/arm/Makefile | 1 + xen/drivers/passthrough/arm/iommu.c | 72 ++++++++++++++++++++++++++++++++++ xen/include/asm-arm/device.h | 3 +- xen/include/asm-arm/domain.h | 2 + xen/include/asm-arm/hvm/iommu.h | 10 +++++ xen/include/asm-arm/iommu.h | 36 +++++++++++++++++ 12 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 xen/drivers/passthrough/arm/Makefile create mode 100644 xen/drivers/passthrough/arm/iommu.c create mode 100644 xen/include/asm-arm/hvm/iommu.h create mode 100644 xen/include/asm-arm/iommu.h diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk index c551afb..ec662e2 100644 --- a/xen/arch/arm/Rules.mk +++ b/xen/arch/arm/Rules.mk @@ -9,6 +9,7 @@ HAS_DEVICE_TREE := y HAS_VIDEO := y HAS_ARM_HDLCD := y +HAS_PASSTHROUGH := y CFLAGS += -I$(BASEDIR)/include diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index ccccb77..177e3f0 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -531,6 +531,9 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) if ( is_hardware_domain(d) && (rc = domain_vuart_init(d)) ) goto fail; + if ( (rc = iommu_domain_init(d)) != 0 ) + goto fail; + return 0; fail: @@ -542,6 +545,10 @@ fail: void arch_domain_destroy(struct domain *d) { + /* IOMMU page table is shared with P2M, always call + * iommu_domain_destroy() before p2m_teardown(). + */ + iommu_domain_destroy(d); p2m_teardown(d); domain_vgic_free(d); domain_vuart_free(d); diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index af5cd6c..12e8238 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -679,7 +679,7 @@ static int make_timer_node(const struct domain *d, void *fdt, } /* Map the device in the domain */ -static int map_device(struct domain *d, const struct dt_device_node *dev) +static int map_device(struct domain *d, struct dt_device_node *dev) { unsigned int nirq; unsigned int naddr; @@ -694,6 +694,18 @@ static int map_device(struct domain *d, const struct dt_device_node *dev) DPRINT("%s nirq = %d naddr = %u\n", dt_node_full_name(dev), nirq, naddr); + if ( dt_device_is_protected(dev) ) + { + DPRINT("%s setup iommu\n", dt_node_full_name(dev)); + res = iommu_assign_dt_device(d, dev); + if ( res ) + { + printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n", + dt_node_full_name(dev)); + return res; + } + } + /* Map IRQs */ for ( i = 0; i < nirq; i++ ) { @@ -765,7 +777,7 @@ static int map_device(struct domain *d, const struct dt_device_node *dev) } static int handle_node(struct domain *d, struct kernel_info *kinfo, - const struct dt_device_node *node) + struct dt_device_node *node) { static const struct dt_device_match skip_matches[] __initconst = { @@ -786,7 +798,7 @@ static int handle_node(struct domain *d, struct kernel_info *kinfo, DT_MATCH_TIMER, { /* sentinel */ }, }; - const struct dt_device_node *child; + struct dt_device_node *child; int res; const char *name; const char *path; @@ -1014,11 +1026,14 @@ int construct_dom0(struct domain *d) printk("*** LOADING DOMAIN 0 ***\n"); + iommu_hwdom_init(d); + d->max_pages = ~0U; kinfo.unassigned_mem = dom0_mem; rc = kernel_probe(&kinfo); + if ( rc < 0 ) return rc; diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index 603c097..21219de 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -451,6 +451,9 @@ static int apply_p2m_changes(struct domain *d, if ( flush ) { + unsigned long sgfn = paddr_to_pfn(start_gpaddr); + unsigned long egfn = paddr_to_pfn(end_gpaddr); + /* Update the VTTBR if necessary with the domain where mappings * are created. In this case it's only necessary to flush TLBs * on every CPUs with the current VMID (our domain). @@ -459,6 +462,7 @@ static int apply_p2m_changes(struct domain *d, p2m_load_VTTBR(d); flush_tlb(); + iommu_iotlb_flush(d, sgfn, egfn - sgfn); if ( d != current->domain ) p2m_load_VTTBR(current->domain); diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 40ba26e..b9ce7a9 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -736,6 +736,8 @@ void __init start_xen(unsigned long boot_phys_offset, local_irq_enable(); local_abort_enable(); + iommu_setup(); + smp_prepare_cpus(cpus); initialize_keytable(); diff --git a/xen/drivers/passthrough/Makefile b/xen/drivers/passthrough/Makefile index 5a0a35e..16e9027 100644 --- a/xen/drivers/passthrough/Makefile +++ b/xen/drivers/passthrough/Makefile @@ -1,6 +1,7 @@ subdir-$(x86) += vtd subdir-$(x86) += amd subdir-$(x86_64) += x86 +subdir-$(arm) += arm obj-y += iommu.o obj-$(x86) += io.o diff --git a/xen/drivers/passthrough/arm/Makefile b/xen/drivers/passthrough/arm/Makefile new file mode 100644 index 0000000..0484b79 --- /dev/null +++ b/xen/drivers/passthrough/arm/Makefile @@ -0,0 +1 @@ +obj-y += iommu.o diff --git a/xen/drivers/passthrough/arm/iommu.c b/xen/drivers/passthrough/arm/iommu.c new file mode 100644 index 0000000..5d27b35 --- /dev/null +++ b/xen/drivers/passthrough/arm/iommu.c @@ -0,0 +1,72 @@ +/* + * xen/drivers/passthrough/arm/iommu.c + * + * Generic IOMMU framework via the device tree + * + * Julien Grall + * Copyright (c) 2014 Linaro Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +static const struct iommu_ops *iommu_ops; + +const struct iommu_ops *iommu_get_ops(void) +{ + return iommu_ops; +} + +void __init iommu_set_ops(const struct iommu_ops *ops) +{ + BUG_ON(ops == NULL); + + if ( iommu_ops && iommu_ops != ops ) + printk("WARNING: IOMMU ops already set to a different value\n"); + + iommu_ops = ops; +} + +int __init iommu_hardware_setup(void) +{ + struct dt_device_node *np; + int rc; + unsigned int num_iommus = 0; + + dt_for_each_device_node(dt_host, np) + { + rc = device_init(np, DEVICE_IOMMU, NULL); + if ( !rc ) + num_iommus++; + } + + return ( num_iommus > 0 ) ? 0 : -ENODEV; +} + +void __hwdom_init arch_iommu_check_hwdom_reqs(struct domain *d) +{ + /* ARM doesn't require specific check for hwdom */ + return; +} + +int arch_iommu_domain_init(struct domain *d) +{ + return iommu_dt_domain_init(d); +} + +void arch_iommu_domain_destroy(struct domain *d) +{ + iommu_dt_domain_destroy(d); +} diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h index 9e47ca6..ed04344 100644 --- a/xen/include/asm-arm/device.h +++ b/xen/include/asm-arm/device.h @@ -6,7 +6,8 @@ enum device_type { - DEVICE_SERIAL + DEVICE_SERIAL, + DEVICE_IOMMU, }; struct device_desc { diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index ec66a4e..21d0920 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -9,6 +9,7 @@ #include #include #include +#include /* Represents state corresponding to a block of 32 interrupts */ struct vgic_irq_rank { @@ -72,6 +73,7 @@ struct pending_irq struct hvm_domain { uint64_t params[HVM_NR_PARAMS]; + struct hvm_iommu iommu; } __cacheline_aligned; #ifdef CONFIG_ARM_64 diff --git a/xen/include/asm-arm/hvm/iommu.h b/xen/include/asm-arm/hvm/iommu.h new file mode 100644 index 0000000..461c8cf --- /dev/null +++ b/xen/include/asm-arm/hvm/iommu.h @@ -0,0 +1,10 @@ +#ifndef __ASM_ARM_HVM_IOMMU_H_ +#define __ASM_ARM_HVM_IOMMU_H_ + +struct arch_hvm_iommu +{ + /* Private information for the IOMMU drivers */ + void *priv; +}; + +#endif /* __ASM_ARM_HVM_IOMMU_H_ */ diff --git a/xen/include/asm-arm/iommu.h b/xen/include/asm-arm/iommu.h new file mode 100644 index 0000000..9322f08 --- /dev/null +++ b/xen/include/asm-arm/iommu.h @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. +*/ +#ifndef __ARCH_ARM_IOMMU_H__ +#define __ARCH_ARM_IOMMU_H__ + +/* Always share P2M Table between the CPU and the IOMMU */ +#define iommu_use_hap_pt(d) (1) +#define domain_hvm_iommu(d) (&d->arch.hvm_domain.iommu) + +const struct iommu_ops *iommu_get_ops(void); +void __init iommu_set_ops(const struct iommu_ops *ops); + +int __init iommu_hardware_setup(void); + +#endif /* __ARCH_ARM_IOMMU_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */