mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
cxl: fix nested locking hang during EEH hotplug
am: 53d43706f2
Change-Id: I2d209e2170524b6aab237f883b17f8a50e94e811
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user