]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/misc/cxl/vphb.c
Merge tag 'sh-for-4.8' of git://git.libc.org/linux-sh
[karo-tx-linux.git] / drivers / misc / cxl / vphb.c
index cdc7723b845dba3a086b4357c6cccca231423e5b..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)
@@ -44,7 +45,6 @@ static bool cxl_pci_enable_device_hook(struct pci_dev *dev)
 {
        struct pci_controller *phb;
        struct cxl_afu *afu;
-       struct cxl_context *ctx;
 
        phb = pci_bus_to_host(dev->bus);
        afu = (struct cxl_afu *)phb->private_data;
@@ -57,30 +57,7 @@ static bool cxl_pci_enable_device_hook(struct pci_dev *dev)
        set_dma_ops(&dev->dev, &dma_direct_ops);
        set_dma_offset(&dev->dev, PAGE_OFFSET);
 
-       /*
-        * Allocate a context to do cxl things too.  If we eventually do real
-        * DMA ops, we'll need a default context to attach them to
-        */
-       ctx = cxl_dev_context_init(dev);
-       if (!ctx)
-               return false;
-       dev->dev.archdata.cxl_ctx = ctx;
-
-       return (cxl_ops->afu_check_and_enable(afu) == 0);
-}
-
-static void cxl_pci_disable_device(struct pci_dev *dev)
-{
-       struct cxl_context *ctx = cxl_get_context(dev);
-
-       if (ctx) {
-               if (ctx->status == STARTED) {
-                       dev_err(&dev->dev, "Default context started\n");
-                       return;
-               }
-               dev->dev.archdata.cxl_ctx = NULL;
-               cxl_release_context(ctx);
-       }
+       return _cxl_pci_associate_default_context(dev, afu);
 }
 
 static resource_size_t cxl_pci_window_alignment(struct pci_bus *bus,
@@ -197,8 +174,8 @@ static struct pci_controller_ops cxl_pci_controller_ops =
 {
        .probe_mode = cxl_pci_probe_mode,
        .enable_device_hook = cxl_pci_enable_device_hook,
-       .disable_device = cxl_pci_disable_device,
-       .release_device = cxl_pci_disable_device,
+       .disable_device = _cxl_pci_disable_device,
+       .release_device = _cxl_pci_disable_device,
        .window_alignment = cxl_pci_window_alignment,
        .reset_secondary_bus = cxl_pci_reset_secondary_bus,
        .setup_msi_irqs = cxl_setup_msi_irqs,
@@ -208,20 +185,30 @@ static struct pci_controller_ops cxl_pci_controller_ops =
 
 int cxl_pci_vphb_add(struct cxl_afu *afu)
 {
-       struct pci_dev *phys_dev;
-       struct pci_controller *phb, *phys_phb;
+       struct pci_controller *phb;
        struct device_node *vphb_dn;
        struct device *parent;
 
-       if (cpu_has_feature(CPU_FTR_HVMODE)) {
-               phys_dev = to_pci_dev(afu->adapter->dev.parent);
-               phys_phb = pci_bus_to_host(phys_dev->bus);
-               vphb_dn = phys_phb->dn;
-               parent = &phys_dev->dev;
-       } else {
-               vphb_dn = afu->adapter->dev.parent->of_node;
-               parent = afu->adapter->dev.parent;
-       }
+       /*
+        * If there are no AFU configuration records we won't have anything to
+        * expose under the vPHB, so skip creating one, returning success since
+        * this is still a valid case. This will also opt us out of EEH
+        * handling since we won't have anything special to do if there are no
+        * kernel drivers attached to the vPHB, and EEH handling is not yet
+        * supported in the peer model.
+        */
+       if (!afu->crs_num)
+               return 0;
+
+       /* The parent device is the adapter. Reuse the device node of
+        * the adapter.
+        * We don't seem to care what device node is used for the vPHB,
+        * but tools such as lsvpd walk up the device parents looking
+        * for a valid location code, so we might as well show devices
+        * attached to the adapter as being located on that adapter.
+        */
+       parent = afu->adapter->dev.parent;
+       vphb_dn = parent->of_node;
 
        /* Alloc and setup PHB data structure */
        phb = pcibios_alloc_controller(vphb_dn);
@@ -272,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)
@@ -287,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);