From: Eric Auger <eric.auger@linaro.org>
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 [thread overview]
Message-ID: <1456856877-4817-13-git-send-email-eric.auger@linaro.org> (raw)
In-Reply-To: <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 <eric.auger@linaro.org>
---
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 <linux/pci.h>
+#include <linux/iommu.h>
+#include <linux/dma-reserved-iommu.h>
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;
}
--
1.9.1
next prev parent reply other threads:[~2016-03-01 18:27 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-01 18:27 [RFC v5 00/17] KVM PCIe/MSI passthrough on ARM/ARM64 Eric Auger
[not found] ` <1456856877-4817-1-git-send-email-eric.auger-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2016-03-01 18:27 ` [RFC v5 01/17] iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute Eric Auger
2016-03-01 18:27 ` [RFC v5 06/17] dma-reserved-iommu: iommu_get/put_single_reserved Eric Auger
[not found] ` <1456856877-4817-7-git-send-email-eric.auger-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2016-03-10 11:52 ` Jean-Philippe Brucker
[not found] ` <20160310115253.GA14609-lfHAr0XZR/HZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>
2016-03-29 17:07 ` Eric Auger
2016-03-01 18:27 ` [RFC v5 02/17] iommu/arm-smmu: advertise DOMAIN_ATTR_MSI_MAPPING attribute Eric Auger
2016-03-01 18:27 ` [RFC v5 03/17] iommu: introduce a reserved iova cookie Eric Auger
2016-03-03 16:26 ` Julien Grall
2016-03-29 17:26 ` Eric Auger
2016-03-01 18:27 ` [RFC v5 04/17] dma-reserved-iommu: alloc/free_reserved_iova_domain Eric Auger
2016-03-01 18:27 ` [RFC v5 05/17] dma-reserved-iommu: reserved binding rb-tree and helpers Eric Auger
2016-03-01 18:27 ` [RFC v5 07/17] dma-reserved-iommu: iommu_unmap_reserved Eric Auger
2016-03-01 18:27 ` [RFC v5 08/17] msi: Add a new MSI_FLAG_IRQ_REMAPPING flag Eric Auger
2016-03-01 18:27 ` [RFC v5 09/17] irqchip/gic-v3-its: ITS advertises MSI_FLAG_IRQ_REMAPPING Eric Auger
2016-03-01 18:27 ` [RFC v5 10/17] msi: export msi_get_domain_info Eric Auger
2016-03-01 18:27 ` [RFC v5 11/17] msi: msi_compose wrapper Eric Auger
2016-03-01 18:27 ` Eric Auger [this message]
2016-03-01 18:27 ` [RFC v5 13/17] vfio: introduce VFIO_IOVA_RESERVED vfio_dma type Eric Auger
2016-03-01 18:27 ` [RFC v5 14/17] vfio: allow the user to register reserved iova range for MSI mapping Eric Auger
2016-03-01 18:27 ` [RFC v5 15/17] vfio/type1: also check IRQ remapping capability at msi domain Eric Auger
2016-03-01 18:27 ` [RFC v5 16/17] iommu/arm-smmu: do not advertise IOMMU_CAP_INTR_REMAP Eric Auger
2016-03-01 18:27 ` [RFC v5 17/17] vfio/type1: return MSI mapping requirements with VFIO_IOMMU_GET_INFO Eric Auger
2016-03-02 8:11 ` [RFC v5 00/17] KVM PCIe/MSI passthrough on ARM/ARM64 Jaggi, Manish
[not found] ` <BY1PR0701MB1594168E79366B507B7C8A16E1BC0-vsFp3N3nJ9josxbTuffl3E5OhdzP3rhOnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
2016-03-02 12:30 ` Eric Auger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1456856877-4817-13-git-send-email-eric.auger@linaro.org \
--to=eric.auger@linaro.org \
--cc=Bharat.Bhushan@freescale.com \
--cc=Manish.Jaggi@caviumnetworks.com \
--cc=alex.williamson@redhat.com \
--cc=christoffer.dall@linaro.org \
--cc=eric.auger@st.com \
--cc=iommu@lists.linux-foundation.org \
--cc=jason@lakedaemon.net \
--cc=joro@8bytes.org \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=p.fedin@samsung.com \
--cc=patches@linaro.org \
--cc=pranav.sawargaonkar@gmail.com \
--cc=robin.murphy@arm.com \
--cc=suravee.suthikulpanit@amd.com \
--cc=tglx@linutronix.de \
--cc=will.deacon@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).