Skip to content

Commit a235d7d

Browse files
djbwdavejiang
authored andcommitted
cxl/region: Split commit_store() into __commit() and queue_reset() helpers
The complexity of dropping the lock is removed in favor of splitting commit operations to a helper, and leaving all the complexities of "decommit" for commit_store() to coordinate the different locking contexts. The CPU cache-invalidation in the decommit path is solely handled now by cxl_region_decode_reset(). Previously the CPU caches were being needlessly flushed twice in the decommit path where the first flush had no guarantee that the memory would not be immediately re-dirtied. Cc: Davidlohr Bueso <[email protected]> Cc: Jonathan Cameron <[email protected]> Cc: Dave Jiang <[email protected]> Cc: Alison Schofield <[email protected]> Cc: Vishal Verma <[email protected]> Cc: Ira Weiny <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Dan Williams <[email protected]> Reviewed-by: Fabio M. De Francesco <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Dave Jiang <[email protected]>
1 parent 55a89d9 commit a235d7d

File tree

1 file changed

+70
-29
lines changed

1 file changed

+70
-29
lines changed

drivers/cxl/core/region.c

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -349,30 +349,42 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
349349
return rc;
350350
}
351351

352-
static ssize_t commit_store(struct device *dev, struct device_attribute *attr,
353-
const char *buf, size_t len)
352+
static int queue_reset(struct cxl_region *cxlr)
354353
{
355-
struct cxl_region *cxlr = to_cxl_region(dev);
356354
struct cxl_region_params *p = &cxlr->params;
357-
bool commit;
358-
ssize_t rc;
355+
int rc;
359356

360-
rc = kstrtobool(buf, &commit);
357+
rc = down_write_killable(&cxl_region_rwsem);
361358
if (rc)
362359
return rc;
363360

361+
/* Already in the requested state? */
362+
if (p->state < CXL_CONFIG_COMMIT)
363+
goto out;
364+
365+
p->state = CXL_CONFIG_RESET_PENDING;
366+
367+
out:
368+
up_write(&cxl_region_rwsem);
369+
370+
return rc;
371+
}
372+
373+
static int __commit(struct cxl_region *cxlr)
374+
{
375+
struct cxl_region_params *p = &cxlr->params;
376+
int rc;
377+
364378
rc = down_write_killable(&cxl_region_rwsem);
365379
if (rc)
366380
return rc;
367381

368382
/* Already in the requested state? */
369-
if (commit && p->state >= CXL_CONFIG_COMMIT)
370-
goto out;
371-
if (!commit && p->state < CXL_CONFIG_COMMIT)
383+
if (p->state >= CXL_CONFIG_COMMIT)
372384
goto out;
373385

374386
/* Not ready to commit? */
375-
if (commit && p->state < CXL_CONFIG_ACTIVE) {
387+
if (p->state < CXL_CONFIG_ACTIVE) {
376388
rc = -ENXIO;
377389
goto out;
378390
}
@@ -385,31 +397,60 @@ static ssize_t commit_store(struct device *dev, struct device_attribute *attr,
385397
if (rc)
386398
goto out;
387399

388-
if (commit) {
389-
rc = cxl_region_decode_commit(cxlr);
390-
if (rc == 0)
391-
p->state = CXL_CONFIG_COMMIT;
392-
} else {
393-
p->state = CXL_CONFIG_RESET_PENDING;
394-
up_write(&cxl_region_rwsem);
395-
device_release_driver(&cxlr->dev);
396-
down_write(&cxl_region_rwsem);
397-
398-
/*
399-
* The lock was dropped, so need to revalidate that the reset is
400-
* still pending.
401-
*/
402-
if (p->state == CXL_CONFIG_RESET_PENDING) {
403-
cxl_region_decode_reset(cxlr, p->interleave_ways);
404-
p->state = CXL_CONFIG_ACTIVE;
405-
}
406-
}
400+
rc = cxl_region_decode_commit(cxlr);
401+
if (rc == 0)
402+
p->state = CXL_CONFIG_COMMIT;
407403

408404
out:
409405
up_write(&cxl_region_rwsem);
410406

407+
return rc;
408+
}
409+
410+
static ssize_t commit_store(struct device *dev, struct device_attribute *attr,
411+
const char *buf, size_t len)
412+
{
413+
struct cxl_region *cxlr = to_cxl_region(dev);
414+
struct cxl_region_params *p = &cxlr->params;
415+
bool commit;
416+
ssize_t rc;
417+
418+
rc = kstrtobool(buf, &commit);
411419
if (rc)
412420
return rc;
421+
422+
if (commit) {
423+
rc = __commit(cxlr);
424+
if (rc)
425+
return rc;
426+
return len;
427+
}
428+
429+
rc = queue_reset(cxlr);
430+
if (rc)
431+
return rc;
432+
433+
/*
434+
* Unmap the region and depend the reset-pending state to ensure
435+
* it does not go active again until post reset
436+
*/
437+
device_release_driver(&cxlr->dev);
438+
439+
/*
440+
* With the reset pending take cxl_region_rwsem unconditionally
441+
* to ensure the reset gets handled before returning.
442+
*/
443+
guard(rwsem_write)(&cxl_region_rwsem);
444+
445+
/*
446+
* Revalidate that the reset is still pending in case another
447+
* thread already handled this reset.
448+
*/
449+
if (p->state == CXL_CONFIG_RESET_PENDING) {
450+
cxl_region_decode_reset(cxlr, p->interleave_ways);
451+
p->state = CXL_CONFIG_ACTIVE;
452+
}
453+
413454
return len;
414455
}
415456

0 commit comments

Comments
 (0)