Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-6.17/cxl-acquire' into cxl-for-next

Introduce ACQUIRE() and ACQUIRE_ERR() for conditional locks.
Convert CXL subsystem to use the new macros.

+482 -402
+3 -3
drivers/cxl/core/cdat.c
··· 336 336 cxlrd = to_cxl_root_decoder(dev); 337 337 cxlsd = &cxlrd->cxlsd; 338 338 339 - guard(rwsem_read)(&cxl_region_rwsem); 339 + guard(rwsem_read)(&cxl_rwsem.region); 340 340 for (int i = 0; i < cxlsd->nr_targets; i++) { 341 341 if (host_bridge == cxlsd->target[i]->dport_dev) 342 342 return 1; ··· 987 987 bool is_root; 988 988 int rc; 989 989 990 - lockdep_assert_held(&cxl_dpa_rwsem); 990 + lockdep_assert_held(&cxl_rwsem.dpa); 991 991 992 992 struct xarray *usp_xa __free(free_perf_xa) = 993 993 kzalloc(sizeof(*usp_xa), GFP_KERNEL); ··· 1057 1057 { 1058 1058 struct cxl_dpa_perf *perf; 1059 1059 1060 - lockdep_assert_held(&cxl_dpa_rwsem); 1060 + lockdep_assert_held(&cxl_rwsem.dpa); 1061 1061 1062 1062 perf = cxled_get_dpa_perf(cxled); 1063 1063 if (IS_ERR(perf))
+28 -4
drivers/cxl/core/core.h
··· 5 5 #define __CXL_CORE_H__ 6 6 7 7 #include <cxl/mailbox.h> 8 + #include <linux/rwsem.h> 8 9 9 10 extern const struct device_type cxl_nvdimm_bridge_type; 10 11 extern const struct device_type cxl_nvdimm_type; 11 12 extern const struct device_type cxl_pmu_type; 12 13 13 14 extern struct attribute_group cxl_base_attribute_group; 15 + 16 + enum cxl_detach_mode { 17 + DETACH_ONLY, 18 + DETACH_INVALIDATE, 19 + }; 14 20 15 21 #ifdef CONFIG_CXL_REGION 16 22 extern struct device_attribute dev_attr_create_pmem_region; ··· 26 20 extern const struct device_type cxl_pmem_region_type; 27 21 extern const struct device_type cxl_dax_region_type; 28 22 extern const struct device_type cxl_region_type; 29 - void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); 23 + 24 + int cxl_decoder_detach(struct cxl_region *cxlr, 25 + struct cxl_endpoint_decoder *cxled, int pos, 26 + enum cxl_detach_mode mode); 27 + 30 28 #define CXL_REGION_ATTR(x) (&dev_attr_##x.attr) 31 29 #define CXL_REGION_TYPE(x) (&cxl_region_type) 32 30 #define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr), ··· 58 48 { 59 49 return 0; 60 50 } 61 - static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled) 51 + static inline int cxl_decoder_detach(struct cxl_region *cxlr, 52 + struct cxl_endpoint_decoder *cxled, 53 + int pos, enum cxl_detach_mode mode) 62 54 { 63 55 } 64 56 static inline int cxl_region_init(void) ··· 109 97 #define PCI_RCRB_CAP_HDR_NEXT_MASK GENMASK(15, 8) 110 98 #define PCI_CAP_EXP_SIZEOF 0x3c 111 99 112 - extern struct rw_semaphore cxl_dpa_rwsem; 113 - extern struct rw_semaphore cxl_region_rwsem; 100 + struct cxl_rwsem { 101 + /* 102 + * All changes to HPA (interleave configuration) occur with this 103 + * lock held for write. 104 + */ 105 + struct rw_semaphore region; 106 + /* 107 + * All changes to a device DPA space occur with this lock held 108 + * for write. 109 + */ 110 + struct rw_semaphore dpa; 111 + }; 112 + 113 + extern struct cxl_rwsem cxl_rwsem; 114 114 115 115 int cxl_memdev_init(void); 116 116 void cxl_memdev_exit(void);
+20 -24
drivers/cxl/core/edac.c
··· 115 115 flags, min_cycle); 116 116 } 117 117 118 - struct rw_semaphore *region_lock __free(rwsem_read_release) = 119 - rwsem_read_intr_acquire(&cxl_region_rwsem); 120 - if (!region_lock) 121 - return -EINTR; 118 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 119 + if ((ret = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 120 + return ret; 122 121 123 122 cxlr = cxl_ps_ctx->cxlr; 124 123 p = &cxlr->params; ··· 157 158 struct cxl_region *cxlr; 158 159 int ret, i; 159 160 160 - struct rw_semaphore *region_lock __free(rwsem_read_release) = 161 - rwsem_read_intr_acquire(&cxl_region_rwsem); 162 - if (!region_lock) 163 - return -EINTR; 161 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 162 + if ((ret = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 163 + return ret; 164 164 165 165 cxlr = cxl_ps_ctx->cxlr; 166 166 p = &cxlr->params; ··· 1338 1340 struct cxl_memdev_sparing_in_payload sparing_pi; 1339 1341 struct cxl_event_dram *rec = NULL; 1340 1342 u16 validity_flags = 0; 1343 + int ret; 1341 1344 1342 - struct rw_semaphore *region_lock __free(rwsem_read_release) = 1343 - rwsem_read_intr_acquire(&cxl_region_rwsem); 1344 - if (!region_lock) 1345 - return -EINTR; 1345 + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); 1346 + if ((ret = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem))) 1347 + return ret; 1346 1348 1347 - struct rw_semaphore *dpa_lock __free(rwsem_read_release) = 1348 - rwsem_read_intr_acquire(&cxl_dpa_rwsem); 1349 - if (!dpa_lock) 1350 - return -EINTR; 1349 + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); 1350 + if ((ret = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) 1351 + return ret; 1351 1352 1352 1353 if (!cxl_sparing_ctx->cap_safe_when_in_use) { 1353 1354 /* Memory to repair must be offline */ ··· 1784 1787 struct cxl_memdev_ppr_maintenance_attrbs maintenance_attrbs; 1785 1788 struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd; 1786 1789 struct cxl_mem_repair_attrbs attrbs = { 0 }; 1790 + int ret; 1787 1791 1788 - struct rw_semaphore *region_lock __free(rwsem_read_release) = 1789 - rwsem_read_intr_acquire(&cxl_region_rwsem); 1790 - if (!region_lock) 1791 - return -EINTR; 1792 + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); 1793 + if ((ret = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem))) 1794 + return ret; 1792 1795 1793 - struct rw_semaphore *dpa_lock __free(rwsem_read_release) = 1794 - rwsem_read_intr_acquire(&cxl_dpa_rwsem); 1795 - if (!dpa_lock) 1796 - return -EINTR; 1796 + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); 1797 + if ((ret = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) 1798 + return ret; 1797 1799 1798 1800 if (!cxl_ppr_ctx->media_accessible || !cxl_ppr_ctx->data_retained) { 1799 1801 /* Memory to repair must be offline */
+62 -56
drivers/cxl/core/hdm.c
··· 16 16 * for enumerating these registers and capabilities. 17 17 */ 18 18 19 - DECLARE_RWSEM(cxl_dpa_rwsem); 19 + struct cxl_rwsem cxl_rwsem = { 20 + .region = __RWSEM_INITIALIZER(cxl_rwsem.region), 21 + .dpa = __RWSEM_INITIALIZER(cxl_rwsem.dpa), 22 + }; 20 23 21 24 static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, 22 25 int *target_map) ··· 217 214 { 218 215 struct resource *p1, *p2; 219 216 220 - guard(rwsem_read)(&cxl_dpa_rwsem); 217 + guard(rwsem_read)(&cxl_rwsem.dpa); 221 218 for (p1 = cxlds->dpa_res.child; p1; p1 = p1->sibling) { 222 219 __cxl_dpa_debug(file, p1, 0); 223 220 for (p2 = p1->child; p2; p2 = p2->sibling) ··· 269 266 struct resource *res = cxled->dpa_res; 270 267 resource_size_t skip_start; 271 268 272 - lockdep_assert_held_write(&cxl_dpa_rwsem); 269 + lockdep_assert_held_write(&cxl_rwsem.dpa); 273 270 274 271 /* save @skip_start, before @res is released */ 275 272 skip_start = res->start - cxled->skip; ··· 284 281 285 282 static void cxl_dpa_release(void *cxled) 286 283 { 287 - guard(rwsem_write)(&cxl_dpa_rwsem); 284 + guard(rwsem_write)(&cxl_rwsem.dpa); 288 285 __cxl_dpa_release(cxled); 289 286 } 290 287 ··· 296 293 { 297 294 struct cxl_port *port = cxled_to_port(cxled); 298 295 299 - lockdep_assert_held_write(&cxl_dpa_rwsem); 296 + lockdep_assert_held_write(&cxl_rwsem.dpa); 300 297 devm_remove_action(&port->dev, cxl_dpa_release, cxled); 301 298 __cxl_dpa_release(cxled); 302 299 } ··· 364 361 struct resource *res; 365 362 int rc; 366 363 367 - lockdep_assert_held_write(&cxl_dpa_rwsem); 364 + lockdep_assert_held_write(&cxl_rwsem.dpa); 368 365 369 366 if (!len) { 370 367 dev_warn(dev, "decoder%d.%d: empty reservation attempted\n", ··· 473 470 { 474 471 struct device *dev = cxlds->dev; 475 472 476 - guard(rwsem_write)(&cxl_dpa_rwsem); 473 + guard(rwsem_write)(&cxl_rwsem.dpa); 477 474 478 475 if (cxlds->nr_partitions) 479 476 return -EBUSY; ··· 519 516 struct cxl_port *port = cxled_to_port(cxled); 520 517 int rc; 521 518 522 - down_write(&cxl_dpa_rwsem); 523 - rc = __cxl_dpa_reserve(cxled, base, len, skipped); 524 - up_write(&cxl_dpa_rwsem); 519 + scoped_guard(rwsem_write, &cxl_rwsem.dpa) 520 + rc = __cxl_dpa_reserve(cxled, base, len, skipped); 525 521 526 522 if (rc) 527 523 return rc; ··· 531 529 532 530 resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled) 533 531 { 534 - guard(rwsem_read)(&cxl_dpa_rwsem); 532 + guard(rwsem_read)(&cxl_rwsem.dpa); 535 533 if (cxled->dpa_res) 536 534 return resource_size(cxled->dpa_res); 537 535 ··· 542 540 { 543 541 resource_size_t base = -1; 544 542 545 - lockdep_assert_held(&cxl_dpa_rwsem); 543 + lockdep_assert_held(&cxl_rwsem.dpa); 546 544 if (cxled->dpa_res) 547 545 base = cxled->dpa_res->start; 548 546 ··· 561 559 struct cxl_port *port = cxled_to_port(cxled); 562 560 struct device *dev = &cxled->cxld.dev; 563 561 564 - guard(rwsem_write)(&cxl_dpa_rwsem); 562 + guard(rwsem_write)(&cxl_rwsem.dpa); 565 563 if (!cxled->dpa_res) 566 564 return 0; 567 565 if (cxled->cxld.region) { ··· 591 589 struct device *dev = &cxled->cxld.dev; 592 590 int part; 593 591 594 - guard(rwsem_write)(&cxl_dpa_rwsem); 592 + guard(rwsem_write)(&cxl_rwsem.dpa); 595 593 if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) 596 594 return -EBUSY; 597 595 ··· 623 621 struct resource *p, *last; 624 622 int part; 625 623 626 - guard(rwsem_write)(&cxl_dpa_rwsem); 624 + guard(rwsem_write)(&cxl_rwsem.dpa); 627 625 if (cxled->cxld.region) { 628 626 dev_dbg(dev, "decoder attached to %s\n", 629 627 dev_name(&cxled->cxld.region->dev)); ··· 773 771 return -ETIMEDOUT; 774 772 } 775 773 776 - static int cxl_decoder_commit(struct cxl_decoder *cxld) 774 + static void setup_hw_decoder(struct cxl_decoder *cxld, void __iomem *hdm) 777 775 { 778 - struct cxl_port *port = to_cxl_port(cxld->dev.parent); 779 - struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); 780 - void __iomem *hdm = cxlhdm->regs.hdm_decoder; 781 - int id = cxld->id, rc; 776 + int id = cxld->id; 782 777 u64 base, size; 783 778 u32 ctrl; 784 779 785 - if (cxld->flags & CXL_DECODER_F_ENABLE) 786 - return 0; 787 - 788 - if (cxl_num_decoders_committed(port) != id) { 789 - dev_dbg(&port->dev, 790 - "%s: out of order commit, expected decoder%d.%d\n", 791 - dev_name(&cxld->dev), port->id, 792 - cxl_num_decoders_committed(port)); 793 - return -EBUSY; 794 - } 795 - 796 - /* 797 - * For endpoint decoders hosted on CXL memory devices that 798 - * support the sanitize operation, make sure sanitize is not in-flight. 799 - */ 800 - if (is_endpoint_decoder(&cxld->dev)) { 801 - struct cxl_endpoint_decoder *cxled = 802 - to_cxl_endpoint_decoder(&cxld->dev); 803 - struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 804 - struct cxl_memdev_state *mds = 805 - to_cxl_memdev_state(cxlmd->cxlds); 806 - 807 - if (mds && mds->security.sanitize_active) { 808 - dev_dbg(&cxlmd->dev, 809 - "attempted to commit %s during sanitize\n", 810 - dev_name(&cxld->dev)); 811 - return -EBUSY; 812 - } 813 - } 814 - 815 - down_read(&cxl_dpa_rwsem); 816 780 /* common decoder settings */ 817 781 ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id)); 818 782 cxld_set_interleave(cxld, &ctrl); ··· 812 844 } 813 845 814 846 writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 815 - up_read(&cxl_dpa_rwsem); 847 + } 848 + 849 + static int cxl_decoder_commit(struct cxl_decoder *cxld) 850 + { 851 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 852 + struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); 853 + void __iomem *hdm = cxlhdm->regs.hdm_decoder; 854 + int id = cxld->id, rc; 855 + 856 + if (cxld->flags & CXL_DECODER_F_ENABLE) 857 + return 0; 858 + 859 + if (cxl_num_decoders_committed(port) != id) { 860 + dev_dbg(&port->dev, 861 + "%s: out of order commit, expected decoder%d.%d\n", 862 + dev_name(&cxld->dev), port->id, 863 + cxl_num_decoders_committed(port)); 864 + return -EBUSY; 865 + } 866 + 867 + /* 868 + * For endpoint decoders hosted on CXL memory devices that 869 + * support the sanitize operation, make sure sanitize is not in-flight. 870 + */ 871 + if (is_endpoint_decoder(&cxld->dev)) { 872 + struct cxl_endpoint_decoder *cxled = 873 + to_cxl_endpoint_decoder(&cxld->dev); 874 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 875 + struct cxl_memdev_state *mds = 876 + to_cxl_memdev_state(cxlmd->cxlds); 877 + 878 + if (mds && mds->security.sanitize_active) { 879 + dev_dbg(&cxlmd->dev, 880 + "attempted to commit %s during sanitize\n", 881 + dev_name(&cxld->dev)); 882 + return -EBUSY; 883 + } 884 + } 885 + 886 + scoped_guard(rwsem_read, &cxl_rwsem.dpa) 887 + setup_hw_decoder(cxld, hdm); 816 888 817 889 port->commit_end++; 818 890 rc = cxld_await_commit(hdm, cxld->id); ··· 890 882 { 891 883 struct cxl_port *port = to_cxl_port(cxld->dev.parent); 892 884 893 - lockdep_assert_held_write(&cxl_region_rwsem); 885 + lockdep_assert_held_write(&cxl_rwsem.region); 894 886 895 887 /* 896 888 * Once the highest committed decoder is disabled, free any other ··· 922 914 "%s: out of order reset, expected decoder%d.%d\n", 923 915 dev_name(&cxld->dev), port->id, port->commit_end); 924 916 925 - down_read(&cxl_dpa_rwsem); 926 917 ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 927 918 ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT; 928 919 writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); ··· 930 923 writel(0, hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id)); 931 924 writel(0, hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id)); 932 925 writel(0, hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id)); 933 - up_read(&cxl_dpa_rwsem); 934 926 935 927 cxld->flags &= ~CXL_DECODER_F_ENABLE; 936 928 ··· 1038 1032 else 1039 1033 cxld->target_type = CXL_DECODER_DEVMEM; 1040 1034 1041 - guard(rwsem_write)(&cxl_region_rwsem); 1035 + guard(rwsem_write)(&cxl_rwsem.region); 1042 1036 if (cxld->id != cxl_num_decoders_committed(port)) { 1043 1037 dev_warn(&port->dev, 1044 1038 "decoder%d.%d: Committed out of order\n",
+6 -7
drivers/cxl/core/mbox.c
··· 909 909 * translations. Take topology mutation locks and lookup 910 910 * { HPA, REGION } from { DPA, MEMDEV } in the event record. 911 911 */ 912 - guard(rwsem_read)(&cxl_region_rwsem); 913 - guard(rwsem_read)(&cxl_dpa_rwsem); 912 + guard(rwsem_read)(&cxl_rwsem.region); 913 + guard(rwsem_read)(&cxl_rwsem.dpa); 914 914 915 915 dpa = le64_to_cpu(evt->media_hdr.phys_addr) & CXL_DPA_MASK; 916 916 cxlr = cxl_dpa_to_region(cxlmd, dpa); ··· 1265 1265 /* synchronize with cxl_mem_probe() and decoder write operations */ 1266 1266 guard(device)(&cxlmd->dev); 1267 1267 endpoint = cxlmd->endpoint; 1268 - guard(rwsem_read)(&cxl_region_rwsem); 1268 + guard(rwsem_read)(&cxl_rwsem.region); 1269 1269 /* 1270 1270 * Require an endpoint to be safe otherwise the driver can not 1271 1271 * be sure that the device is unmapped. ··· 1401 1401 int nr_records = 0; 1402 1402 int rc; 1403 1403 1404 - rc = mutex_lock_interruptible(&mds->poison.lock); 1405 - if (rc) 1404 + ACQUIRE(mutex_intr, lock)(&mds->poison.mutex); 1405 + if ((rc = ACQUIRE_ERR(mutex_intr, &lock))) 1406 1406 return rc; 1407 1407 1408 1408 po = mds->poison.list_out; ··· 1437 1437 } 1438 1438 } while (po->flags & CXL_POISON_FLAG_MORE); 1439 1439 1440 - mutex_unlock(&mds->poison.lock); 1441 1440 return rc; 1442 1441 } 1443 1442 EXPORT_SYMBOL_NS_GPL(cxl_mem_get_poison, "CXL"); ··· 1472 1473 return rc; 1473 1474 } 1474 1475 1475 - mutex_init(&mds->poison.lock); 1476 + mutex_init(&mds->poison.mutex); 1476 1477 return 0; 1477 1478 } 1478 1479 EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, "CXL");
+18 -32
drivers/cxl/core/memdev.c
··· 232 232 if (!port || !is_cxl_endpoint(port)) 233 233 return -EINVAL; 234 234 235 - rc = down_read_interruptible(&cxl_region_rwsem); 236 - if (rc) 235 + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); 236 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem))) 237 237 return rc; 238 238 239 - rc = down_read_interruptible(&cxl_dpa_rwsem); 240 - if (rc) { 241 - up_read(&cxl_region_rwsem); 239 + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); 240 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) 242 241 return rc; 243 - } 244 242 245 243 if (cxl_num_decoders_committed(port) == 0) { 246 244 /* No regions mapped to this memdev */ ··· 247 249 /* Regions mapped, collect poison by endpoint */ 248 250 rc = cxl_get_poison_by_endpoint(port); 249 251 } 250 - up_read(&cxl_dpa_rwsem); 251 - up_read(&cxl_region_rwsem); 252 252 253 253 return rc; 254 254 } ··· 288 292 if (!IS_ENABLED(CONFIG_DEBUG_FS)) 289 293 return 0; 290 294 291 - rc = down_read_interruptible(&cxl_region_rwsem); 292 - if (rc) 295 + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); 296 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem))) 293 297 return rc; 294 298 295 - rc = down_read_interruptible(&cxl_dpa_rwsem); 296 - if (rc) { 297 - up_read(&cxl_region_rwsem); 299 + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); 300 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) 298 301 return rc; 299 - } 300 302 301 303 rc = cxl_validate_poison_dpa(cxlmd, dpa); 302 304 if (rc) 303 - goto out; 305 + return rc; 304 306 305 307 inject.address = cpu_to_le64(dpa); 306 308 mbox_cmd = (struct cxl_mbox_cmd) { ··· 308 314 }; 309 315 rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 310 316 if (rc) 311 - goto out; 317 + return rc; 312 318 313 319 cxlr = cxl_dpa_to_region(cxlmd, dpa); 314 320 if (cxlr) ··· 321 327 .length = cpu_to_le32(1), 322 328 }; 323 329 trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_INJECT); 324 - out: 325 - up_read(&cxl_dpa_rwsem); 326 - up_read(&cxl_region_rwsem); 327 330 328 - return rc; 331 + return 0; 329 332 } 330 333 EXPORT_SYMBOL_NS_GPL(cxl_inject_poison, "CXL"); 331 334 ··· 338 347 if (!IS_ENABLED(CONFIG_DEBUG_FS)) 339 348 return 0; 340 349 341 - rc = down_read_interruptible(&cxl_region_rwsem); 342 - if (rc) 350 + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); 351 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem))) 343 352 return rc; 344 353 345 - rc = down_read_interruptible(&cxl_dpa_rwsem); 346 - if (rc) { 347 - up_read(&cxl_region_rwsem); 354 + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); 355 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) 348 356 return rc; 349 - } 350 357 351 358 rc = cxl_validate_poison_dpa(cxlmd, dpa); 352 359 if (rc) 353 - goto out; 360 + return rc; 354 361 355 362 /* 356 363 * In CXL 3.0 Spec 8.2.9.8.4.3, the Clear Poison mailbox command ··· 367 378 368 379 rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 369 380 if (rc) 370 - goto out; 381 + return rc; 371 382 372 383 cxlr = cxl_dpa_to_region(cxlmd, dpa); 373 384 if (cxlr) ··· 380 391 .length = cpu_to_le32(1), 381 392 }; 382 393 trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_CLEAR); 383 - out: 384 - up_read(&cxl_dpa_rwsem); 385 - up_read(&cxl_region_rwsem); 386 394 387 - return rc; 395 + return 0; 388 396 } 389 397 EXPORT_SYMBOL_NS_GPL(cxl_clear_poison, "CXL"); 390 398
+9 -18
drivers/cxl/core/port.c
··· 30 30 * instantiated by the core. 31 31 */ 32 32 33 - /* 34 - * All changes to the interleave configuration occur with this lock held 35 - * for write. 36 - */ 37 - DECLARE_RWSEM(cxl_region_rwsem); 38 - 39 33 static DEFINE_IDA(cxl_port_ida); 40 34 static DEFINE_XARRAY(cxl_root_buses); 41 35 42 36 int cxl_num_decoders_committed(struct cxl_port *port) 43 37 { 44 - lockdep_assert_held(&cxl_region_rwsem); 38 + lockdep_assert_held(&cxl_rwsem.region); 45 39 46 40 return port->commit_end + 1; 47 41 } ··· 170 176 ssize_t offset; 171 177 int rc; 172 178 173 - guard(rwsem_read)(&cxl_region_rwsem); 179 + guard(rwsem_read)(&cxl_rwsem.region); 174 180 rc = emit_target_list(cxlsd, buf); 175 181 if (rc < 0) 176 182 return rc; ··· 190 196 struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 191 197 struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 192 198 struct cxl_dev_state *cxlds = cxlmd->cxlds; 193 - /* without @cxl_dpa_rwsem, make sure @part is not reloaded */ 199 + /* without @cxl_rwsem.dpa, make sure @part is not reloaded */ 194 200 int part = READ_ONCE(cxled->part); 195 201 const char *desc; 196 202 ··· 229 235 { 230 236 struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 231 237 232 - guard(rwsem_read)(&cxl_dpa_rwsem); 238 + guard(rwsem_read)(&cxl_rwsem.dpa); 233 239 return sysfs_emit(buf, "%#llx\n", (u64)cxl_dpa_resource_start(cxled)); 234 240 } 235 241 static DEVICE_ATTR_RO(dpa_resource); ··· 554 560 { 555 561 struct cxl_port *port = to_cxl_port(dev); 556 562 557 - guard(rwsem_read)(&cxl_region_rwsem); 563 + guard(rwsem_read)(&cxl_rwsem.region); 558 564 return sysfs_emit(buf, "%d\n", cxl_num_decoders_committed(port)); 559 565 } 560 566 ··· 1716 1722 if (xa_empty(&port->dports)) 1717 1723 return -EINVAL; 1718 1724 1719 - guard(rwsem_write)(&cxl_region_rwsem); 1725 + guard(rwsem_write)(&cxl_rwsem.region); 1720 1726 for (i = 0; i < cxlsd->cxld.interleave_ways; i++) { 1721 1727 struct cxl_dport *dport = find_dport(port, target_map[i]); 1722 1728 ··· 1995 2001 1996 2002 static void cxld_unregister(void *dev) 1997 2003 { 1998 - struct cxl_endpoint_decoder *cxled; 1999 - 2000 - if (is_endpoint_decoder(dev)) { 2001 - cxled = to_cxl_endpoint_decoder(dev); 2002 - cxl_decoder_kill_region(cxled); 2003 - } 2004 + if (is_endpoint_decoder(dev)) 2005 + cxl_decoder_detach(NULL, to_cxl_endpoint_decoder(dev), -1, 2006 + DETACH_INVALIDATE); 2004 2007 2005 2008 device_unregister(dev); 2006 2009 }
+249 -228
drivers/cxl/core/region.c
··· 141 141 struct cxl_region_params *p = &cxlr->params; 142 142 ssize_t rc; 143 143 144 - rc = down_read_interruptible(&cxl_region_rwsem); 145 - if (rc) 144 + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); 145 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &region_rwsem))) 146 146 return rc; 147 147 if (cxlr->mode != CXL_PARTMODE_PMEM) 148 - rc = sysfs_emit(buf, "\n"); 149 - else 150 - rc = sysfs_emit(buf, "%pUb\n", &p->uuid); 151 - up_read(&cxl_region_rwsem); 152 - 153 - return rc; 148 + return sysfs_emit(buf, "\n"); 149 + return sysfs_emit(buf, "%pUb\n", &p->uuid); 154 150 } 155 151 156 152 static int is_dup(struct device *match, void *data) ··· 158 162 if (!is_cxl_region(match)) 159 163 return 0; 160 164 161 - lockdep_assert_held(&cxl_region_rwsem); 165 + lockdep_assert_held(&cxl_rwsem.region); 162 166 cxlr = to_cxl_region(match); 163 167 p = &cxlr->params; 164 168 ··· 188 192 if (uuid_is_null(&temp)) 189 193 return -EINVAL; 190 194 191 - rc = down_write_killable(&cxl_region_rwsem); 192 - if (rc) 195 + ACQUIRE(rwsem_write_kill, region_rwsem)(&cxl_rwsem.region); 196 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &region_rwsem))) 193 197 return rc; 194 198 195 199 if (uuid_equal(&p->uuid, &temp)) 196 - goto out; 200 + return len; 197 201 198 - rc = -EBUSY; 199 202 if (p->state >= CXL_CONFIG_ACTIVE) 200 - goto out; 203 + return -EBUSY; 201 204 202 205 rc = bus_for_each_dev(&cxl_bus_type, NULL, &temp, is_dup); 203 206 if (rc < 0) 204 - goto out; 207 + return rc; 205 208 206 209 uuid_copy(&p->uuid, &temp); 207 - out: 208 - up_write(&cxl_region_rwsem); 209 210 210 - if (rc) 211 - return rc; 212 211 return len; 213 212 } 214 213 static DEVICE_ATTR_RW(uuid); ··· 340 349 return rc; 341 350 } 342 351 352 + static int queue_reset(struct cxl_region *cxlr) 353 + { 354 + struct cxl_region_params *p = &cxlr->params; 355 + int rc; 356 + 357 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 358 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 359 + return rc; 360 + 361 + /* Already in the requested state? */ 362 + if (p->state < CXL_CONFIG_COMMIT) 363 + return 0; 364 + 365 + p->state = CXL_CONFIG_RESET_PENDING; 366 + 367 + return 0; 368 + } 369 + 370 + static int __commit(struct cxl_region *cxlr) 371 + { 372 + struct cxl_region_params *p = &cxlr->params; 373 + int rc; 374 + 375 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 376 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 377 + return rc; 378 + 379 + /* Already in the requested state? */ 380 + if (p->state >= CXL_CONFIG_COMMIT) 381 + return 0; 382 + 383 + /* Not ready to commit? */ 384 + if (p->state < CXL_CONFIG_ACTIVE) 385 + return -ENXIO; 386 + 387 + /* 388 + * Invalidate caches before region setup to drop any speculative 389 + * consumption of this address space 390 + */ 391 + rc = cxl_region_invalidate_memregion(cxlr); 392 + if (rc) 393 + return rc; 394 + 395 + rc = cxl_region_decode_commit(cxlr); 396 + if (rc) 397 + return rc; 398 + 399 + p->state = CXL_CONFIG_COMMIT; 400 + 401 + return 0; 402 + } 403 + 343 404 static ssize_t commit_store(struct device *dev, struct device_attribute *attr, 344 405 const char *buf, size_t len) 345 406 { ··· 404 361 if (rc) 405 362 return rc; 406 363 407 - rc = down_write_killable(&cxl_region_rwsem); 364 + if (commit) { 365 + rc = __commit(cxlr); 366 + if (rc) 367 + return rc; 368 + return len; 369 + } 370 + 371 + rc = queue_reset(cxlr); 408 372 if (rc) 409 373 return rc; 410 - 411 - /* Already in the requested state? */ 412 - if (commit && p->state >= CXL_CONFIG_COMMIT) 413 - goto out; 414 - if (!commit && p->state < CXL_CONFIG_COMMIT) 415 - goto out; 416 - 417 - /* Not ready to commit? */ 418 - if (commit && p->state < CXL_CONFIG_ACTIVE) { 419 - rc = -ENXIO; 420 - goto out; 421 - } 422 374 423 375 /* 424 - * Invalidate caches before region setup to drop any speculative 425 - * consumption of this address space 376 + * Unmap the region and depend the reset-pending state to ensure 377 + * it does not go active again until post reset 426 378 */ 427 - rc = cxl_region_invalidate_memregion(cxlr); 428 - if (rc) 429 - goto out; 379 + device_release_driver(&cxlr->dev); 430 380 431 - if (commit) { 432 - rc = cxl_region_decode_commit(cxlr); 433 - if (rc == 0) 434 - p->state = CXL_CONFIG_COMMIT; 435 - } else { 436 - p->state = CXL_CONFIG_RESET_PENDING; 437 - up_write(&cxl_region_rwsem); 438 - device_release_driver(&cxlr->dev); 439 - down_write(&cxl_region_rwsem); 381 + /* 382 + * With the reset pending take cxl_rwsem.region unconditionally 383 + * to ensure the reset gets handled before returning. 384 + */ 385 + guard(rwsem_write)(&cxl_rwsem.region); 440 386 441 - /* 442 - * The lock was dropped, so need to revalidate that the reset is 443 - * still pending. 444 - */ 445 - if (p->state == CXL_CONFIG_RESET_PENDING) { 446 - cxl_region_decode_reset(cxlr, p->interleave_ways); 447 - p->state = CXL_CONFIG_ACTIVE; 448 - } 387 + /* 388 + * Revalidate that the reset is still pending in case another 389 + * thread already handled this reset. 390 + */ 391 + if (p->state == CXL_CONFIG_RESET_PENDING) { 392 + cxl_region_decode_reset(cxlr, p->interleave_ways); 393 + p->state = CXL_CONFIG_ACTIVE; 449 394 } 450 395 451 - out: 452 - up_write(&cxl_region_rwsem); 453 - 454 - if (rc) 455 - return rc; 456 396 return len; 457 397 } 458 398 ··· 446 420 struct cxl_region_params *p = &cxlr->params; 447 421 ssize_t rc; 448 422 449 - rc = down_read_interruptible(&cxl_region_rwsem); 450 - if (rc) 423 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 424 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 451 425 return rc; 452 - rc = sysfs_emit(buf, "%d\n", p->state >= CXL_CONFIG_COMMIT); 453 - up_read(&cxl_region_rwsem); 454 - 455 - return rc; 426 + return sysfs_emit(buf, "%d\n", p->state >= CXL_CONFIG_COMMIT); 456 427 } 457 428 static DEVICE_ATTR_RW(commit); 458 429 ··· 473 450 { 474 451 struct cxl_region *cxlr = to_cxl_region(dev); 475 452 struct cxl_region_params *p = &cxlr->params; 476 - ssize_t rc; 453 + int rc; 477 454 478 - rc = down_read_interruptible(&cxl_region_rwsem); 479 - if (rc) 455 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 456 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 480 457 return rc; 481 - rc = sysfs_emit(buf, "%d\n", p->interleave_ways); 482 - up_read(&cxl_region_rwsem); 483 - 484 - return rc; 458 + return sysfs_emit(buf, "%d\n", p->interleave_ways); 485 459 } 486 460 487 461 static const struct attribute_group *get_cxl_region_target_group(void); ··· 513 493 return -EINVAL; 514 494 } 515 495 516 - rc = down_write_killable(&cxl_region_rwsem); 517 - if (rc) 496 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 497 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 518 498 return rc; 519 - if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) { 520 - rc = -EBUSY; 521 - goto out; 522 - } 499 + 500 + if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) 501 + return -EBUSY; 523 502 524 503 save = p->interleave_ways; 525 504 p->interleave_ways = val; 526 505 rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_target_group()); 527 - if (rc) 506 + if (rc) { 528 507 p->interleave_ways = save; 529 - out: 530 - up_write(&cxl_region_rwsem); 531 - if (rc) 532 508 return rc; 509 + } 510 + 533 511 return len; 534 512 } 535 513 static DEVICE_ATTR_RW(interleave_ways); ··· 538 520 { 539 521 struct cxl_region *cxlr = to_cxl_region(dev); 540 522 struct cxl_region_params *p = &cxlr->params; 541 - ssize_t rc; 523 + int rc; 542 524 543 - rc = down_read_interruptible(&cxl_region_rwsem); 544 - if (rc) 525 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 526 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 545 527 return rc; 546 - rc = sysfs_emit(buf, "%d\n", p->interleave_granularity); 547 - up_read(&cxl_region_rwsem); 548 - 549 - return rc; 528 + return sysfs_emit(buf, "%d\n", p->interleave_granularity); 550 529 } 551 530 552 531 static ssize_t interleave_granularity_store(struct device *dev, ··· 576 561 if (cxld->interleave_ways > 1 && val != cxld->interleave_granularity) 577 562 return -EINVAL; 578 563 579 - rc = down_write_killable(&cxl_region_rwsem); 580 - if (rc) 564 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 565 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 581 566 return rc; 582 - if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) { 583 - rc = -EBUSY; 584 - goto out; 585 - } 567 + 568 + if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) 569 + return -EBUSY; 586 570 587 571 p->interleave_granularity = val; 588 - out: 589 - up_write(&cxl_region_rwsem); 590 - if (rc) 591 - return rc; 572 + 592 573 return len; 593 574 } 594 575 static DEVICE_ATTR_RW(interleave_granularity); ··· 595 584 struct cxl_region *cxlr = to_cxl_region(dev); 596 585 struct cxl_region_params *p = &cxlr->params; 597 586 u64 resource = -1ULL; 598 - ssize_t rc; 587 + int rc; 599 588 600 - rc = down_read_interruptible(&cxl_region_rwsem); 601 - if (rc) 589 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 590 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 602 591 return rc; 592 + 603 593 if (p->res) 604 594 resource = p->res->start; 605 - rc = sysfs_emit(buf, "%#llx\n", resource); 606 - up_read(&cxl_region_rwsem); 607 - 608 - return rc; 595 + return sysfs_emit(buf, "%#llx\n", resource); 609 596 } 610 597 static DEVICE_ATTR_RO(resource); 611 598 ··· 631 622 struct resource *res; 632 623 u64 remainder = 0; 633 624 634 - lockdep_assert_held_write(&cxl_region_rwsem); 625 + lockdep_assert_held_write(&cxl_rwsem.region); 635 626 636 627 /* Nothing to do... */ 637 628 if (p->res && resource_size(p->res) == size) ··· 673 664 struct cxl_region_params *p = &cxlr->params; 674 665 675 666 if (device_is_registered(&cxlr->dev)) 676 - lockdep_assert_held_write(&cxl_region_rwsem); 667 + lockdep_assert_held_write(&cxl_rwsem.region); 677 668 if (p->res) { 678 669 /* 679 670 * Autodiscovered regions may not have been able to insert their ··· 690 681 { 691 682 struct cxl_region_params *p = &cxlr->params; 692 683 693 - lockdep_assert_held_write(&cxl_region_rwsem); 684 + lockdep_assert_held_write(&cxl_rwsem.region); 694 685 695 686 if (!p->res) 696 687 return 0; ··· 714 705 if (rc) 715 706 return rc; 716 707 717 - rc = down_write_killable(&cxl_region_rwsem); 718 - if (rc) 708 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 709 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 719 710 return rc; 720 711 721 712 if (val) 722 713 rc = alloc_hpa(cxlr, val); 723 714 else 724 715 rc = free_hpa(cxlr); 725 - up_write(&cxl_region_rwsem); 726 716 727 717 if (rc) 728 718 return rc; ··· 737 729 u64 size = 0; 738 730 ssize_t rc; 739 731 740 - rc = down_read_interruptible(&cxl_region_rwsem); 741 - if (rc) 732 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 733 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 742 734 return rc; 743 735 if (p->res) 744 736 size = resource_size(p->res); 745 - rc = sysfs_emit(buf, "%#llx\n", size); 746 - up_read(&cxl_region_rwsem); 747 - 748 - return rc; 737 + return sysfs_emit(buf, "%#llx\n", size); 749 738 } 750 739 static DEVICE_ATTR_RW(size); 751 740 ··· 768 763 struct cxl_endpoint_decoder *cxled; 769 764 int rc; 770 765 771 - rc = down_read_interruptible(&cxl_region_rwsem); 772 - if (rc) 766 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 767 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 773 768 return rc; 774 769 775 770 if (pos >= p->interleave_ways) { 776 771 dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos, 777 772 p->interleave_ways); 778 - rc = -ENXIO; 779 - goto out; 773 + return -ENXIO; 780 774 } 781 775 782 776 cxled = p->targets[pos]; 783 777 if (!cxled) 784 - rc = sysfs_emit(buf, "\n"); 785 - else 786 - rc = sysfs_emit(buf, "%s\n", dev_name(&cxled->cxld.dev)); 787 - out: 788 - up_read(&cxl_region_rwsem); 789 - 790 - return rc; 778 + return sysfs_emit(buf, "\n"); 779 + return sysfs_emit(buf, "%s\n", dev_name(&cxled->cxld.dev)); 791 780 } 792 781 793 782 static int check_commit_order(struct device *dev, void *data) ··· 896 897 /* 897 898 * This decoder is pinned registered as long as the endpoint decoder is 898 899 * registered, and endpoint decoder unregistration holds the 899 - * cxl_region_rwsem over unregister events, so no need to hold on to 900 + * cxl_rwsem.region over unregister events, so no need to hold on to 900 901 * this extra reference. 901 902 */ 902 903 put_device(dev); ··· 1087 1088 unsigned long index; 1088 1089 int rc = -EBUSY; 1089 1090 1090 - lockdep_assert_held_write(&cxl_region_rwsem); 1091 + lockdep_assert_held_write(&cxl_rwsem.region); 1091 1092 1092 1093 cxl_rr = cxl_rr_load(port, cxlr); 1093 1094 if (cxl_rr) { ··· 1197 1198 struct cxl_region_ref *cxl_rr; 1198 1199 struct cxl_ep *ep = NULL; 1199 1200 1200 - lockdep_assert_held_write(&cxl_region_rwsem); 1201 + lockdep_assert_held_write(&cxl_rwsem.region); 1201 1202 1202 1203 cxl_rr = cxl_rr_load(port, cxlr); 1203 1204 if (!cxl_rr) ··· 2093 2094 return 0; 2094 2095 } 2095 2096 2096 - static int cxl_region_detach(struct cxl_endpoint_decoder *cxled) 2097 + static struct cxl_region * 2098 + __cxl_decoder_detach(struct cxl_region *cxlr, 2099 + struct cxl_endpoint_decoder *cxled, int pos, 2100 + enum cxl_detach_mode mode) 2097 2101 { 2098 - struct cxl_port *iter, *ep_port = cxled_to_port(cxled); 2099 - struct cxl_region *cxlr = cxled->cxld.region; 2100 2102 struct cxl_region_params *p; 2101 - int rc = 0; 2102 2103 2103 - lockdep_assert_held_write(&cxl_region_rwsem); 2104 + lockdep_assert_held_write(&cxl_rwsem.region); 2104 2105 2105 - if (!cxlr) 2106 - return 0; 2106 + if (!cxled) { 2107 + p = &cxlr->params; 2107 2108 2108 - p = &cxlr->params; 2109 - get_device(&cxlr->dev); 2109 + if (pos >= p->interleave_ways) { 2110 + dev_dbg(&cxlr->dev, "position %d out of range %d\n", 2111 + pos, p->interleave_ways); 2112 + return ERR_PTR(-ENXIO); 2113 + } 2114 + 2115 + if (!p->targets[pos]) 2116 + return NULL; 2117 + cxled = p->targets[pos]; 2118 + } else { 2119 + cxlr = cxled->cxld.region; 2120 + if (!cxlr) 2121 + return NULL; 2122 + p = &cxlr->params; 2123 + } 2124 + 2125 + if (mode == DETACH_INVALIDATE) 2126 + cxled->part = -1; 2110 2127 2111 2128 if (p->state > CXL_CONFIG_ACTIVE) { 2112 2129 cxl_region_decode_reset(cxlr, p->interleave_ways); 2113 2130 p->state = CXL_CONFIG_ACTIVE; 2114 2131 } 2115 2132 2116 - for (iter = ep_port; !is_cxl_root(iter); 2133 + for (struct cxl_port *iter = cxled_to_port(cxled); !is_cxl_root(iter); 2117 2134 iter = to_cxl_port(iter->dev.parent)) 2118 2135 cxl_port_detach_region(iter, cxlr, cxled); 2119 2136 ··· 2140 2125 dev_WARN_ONCE(&cxlr->dev, 1, "expected %s:%s at position %d\n", 2141 2126 dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 2142 2127 cxled->pos); 2143 - goto out; 2128 + return NULL; 2144 2129 } 2145 2130 2146 2131 if (p->state == CXL_CONFIG_ACTIVE) { ··· 2154 2139 .end = -1, 2155 2140 }; 2156 2141 2157 - /* notify the region driver that one of its targets has departed */ 2158 - up_write(&cxl_region_rwsem); 2159 - device_release_driver(&cxlr->dev); 2160 - down_write(&cxl_region_rwsem); 2161 - out: 2162 - put_device(&cxlr->dev); 2163 - return rc; 2142 + get_device(&cxlr->dev); 2143 + return cxlr; 2164 2144 } 2165 2145 2166 - void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled) 2146 + /* 2147 + * Cleanup a decoder's interest in a region. There are 2 cases to 2148 + * handle, removing an unknown @cxled from a known position in a region 2149 + * (detach_target()) or removing a known @cxled from an unknown @cxlr 2150 + * (cxld_unregister()) 2151 + * 2152 + * When the detachment finds a region release the region driver. 2153 + */ 2154 + int cxl_decoder_detach(struct cxl_region *cxlr, 2155 + struct cxl_endpoint_decoder *cxled, int pos, 2156 + enum cxl_detach_mode mode) 2167 2157 { 2168 - down_write(&cxl_region_rwsem); 2169 - cxled->part = -1; 2170 - cxl_region_detach(cxled); 2171 - up_write(&cxl_region_rwsem); 2158 + struct cxl_region *detach; 2159 + 2160 + /* when the decoder is being destroyed lock unconditionally */ 2161 + if (mode == DETACH_INVALIDATE) { 2162 + guard(rwsem_write)(&cxl_rwsem.region); 2163 + detach = __cxl_decoder_detach(cxlr, cxled, pos, mode); 2164 + } else { 2165 + int rc; 2166 + 2167 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 2168 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 2169 + return rc; 2170 + detach = __cxl_decoder_detach(cxlr, cxled, pos, mode); 2171 + } 2172 + 2173 + if (detach) { 2174 + device_release_driver(&detach->dev); 2175 + put_device(&detach->dev); 2176 + } 2177 + return 0; 2178 + } 2179 + 2180 + static int __attach_target(struct cxl_region *cxlr, 2181 + struct cxl_endpoint_decoder *cxled, int pos, 2182 + unsigned int state) 2183 + { 2184 + int rc; 2185 + 2186 + if (state == TASK_INTERRUPTIBLE) { 2187 + ACQUIRE(rwsem_write_kill, rwsem)(&cxl_rwsem.region); 2188 + if ((rc = ACQUIRE_ERR(rwsem_write_kill, &rwsem))) 2189 + return rc; 2190 + guard(rwsem_read)(&cxl_rwsem.dpa); 2191 + return cxl_region_attach(cxlr, cxled, pos); 2192 + } 2193 + guard(rwsem_write)(&cxl_rwsem.region); 2194 + guard(rwsem_read)(&cxl_rwsem.dpa); 2195 + return cxl_region_attach(cxlr, cxled, pos); 2172 2196 } 2173 2197 2174 2198 static int attach_target(struct cxl_region *cxlr, 2175 2199 struct cxl_endpoint_decoder *cxled, int pos, 2176 2200 unsigned int state) 2177 2201 { 2178 - int rc = 0; 2202 + int rc = __attach_target(cxlr, cxled, pos, state); 2179 2203 2180 - if (state == TASK_INTERRUPTIBLE) 2181 - rc = down_write_killable(&cxl_region_rwsem); 2182 - else 2183 - down_write(&cxl_region_rwsem); 2184 - if (rc) 2185 - return rc; 2204 + if (rc == 0) 2205 + return 0; 2186 2206 2187 - down_read(&cxl_dpa_rwsem); 2188 - rc = cxl_region_attach(cxlr, cxled, pos); 2189 - up_read(&cxl_dpa_rwsem); 2190 - up_write(&cxl_region_rwsem); 2191 - 2192 - if (rc) 2193 - dev_warn(cxled->cxld.dev.parent, 2194 - "failed to attach %s to %s: %d\n", 2195 - dev_name(&cxled->cxld.dev), dev_name(&cxlr->dev), rc); 2196 - 2207 + dev_warn(cxled->cxld.dev.parent, "failed to attach %s to %s: %d\n", 2208 + dev_name(&cxled->cxld.dev), dev_name(&cxlr->dev), rc); 2197 2209 return rc; 2198 2210 } 2199 2211 2200 2212 static int detach_target(struct cxl_region *cxlr, int pos) 2201 2213 { 2202 - struct cxl_region_params *p = &cxlr->params; 2203 - int rc; 2204 - 2205 - rc = down_write_killable(&cxl_region_rwsem); 2206 - if (rc) 2207 - return rc; 2208 - 2209 - if (pos >= p->interleave_ways) { 2210 - dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos, 2211 - p->interleave_ways); 2212 - rc = -ENXIO; 2213 - goto out; 2214 - } 2215 - 2216 - if (!p->targets[pos]) { 2217 - rc = 0; 2218 - goto out; 2219 - } 2220 - 2221 - rc = cxl_region_detach(p->targets[pos]); 2222 - out: 2223 - up_write(&cxl_region_rwsem); 2224 - return rc; 2214 + return cxl_decoder_detach(cxlr, NULL, pos, DETACH_ONLY); 2225 2215 } 2226 2216 2227 2217 static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos, ··· 2480 2460 return NOTIFY_DONE; 2481 2461 2482 2462 /* 2483 - * No need to hold cxl_region_rwsem; region parameters are stable 2463 + * No need to hold cxl_rwsem.region; region parameters are stable 2484 2464 * within the cxl_region driver. 2485 2465 */ 2486 2466 region_nid = phys_to_target_node(cxlr->params.res->start); ··· 2503 2483 int region_nid; 2504 2484 2505 2485 /* 2506 - * No need to hold cxl_region_rwsem; region parameters are stable 2486 + * No need to hold cxl_rwsem.region; region parameters are stable 2507 2487 * within the cxl_region driver. 2508 2488 */ 2509 2489 region_nid = phys_to_target_node(cxlr->params.res->start); ··· 2652 2632 struct cxl_decoder *cxld = to_cxl_decoder(dev); 2653 2633 ssize_t rc; 2654 2634 2655 - rc = down_read_interruptible(&cxl_region_rwsem); 2656 - if (rc) 2635 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 2636 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) 2657 2637 return rc; 2658 2638 2659 2639 if (cxld->region) 2660 - rc = sysfs_emit(buf, "%s\n", dev_name(&cxld->region->dev)); 2661 - else 2662 - rc = sysfs_emit(buf, "\n"); 2663 - up_read(&cxl_region_rwsem); 2664 - 2665 - return rc; 2640 + return sysfs_emit(buf, "%s\n", dev_name(&cxld->region->dev)); 2641 + return sysfs_emit(buf, "\n"); 2666 2642 } 2667 2643 DEVICE_ATTR_RO(region); 2668 2644 ··· 2997 2981 struct device *dev; 2998 2982 int i; 2999 2983 3000 - guard(rwsem_read)(&cxl_region_rwsem); 2984 + guard(rwsem_read)(&cxl_rwsem.region); 3001 2985 if (p->state != CXL_CONFIG_COMMIT) 3002 2986 return -ENXIO; 3003 2987 ··· 3009 2993 cxlr_pmem->hpa_range.start = p->res->start; 3010 2994 cxlr_pmem->hpa_range.end = p->res->end; 3011 2995 3012 - /* Snapshot the region configuration underneath the cxl_region_rwsem */ 2996 + /* Snapshot the region configuration underneath the cxl_rwsem.region */ 3013 2997 cxlr_pmem->nr_mappings = p->nr_targets; 3014 2998 for (i = 0; i < p->nr_targets; i++) { 3015 2999 struct cxl_endpoint_decoder *cxled = p->targets[i]; ··· 3086 3070 struct cxl_dax_region *cxlr_dax; 3087 3071 struct device *dev; 3088 3072 3089 - guard(rwsem_read)(&cxl_region_rwsem); 3073 + guard(rwsem_read)(&cxl_rwsem.region); 3090 3074 if (p->state != CXL_CONFIG_COMMIT) 3091 3075 return ERR_PTR(-ENXIO); 3092 3076 ··· 3286 3270 cxlr = to_cxl_region(dev); 3287 3271 p = &cxlr->params; 3288 3272 3289 - guard(rwsem_read)(&cxl_region_rwsem); 3273 + guard(rwsem_read)(&cxl_rwsem.region); 3290 3274 if (p->res && p->res->start == r->start && p->res->end == r->end) 3291 3275 return 1; 3292 3276 ··· 3341 3325 struct resource *res; 3342 3326 int rc; 3343 3327 3344 - guard(rwsem_write)(&cxl_region_rwsem); 3328 + guard(rwsem_write)(&cxl_rwsem.region); 3345 3329 p = &cxlr->params; 3346 3330 if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) { 3347 3331 dev_err(cxlmd->dev.parent, ··· 3477 3461 3478 3462 attach_target(cxlr, cxled, -1, TASK_UNINTERRUPTIBLE); 3479 3463 3480 - down_read(&cxl_region_rwsem); 3481 - p = &cxlr->params; 3482 - attach = p->state == CXL_CONFIG_COMMIT; 3483 - up_read(&cxl_region_rwsem); 3464 + scoped_guard(rwsem_read, &cxl_rwsem.region) { 3465 + p = &cxlr->params; 3466 + attach = p->state == CXL_CONFIG_COMMIT; 3467 + } 3484 3468 3485 3469 if (attach) { 3486 3470 /* ··· 3505 3489 if (!endpoint) 3506 3490 return ~0ULL; 3507 3491 3508 - guard(rwsem_write)(&cxl_region_rwsem); 3492 + guard(rwsem_write)(&cxl_rwsem.region); 3509 3493 3510 3494 xa_for_each(&endpoint->regions, index, iter) { 3511 3495 struct cxl_region_params *p = &iter->region->params; ··· 3542 3526 unregister_mt_adistance_algorithm(&cxlr->adist_notifier); 3543 3527 } 3544 3528 3545 - static int cxl_region_probe(struct device *dev) 3529 + static int cxl_region_can_probe(struct cxl_region *cxlr) 3546 3530 { 3547 - struct cxl_region *cxlr = to_cxl_region(dev); 3548 3531 struct cxl_region_params *p = &cxlr->params; 3549 3532 int rc; 3550 3533 3551 - rc = down_read_interruptible(&cxl_region_rwsem); 3552 - if (rc) { 3534 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 3535 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) { 3553 3536 dev_dbg(&cxlr->dev, "probe interrupted\n"); 3554 3537 return rc; 3555 3538 } 3556 3539 3557 3540 if (p->state < CXL_CONFIG_COMMIT) { 3558 3541 dev_dbg(&cxlr->dev, "config state: %d\n", p->state); 3559 - rc = -ENXIO; 3560 - goto out; 3542 + return -ENXIO; 3561 3543 } 3562 3544 3563 3545 if (test_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags)) { 3564 3546 dev_err(&cxlr->dev, 3565 3547 "failed to activate, re-commit region and retry\n"); 3566 - rc = -ENXIO; 3567 - goto out; 3548 + return -ENXIO; 3568 3549 } 3550 + 3551 + return 0; 3552 + } 3553 + 3554 + static int cxl_region_probe(struct device *dev) 3555 + { 3556 + struct cxl_region *cxlr = to_cxl_region(dev); 3557 + struct cxl_region_params *p = &cxlr->params; 3558 + int rc; 3559 + 3560 + rc = cxl_region_can_probe(cxlr); 3561 + if (rc) 3562 + return rc; 3569 3563 3570 3564 /* 3571 3565 * From this point on any path that changes the region's state away from 3572 3566 * CXL_CONFIG_COMMIT is also responsible for releasing the driver. 3573 3567 */ 3574 - out: 3575 - up_read(&cxl_region_rwsem); 3576 - 3577 - if (rc) 3578 - return rc; 3579 3568 3580 3569 cxlr->memory_notifier.notifier_call = cxl_region_perf_attrs_callback; 3581 3570 cxlr->memory_notifier.priority = CXL_CALLBACK_PRI;
+1 -12
drivers/cxl/cxl.h
··· 471 471 * @nr_targets: number of targets 472 472 * @cache_size: extended linear cache size if exists, otherwise zero. 473 473 * 474 - * State transitions are protected by the cxl_region_rwsem 474 + * State transitions are protected by cxl_rwsem.region 475 475 */ 476 476 struct cxl_region_params { 477 477 enum cxl_config_state state; ··· 914 914 #endif 915 915 916 916 u16 cxl_gpf_get_dvsec(struct device *dev); 917 - 918 - static inline struct rw_semaphore *rwsem_read_intr_acquire(struct rw_semaphore *rwsem) 919 - { 920 - if (down_read_interruptible(rwsem)) 921 - return NULL; 922 - 923 - return rwsem; 924 - } 925 - 926 - DEFINE_FREE(rwsem_read_release, struct rw_semaphore *, if (_T) up_read(_T)) 927 - 928 917 #endif /* __CXL_H__ */
+2 -2
drivers/cxl/cxlmem.h
··· 254 254 * @max_errors: Maximum media error records held in device cache 255 255 * @enabled_cmds: All poison commands enabled in the CEL 256 256 * @list_out: The poison list payload returned by device 257 - * @lock: Protect reads of the poison list 257 + * @mutex: Protect reads of the poison list 258 258 * 259 259 * Reads of the poison list are synchronized to ensure that a reader 260 260 * does not get an incomplete list because their request overlapped ··· 265 265 u32 max_errors; 266 266 DECLARE_BITMAP(enabled_cmds, CXL_POISON_ENABLED_MAX); 267 267 struct cxl_mbox_poison_out *list_out; 268 - struct mutex lock; /* Protect reads of poison list */ 268 + struct mutex mutex; /* Protect reads of poison list */ 269 269 }; 270 270 271 271 /*
+81 -14
include/linux/cleanup.h
··· 3 3 #define _LINUX_CLEANUP_H 4 4 5 5 #include <linux/compiler.h> 6 + #include <linux/err.h> 7 + #include <linux/args.h> 6 8 7 9 /** 8 10 * DOC: scope-based cleanup helpers ··· 63 61 * Observe the lock is held for the remainder of the "if ()" block not 64 62 * the remainder of "func()". 65 63 * 66 - * Now, when a function uses both __free() and guard(), or multiple 67 - * instances of __free(), the LIFO order of variable definition order 68 - * matters. GCC documentation says: 64 + * The ACQUIRE() macro can be used in all places that guard() can be 65 + * used and additionally support conditional locks 66 + * 67 + * 68 + * DEFINE_GUARD_COND(pci_dev, _try, pci_dev_trylock(_T)) 69 + * ... 70 + * ACQUIRE(pci_dev_try, lock)(dev); 71 + * rc = ACQUIRE_ERR(pci_dev_try, &lock); 72 + * if (rc) 73 + * return rc; 74 + * // @lock is held 75 + * 76 + * Now, when a function uses both __free() and guard()/ACQUIRE(), or 77 + * multiple instances of __free(), the LIFO order of variable definition 78 + * order matters. GCC documentation says: 69 79 * 70 80 * "When multiple variables in the same scope have cleanup attributes, 71 81 * at exit from the scope their associated cleanup functions are run in ··· 319 305 * acquire fails. 320 306 * 321 307 * Only for conditional locks. 308 + * 309 + * ACQUIRE(name, var): 310 + * a named instance of the (guard) class, suitable for conditional 311 + * locks when paired with ACQUIRE_ERR(). 312 + * 313 + * ACQUIRE_ERR(name, &var): 314 + * a helper that is effectively a PTR_ERR() conversion of the guard 315 + * pointer. Returns 0 when the lock was acquired and a negative 316 + * error code otherwise. 322 317 */ 323 318 324 319 #define __DEFINE_CLASS_IS_CONDITIONAL(_name, _is_cond) \ 325 320 static __maybe_unused const bool class_##_name##_is_conditional = _is_cond 326 321 327 - #define __DEFINE_GUARD_LOCK_PTR(_name, _exp) \ 328 - static inline void * class_##_name##_lock_ptr(class_##_name##_t *_T) \ 329 - { return (void *)(__force unsigned long)*(_exp); } 322 + #define __GUARD_IS_ERR(_ptr) \ 323 + ({ \ 324 + unsigned long _rc = (__force unsigned long)(_ptr); \ 325 + unlikely((_rc - 1) >= -MAX_ERRNO - 1); \ 326 + }) 327 + 328 + #define __DEFINE_GUARD_LOCK_PTR(_name, _exp) \ 329 + static inline void *class_##_name##_lock_ptr(class_##_name##_t *_T) \ 330 + { \ 331 + void *_ptr = (void *)(__force unsigned long)*(_exp); \ 332 + if (IS_ERR(_ptr)) { \ 333 + _ptr = NULL; \ 334 + } \ 335 + return _ptr; \ 336 + } \ 337 + static inline int class_##_name##_lock_err(class_##_name##_t *_T) \ 338 + { \ 339 + long _rc = (__force unsigned long)*(_exp); \ 340 + if (!_rc) { \ 341 + _rc = -EBUSY; \ 342 + } \ 343 + if (!IS_ERR_VALUE(_rc)) { \ 344 + _rc = 0; \ 345 + } \ 346 + return _rc; \ 347 + } 330 348 331 349 #define DEFINE_CLASS_IS_GUARD(_name) \ 332 350 __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \ ··· 369 323 __DEFINE_GUARD_LOCK_PTR(_name, _T) 370 324 371 325 #define DEFINE_GUARD(_name, _type, _lock, _unlock) \ 372 - DEFINE_CLASS(_name, _type, if (_T) { _unlock; }, ({ _lock; _T; }), _type _T); \ 326 + DEFINE_CLASS(_name, _type, if (!__GUARD_IS_ERR(_T)) { _unlock; }, ({ _lock; _T; }), _type _T); \ 373 327 DEFINE_CLASS_IS_GUARD(_name) 374 328 375 - #define DEFINE_GUARD_COND(_name, _ext, _condlock) \ 329 + #define DEFINE_GUARD_COND_4(_name, _ext, _lock, _cond) \ 376 330 __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \ 377 331 EXTEND_CLASS(_name, _ext, \ 378 - ({ void *_t = _T; if (_T && !(_condlock)) _t = NULL; _t; }), \ 332 + ({ void *_t = _T; int _RET = (_lock); if (_T && !(_cond)) _t = ERR_PTR(_RET); _t; }), \ 379 333 class_##_name##_t _T) \ 380 334 static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \ 381 - { return class_##_name##_lock_ptr(_T); } 335 + { return class_##_name##_lock_ptr(_T); } \ 336 + static inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \ 337 + { return class_##_name##_lock_err(_T); } 338 + 339 + /* 340 + * Default binary condition; success on 'true'. 341 + */ 342 + #define DEFINE_GUARD_COND_3(_name, _ext, _lock) \ 343 + DEFINE_GUARD_COND_4(_name, _ext, _lock, _RET) 344 + 345 + #define DEFINE_GUARD_COND(X...) CONCATENATE(DEFINE_GUARD_COND_, COUNT_ARGS(X))(X) 382 346 383 347 #define guard(_name) \ 384 348 CLASS(_name, __UNIQUE_ID(guard)) 385 349 386 350 #define __guard_ptr(_name) class_##_name##_lock_ptr 351 + #define __guard_err(_name) class_##_name##_lock_err 387 352 #define __is_cond_ptr(_name) class_##_name##_is_conditional 353 + 354 + #define ACQUIRE(_name, _var) CLASS(_name, _var) 355 + #define ACQUIRE_ERR(_name, _var) __guard_err(_name)(_var) 388 356 389 357 /* 390 358 * Helper macro for scoped_guard(). ··· 461 401 \ 462 402 static inline void class_##_name##_destructor(class_##_name##_t *_T) \ 463 403 { \ 464 - if (_T->lock) { _unlock; } \ 404 + if (!__GUARD_IS_ERR(_T->lock)) { _unlock; } \ 465 405 } \ 466 406 \ 467 407 __DEFINE_GUARD_LOCK_PTR(_name, &_T->lock) ··· 493 433 __DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__) \ 494 434 __DEFINE_LOCK_GUARD_0(_name, _lock) 495 435 496 - #define DEFINE_LOCK_GUARD_1_COND(_name, _ext, _condlock) \ 436 + #define DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _cond) \ 497 437 __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \ 498 438 EXTEND_CLASS(_name, _ext, \ 499 439 ({ class_##_name##_t _t = { .lock = l }, *_T = &_t;\ 500 - if (_T->lock && !(_condlock)) _T->lock = NULL; \ 440 + int _RET = (_lock); \ 441 + if (_T->lock && !(_cond)) _T->lock = ERR_PTR(_RET);\ 501 442 _t; }), \ 502 443 typeof_member(class_##_name##_t, lock) l) \ 503 444 static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \ 504 - { return class_##_name##_lock_ptr(_T); } 445 + { return class_##_name##_lock_ptr(_T); } \ 446 + static inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \ 447 + { return class_##_name##_lock_err(_T); } 505 448 449 + #define DEFINE_LOCK_GUARD_1_COND_3(_name, _ext, _lock) \ 450 + DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _RET) 451 + 452 + #define DEFINE_LOCK_GUARD_1_COND(X...) CONCATENATE(DEFINE_LOCK_GUARD_1_COND_, COUNT_ARGS(X))(X) 506 453 507 454 #endif /* _LINUX_CLEANUP_H */
+1 -1
include/linux/mutex.h
··· 224 224 225 225 DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T)) 226 226 DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T)) 227 - DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) == 0) 227 + DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T), _RET == 0) 228 228 229 229 extern unsigned long mutex_get_owner(struct mutex *lock); 230 230
+2 -1
include/linux/rwsem.h
··· 240 240 241 241 DEFINE_GUARD(rwsem_read, struct rw_semaphore *, down_read(_T), up_read(_T)) 242 242 DEFINE_GUARD_COND(rwsem_read, _try, down_read_trylock(_T)) 243 - DEFINE_GUARD_COND(rwsem_read, _intr, down_read_interruptible(_T) == 0) 243 + DEFINE_GUARD_COND(rwsem_read, _intr, down_read_interruptible(_T), _RET == 0) 244 244 245 245 DEFINE_GUARD(rwsem_write, struct rw_semaphore *, down_write(_T), up_write(_T)) 246 246 DEFINE_GUARD_COND(rwsem_write, _try, down_write_trylock(_T)) 247 + DEFINE_GUARD_COND(rwsem_write, _kill, down_write_killable(_T), _RET == 0) 247 248 248 249 /* 249 250 * downgrade write lock to read lock