summaryrefslogtreecommitdiff
path: root/drivers/misc/cxl/vphb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/cxl/vphb.c')
-rw-r--r--drivers/misc/cxl/vphb.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c
index 2eba002b580b..6dd16a6d153f 100644
--- a/drivers/misc/cxl/vphb.c
+++ b/drivers/misc/cxl/vphb.c
@@ -138,6 +138,26 @@ static int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn,
return 0;
}
+
+static inline bool cxl_config_link_ok(struct pci_bus *bus)
+{
+ struct pci_controller *phb;
+ struct cxl_afu *afu;
+
+ /* Config space IO is based on phb->cfg_addr, which is based on
+ * afu_desc_mmio. This isn't safe to read/write when the link
+ * goes down, as EEH tears down MMIO space.
+ *
+ * Check if the link is OK before proceeding.
+ */
+
+ phb = pci_bus_to_host(bus);
+ if (phb == NULL)
+ return false;
+ afu = (struct cxl_afu *)phb->private_data;
+ return cxl_adapter_link_ok(afu->adapter);
+}
+
static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
@@ -150,6 +170,9 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
if (rc)
return rc;
+ if (!cxl_config_link_ok(bus))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
/* Can only read 32 bits */
*val = (in_le32(ioaddr) >> shift) & mask;
return PCIBIOS_SUCCESSFUL;
@@ -167,6 +190,9 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
if (rc)
return rc;
+ if (!cxl_config_link_ok(bus))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
/* Can only write 32 bits so do read-modify-write */
mask <<= shift;
val <<= shift;
@@ -240,6 +266,14 @@ int cxl_pci_vphb_add(struct cxl_afu *afu)
return 0;
}
+void cxl_pci_vphb_reconfigure(struct cxl_afu *afu)
+{
+ /* When we are reconfigured, the AFU's MMIO space is unmapped
+ * and remapped. We need to reflect this in the PHB's view of
+ * the world.
+ */
+ afu->phb->cfg_addr = afu->afu_desc_mmio + afu->crs_offset;
+}
void cxl_pci_vphb_remove(struct cxl_afu *afu)
{