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.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c
index 2eba002b580b..2930911c1e42 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;