Now struct msi_desc can carry a preset IOVA for MSI doorbell address. This
is typically preset by user space when engaging a 2-stage translation. So,
use the preset IOVA instead of kernel-level IOVA allocations in dma-iommu.
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/irqchip/irq-gic-v3-its.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index ab597e74ba08..bc1768576546 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1723,6 +1723,8 @@ static u64 its_irq_get_msi_base(struct its_device *its_dev)
static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
+ struct msi_desc *desc = irq_data_get_msi_desc(d);
+ dma_addr_t iova = msi_desc_get_iova(desc);
struct its_node *its;
u64 addr;
@@ -1733,7 +1735,13 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
msg->address_hi = upper_32_bits(addr);
msg->data = its_get_event_id(d);
- iommu_dma_compose_msi_msg(irq_data_get_msi_desc(d), msg);
+ /* Bypass iommu_dma_compose_msi_msg if msi_iova is preset */
+ if (iova == PHYS_ADDR_MAX) {
+ iommu_dma_compose_msi_msg(desc, msg);
+ } else {
+ msg->address_lo = lower_32_bits(iova);
+ msg->address_hi = upper_32_bits(iova);
+ }
}
static int its_irq_set_irqchip_state(struct irq_data *d,
@@ -3570,6 +3578,7 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
{
msi_alloc_info_t *info = args;
struct its_device *its_dev = info->scratchpad[0].ptr;
+ dma_addr_t iova = msi_desc_get_iova(info->desc);
struct its_node *its = its_dev->its;
struct irq_data *irqd;
irq_hw_number_t hwirq;
@@ -3580,9 +3589,13 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
if (err)
return err;
- err = iommu_dma_prepare_msi(info->desc, its->get_msi_base(its_dev));
- if (err)
- return err;
+ /* Bypass iommu_dma_prepare_msi if msi_iova is preset */
+ if (iova == PHYS_ADDR_MAX) {
+ err = iommu_dma_prepare_msi(info->desc,
+ its->get_msi_base(its_dev));
+ if (err)
+ return err;
+ }
for (i = 0; i < nr_irqs; i++) {
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
--
2.43.0