From patchwork Tue Mar 1 18:27:52 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Auger Eric X-Patchwork-Id: 63335 Delivered-To: patches@linaro.org Received: by 10.112.199.169 with SMTP id jl9csp1981653lbc; Tue, 1 Mar 2016 10:28:51 -0800 (PST) X-Received: by 10.194.115.196 with SMTP id jq4mr21798994wjb.101.1456856931793; Tue, 01 Mar 2016 10:28:51 -0800 (PST) Return-Path: Received: from mail-wm0-x22f.google.com (mail-wm0-x22f.google.com. [2a00:1450:400c:c09::22f]) by mx.google.com with ESMTPS id s132si416841wmf.100.2016.03.01.10.28.51 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 01 Mar 2016 10:28:51 -0800 (PST) Received-SPF: pass (google.com: domain of eric.auger@linaro.org designates 2a00:1450:400c:c09::22f as permitted sender) client-ip=2a00:1450:400c:c09::22f; Authentication-Results: mx.google.com; spf=pass (google.com: domain of eric.auger@linaro.org designates 2a00:1450:400c:c09::22f as permitted sender) smtp.mailfrom=eric.auger@linaro.org; dkim=pass header.i=@linaro.org Received: by mail-wm0-x22f.google.com with SMTP id n186so50803379wmn.1 for ; Tue, 01 Mar 2016 10:28:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=eTGNGTGbbaLnqX9zH9YPUUvZMADk97YTsd3rgkXU0yk=; b=CU8JPrspSbDAx/fIcS6McYiCIdhknFo+lFkNGUIxFDbsB76cEJuHY/hk+Xtl6G8SsP Zg1o/s/AMamqOR4RQTbds2252gScXZt9MQSArwxyowyYffp2KzdyBVX72mgtR5KXsX11 YHdGQseqPEiLWTe9GvYWjVJu5hmMgzT10TO8E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=eTGNGTGbbaLnqX9zH9YPUUvZMADk97YTsd3rgkXU0yk=; b=AqGCuLVogcgjlhYdpgJ4wXAZf/6JDdWgBJoAHCewXnHalKh5GPCieAFoHgbOT440EN GM91mgdTsQiv5luRJUabf4CSluFxcWVfhE0QAibMDq4WP+LpVeFzaoJuRc42+/lT7mNW I1DG2Zv5w+BTItLOY+izQCTc3wDxJyCQo3nDGIfdKqRd2IxzoH8iyeVnVwfKDIFxXsQk RoH2mmbKCbw78qRpSHztTnx1mfjT7Qfo62h4IF5Wk0ujZI8caxWp19+2dec6xbknsV4l Un/UWkidRuDg9qpMgxtN84t6OiI9zIAU1EC2vStnP4Uc9hoM/4N5XrtB8vzzbmXE3X93 sNBg== X-Gm-Message-State: AD7BkJK8cQiMLiQxHRVbJEe4o/ku8XPwoHlYVxia7ijBJWuA/c0Ecz0FciUJbFPo7DzHpfacigU= X-Received: by 10.28.145.8 with SMTP id t8mr411484wmd.103.1456856931589; Tue, 01 Mar 2016 10:28:51 -0800 (PST) Return-Path: Received: from new-host-8.home (LMontsouris-657-1-37-90.w80-11.abo.wanadoo.fr. [80.11.198.90]) by smtp.gmail.com with ESMTPSA id k8sm32176385wjr.38.2016.03.01.10.28.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 01 Mar 2016 10:28:48 -0800 (PST) From: Eric Auger To: eric.auger@st.com, eric.auger@linaro.org, robin.murphy@arm.com, alex.williamson@redhat.com, will.deacon@arm.com, joro@8bytes.org, tglx@linutronix.de, jason@lakedaemon.net, marc.zyngier@arm.com, christoffer.dall@linaro.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Cc: suravee.suthikulpanit@amd.com, patches@linaro.org, linux-kernel@vger.kernel.org, Manish.Jaggi@caviumnetworks.com, Bharat.Bhushan@freescale.com, pranav.sawargaonkar@gmail.com, p.fedin@samsung.com, iommu@lists.linux-foundation.org Subject: [RFC v5 12/17] msi: IOMMU map the doorbell address when needed Date: Tue, 1 Mar 2016 18:27:52 +0000 Message-Id: <1456856877-4817-13-git-send-email-eric.auger@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1456856877-4817-1-git-send-email-eric.auger@linaro.org> References: <1456856877-4817-1-git-send-email-eric.auger@linaro.org> In case the msi is emitted by a device attached to an iommu domain and this iommu domain requires MSI mapping, the msi address (aka doorbell) must be mapped in the IOMMU. Else MSI write transaction will cause a fault. We perform this action at msi message composition time. On any MSI address change and MSI message erasure we decrement the reference counter to the IOMMU binding. In case the mapping fails we just WARN_ON. Signed-off-by: Eric Auger --- v5: - use macros to increase the readability - add comments - fix a typo that caused a compilation error if CONFIG_IOMMU_API is not set --- include/linux/msi.h | 15 +++++++ kernel/irq/msi.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) -- 1.9.1 diff --git a/include/linux/msi.h b/include/linux/msi.h index 03eda72..b920cac 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -10,6 +10,21 @@ struct msi_msg { u32 data; /* 16 bits of msi message data */ }; +/* Helpers to convert the msi message address to a an iova/physical address */ +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +#define msg_to_dma_addr(msg) \ + (((dma_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo) +#else +#define msg_to_dma_addr(msg) ((msg)->address_lo) +#endif + +#ifdef CONFIG_PHYS_ADDR_T_64BIT +#define msg_to_phys_addr(msg) \ + (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo) +#else +#define msg_to_phys_addr(msg) ((msg)->address_lo) +#endif + extern int pci_msi_ignore_mask; /* Helper functions */ struct irq_data; diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 72bf4d6..8ddbe57 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -17,6 +17,8 @@ /* Temparory solution for building, will be removed later */ #include +#include +#include struct msi_desc *alloc_msi_entry(struct device *dev) { @@ -55,16 +57,133 @@ static inline void irq_chip_write_msi_msg(struct irq_data *data, data->chip->irq_write_msi_msg(data, msg); } +/** + * msi_map_doorbell: make sure an IOMMU mapping exists on domain @d + * for the message physical address (aka. doorbell) + * + * Either allocate an IOVA and create a mapping or simply increment + * a reference count on the existing IOMMU mapping + * @d: iommu domain handle the mapping belongs to + * @msg: msi message handle + */ +static int msi_map_doorbell(struct iommu_domain *d, struct msi_msg *msg) +{ +#ifdef CONFIG_IOMMU_DMA_RESERVED + phys_addr_t addr; + dma_addr_t iova; + int ret; + + addr = msg_to_phys_addr(msg); + ret = iommu_get_single_reserved(d, addr, IOMMU_WRITE, &iova); + if (!ret) { + msg->address_lo = lower_32_bits(iova); + msg->address_hi = upper_32_bits(iova); + } + return ret; +#else + return -ENODEV; +#endif +} + +/** + * msi_unmap_doorbell: decrements the reference count on an existing + * doorbell IOMMU mapping + * + * @d: iommu domain the mapping is attached to + * @msg: msi message containing the doorbell IOVA to unbind + */ +static void msi_unmap_doorbell(struct iommu_domain *d, struct msi_msg *msg) +{ +#ifdef CONFIG_IOMMU_DMA_RESERVED + dma_addr_t iova; + + iova = msg_to_dma_addr(msg); + iommu_put_single_reserved(d, iova); +#endif +} + +#ifdef CONFIG_IOMMU_API +/** + * irq_data_to_msi_mapping_domain: checks if an irq corresponds to + * an MSI whose write address must be mapped in an IOMMU domain + * + * determine whether the irq corresponds to an MSI emitted by a device, + * upstream to an IOMMU, and if this IOMMU requires a binding of the + * MSI address + * + * @irq_data: irq data handle + */ +static struct iommu_domain * +irq_data_to_msi_mapping_domain(struct irq_data *irq_data) +{ + struct iommu_domain *d; + struct msi_desc *desc; + struct device *dev; + int ret; + + desc = irq_data_get_msi_desc(irq_data); + if (!desc) + return NULL; + + dev = msi_desc_to_dev(desc); + + d = iommu_get_domain_for_dev(dev); + if (!d) + return NULL; + + ret = iommu_domain_get_attr(d, DOMAIN_ATTR_MSI_MAPPING, NULL); + if (!ret) + return d; + else + return NULL; +} +#else +static inline struct iommu_domain * +irq_data_to_msi_mapping_domain(struct irq_data *irq_data) +{ + return NULL; +} +#endif /* CONFIG_IOMMU_API */ + static int msi_compose(struct irq_data *irq_data, struct msi_msg *msg, bool erase) { + struct msi_msg old_msg; + struct iommu_domain *d; int ret = 0; + /* + * Does this IRQ require an MSI address mapping in an IOMMU? + * If it does, read the existing cached message. This will allow + * to check if the IOMMU mapping needs an update + */ + d = irq_data_to_msi_mapping_domain(irq_data); + if (unlikely(d)) + get_cached_msi_msg(irq_data->irq, &old_msg); + if (erase) memset(msg, 0, sizeof(*msg)); else ret = irq_chip_compose_msi_msg(irq_data, msg); + if (!d) + goto out; + + /* + * An MSI address IOMMU binding needs to be handled. + * In case we have a change in the MSI address or an MSI + * message erasure, destroy the existing binding. + * In case we have an actual MSI message composition + * bind the new MSI address + */ + if ((old_msg.address_lo != msg->address_lo) || + (old_msg.address_hi != msg->address_hi)) + msi_unmap_doorbell(d, &old_msg); + + if (!erase) + WARN_ON(msi_map_doorbell(d, msg)); + +out: return ret; }