cxl: Add support for using the kernel API with a real PHB
authorIan Munsie <imunsie@au1.ibm.com>
Wed, 13 Jul 2016 21:17:07 +0000 (07:17 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 14 Jul 2016 10:26:56 +0000 (20:26 +1000)
This hooks up support for using the kernel API with a real PHB. After
the AFU initialisation has completed it calls into the PHB code to pass
it the AFU that will be used by other peer physical functions on the
adapter.

The cxl_pci_to_afu API is extended to work with peer PCI devices,
retrieving the peer AFU from the PHB. This API may also now return an
error if it is called on a PCI device that is not associated with either
a cxl vPHB or a peer PCI device to an AFU, and this error is propagated
down.

Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
drivers/misc/cxl/api.c
drivers/misc/cxl/pci.c
drivers/misc/cxl/vphb.c

index 7707055d33abadb49765eccd4dcf3b595774d077..6a030bf716559bb279768bbe87b4ba700e9bfb3d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <misc/cxl.h>
 #include <linux/fs.h>
+#include <asm/pnv-pci.h>
 
 #include "cxl.h"
 
@@ -24,6 +25,8 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
        int rc;
 
        afu = cxl_pci_to_afu(dev);
+       if (IS_ERR(afu))
+               return ERR_CAST(afu);
 
        ctx = cxl_context_alloc();
        if (IS_ERR(ctx)) {
@@ -438,6 +441,8 @@ EXPORT_SYMBOL_GPL(cxl_perst_reloads_same_image);
 ssize_t cxl_read_adapter_vpd(struct pci_dev *dev, void *buf, size_t count)
 {
        struct cxl_afu *afu = cxl_pci_to_afu(dev);
+       if (IS_ERR(afu))
+               return -ENODEV;
 
        return cxl_ops->read_adapter_vpd(afu->adapter, buf, count);
 }
index dd7ff221288b00a061d9ac1dc41bd0f63dd82f97..cb5d172fec1b3d02b6930a01ba3ac8572e4b475a 100644 (file)
@@ -1502,6 +1502,9 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
                        dev_err(&dev->dev, "AFU %i failed to start: %i\n", slice, rc);
        }
 
+       if (pnv_pci_on_cxl_phb(dev) && adapter->slices >= 1)
+               pnv_cxl_phb_set_peer_afu(dev, adapter->afu[0]);
+
        return 0;
 }
 
index 8865e8d9b3c59ed8d774e964f898b9343689f5d2..dee8def1c1936c36fc82d894e269c1d8825d5c29 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/pci.h>
 #include <misc/cxl.h>
+#include <asm/pnv-pci.h>
 #include "cxl.h"
 
 static int cxl_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
@@ -258,13 +259,18 @@ void cxl_pci_vphb_remove(struct cxl_afu *afu)
        pcibios_free_controller(phb);
 }
 
+static bool _cxl_pci_is_vphb_device(struct pci_controller *phb)
+{
+       return (phb->ops == &cxl_pcie_pci_ops);
+}
+
 bool cxl_pci_is_vphb_device(struct pci_dev *dev)
 {
        struct pci_controller *phb;
 
        phb = pci_bus_to_host(dev->bus);
 
-       return (phb->ops == &cxl_pcie_pci_ops);
+       return _cxl_pci_is_vphb_device(phb);
 }
 
 struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev)
@@ -273,7 +279,13 @@ struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev)
 
        phb = pci_bus_to_host(dev->bus);
 
-       return (struct cxl_afu *)phb->private_data;
+       if (_cxl_pci_is_vphb_device(phb))
+               return (struct cxl_afu *)phb->private_data;
+
+       if (pnv_pci_on_cxl_phb(dev))
+               return pnv_cxl_phb_to_afu(phb);
+
+       return ERR_PTR(-ENODEV);
 }
 EXPORT_SYMBOL_GPL(cxl_pci_to_afu);