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;
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;
if ((rc = cxl_native_register_psl_irq(afu)))
goto err2;
- up_write(&afu->configured_rwsem);
+ atomic_set(&afu->configured_state, 0);
return 0;
err2:
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);
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)
{
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);
}
out:
- up_read(&afu->configured_rwsem);
+ cxl_afu_configured_put(afu);
return rc ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
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);
}
out:
- up_read(&afu->configured_rwsem);
+ cxl_afu_configured_put(afu);
return rc ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL;
}