Commit d03fcf50 authored by Dan Williams's avatar Dan Williams Committed by Dave Jiang
Browse files

cxl: Convert to ACQUIRE() for conditional rwsem locking



Use ACQUIRE() to cleanup conditional locking paths in the CXL driver
The ACQUIRE() macro and its associated ACQUIRE_ERR() helpers, like
scoped_cond_guard(), arrange for scoped-based conditional locking. Unlike
scoped_cond_guard(), these macros arrange for an ERR_PTR() to be retrieved
representing the state of the conditional lock.

The goal of this conversion is to complete the removal of all explicit
unlock calls in the subsystem. I.e. the methods to acquire a lock are
solely via guard(), scoped_guard() (for limited cases), or ACQUIRE(). All
unlock is implicit / scope-based. In order to make sure all lock sites are
converted, the existing rwsem's are consolidated and renamed in 'struct
cxl_rwsem'. While that makes the patch noisier it gives a clean cut-off
between old-world (explicit unlock allowed), and new world (explicit unlock
deleted).

Cc: David Lechner <dlechner@baylibre.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Fabio M. De Francesco <fabio.m.de.francesco@linux.intel.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Jonathan Cameron <jonathan.cameron@huawei.com>
Cc: Dave Jiang <dave.jiang@intel.com>
Cc: Alison Schofield <alison.schofield@intel.com>
Cc: Vishal Verma <vishal.l.verma@intel.com>
Cc: Ira Weiny <ira.weiny@intel.com>
Cc: Shiju Jose <shiju.jose@huawei.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Reviewed-by: default avatarJonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: default avatarFabio M. De Francesco <fabio.m.de.francesco@linux.intel.com>
Reviewed-by: default avatarDave Jiang <dave.jiang@intel.com>
Tested-by: default avatarShiju Jose <shiju.jose@huawei.com>
Link: https://patch.msgid.link/20250711234932.671292-9-dan.j.williams@intel.com


Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
parent b3a88225
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -336,7 +336,7 @@ static int match_cxlrd_hb(struct device *dev, void *data)
	cxlrd = to_cxl_root_decoder(dev);
	cxlsd = &cxlrd->cxlsd;

	guard(rwsem_read)(&cxl_region_rwsem);
	guard(rwsem_read)(&cxl_rwsem.region);
	for (int i = 0; i < cxlsd->nr_targets; i++) {
		if (host_bridge == cxlsd->target[i]->dport_dev)
			return 1;
@@ -987,7 +987,7 @@ void cxl_region_shared_upstream_bandwidth_update(struct cxl_region *cxlr)
	bool is_root;
	int rc;

	lockdep_assert_held(&cxl_dpa_rwsem);
	lockdep_assert_held(&cxl_rwsem.dpa);

	struct xarray *usp_xa __free(free_perf_xa) =
		kzalloc(sizeof(*usp_xa), GFP_KERNEL);
@@ -1057,7 +1057,7 @@ void cxl_region_perf_data_calculate(struct cxl_region *cxlr,
{
	struct cxl_dpa_perf *perf;

	lockdep_assert_held(&cxl_dpa_rwsem);
	lockdep_assert_held(&cxl_rwsem.dpa);

	perf = cxled_get_dpa_perf(cxled);
	if (IS_ERR(perf))
+15 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#define __CXL_CORE_H__

#include <cxl/mailbox.h>
#include <linux/rwsem.h>

extern const struct device_type cxl_nvdimm_bridge_type;
extern const struct device_type cxl_nvdimm_type;
@@ -107,8 +108,20 @@ u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb);
#define PCI_RCRB_CAP_HDR_NEXT_MASK	GENMASK(15, 8)
#define PCI_CAP_EXP_SIZEOF		0x3c

extern struct rw_semaphore cxl_dpa_rwsem;
extern struct rw_semaphore cxl_region_rwsem;
struct cxl_rwsem {
	/*
	 * All changes to HPA (interleave configuration) occur with this
	 * lock held for write.
	 */
	struct rw_semaphore region;
	/*
	 * All changes to a device DPA space occur with this lock held
	 * for write.
	 */
	struct rw_semaphore dpa;
};

extern struct cxl_rwsem cxl_rwsem;

int cxl_memdev_init(void);
void cxl_memdev_exit(void);
+20 −24
Original line number Diff line number Diff line
@@ -115,10 +115,9 @@ static int cxl_scrub_get_attrbs(struct cxl_patrol_scrub_context *cxl_ps_ctx,
						flags, min_cycle);
	}

	struct rw_semaphore *region_lock __free(rwsem_read_release) =
		rwsem_read_intr_acquire(&cxl_region_rwsem);
	if (!region_lock)
		return -EINTR;
	ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region);
	if ((ret = ACQUIRE_ERR(rwsem_read_intr, &rwsem)))
		return ret;

	cxlr = cxl_ps_ctx->cxlr;
	p = &cxlr->params;
@@ -158,10 +157,9 @@ static int cxl_scrub_set_attrbs_region(struct device *dev,
	struct cxl_region *cxlr;
	int ret, i;

	struct rw_semaphore *region_lock __free(rwsem_read_release) =
		rwsem_read_intr_acquire(&cxl_region_rwsem);
	if (!region_lock)
		return -EINTR;
	ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region);
	if ((ret = ACQUIRE_ERR(rwsem_read_intr, &rwsem)))
		return ret;

	cxlr = cxl_ps_ctx->cxlr;
	p = &cxlr->params;
@@ -1340,16 +1338,15 @@ cxl_mem_perform_sparing(struct device *dev,
	struct cxl_memdev_sparing_in_payload sparing_pi;
	struct cxl_event_dram *rec = NULL;
	u16 validity_flags = 0;
	int ret;

	struct rw_semaphore *region_lock __free(rwsem_read_release) =
		rwsem_read_intr_acquire(&cxl_region_rwsem);
	if (!region_lock)
		return -EINTR;
	ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region);
	if ((ret = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem)))
		return ret;

	struct rw_semaphore *dpa_lock __free(rwsem_read_release) =
		rwsem_read_intr_acquire(&cxl_dpa_rwsem);
	if (!dpa_lock)
		return -EINTR;
	ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa);
	if ((ret = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem)))
		return ret;

	if (!cxl_sparing_ctx->cap_safe_when_in_use) {
		/* Memory to repair must be offline */
@@ -1787,16 +1784,15 @@ static int cxl_mem_perform_ppr(struct cxl_ppr_context *cxl_ppr_ctx)
	struct cxl_memdev_ppr_maintenance_attrbs maintenance_attrbs;
	struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd;
	struct cxl_mem_repair_attrbs attrbs = { 0 };
	int ret;

	struct rw_semaphore *region_lock __free(rwsem_read_release) =
		rwsem_read_intr_acquire(&cxl_region_rwsem);
	if (!region_lock)
		return -EINTR;
	ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region);
	if ((ret = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem)))
		return ret;

	struct rw_semaphore *dpa_lock __free(rwsem_read_release) =
		rwsem_read_intr_acquire(&cxl_dpa_rwsem);
	if (!dpa_lock)
		return -EINTR;
	ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa);
	if ((ret = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem)))
		return ret;

	if (!cxl_ppr_ctx->media_accessible || !cxl_ppr_ctx->data_retained) {
		/* Memory to repair must be offline */
+21 −20
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@
 * for enumerating these registers and capabilities.
 */

DECLARE_RWSEM(cxl_dpa_rwsem);
struct cxl_rwsem cxl_rwsem = {
	.region = __RWSEM_INITIALIZER(cxl_rwsem.region),
	.dpa = __RWSEM_INITIALIZER(cxl_rwsem.dpa),
};

static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
			   int *target_map)
@@ -214,7 +217,7 @@ void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds)
{
	struct resource *p1, *p2;

	guard(rwsem_read)(&cxl_dpa_rwsem);
	guard(rwsem_read)(&cxl_rwsem.dpa);
	for (p1 = cxlds->dpa_res.child; p1; p1 = p1->sibling) {
		__cxl_dpa_debug(file, p1, 0);
		for (p2 = p1->child; p2; p2 = p2->sibling)
@@ -266,7 +269,7 @@ static void __cxl_dpa_release(struct cxl_endpoint_decoder *cxled)
	struct resource *res = cxled->dpa_res;
	resource_size_t skip_start;

	lockdep_assert_held_write(&cxl_dpa_rwsem);
	lockdep_assert_held_write(&cxl_rwsem.dpa);

	/* save @skip_start, before @res is released */
	skip_start = res->start - cxled->skip;
@@ -281,7 +284,7 @@ static void __cxl_dpa_release(struct cxl_endpoint_decoder *cxled)

static void cxl_dpa_release(void *cxled)
{
	guard(rwsem_write)(&cxl_dpa_rwsem);
	guard(rwsem_write)(&cxl_rwsem.dpa);
	__cxl_dpa_release(cxled);
}

@@ -293,7 +296,7 @@ static void devm_cxl_dpa_release(struct cxl_endpoint_decoder *cxled)
{
	struct cxl_port *port = cxled_to_port(cxled);

	lockdep_assert_held_write(&cxl_dpa_rwsem);
	lockdep_assert_held_write(&cxl_rwsem.dpa);
	devm_remove_action(&port->dev, cxl_dpa_release, cxled);
	__cxl_dpa_release(cxled);
}
@@ -361,7 +364,7 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
	struct resource *res;
	int rc;

	lockdep_assert_held_write(&cxl_dpa_rwsem);
	lockdep_assert_held_write(&cxl_rwsem.dpa);

	if (!len) {
		dev_warn(dev, "decoder%d.%d: empty reservation attempted\n",
@@ -470,7 +473,7 @@ int cxl_dpa_setup(struct cxl_dev_state *cxlds, const struct cxl_dpa_info *info)
{
	struct device *dev = cxlds->dev;

	guard(rwsem_write)(&cxl_dpa_rwsem);
	guard(rwsem_write)(&cxl_rwsem.dpa);

	if (cxlds->nr_partitions)
		return -EBUSY;
@@ -516,9 +519,8 @@ int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
	struct cxl_port *port = cxled_to_port(cxled);
	int rc;

	down_write(&cxl_dpa_rwsem);
	scoped_guard(rwsem_write, &cxl_rwsem.dpa)
		rc = __cxl_dpa_reserve(cxled, base, len, skipped);
	up_write(&cxl_dpa_rwsem);

	if (rc)
		return rc;
@@ -529,7 +531,7 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_dpa_reserve, "CXL");

resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled)
{
	guard(rwsem_read)(&cxl_dpa_rwsem);
	guard(rwsem_read)(&cxl_rwsem.dpa);
	if (cxled->dpa_res)
		return resource_size(cxled->dpa_res);

@@ -540,7 +542,7 @@ resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled)
{
	resource_size_t base = -1;

	lockdep_assert_held(&cxl_dpa_rwsem);
	lockdep_assert_held(&cxl_rwsem.dpa);
	if (cxled->dpa_res)
		base = cxled->dpa_res->start;

@@ -552,7 +554,7 @@ int cxl_dpa_free(struct cxl_endpoint_decoder *cxled)
	struct cxl_port *port = cxled_to_port(cxled);
	struct device *dev = &cxled->cxld.dev;

	guard(rwsem_write)(&cxl_dpa_rwsem);
	guard(rwsem_write)(&cxl_rwsem.dpa);
	if (!cxled->dpa_res)
		return 0;
	if (cxled->cxld.region) {
@@ -582,7 +584,7 @@ int cxl_dpa_set_part(struct cxl_endpoint_decoder *cxled,
	struct device *dev = &cxled->cxld.dev;
	int part;

	guard(rwsem_write)(&cxl_dpa_rwsem);
	guard(rwsem_write)(&cxl_rwsem.dpa);
	if (cxled->cxld.flags & CXL_DECODER_F_ENABLE)
		return -EBUSY;

@@ -614,7 +616,7 @@ static int __cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, u64 size)
	struct resource *p, *last;
	int part;

	guard(rwsem_write)(&cxl_dpa_rwsem);
	guard(rwsem_write)(&cxl_rwsem.dpa);
	if (cxled->cxld.region) {
		dev_dbg(dev, "decoder attached to %s\n",
			dev_name(&cxled->cxld.region->dev));
@@ -842,9 +844,8 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld)
		}
	}

	down_read(&cxl_dpa_rwsem);
	scoped_guard(rwsem_read, &cxl_rwsem.dpa)
		setup_hw_decoder(cxld, hdm);
	up_read(&cxl_dpa_rwsem);

	port->commit_end++;
	rc = cxld_await_commit(hdm, cxld->id);
@@ -882,7 +883,7 @@ void cxl_port_commit_reap(struct cxl_decoder *cxld)
{
	struct cxl_port *port = to_cxl_port(cxld->dev.parent);

	lockdep_assert_held_write(&cxl_region_rwsem);
	lockdep_assert_held_write(&cxl_rwsem.region);

	/*
	 * Once the highest committed decoder is disabled, free any other
@@ -1030,7 +1031,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
		else
			cxld->target_type = CXL_DECODER_DEVMEM;

		guard(rwsem_write)(&cxl_region_rwsem);
		guard(rwsem_write)(&cxl_rwsem.region);
		if (cxld->id != cxl_num_decoders_committed(port)) {
			dev_warn(&port->dev,
				 "decoder%d.%d: Committed out of order\n",
+3 −3
Original line number Diff line number Diff line
@@ -909,8 +909,8 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
		 * translations. Take topology mutation locks and lookup
		 * { HPA, REGION } from { DPA, MEMDEV } in the event record.
		 */
		guard(rwsem_read)(&cxl_region_rwsem);
		guard(rwsem_read)(&cxl_dpa_rwsem);
		guard(rwsem_read)(&cxl_rwsem.region);
		guard(rwsem_read)(&cxl_rwsem.dpa);

		dpa = le64_to_cpu(evt->media_hdr.phys_addr) & CXL_DPA_MASK;
		cxlr = cxl_dpa_to_region(cxlmd, dpa);
@@ -1265,7 +1265,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
	/* synchronize with cxl_mem_probe() and decoder write operations */
	guard(device)(&cxlmd->dev);
	endpoint = cxlmd->endpoint;
	guard(rwsem_read)(&cxl_region_rwsem);
	guard(rwsem_read)(&cxl_rwsem.region);
	/*
	 * Require an endpoint to be safe otherwise the driver can not
	 * be sure that the device is unmapped.
Loading