sparc64: Bind PCIe devices to use IOMMU v2 service
authorTushar Dave <tushar.n.dave@oracle.com>
Fri, 28 Oct 2016 17:12:43 +0000 (10:12 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Nov 2016 19:16:59 +0000 (11:16 -0800)
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().

Signed-off-by: Tushar Dave <tushar.n.dave@oracle.com>
Reviewed-by: chris hyser <chris.hyser@oracle.com>
Acked-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/pci_sun4v.h
arch/sparc/kernel/pci_sun4v_asm.S

index 242477cbfdf2095b4f1e45e565e67db9a461497f..d4208aa933830c8b2f7023cd4a73e3186377b0ee 100644 (file)
@@ -216,6 +216,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)
 {
@@ -629,6 +666,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 0ef6d1c456e7e92891d26b7360c2f1492e776901..1019e0fe6e9dd0466ed54c36385392acd09cd1c3 100644 (file)
@@ -96,4 +96,7 @@ unsigned long pci_sun4v_iotsb_conf(unsigned long devhandle,
                                   unsigned long page_size,
                                   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 fd94d0e4a41d97aaa38b2548c28ed734b091f58f..22024a96c317559b1605a2a69fb55adcdb628297 100644 (file)
@@ -378,3 +378,17 @@ ENTRY(pci_sun4v_iotsb_conf)
        retl
         stx    %o1, [%g1]
 ENDPROC(pci_sun4v_iotsb_conf)
+
+       /*
+        * %o0: devhandle
+        * %o1: iotsb_num/iotsb_handle
+        * %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)