]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: Bind PCIe devices to use IOMMU v2 service
authorAllen Pais <allen.pais@oracle.com>
Fri, 7 Jul 2017 07:59:20 +0000 (13:29 +0530)
committerAllen Pais <allen.pais@oracle.com>
Tue, 11 Jul 2017 07:36:50 +0000 (13:06 +0530)
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 <chris.hyser@oracle.com>
Signed-off-by: Tushar Dave <tushar.n.dave@oracle.com>
Signed-off-by: Allen Pais <allen.pais@oracle.com>
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/pci_sun4v.h
arch/sparc/kernel/pci_sun4v_asm.S

index 459f5bd14346613d0a45c2e9fd778bbdef569154..a43e70cdb6459e09c29aae83f8f204af44b5830c 100644 (file)
@@ -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:
index d0b9f5eefdddd961fc9c8dfa8d3ff4ad6cbd4762..25826c6e3abea66b9e5c1f3ac121d4e1128bbdd2 100644 (file)
@@ -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) */
index 1b70b565691a757b66e683d63d89d8ff569730bc..00e55efdc379ed212430bb7bd87f7f10457d89bb 100644 (file)
@@ -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)