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: Eric Auger X-Patchwork-Id: 8468851 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 173EBC0553 for ; Tue, 1 Mar 2016 18:35:40 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 07E6F20266 for ; Tue, 1 Mar 2016 18:35:39 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 03EAA20115 for ; Tue, 1 Mar 2016 18:35:38 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aap7M-0008J6-DJ; Tue, 01 Mar 2016 18:33:56 +0000 Received: from mail-wm0-x231.google.com ([2a00:1450:400c:c09::231]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aap2n-0001mY-EQ for linux-arm-kernel@lists.infradead.org; Tue, 01 Mar 2016 18:29:18 +0000 Received: by mail-wm0-x231.google.com with SMTP id n186so50803375wmn.1 for ; Tue, 01 Mar 2016 10:28:52 -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=Z4qbTPAoWo2MMb+RFo+cQ7Z2G0u/FqPoXV6mtHLWRgNYaNGHDYrNwBNVFWdsErl5D6 yYetGyMxaFUmqHOd6jZ4ltoINwHbg+GjvK1GxfrIMF7mn0jvOrhaa0H4mWX0hq2E5T6t OqAQpKFuAhX7VQYm0qBX7Hs801EPvZD86ETRcBMeiDeDtGam+IarAVuUM0OQT3dACyvX 0KYli+ih5f2gmK+MtaVP7bzA/eUHHBfugoE9Z36cW+X/Z2r6Dp2HWsB5KhhetzguuGkp CqV+KRyyaGgErwmUjoVnzX6V6pYvZxx8qljZSuvB8UfOWvWMn4Q6TSJ/K+LDrJfGIoCw NUbQ== X-Gm-Message-State: AD7BkJLEq3MHLC60KiQ9bioIIIE3XD09xl7rb5NVhS5cobl7DYaHsoRBipSRhn3W+/1DzFaY X-Received: by 10.28.145.8 with SMTP id t8mr411484wmd.103.1456856931589; Tue, 01 Mar 2016 10:28:51 -0800 (PST) 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 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> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160301_102913_906130_4B92F19E X-CRM114-Status: GOOD ( 19.43 ) X-Spam-Score: -2.7 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org, Manish.Jaggi@caviumnetworks.com, p.fedin@samsung.com, linux-kernel@vger.kernel.org, Bharat.Bhushan@freescale.com, iommu@lists.linux-foundation.org, pranav.sawargaonkar@gmail.com, suravee.suthikulpanit@amd.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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(+) 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; }