diff options
Diffstat (limited to 'drivers/misc/cxl/vphb.c')
| -rw-r--r-- | drivers/misc/cxl/vphb.c | 34 | 
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)  {  |