Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iommu/dma: Add support for mapping MSIs

When an MSI doorbell is located downstream of an IOMMU, attaching
devices to a DMA ops domain and switching on translation leads to a rude
shock when their attempt to write to the physical address returned by
the irqchip driver faults (or worse, writes into some already-mapped
buffer) and no interrupt is forthcoming.

Address this by adding a hook for relevant irqchip drivers to call from
their compose_msi_msg() callback, to swizzle the physical address with
an appropriatly-mapped IOVA for any device attached to one of our DMA
ops domains.

Acked-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>

authored by

Robin Murphy and committed by
Will Deacon
44bb7e24 455eb7d3

+136 -15
+121 -15
drivers/iommu/dma-iommu.c
··· 25 25 #include <linux/huge_mm.h> 26 26 #include <linux/iommu.h> 27 27 #include <linux/iova.h> 28 + #include <linux/irq.h> 28 29 #include <linux/mm.h> 29 30 #include <linux/scatterlist.h> 30 31 #include <linux/vmalloc.h> 32 + 33 + struct iommu_dma_msi_page { 34 + struct list_head list; 35 + dma_addr_t iova; 36 + phys_addr_t phys; 37 + }; 38 + 39 + struct iommu_dma_cookie { 40 + struct iova_domain iovad; 41 + struct list_head msi_page_list; 42 + spinlock_t msi_lock; 43 + }; 44 + 45 + static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain) 46 + { 47 + return &((struct iommu_dma_cookie *)domain->iova_cookie)->iovad; 48 + } 31 49 32 50 int iommu_dma_init(void) 33 51 { ··· 61 43 */ 62 44 int iommu_get_dma_cookie(struct iommu_domain *domain) 63 45 { 64 - struct iova_domain *iovad; 46 + struct iommu_dma_cookie *cookie; 65 47 66 48 if (domain->iova_cookie) 67 49 return -EEXIST; 68 50 69 - iovad = kzalloc(sizeof(*iovad), GFP_KERNEL); 70 - domain->iova_cookie = iovad; 51 + cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); 52 + if (!cookie) 53 + return -ENOMEM; 71 54 72 - return iovad ? 0 : -ENOMEM; 55 + spin_lock_init(&cookie->msi_lock); 56 + INIT_LIST_HEAD(&cookie->msi_page_list); 57 + domain->iova_cookie = cookie; 58 + return 0; 73 59 } 74 60 EXPORT_SYMBOL(iommu_get_dma_cookie); 75 61 ··· 85 63 */ 86 64 void iommu_put_dma_cookie(struct iommu_domain *domain) 87 65 { 88 - struct iova_domain *iovad = domain->iova_cookie; 66 + struct iommu_dma_cookie *cookie = domain->iova_cookie; 67 + struct iommu_dma_msi_page *msi, *tmp; 89 68 90 - if (!iovad) 69 + if (!cookie) 91 70 return; 92 71 93 - if (iovad->granule) 94 - put_iova_domain(iovad); 95 - kfree(iovad); 72 + if (cookie->iovad.granule) 73 + put_iova_domain(&cookie->iovad); 74 + 75 + list_for_each_entry_safe(msi, tmp, &cookie->msi_page_list, list) { 76 + list_del(&msi->list); 77 + kfree(msi); 78 + } 79 + kfree(cookie); 96 80 domain->iova_cookie = NULL; 97 81 } 98 82 EXPORT_SYMBOL(iommu_put_dma_cookie); ··· 116 88 */ 117 89 int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size) 118 90 { 119 - struct iova_domain *iovad = domain->iova_cookie; 91 + struct iova_domain *iovad = cookie_iovad(domain); 120 92 unsigned long order, base_pfn, end_pfn; 121 93 122 94 if (!iovad) ··· 183 155 static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, 184 156 dma_addr_t dma_limit) 185 157 { 186 - struct iova_domain *iovad = domain->iova_cookie; 158 + struct iova_domain *iovad = cookie_iovad(domain); 187 159 unsigned long shift = iova_shift(iovad); 188 160 unsigned long length = iova_align(iovad, size) >> shift; 189 161 ··· 199 171 /* The IOVA allocator knows what we mapped, so just unmap whatever that was */ 200 172 static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr) 201 173 { 202 - struct iova_domain *iovad = domain->iova_cookie; 174 + struct iova_domain *iovad = cookie_iovad(domain); 203 175 unsigned long shift = iova_shift(iovad); 204 176 unsigned long pfn = dma_addr >> shift; 205 177 struct iova *iova = find_iova(iovad, pfn); ··· 322 294 void (*flush_page)(struct device *, const void *, phys_addr_t)) 323 295 { 324 296 struct iommu_domain *domain = iommu_get_domain_for_dev(dev); 325 - struct iova_domain *iovad = domain->iova_cookie; 297 + struct iova_domain *iovad = cookie_iovad(domain); 326 298 struct iova *iova; 327 299 struct page **pages; 328 300 struct sg_table sgt; ··· 414 386 { 415 387 dma_addr_t dma_addr; 416 388 struct iommu_domain *domain = iommu_get_domain_for_dev(dev); 417 - struct iova_domain *iovad = domain->iova_cookie; 389 + struct iova_domain *iovad = cookie_iovad(domain); 418 390 phys_addr_t phys = page_to_phys(page) + offset; 419 391 size_t iova_off = iova_offset(iovad, phys); 420 392 size_t len = iova_align(iovad, size + iova_off); ··· 523 495 int nents, int prot) 524 496 { 525 497 struct iommu_domain *domain = iommu_get_domain_for_dev(dev); 526 - struct iova_domain *iovad = domain->iova_cookie; 498 + struct iova_domain *iovad = cookie_iovad(domain); 527 499 struct iova *iova; 528 500 struct scatterlist *s, *prev = NULL; 529 501 dma_addr_t dma_addr; ··· 614 586 int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) 615 587 { 616 588 return dma_addr == DMA_ERROR_CODE; 589 + } 590 + 591 + static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, 592 + phys_addr_t msi_addr, struct iommu_domain *domain) 593 + { 594 + struct iommu_dma_cookie *cookie = domain->iova_cookie; 595 + struct iommu_dma_msi_page *msi_page; 596 + struct iova_domain *iovad = &cookie->iovad; 597 + struct iova *iova; 598 + int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; 599 + 600 + msi_addr &= ~(phys_addr_t)iova_mask(iovad); 601 + list_for_each_entry(msi_page, &cookie->msi_page_list, list) 602 + if (msi_page->phys == msi_addr) 603 + return msi_page; 604 + 605 + msi_page = kzalloc(sizeof(*msi_page), GFP_ATOMIC); 606 + if (!msi_page) 607 + return NULL; 608 + 609 + iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev)); 610 + if (!iova) 611 + goto out_free_page; 612 + 613 + msi_page->phys = msi_addr; 614 + msi_page->iova = iova_dma_addr(iovad, iova); 615 + if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot)) 616 + goto out_free_iova; 617 + 618 + INIT_LIST_HEAD(&msi_page->list); 619 + list_add(&msi_page->list, &cookie->msi_page_list); 620 + return msi_page; 621 + 622 + out_free_iova: 623 + __free_iova(iovad, iova); 624 + out_free_page: 625 + kfree(msi_page); 626 + return NULL; 627 + } 628 + 629 + void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) 630 + { 631 + struct device *dev = msi_desc_to_dev(irq_get_msi_desc(irq)); 632 + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); 633 + struct iommu_dma_cookie *cookie; 634 + struct iommu_dma_msi_page *msi_page; 635 + phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo; 636 + unsigned long flags; 637 + 638 + if (!domain || !domain->iova_cookie) 639 + return; 640 + 641 + cookie = domain->iova_cookie; 642 + 643 + /* 644 + * We disable IRQs to rule out a possible inversion against 645 + * irq_desc_lock if, say, someone tries to retarget the affinity 646 + * of an MSI from within an IPI handler. 647 + */ 648 + spin_lock_irqsave(&cookie->msi_lock, flags); 649 + msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain); 650 + spin_unlock_irqrestore(&cookie->msi_lock, flags); 651 + 652 + if (WARN_ON(!msi_page)) { 653 + /* 654 + * We're called from a void callback, so the best we can do is 655 + * 'fail' by filling the message with obviously bogus values. 656 + * Since we got this far due to an IOMMU being present, it's 657 + * not like the existing address would have worked anyway... 658 + */ 659 + msg->address_hi = ~0U; 660 + msg->address_lo = ~0U; 661 + msg->data = ~0U; 662 + } else { 663 + msg->address_hi = upper_32_bits(msi_page->iova); 664 + msg->address_lo &= iova_mask(&cookie->iovad); 665 + msg->address_lo += lower_32_bits(msi_page->iova); 666 + } 617 667 }
+3
drivers/irqchip/irq-gic-v2m.c
··· 16 16 #define pr_fmt(fmt) "GICv2m: " fmt 17 17 18 18 #include <linux/acpi.h> 19 + #include <linux/dma-iommu.h> 19 20 #include <linux/irq.h> 20 21 #include <linux/irqdomain.h> 21 22 #include <linux/kernel.h> ··· 109 108 110 109 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) 111 110 msg->data -= v2m->spi_offset; 111 + 112 + iommu_dma_map_msi_msg(data->irq, msg); 112 113 } 113 114 114 115 static struct irq_chip gicv2m_irq_chip = {
+3
drivers/irqchip/irq-gic-v3-its.c
··· 18 18 #include <linux/bitmap.h> 19 19 #include <linux/cpu.h> 20 20 #include <linux/delay.h> 21 + #include <linux/dma-iommu.h> 21 22 #include <linux/interrupt.h> 22 23 #include <linux/log2.h> 23 24 #include <linux/mm.h> ··· 656 655 msg->address_lo = addr & ((1UL << 32) - 1); 657 656 msg->address_hi = addr >> 32; 658 657 msg->data = its_get_event_id(d); 658 + 659 + iommu_dma_map_msi_msg(d->irq, msg); 659 660 } 660 661 661 662 static struct irq_chip its_irq_chip = {
+9
include/linux/dma-iommu.h
··· 21 21 22 22 #ifdef CONFIG_IOMMU_DMA 23 23 #include <linux/iommu.h> 24 + #include <linux/msi.h> 24 25 25 26 int iommu_dma_init(void); 26 27 ··· 63 62 int iommu_dma_supported(struct device *dev, u64 mask); 64 63 int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); 65 64 65 + /* The DMA API isn't _quite_ the whole story, though... */ 66 + void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); 67 + 66 68 #else 67 69 68 70 struct iommu_domain; 71 + struct msi_msg; 69 72 70 73 static inline int iommu_dma_init(void) 71 74 { ··· 82 77 } 83 78 84 79 static inline void iommu_put_dma_cookie(struct iommu_domain *domain) 80 + { 81 + } 82 + 83 + static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) 85 84 { 86 85 } 87 86