cxl: fix nested locking hang during EEH hotplug

am: 53d43706f2

Change-Id: I2d209e2170524b6aab237f883b17f8a50e94e811
This commit is contained in:
Andrew Donnellan
2017-03-15 02:20:57 +00:00
committed by android-build-merger
4 changed files with 27 additions and 10 deletions

View File

@@ -418,8 +418,9 @@ struct cxl_afu {
struct dentry *debugfs;
struct mutex contexts_lock;
spinlock_t afu_cntl_lock;
/* Used to block access to AFU config space while deconfigured */
struct rw_semaphore configured_rwsem;
/* -1: AFU deconfigured/locked, >= 0: number of readers */
atomic_t configured_state;
/* AFU error buffer fields and bin attribute for sysfs */
u64 eb_len, eb_offset;

View File

@@ -268,8 +268,7 @@ struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice)
idr_init(&afu->contexts_idr);
mutex_init(&afu->contexts_lock);
spin_lock_init(&afu->afu_cntl_lock);
init_rwsem(&afu->configured_rwsem);
down_write(&afu->configured_rwsem);
atomic_set(&afu->configured_state, -1);
afu->prefault_mode = CXL_PREFAULT_NONE;
afu->irqs_max = afu->adapter->user_irqs;

View File

@@ -1129,7 +1129,7 @@ static int pci_configure_afu(struct cxl_afu *afu, struct cxl *adapter, struct pc
if ((rc = cxl_native_register_psl_irq(afu)))
goto err2;
up_write(&afu->configured_rwsem);
atomic_set(&afu->configured_state, 0);
return 0;
err2:
@@ -1142,7 +1142,14 @@ err1:
static void pci_deconfigure_afu(struct cxl_afu *afu)
{
down_write(&afu->configured_rwsem);
/*
* It's okay to deconfigure when AFU is already locked, otherwise wait
* until there are no readers
*/
if (atomic_read(&afu->configured_state) != -1) {
while (atomic_cmpxchg(&afu->configured_state, 0, -1) != -1)
schedule();
}
cxl_native_release_psl_irq(afu);
if (afu->adapter->native->sl_ops->release_serr_irq)
afu->adapter->native->sl_ops->release_serr_irq(afu);

View File

@@ -83,6 +83,16 @@ static inline struct cxl_afu *pci_bus_to_afu(struct pci_bus *bus)
return phb ? phb->private_data : NULL;
}
static void cxl_afu_configured_put(struct cxl_afu *afu)
{
atomic_dec_if_positive(&afu->configured_state);
}
static bool cxl_afu_configured_get(struct cxl_afu *afu)
{
return atomic_inc_unless_negative(&afu->configured_state);
}
static inline int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn,
struct cxl_afu *afu, int *_record)
{
@@ -107,7 +117,7 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
afu = pci_bus_to_afu(bus);
/* Grab a reader lock on afu. */
if (afu == NULL || !down_read_trylock(&afu->configured_rwsem))
if (afu == NULL || !cxl_afu_configured_get(afu))
return PCIBIOS_DEVICE_NOT_FOUND;
rc = cxl_pcie_config_info(bus, devfn, afu, &record);
@@ -132,7 +142,7 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
}
out:
up_read(&afu->configured_rwsem);
cxl_afu_configured_put(afu);
return rc ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
@@ -144,7 +154,7 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
afu = pci_bus_to_afu(bus);
/* Grab a reader lock on afu. */
if (afu == NULL || !down_read_trylock(&afu->configured_rwsem))
if (afu == NULL || !cxl_afu_configured_get(afu))
return PCIBIOS_DEVICE_NOT_FOUND;
rc = cxl_pcie_config_info(bus, devfn, afu, &record);
@@ -166,7 +176,7 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
}
out:
up_read(&afu->configured_rwsem);
cxl_afu_configured_put(afu);
return rc ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL;
}