From: Allen Pais Date: Fri, 7 Jul 2017 07:59:20 +0000 (+0530) Subject: sparc64: Bind PCIe devices to use IOMMU v2 service X-Git-Tag: v4.1.12-106.0.20170720_1900~84 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=3820f41b6844904aeb9e146d7a080ed808fc3de9;p=users%2Fjedix%2Flinux-maple.git sparc64: Bind PCIe devices to use IOMMU v2 service In order to use Hypervisor (HV) IOMMU v2 API for map/demap, each PCIe device has to be bound to IOTSB using HV API pci_iotsb_bind(). Orabug: 23239179 Reviewed-by: chris hyser Signed-off-by: Tushar Dave Signed-off-by: Allen Pais --- diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 459f5bd14346..a43e70cdb645 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -233,6 +233,43 @@ range_alloc_fail: return NULL; } +unsigned long dma_4v_iotsb_bind(unsigned long devhandle, + unsigned long iotsb_num, + struct pci_bus *bus_dev) +{ + struct pci_dev *pdev; + unsigned long err; + unsigned int bus; + unsigned int device; + unsigned int fun; + + list_for_each_entry(pdev, &bus_dev->devices, bus_list) { + if (pdev->subordinate) { + /* No need to bind pci bridge */ + dma_4v_iotsb_bind(devhandle, iotsb_num, + pdev->subordinate); + } else { + bus = bus_dev->number; + device = PCI_SLOT(pdev->devfn); + fun = PCI_FUNC(pdev->devfn); + err = pci_sun4v_iotsb_bind(devhandle, iotsb_num, + HV_PCI_DEVICE_BUILD(bus, + device, + fun)); + + /* If bind fails for one device it is going to fail + * for rest of the devices because we are sharing + * IOTSB. So in case of failure simply return with + * error. + */ + if (err) + return err; + } + } + + return 0; +} + static void dma_4v_iommu_demap(void *demap_arg, unsigned long entry, unsigned long npages) { @@ -665,6 +702,12 @@ static int pci_sun4v_atu_alloc_iotsb(struct pci_pbm_info *pbm) } iotsb->iotsb_num = iotsb_num; + err = dma_4v_iotsb_bind(pbm->devhandle, iotsb_num, pbm->pci_bus); + if (err) { + pr_err(PFX "pci_iotsb_bind failed error: %ld\n", err); + goto iotsb_conf_failed; + } + return 0; iotsb_conf_failed: diff --git a/arch/sparc/kernel/pci_sun4v.h b/arch/sparc/kernel/pci_sun4v.h index d0b9f5eefddd..25826c6e3abe 100644 --- a/arch/sparc/kernel/pci_sun4v.h +++ b/arch/sparc/kernel/pci_sun4v.h @@ -99,4 +99,8 @@ unsigned long pci_sun4v_iotsb_conf(unsigned long devhandle, unsigned long dvma_base, u64 *iotsb_num); +unsigned long pci_sun4v_iotsb_bind(unsigned long devhandle, + unsigned long iotsb_num, + unsigned int pci_device); + #endif /* !(_PCI_SUN4V_H) */ diff --git a/arch/sparc/kernel/pci_sun4v_asm.S b/arch/sparc/kernel/pci_sun4v_asm.S index 1b70b565691a..00e55efdc379 100644 --- a/arch/sparc/kernel/pci_sun4v_asm.S +++ b/arch/sparc/kernel/pci_sun4v_asm.S @@ -393,3 +393,17 @@ ENTRY(pci_sun4v_iotsb_conf) ret restore ENDPROC(pci_sun4v_iotsb_conf) + + /* + * %o0: devhandle + * %o1: iotsb + * %o2: pci_device + * + * returns %o0: status + */ +ENTRY(pci_sun4v_iotsb_bind) + mov HV_FAST_PCI_IOTSB_BIND, %o5 + ta HV_FAST_TRAP + retl + nop +ENDPROC(pci_sun4v_iotsb_bind)