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

Merge tag 'cxl-for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Pull CXL updates from Dave Jiang:
"The most significant changes in this pull request is the series that
introduces ACQUIRE() and ACQUIRE_ERR() macros to replace conditional
locking and ease the pain points of scoped_cond_guard().

The series also includes follow on changes that refactor the CXL
sub-system to utilize the new macros.

Detail summary:

- Add documentation template for CXL conventions to document CXL
platform quirks

- Replace mutex_lock_io() with mutex_lock() for mailbox

- Add location limit for fake CFMWS range for cxl_test, ARM platform
enabling

- CXL documentation typo and clarity fixes

- Use correct format specifier for function cxl_set_ecs_threshold()

- Make cxl_bus_type constant

- Introduce new helper cxl_resource_contains_addr() to check address
availability

- Fix wrong DPA checking for PPR operation

- Remove core/acpi.c and CXL core dependency on ACPI

- Introduce ACQUIRE() and ACQUIRE_ERR() for conditional locks

- Add CXL updates utilizing ACQUIRE() macro to remove gotos and
improve readability

- Add return for the dummy version of cxl_decoder_detach() without
CONFIG_CXL_REGION

- CXL events updates for spec r3.2

- Fix return of __cxl_decoder_detach() error path

- CXL debugfs documentation fix"

* tag 'cxl-for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (28 commits)
Documentation/ABI/testing/debugfs-cxl: Add 'cxl' to clear_poison path
cxl/region: Fix an ERR_PTR() vs NULL bug
cxl/events: Trace Memory Sparing Event Record
cxl/events: Add extra validity checks for CVME count in DRAM Event Record
cxl/events: Add extra validity checks for corrected memory error count in General Media Event Record
cxl/events: Update Common Event Record to CXL spec rev 3.2
cxl: Fix -Werror=return-type in cxl_decoder_detach()
cleanup: Fix documentation build error for ACQUIRE updates
cxl: Convert to ACQUIRE() for conditional rwsem locking
cxl/region: Consolidate cxl_decoder_kill_region() and cxl_region_detach()
cxl/region: Move ready-to-probe state check to a helper
cxl/region: Split commit_store() into __commit() and queue_reset() helpers
cxl/decoder: Drop pointless locking
cxl/decoder: Move decoder register programming to a helper
cxl/mbox: Convert poison list mutex to ACQUIRE()
cleanup: Introduce ACQUIRE() and ACQUIRE_ERR() for conditional locks
cxl: Remove core/acpi.c and cxl core dependency on ACPI
cxl/core: Using cxl_resource_contains_addr() to check address availability
cxl/edac: Fix wrong dpa checking for PPR operation
cxl/core: Introduce a new helper cxl_resource_contains_addr()
...

+829 -455
+1 -1
Documentation/ABI/testing/debugfs-cxl
··· 20 20 visible for devices supporting the capability. 21 21 22 22 23 - What: /sys/kernel/debug/memX/clear_poison 23 + What: /sys/kernel/debug/cxl/memX/clear_poison 24 24 Date: April, 2023 25 25 KernelVersion: v6.4 26 26 Contact: linux-cxl@vger.kernel.org
+47
Documentation/driver-api/cxl/conventions.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + .. include:: <isonum.txt> 3 + 4 + ======================================= 5 + Compute Express Link: Linux Conventions 6 + ======================================= 7 + 8 + There exists shipping platforms that bend or break CXL specification 9 + expectations. Record the details and the rationale for those deviations. 10 + Borrow the ACPI Code First template format to capture the assumptions 11 + and tradeoffs such that multiple platform implementations can follow the 12 + same convention. 13 + 14 + <(template) Title> 15 + ================== 16 + 17 + Document 18 + -------- 19 + CXL Revision <rev>, Version <ver> 20 + 21 + License 22 + ------- 23 + SPDX-License Identifier: CC-BY-4.0 24 + 25 + Creator/Contributors 26 + -------------------- 27 + 28 + Summary of the Change 29 + --------------------- 30 + 31 + <Detail the conflict with the specification and where available the 32 + assumptions and tradeoffs taken by the hardware platform.> 33 + 34 + 35 + Benefits of the Change 36 + ---------------------- 37 + 38 + <Detail what happens if platforms and Linux do not adopt this 39 + convention.> 40 + 41 + References 42 + ---------- 43 + 44 + Detailed Description of the Change 45 + ---------------------------------- 46 + 47 + <Propose spec language that corrects the conflict.>
+5 -5
Documentation/driver-api/cxl/devices/device-types.rst
··· 63 63 64 64 * Supports cxl.io, cxl.cache, and cxl.mem protocols 65 65 * Optionally implements coherent cache and Host-Managed Device Memory 66 - * Is typically an accelerator device w/ high bandwidth memory. 66 + * Is typically an accelerator device with high bandwidth memory. 67 67 68 68 The primary difference between a type-1 and type-2 device is the presence 69 69 of host-managed device memory, which allows the device to operate on a 70 - local memory bank - while the CPU sill has coherent DMA to the same memory. 70 + local memory bank - while the CPU still has coherent DMA to the same memory. 71 71 72 - The allows things like GPUs to expose their memory via DAX devices or file 72 + This allows things like GPUs to expose their memory via DAX devices or file 73 73 descriptors, allows drivers and programs direct access to device memory 74 74 rather than use block-transfer semantics. 75 75 ··· 89 89 Switch 90 90 ------ 91 91 92 - A CXL switch is a device capacity of routing any CXL (and by extension, PCIe) 92 + A CXL switch is a device capable of routing any CXL (and by extension, PCIe) 93 93 protocol between an upstream, downstream, or peer devices. Many devices, such 94 94 as Multi-Logical Devices, imply the presence of switching in some manner. 95 95 ··· 103 103 one or more heads. 104 104 105 105 A Multi-Logical Device (MLD) is a device which may present multiple devices 106 - to one or more devices. 106 + to one or more upstream devices. 107 107 108 108 A Single-Headed Device exposes only a single physical connection. 109 109
+1
Documentation/driver-api/cxl/index.rst
··· 14 14 15 15 theory-of-operation 16 16 maturity-map 17 + conventions 17 18 18 19 .. toctree:: 19 20 :maxdepth: 2
+1 -1
Documentation/driver-api/cxl/linux/cxl-driver.rst
··· 20 20 * cxl_port - initializes root and provides port enumeration interface. 21 21 * cxl_acpi - initializes root decoders and interacts with ACPI data. 22 22 * cxl_p/mem - initializes memory devices 23 - * cxl_pci - uses cxl_port to enumates the actual fabric hierarchy. 23 + * cxl_pci - uses cxl_port to enumerate the actual fabric hierarchy. 24 24 25 25 Driver Devices 26 26 ==============
+6 -6
Documentation/driver-api/cxl/theory-of-operation.rst
··· 29 29 (Linux term for the top of the CXL decode topology). From there, PCIe topology 30 30 dictates which endpoints can participate in which Host Bridge decode regimes. 31 31 Each PCIe Switch in the path between the root and an endpoint introduces a point 32 - at which the interleave can be split. For example platform firmware may say at a 33 - given range only decodes to 1 one Host Bridge, but that Host Bridge may in turn 32 + at which the interleave can be split. For example, platform firmware may say a 33 + given range only decodes to one Host Bridge, but that Host Bridge may in turn 34 34 interleave cycles across multiple Root Ports. An intervening Switch between a 35 35 port and an endpoint may interleave cycles across multiple Downstream Switch 36 36 Ports, etc. ··· 187 187 represent the decode from SPA (System Physical Address) to DPA (Device Physical 188 188 Address). 189 189 190 - Continuing the RAID analogy, disks have both topology metadata and on device 190 + Continuing the RAID analogy, disks have both topology metadata and on-device 191 191 metadata that determine RAID set assembly. CXL Port topology and CXL Port link 192 192 status is metadata for CXL.mem set assembly. The CXL Port topology is enumerated 193 193 by the arrival of a CXL.mem device. I.e. unless and until the PCIe core attaches ··· 197 197 ->remove() event cleans up the port data that was established to support that 198 198 Memory Expander. 199 199 200 - The port metadata and potential decode schemes that a give memory device may 200 + The port metadata and potential decode schemes that a given memory device may 201 201 participate can be determined via a command like:: 202 202 203 203 # cxl list -BDMu -d root -m mem3 ··· 249 249 ...which queries the CXL topology to ask "given CXL Memory Expander with a kernel 250 250 device name of 'mem3' which platform level decode ranges may this device 251 251 participate". A given expander can participate in multiple CXL.mem interleave 252 - sets simultaneously depending on how many decoder resource it has. In this 253 - example mem3 can participate in one or more of a PMEM interleave that spans to 252 + sets simultaneously depending on how many decoder resources it has. In this 253 + example mem3 can participate in one or more of a PMEM interleave that spans two 254 254 Host Bridges, a PMEM interleave that targets a single Host Bridge, a Volatile 255 255 memory interleave that spans 2 Host Bridges, and a Volatile memory interleave 256 256 that only targets a single Host Bridge.
+59
drivers/cxl/acpi.c
··· 335 335 return rc; 336 336 } 337 337 338 + static int cxl_acpi_set_cache_size(struct cxl_root_decoder *cxlrd) 339 + { 340 + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; 341 + struct range *hpa = &cxld->hpa_range; 342 + resource_size_t size = range_len(hpa); 343 + resource_size_t start = hpa->start; 344 + resource_size_t cache_size; 345 + struct resource res; 346 + int nid, rc; 347 + 348 + res = DEFINE_RES(start, size, 0); 349 + nid = phys_to_target_node(start); 350 + 351 + rc = hmat_get_extended_linear_cache_size(&res, nid, &cache_size); 352 + if (rc) 353 + return rc; 354 + 355 + /* 356 + * The cache range is expected to be within the CFMWS. 357 + * Currently there is only support cache_size == cxl_size. CXL 358 + * size is then half of the total CFMWS window size. 359 + */ 360 + size = size >> 1; 361 + if (cache_size && size != cache_size) { 362 + dev_warn(&cxld->dev, 363 + "Extended Linear Cache size %pa != CXL size %pa. No Support!", 364 + &cache_size, &size); 365 + return -ENXIO; 366 + } 367 + 368 + cxlrd->cache_size = cache_size; 369 + 370 + return 0; 371 + } 372 + 373 + static void cxl_setup_extended_linear_cache(struct cxl_root_decoder *cxlrd) 374 + { 375 + int rc; 376 + 377 + rc = cxl_acpi_set_cache_size(cxlrd); 378 + if (!rc) 379 + return; 380 + 381 + if (rc != -EOPNOTSUPP) { 382 + /* 383 + * Failing to support extended linear cache region resize does not 384 + * prevent the region from functioning. Only causes cxl list showing 385 + * incorrect region size. 386 + */ 387 + dev_warn(cxlrd->cxlsd.cxld.dev.parent, 388 + "Extended linear cache calculation failed rc:%d\n", rc); 389 + } 390 + 391 + /* Ignoring return code */ 392 + cxlrd->cache_size = 0; 393 + } 394 + 338 395 DEFINE_FREE(put_cxlrd, struct cxl_root_decoder *, 339 396 if (!IS_ERR_OR_NULL(_T)) put_device(&_T->cxlsd.cxld.dev)) 340 397 DEFINE_FREE(del_cxl_resource, struct resource *, if (_T) del_cxl_resource(_T)) ··· 450 393 if (ways == 1) 451 394 ig = CXL_DECODER_MIN_GRANULARITY; 452 395 cxld->interleave_granularity = ig; 396 + 397 + cxl_setup_extended_linear_cache(cxlrd); 453 398 454 399 if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) { 455 400 if (ways != 1 && ways != 3) {
-1
drivers/cxl/core/Makefile
··· 15 15 cxl_core-y += pmu.o 16 16 cxl_core-y += cdat.o 17 17 cxl_core-y += ras.o 18 - cxl_core-y += acpi.o 19 18 cxl_core-$(CONFIG_TRACING) += trace.o 20 19 cxl_core-$(CONFIG_CXL_REGION) += region.o 21 20 cxl_core-$(CONFIG_CXL_MCE) += mce.o
-11
drivers/cxl/core/acpi.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* Copyright(c) 2024 Intel Corporation. All rights reserved. */ 3 - #include <linux/acpi.h> 4 - #include "cxl.h" 5 - #include "core.h" 6 - 7 - int cxl_acpi_get_extended_linear_cache_size(struct resource *backing_res, 8 - int nid, resource_size_t *size) 9 - { 10 - return hmat_get_extended_linear_cache_size(backing_res, nid, size); 11 - }
+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))
+30 -6
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 { 55 + return 0; 63 56 } 64 57 static inline int cxl_region_init(void) 65 58 { ··· 93 80 int cxl_dpa_free(struct cxl_endpoint_decoder *cxled); 94 81 resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled); 95 82 resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled); 83 + bool cxl_resource_contains_addr(const struct resource *res, const resource_size_t addr); 96 84 97 85 enum cxl_rcrb { 98 86 CXL_RCRB_DOWNSTREAM, ··· 110 96 #define PCI_RCRB_CAP_HDR_NEXT_MASK GENMASK(15, 8) 111 97 #define PCI_CAP_EXP_SIZEOF 0x3c 112 98 113 - extern struct rw_semaphore cxl_dpa_rwsem; 114 - extern struct rw_semaphore cxl_region_rwsem; 99 + struct cxl_rwsem { 100 + /* 101 + * All changes to HPA (interleave configuration) occur with this 102 + * lock held for write. 103 + */ 104 + struct rw_semaphore region; 105 + /* 106 + * All changes to a device DPA space occur with this lock held 107 + * for write. 108 + */ 109 + struct rw_semaphore dpa; 110 + }; 111 + 112 + extern struct cxl_rwsem cxl_rwsem; 115 113 116 114 int cxl_memdev_init(void); 117 115 void cxl_memdev_exit(void); ··· 146 120 int cxl_ras_init(void); 147 121 void cxl_ras_exit(void); 148 122 int cxl_gpf_port_setup(struct cxl_dport *dport); 149 - int cxl_acpi_get_extended_linear_cache_size(struct resource *backing_res, 150 - int nid, resource_size_t *size); 151 123 152 124 #ifdef CONFIG_CXL_FEATURES 153 125 struct cxl_feat_entry *
+27 -28
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; ··· 695 697 ECS_THRESHOLD_IDX_4096); 696 698 break; 697 699 default: 698 - dev_dbg(dev, "Invalid CXL ECS threshold count(%d) to set\n", 700 + dev_dbg(dev, "Invalid CXL ECS threshold count(%u) to set\n", 699 701 val); 700 702 dev_dbg(dev, "Supported ECS threshold counts: %u, %u, %u\n", 701 703 ECS_THRESHOLD_256, ECS_THRESHOLD_1024, ··· 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 */ ··· 1520 1523 struct cxl_memdev *cxlmd = ctx->cxlmd; 1521 1524 struct cxl_dev_state *cxlds = cxlmd->cxlds; 1522 1525 1523 - if (dpa < cxlds->dpa_res.start || dpa > cxlds->dpa_res.end) 1526 + if (!cxl_resource_contains_addr(&cxlds->dpa_res, dpa)) 1524 1527 return -EINVAL; 1525 1528 1526 1529 ctx->dpa = dpa; ··· 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 */ ··· 1888 1892 struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd; 1889 1893 struct cxl_dev_state *cxlds = cxlmd->cxlds; 1890 1894 1891 - if (dpa < cxlds->dpa_res.start || dpa > cxlds->dpa_res.end) 1895 + if (!cxl_resource_contains_addr(&cxlds->dpa_res, dpa)) 1892 1896 return -EINVAL; 1893 1897 1894 1898 cxl_ppr_ctx->dpa = dpa; ··· 1919 1923 static int cxl_do_ppr(struct device *dev, void *drv_data, u32 val) 1920 1924 { 1921 1925 struct cxl_ppr_context *cxl_ppr_ctx = drv_data; 1926 + struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd; 1927 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 1922 1928 1923 - if (!cxl_ppr_ctx->dpa || val != EDAC_DO_MEM_REPAIR) 1929 + if (val != EDAC_DO_MEM_REPAIR || 1930 + !cxl_resource_contains_addr(&cxlds->dpa_res, cxl_ppr_ctx->dpa)) 1924 1931 return -EINVAL; 1925 1932 1926 1933 return cxl_mem_perform_ppr(cxl_ppr_ctx);
+69 -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 549 547 return base; 548 + } 549 + 550 + bool cxl_resource_contains_addr(const struct resource *res, const resource_size_t addr) 551 + { 552 + struct resource _addr = DEFINE_RES_MEM(addr, 1); 553 + 554 + return resource_contains(res, &_addr); 550 555 } 551 556 552 557 int cxl_dpa_free(struct cxl_endpoint_decoder *cxled) ··· 561 552 struct cxl_port *port = cxled_to_port(cxled); 562 553 struct device *dev = &cxled->cxld.dev; 563 554 564 - guard(rwsem_write)(&cxl_dpa_rwsem); 555 + guard(rwsem_write)(&cxl_rwsem.dpa); 565 556 if (!cxled->dpa_res) 566 557 return 0; 567 558 if (cxled->cxld.region) { ··· 591 582 struct device *dev = &cxled->cxld.dev; 592 583 int part; 593 584 594 - guard(rwsem_write)(&cxl_dpa_rwsem); 585 + guard(rwsem_write)(&cxl_rwsem.dpa); 595 586 if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) 596 587 return -EBUSY; 597 588 ··· 623 614 struct resource *p, *last; 624 615 int part; 625 616 626 - guard(rwsem_write)(&cxl_dpa_rwsem); 617 + guard(rwsem_write)(&cxl_rwsem.dpa); 627 618 if (cxled->cxld.region) { 628 619 dev_dbg(dev, "decoder attached to %s\n", 629 620 dev_name(&cxled->cxld.region->dev)); ··· 773 764 return -ETIMEDOUT; 774 765 } 775 766 776 - static int cxl_decoder_commit(struct cxl_decoder *cxld) 767 + static void setup_hw_decoder(struct cxl_decoder *cxld, void __iomem *hdm) 777 768 { 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; 769 + int id = cxld->id; 782 770 u64 base, size; 783 771 u32 ctrl; 784 772 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 773 /* common decoder settings */ 817 774 ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id)); 818 775 cxld_set_interleave(cxld, &ctrl); ··· 812 837 } 813 838 814 839 writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 815 - up_read(&cxl_dpa_rwsem); 840 + } 841 + 842 + static int cxl_decoder_commit(struct cxl_decoder *cxld) 843 + { 844 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 845 + struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); 846 + void __iomem *hdm = cxlhdm->regs.hdm_decoder; 847 + int id = cxld->id, rc; 848 + 849 + if (cxld->flags & CXL_DECODER_F_ENABLE) 850 + return 0; 851 + 852 + if (cxl_num_decoders_committed(port) != id) { 853 + dev_dbg(&port->dev, 854 + "%s: out of order commit, expected decoder%d.%d\n", 855 + dev_name(&cxld->dev), port->id, 856 + cxl_num_decoders_committed(port)); 857 + return -EBUSY; 858 + } 859 + 860 + /* 861 + * For endpoint decoders hosted on CXL memory devices that 862 + * support the sanitize operation, make sure sanitize is not in-flight. 863 + */ 864 + if (is_endpoint_decoder(&cxld->dev)) { 865 + struct cxl_endpoint_decoder *cxled = 866 + to_cxl_endpoint_decoder(&cxld->dev); 867 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 868 + struct cxl_memdev_state *mds = 869 + to_cxl_memdev_state(cxlmd->cxlds); 870 + 871 + if (mds && mds->security.sanitize_active) { 872 + dev_dbg(&cxlmd->dev, 873 + "attempted to commit %s during sanitize\n", 874 + dev_name(&cxld->dev)); 875 + return -EBUSY; 876 + } 877 + } 878 + 879 + scoped_guard(rwsem_read, &cxl_rwsem.dpa) 880 + setup_hw_decoder(cxld, hdm); 816 881 817 882 port->commit_end++; 818 883 rc = cxld_await_commit(hdm, cxld->id); ··· 890 875 { 891 876 struct cxl_port *port = to_cxl_port(cxld->dev.parent); 892 877 893 - lockdep_assert_held_write(&cxl_region_rwsem); 878 + lockdep_assert_held_write(&cxl_rwsem.region); 894 879 895 880 /* 896 881 * Once the highest committed decoder is disabled, free any other ··· 922 907 "%s: out of order reset, expected decoder%d.%d\n", 923 908 dev_name(&cxld->dev), port->id, port->commit_end); 924 909 925 - down_read(&cxl_dpa_rwsem); 926 910 ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 927 911 ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT; 928 912 writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); ··· 930 916 writel(0, hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id)); 931 917 writel(0, hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id)); 932 918 writel(0, hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id)); 933 - up_read(&cxl_dpa_rwsem); 934 919 935 920 cxld->flags &= ~CXL_DECODER_F_ENABLE; 936 921 ··· 1038 1025 else 1039 1026 cxld->target_type = CXL_DECODER_DEVMEM; 1040 1027 1041 - guard(rwsem_write)(&cxl_region_rwsem); 1028 + guard(rwsem_write)(&cxl_rwsem.region); 1042 1029 if (cxld->id != cxl_num_decoders_committed(port)) { 1043 1030 dev_warn(&port->dev, 1044 1031 "decoder%d.%d: Committed out of order\n",
+30 -7
drivers/cxl/core/mbox.c
··· 899 899 trace_cxl_generic_event(cxlmd, type, uuid, &evt->generic); 900 900 return; 901 901 } 902 + if (event_type == CXL_CPER_EVENT_MEM_SPARING) { 903 + trace_cxl_memory_sparing(cxlmd, type, &evt->mem_sparing); 904 + return; 905 + } 902 906 903 907 if (trace_cxl_general_media_enabled() || trace_cxl_dram_enabled()) { 904 908 u64 dpa, hpa = ULLONG_MAX, hpa_alias = ULLONG_MAX; ··· 913 909 * translations. Take topology mutation locks and lookup 914 910 * { HPA, REGION } from { DPA, MEMDEV } in the event record. 915 911 */ 916 - guard(rwsem_read)(&cxl_region_rwsem); 917 - guard(rwsem_read)(&cxl_dpa_rwsem); 912 + guard(rwsem_read)(&cxl_rwsem.region); 913 + guard(rwsem_read)(&cxl_rwsem.dpa); 918 914 919 915 dpa = le64_to_cpu(evt->media_hdr.phys_addr) & CXL_DPA_MASK; 920 916 cxlr = cxl_dpa_to_region(cxlmd, dpa); ··· 930 926 if (cxl_store_rec_gen_media((struct cxl_memdev *)cxlmd, evt)) 931 927 dev_dbg(&cxlmd->dev, "CXL store rec_gen_media failed\n"); 932 928 929 + if (evt->gen_media.media_hdr.descriptor & 930 + CXL_GMER_EVT_DESC_THRESHOLD_EVENT) 931 + WARN_ON_ONCE((evt->gen_media.media_hdr.type & 932 + CXL_GMER_MEM_EVT_TYPE_AP_CME_COUNTER_EXPIRE) && 933 + !get_unaligned_le24(evt->gen_media.cme_count)); 934 + else 935 + WARN_ON_ONCE(evt->gen_media.media_hdr.type & 936 + CXL_GMER_MEM_EVT_TYPE_AP_CME_COUNTER_EXPIRE); 937 + 933 938 trace_cxl_general_media(cxlmd, type, cxlr, hpa, 934 939 hpa_alias, &evt->gen_media); 935 940 } else if (event_type == CXL_CPER_EVENT_DRAM) { 936 941 if (cxl_store_rec_dram((struct cxl_memdev *)cxlmd, evt)) 937 942 dev_dbg(&cxlmd->dev, "CXL store rec_dram failed\n"); 943 + 944 + if (evt->dram.media_hdr.descriptor & 945 + CXL_GMER_EVT_DESC_THRESHOLD_EVENT) 946 + WARN_ON_ONCE((evt->dram.media_hdr.type & 947 + CXL_DER_MEM_EVT_TYPE_AP_CME_COUNTER_EXPIRE) && 948 + !get_unaligned_le24(evt->dram.cvme_count)); 949 + else 950 + WARN_ON_ONCE(evt->dram.media_hdr.type & 951 + CXL_DER_MEM_EVT_TYPE_AP_CME_COUNTER_EXPIRE); 938 952 939 953 trace_cxl_dram(cxlmd, type, cxlr, hpa, hpa_alias, 940 954 &evt->dram); ··· 974 952 ev_type = CXL_CPER_EVENT_DRAM; 975 953 else if (uuid_equal(uuid, &CXL_EVENT_MEM_MODULE_UUID)) 976 954 ev_type = CXL_CPER_EVENT_MEM_MODULE; 955 + else if (uuid_equal(uuid, &CXL_EVENT_MEM_SPARING_UUID)) 956 + ev_type = CXL_CPER_EVENT_MEM_SPARING; 977 957 978 958 cxl_event_trace_record(cxlmd, type, ev_type, uuid, &record->event); 979 959 } ··· 1289 1265 /* synchronize with cxl_mem_probe() and decoder write operations */ 1290 1266 guard(device)(&cxlmd->dev); 1291 1267 endpoint = cxlmd->endpoint; 1292 - guard(rwsem_read)(&cxl_region_rwsem); 1268 + guard(rwsem_read)(&cxl_rwsem.region); 1293 1269 /* 1294 1270 * Require an endpoint to be safe otherwise the driver can not 1295 1271 * be sure that the device is unmapped. ··· 1425 1401 int nr_records = 0; 1426 1402 int rc; 1427 1403 1428 - rc = mutex_lock_interruptible(&mds->poison.lock); 1429 - if (rc) 1404 + ACQUIRE(mutex_intr, lock)(&mds->poison.mutex); 1405 + if ((rc = ACQUIRE_ERR(mutex_intr, &lock))) 1430 1406 return rc; 1431 1407 1432 1408 po = mds->poison.list_out; ··· 1461 1437 } 1462 1438 } while (po->flags & CXL_POISON_FLAG_MORE); 1463 1439 1464 - mutex_unlock(&mds->poison.lock); 1465 1440 return rc; 1466 1441 } 1467 1442 EXPORT_SYMBOL_NS_GPL(cxl_mem_get_poison, "CXL"); ··· 1496 1473 return rc; 1497 1474 } 1498 1475 1499 - mutex_init(&mds->poison.lock); 1476 + mutex_init(&mds->poison.mutex); 1500 1477 return 0; 1501 1478 } 1502 1479 EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, "CXL");
+19 -33
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 } ··· 263 267 dev_dbg(cxlds->dev, "device has no dpa resource\n"); 264 268 return -EINVAL; 265 269 } 266 - if (dpa < cxlds->dpa_res.start || dpa > cxlds->dpa_res.end) { 270 + if (!cxl_resource_contains_addr(&cxlds->dpa_res, dpa)) { 267 271 dev_dbg(cxlds->dev, "dpa:0x%llx not in resource:%pR\n", 268 272 dpa, &cxlds->dpa_res); 269 273 return -EINVAL; ··· 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
+10 -19
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 } ··· 2284 2293 NULL, 2285 2294 }; 2286 2295 2287 - struct bus_type cxl_bus_type = { 2296 + const struct bus_type cxl_bus_type = { 2288 2297 .name = "cxl", 2289 2298 .uevent = cxl_bus_uevent, 2290 2299 .match = cxl_bus_match,
+253 -237
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 NULL; 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 ··· 2863 2847 if (!cxled || !cxled->dpa_res || !resource_size(cxled->dpa_res)) 2864 2848 return 0; 2865 2849 2866 - if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) 2850 + if (!cxl_resource_contains_addr(cxled->dpa_res, dpa)) 2867 2851 return 0; 2868 2852 2869 2853 /* ··· 2975 2959 if (cxlrd->hpa_to_spa) 2976 2960 hpa = cxlrd->hpa_to_spa(cxlrd, hpa); 2977 2961 2978 - if (hpa < p->res->start || hpa > p->res->end) { 2962 + if (!cxl_resource_contains_addr(p->res, hpa)) { 2979 2963 dev_dbg(&cxlr->dev, 2980 2964 "Addr trans fail: hpa 0x%llx not in region\n", hpa); 2981 2965 return ULLONG_MAX; ··· 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 ··· 3298 3282 { 3299 3283 struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); 3300 3284 struct cxl_region_params *p = &cxlr->params; 3301 - int nid = phys_to_target_node(res->start); 3302 3285 resource_size_t size = resource_size(res); 3303 3286 resource_size_t cache_size, start; 3304 - int rc; 3305 3287 3306 - rc = cxl_acpi_get_extended_linear_cache_size(res, nid, &cache_size); 3307 - if (rc) 3308 - return rc; 3309 - 3288 + cache_size = cxlrd->cache_size; 3310 3289 if (!cache_size) 3311 3290 return 0; 3312 3291 ··· 3341 3330 struct resource *res; 3342 3331 int rc; 3343 3332 3344 - guard(rwsem_write)(&cxl_region_rwsem); 3333 + guard(rwsem_write)(&cxl_rwsem.region); 3345 3334 p = &cxlr->params; 3346 3335 if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) { 3347 3336 dev_err(cxlmd->dev.parent, ··· 3477 3466 3478 3467 attach_target(cxlr, cxled, -1, TASK_UNINTERRUPTIBLE); 3479 3468 3480 - down_read(&cxl_region_rwsem); 3481 - p = &cxlr->params; 3482 - attach = p->state == CXL_CONFIG_COMMIT; 3483 - up_read(&cxl_region_rwsem); 3469 + scoped_guard(rwsem_read, &cxl_rwsem.region) { 3470 + p = &cxlr->params; 3471 + attach = p->state == CXL_CONFIG_COMMIT; 3472 + } 3484 3473 3485 3474 if (attach) { 3486 3475 /* ··· 3505 3494 if (!endpoint) 3506 3495 return ~0ULL; 3507 3496 3508 - guard(rwsem_write)(&cxl_region_rwsem); 3497 + guard(rwsem_write)(&cxl_rwsem.region); 3509 3498 3510 3499 xa_for_each(&endpoint->regions, index, iter) { 3511 3500 struct cxl_region_params *p = &iter->region->params; 3512 3501 3513 - if (p->res->start <= spa && spa <= p->res->end) { 3502 + if (cxl_resource_contains_addr(p->res, spa)) { 3514 3503 if (!p->cache_size) 3515 3504 return ~0ULL; 3516 3505 ··· 3542 3531 unregister_mt_adistance_algorithm(&cxlr->adist_notifier); 3543 3532 } 3544 3533 3545 - static int cxl_region_probe(struct device *dev) 3534 + static int cxl_region_can_probe(struct cxl_region *cxlr) 3546 3535 { 3547 - struct cxl_region *cxlr = to_cxl_region(dev); 3548 3536 struct cxl_region_params *p = &cxlr->params; 3549 3537 int rc; 3550 3538 3551 - rc = down_read_interruptible(&cxl_region_rwsem); 3552 - if (rc) { 3539 + ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); 3540 + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) { 3553 3541 dev_dbg(&cxlr->dev, "probe interrupted\n"); 3554 3542 return rc; 3555 3543 } 3556 3544 3557 3545 if (p->state < CXL_CONFIG_COMMIT) { 3558 3546 dev_dbg(&cxlr->dev, "config state: %d\n", p->state); 3559 - rc = -ENXIO; 3560 - goto out; 3547 + return -ENXIO; 3561 3548 } 3562 3549 3563 3550 if (test_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags)) { 3564 3551 dev_err(&cxlr->dev, 3565 3552 "failed to activate, re-commit region and retry\n"); 3566 - rc = -ENXIO; 3567 - goto out; 3553 + return -ENXIO; 3568 3554 } 3555 + 3556 + return 0; 3557 + } 3558 + 3559 + static int cxl_region_probe(struct device *dev) 3560 + { 3561 + struct cxl_region *cxlr = to_cxl_region(dev); 3562 + struct cxl_region_params *p = &cxlr->params; 3563 + int rc; 3564 + 3565 + rc = cxl_region_can_probe(cxlr); 3566 + if (rc) 3567 + return rc; 3569 3568 3570 3569 /* 3571 3570 * From this point on any path that changes the region's state away from 3572 3571 * CXL_CONFIG_COMMIT is also responsible for releasing the driver. 3573 3572 */ 3574 - out: 3575 - up_read(&cxl_region_rwsem); 3576 - 3577 - if (rc) 3578 - return rc; 3579 3573 3580 3574 cxlr->node_notifier.notifier_call = cxl_region_perf_attrs_callback; 3581 3575 cxlr->node_notifier.priority = CXL_CALLBACK_PRI;
+127 -6
drivers/cxl/core/trace.h
··· 214 214 #define CXL_EVENT_RECORD_FLAG_PERF_DEGRADED BIT(4) 215 215 #define CXL_EVENT_RECORD_FLAG_HW_REPLACE BIT(5) 216 216 #define CXL_EVENT_RECORD_FLAG_MAINT_OP_SUB_CLASS_VALID BIT(6) 217 + #define CXL_EVENT_RECORD_FLAG_LD_ID_VALID BIT(7) 218 + #define CXL_EVENT_RECORD_FLAG_HEAD_ID_VALID BIT(8) 217 219 #define show_hdr_flags(flags) __print_flags(flags, " | ", \ 218 220 { CXL_EVENT_RECORD_FLAG_PERMANENT, "PERMANENT_CONDITION" }, \ 219 221 { CXL_EVENT_RECORD_FLAG_MAINT_NEEDED, "MAINTENANCE_NEEDED" }, \ 220 222 { CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, "PERFORMANCE_DEGRADED" }, \ 221 223 { CXL_EVENT_RECORD_FLAG_HW_REPLACE, "HARDWARE_REPLACEMENT_NEEDED" }, \ 222 - { CXL_EVENT_RECORD_FLAG_MAINT_OP_SUB_CLASS_VALID, "MAINT_OP_SUB_CLASS_VALID" } \ 224 + { CXL_EVENT_RECORD_FLAG_MAINT_OP_SUB_CLASS_VALID, "MAINT_OP_SUB_CLASS_VALID" }, \ 225 + { CXL_EVENT_RECORD_FLAG_LD_ID_VALID, "LD_ID_VALID" }, \ 226 + { CXL_EVENT_RECORD_FLAG_HEAD_ID_VALID, "HEAD_ID_VALID" } \ 223 227 ) 224 228 225 229 /* ··· 251 247 __field(u64, hdr_timestamp) \ 252 248 __field(u8, hdr_length) \ 253 249 __field(u8, hdr_maint_op_class) \ 254 - __field(u8, hdr_maint_op_sub_class) 250 + __field(u8, hdr_maint_op_sub_class) \ 251 + __field(u16, hdr_ld_id) \ 252 + __field(u8, hdr_head_id) 255 253 256 254 #define CXL_EVT_TP_fast_assign(cxlmd, l, hdr) \ 257 255 __assign_str(memdev); \ ··· 266 260 __entry->hdr_related_handle = le16_to_cpu((hdr).related_handle); \ 267 261 __entry->hdr_timestamp = le64_to_cpu((hdr).timestamp); \ 268 262 __entry->hdr_maint_op_class = (hdr).maint_op_class; \ 269 - __entry->hdr_maint_op_sub_class = (hdr).maint_op_sub_class 263 + __entry->hdr_maint_op_sub_class = (hdr).maint_op_sub_class; \ 264 + __entry->hdr_ld_id = le16_to_cpu((hdr).ld_id); \ 265 + __entry->hdr_head_id = (hdr).head_id 270 266 271 267 #define CXL_EVT_TP_printk(fmt, ...) \ 272 268 TP_printk("memdev=%s host=%s serial=%lld log=%s : time=%llu uuid=%pUb " \ 273 269 "len=%d flags='%s' handle=%x related_handle=%x " \ 274 - "maint_op_class=%u maint_op_sub_class=%u : " fmt, \ 270 + "maint_op_class=%u maint_op_sub_class=%u " \ 271 + "ld_id=%x head_id=%x : " fmt, \ 275 272 __get_str(memdev), __get_str(host), __entry->serial, \ 276 273 cxl_event_log_type_str(__entry->log), \ 277 274 __entry->hdr_timestamp, &__entry->hdr_uuid, __entry->hdr_length,\ 278 275 show_hdr_flags(__entry->hdr_flags), __entry->hdr_handle, \ 279 276 __entry->hdr_related_handle, __entry->hdr_maint_op_class, \ 280 277 __entry->hdr_maint_op_sub_class, \ 278 + __entry->hdr_ld_id, __entry->hdr_head_id, \ 281 279 ##__VA_ARGS__) 282 280 283 281 TRACE_EVENT(cxl_generic_event, ··· 506 496 uuid_copy(&__entry->region_uuid, &uuid_null); 507 497 } 508 498 __entry->cme_threshold_ev_flags = rec->cme_threshold_ev_flags; 509 - __entry->cme_count = get_unaligned_le24(rec->cme_count); 499 + if (rec->media_hdr.descriptor & CXL_GMER_EVT_DESC_THRESHOLD_EVENT) 500 + __entry->cme_count = get_unaligned_le24(rec->cme_count); 501 + else 502 + __entry->cme_count = 0; 510 503 ), 511 504 512 505 CXL_EVT_TP_printk("dpa=%llx dpa_flags='%s' " \ ··· 661 648 CXL_EVENT_GEN_MED_COMP_ID_SIZE); 662 649 __entry->sub_channel = rec->sub_channel; 663 650 __entry->cme_threshold_ev_flags = rec->cme_threshold_ev_flags; 664 - __entry->cvme_count = get_unaligned_le24(rec->cvme_count); 651 + if (rec->media_hdr.descriptor & CXL_GMER_EVT_DESC_THRESHOLD_EVENT) 652 + __entry->cvme_count = get_unaligned_le24(rec->cvme_count); 653 + else 654 + __entry->cvme_count = 0; 665 655 ), 666 656 667 657 CXL_EVT_TP_printk("dpa=%llx dpa_flags='%s' descriptor='%s' type='%s' sub_type='%s' " \ ··· 884 868 CXL_MMER_VALID_COMPONENT_ID_FORMAT, __entry->comp_id), 885 869 show_pldm_resource_id(__entry->validity_flags, CXL_MMER_VALID_COMPONENT, 886 870 CXL_MMER_VALID_COMPONENT_ID_FORMAT, __entry->comp_id) 871 + ) 872 + ); 873 + 874 + /* 875 + * Memory Sparing Event Record - MSER 876 + * 877 + * CXL rev 3.2 section 8.2.10.2.1.4; Table 8-60 878 + */ 879 + #define CXL_MSER_QUERY_RESOURCE_FLAG BIT(0) 880 + #define CXL_MSER_HARD_SPARING_FLAG BIT(1) 881 + #define CXL_MSER_DEV_INITED_FLAG BIT(2) 882 + #define show_mem_sparing_flags(flags) __print_flags(flags, "|", \ 883 + { CXL_MSER_QUERY_RESOURCE_FLAG, "Query Resources" }, \ 884 + { CXL_MSER_HARD_SPARING_FLAG, "Hard Sparing" }, \ 885 + { CXL_MSER_DEV_INITED_FLAG, "Device Initiated Sparing" } \ 886 + ) 887 + 888 + #define CXL_MSER_VALID_CHANNEL BIT(0) 889 + #define CXL_MSER_VALID_RANK BIT(1) 890 + #define CXL_MSER_VALID_NIBBLE BIT(2) 891 + #define CXL_MSER_VALID_BANK_GROUP BIT(3) 892 + #define CXL_MSER_VALID_BANK BIT(4) 893 + #define CXL_MSER_VALID_ROW BIT(5) 894 + #define CXL_MSER_VALID_COLUMN BIT(6) 895 + #define CXL_MSER_VALID_COMPONENT_ID BIT(7) 896 + #define CXL_MSER_VALID_COMPONENT_ID_FORMAT BIT(8) 897 + #define CXL_MSER_VALID_SUB_CHANNEL BIT(9) 898 + #define show_mem_sparing_valid_flags(flags) __print_flags(flags, "|", \ 899 + { CXL_MSER_VALID_CHANNEL, "CHANNEL" }, \ 900 + { CXL_MSER_VALID_RANK, "RANK" }, \ 901 + { CXL_MSER_VALID_NIBBLE, "NIBBLE" }, \ 902 + { CXL_MSER_VALID_BANK_GROUP, "BANK GROUP" }, \ 903 + { CXL_MSER_VALID_BANK, "BANK" }, \ 904 + { CXL_MSER_VALID_ROW, "ROW" }, \ 905 + { CXL_MSER_VALID_COLUMN, "COLUMN" }, \ 906 + { CXL_MSER_VALID_COMPONENT_ID, "COMPONENT ID" }, \ 907 + { CXL_MSER_VALID_COMPONENT_ID_FORMAT, "COMPONENT ID PLDM FORMAT" }, \ 908 + { CXL_MSER_VALID_SUB_CHANNEL, "SUB CHANNEL" } \ 909 + ) 910 + 911 + TRACE_EVENT(cxl_memory_sparing, 912 + 913 + TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log, 914 + struct cxl_event_mem_sparing *rec), 915 + 916 + TP_ARGS(cxlmd, log, rec), 917 + 918 + TP_STRUCT__entry( 919 + CXL_EVT_TP_entry 920 + 921 + /* Memory Sparing Event */ 922 + __field(u8, flags) 923 + __field(u8, result) 924 + __field(u16, validity_flags) 925 + __field(u16, res_avail) 926 + __field(u8, channel) 927 + __field(u8, rank) 928 + __field(u32, nibble_mask) 929 + __field(u8, bank_group) 930 + __field(u8, bank) 931 + __field(u32, row) 932 + __field(u16, column) 933 + __field(u8, sub_channel) 934 + __array(u8, comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE) 935 + ), 936 + 937 + TP_fast_assign( 938 + CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); 939 + __entry->hdr_uuid = CXL_EVENT_MEM_SPARING_UUID; 940 + 941 + /* Memory Sparing Event */ 942 + __entry->flags = rec->flags; 943 + __entry->result = rec->result; 944 + __entry->validity_flags = le16_to_cpu(rec->validity_flags); 945 + __entry->res_avail = le16_to_cpu(rec->res_avail); 946 + __entry->channel = rec->channel; 947 + __entry->rank = rec->rank; 948 + __entry->nibble_mask = get_unaligned_le24(rec->nibble_mask); 949 + __entry->bank_group = rec->bank_group; 950 + __entry->bank = rec->bank; 951 + __entry->row = get_unaligned_le24(rec->row); 952 + __entry->column = le16_to_cpu(rec->column); 953 + __entry->sub_channel = rec->sub_channel; 954 + memcpy(__entry->comp_id, &rec->component_id, 955 + CXL_EVENT_GEN_MED_COMP_ID_SIZE); 956 + ), 957 + 958 + CXL_EVT_TP_printk("flags='%s' result=%u validity_flags='%s' " \ 959 + "spare resource avail=%u channel=%u rank=%u " \ 960 + "nibble_mask=%x bank_group=%u bank=%u " \ 961 + "row=%u column=%u sub_channel=%u " \ 962 + "comp_id=%s comp_id_pldm_valid_flags='%s' " \ 963 + "pldm_entity_id=%s pldm_resource_id=%s", 964 + show_mem_sparing_flags(__entry->flags), 965 + __entry->result, 966 + show_mem_sparing_valid_flags(__entry->validity_flags), 967 + __entry->res_avail, __entry->channel, __entry->rank, 968 + __entry->nibble_mask, __entry->bank_group, __entry->bank, 969 + __entry->row, __entry->column, __entry->sub_channel, 970 + __print_hex(__entry->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE), 971 + show_comp_id_pldm_flags(__entry->comp_id[0]), 972 + show_pldm_entity_id(__entry->validity_flags, CXL_MSER_VALID_COMPONENT_ID, 973 + CXL_MSER_VALID_COMPONENT_ID_FORMAT, __entry->comp_id), 974 + show_pldm_resource_id(__entry->validity_flags, CXL_MSER_VALID_COMPONENT_ID, 975 + CXL_MSER_VALID_COMPONENT_ID_FORMAT, __entry->comp_id) 887 976 ) 888 977 ); 889 978
+4 -13
drivers/cxl/cxl.h
··· 424 424 /** 425 425 * struct cxl_root_decoder - Static platform CXL address decoder 426 426 * @res: host / parent resource for region allocations 427 + * @cache_size: extended linear cache size if exists, otherwise zero. 427 428 * @region_id: region id for next region provisioning event 428 429 * @hpa_to_spa: translate CXL host-physical-address to Platform system-physical-address 429 430 * @platform_data: platform specific configuration data ··· 434 433 */ 435 434 struct cxl_root_decoder { 436 435 struct resource *res; 436 + resource_size_t cache_size; 437 437 atomic_t region_id; 438 438 cxl_hpa_to_spa_fn hpa_to_spa; 439 439 void *platform_data; ··· 472 470 * @nr_targets: number of targets 473 471 * @cache_size: extended linear cache size if exists, otherwise zero. 474 472 * 475 - * State transitions are protected by the cxl_region_rwsem 473 + * State transitions are protected by cxl_rwsem.region 476 474 */ 477 475 struct cxl_region_params { 478 476 enum cxl_config_state state; ··· 818 816 819 817 bool is_cxl_region(struct device *dev); 820 818 821 - extern struct bus_type cxl_bus_type; 819 + extern const struct bus_type cxl_bus_type; 822 820 823 821 struct cxl_driver { 824 822 const char *name; ··· 915 913 #endif 916 914 917 915 u16 cxl_gpf_get_dvsec(struct device *dev); 918 - 919 - static inline struct rw_semaphore *rwsem_read_intr_acquire(struct rw_semaphore *rwsem) 920 - { 921 - if (down_read_interruptible(rwsem)) 922 - return NULL; 923 - 924 - return rwsem; 925 - } 926 - 927 - DEFINE_FREE(rwsem_read_release, struct rw_semaphore *, if (_T) up_read(_T)) 928 - 929 916 #endif /* __CXL_H__ */
+10 -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 /* ··· 632 632 #define CXL_EVENT_MEM_MODULE_UUID \ 633 633 UUID_INIT(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86, 0x79, 0xba, 0xb1, \ 634 634 0x13, 0xb7, 0x74) 635 + 636 + /* 637 + * Memory Sparing Event Record UUID 638 + * CXL rev 3.2 section 8.2.10.2.1.4: Table 8-60 639 + */ 640 + #define CXL_EVENT_MEM_SPARING_UUID \ 641 + UUID_INIT(0xe71f3a40, 0x2d29, 0x4092, 0x8a, 0x39, 0x4d, 0x1c, 0x96, \ 642 + 0x6c, 0x7c, 0x65) 635 643 636 644 /* 637 645 * Get Event Records output payload
+1 -1
drivers/cxl/pci.c
··· 379 379 { 380 380 int rc; 381 381 382 - mutex_lock_io(&cxl_mbox->mbox_mutex); 382 + mutex_lock(&cxl_mbox->mbox_mutex); 383 383 rc = __cxl_pci_mbox_send_cmd(cxl_mbox, cmd); 384 384 mutex_unlock(&cxl_mbox->mbox_mutex); 385 385
+36 -1
include/cxl/event.h
··· 19 19 __le64 timestamp; 20 20 u8 maint_op_class; 21 21 u8 maint_op_sub_class; 22 - u8 reserved[14]; 22 + __le16 ld_id; 23 + u8 head_id; 24 + u8 reserved[11]; 23 25 } __packed; 24 26 25 27 struct cxl_event_media_hdr { ··· 110 108 u8 reserved[0x2a]; 111 109 } __packed; 112 110 111 + /* 112 + * Memory Sparing Event Record - MSER 113 + * CXL rev 3.2 section 8.2.10.2.1.4; Table 8-60 114 + */ 115 + struct cxl_event_mem_sparing { 116 + struct cxl_event_record_hdr hdr; 117 + /* 118 + * The fields maintenance operation class and maintenance operation 119 + * subclass defined in the Memory Sparing Event Record are the 120 + * duplication of the same in the common event record. Thus defined 121 + * as reserved and to be removed after the spec correction. 122 + */ 123 + u8 rsv1; 124 + u8 rsv2; 125 + u8 flags; 126 + u8 result; 127 + __le16 validity_flags; 128 + u8 reserved1[6]; 129 + __le16 res_avail; 130 + u8 channel; 131 + u8 rank; 132 + u8 nibble_mask[3]; 133 + u8 bank_group; 134 + u8 bank; 135 + u8 row[3]; 136 + __le16 column; 137 + u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; 138 + u8 sub_channel; 139 + u8 reserved2[0x25]; 140 + } __packed; 141 + 113 142 union cxl_event { 114 143 struct cxl_event_generic generic; 115 144 struct cxl_event_gen_media gen_media; 116 145 struct cxl_event_dram dram; 117 146 struct cxl_event_mem_module mem_module; 147 + struct cxl_event_mem_sparing mem_sparing; 118 148 /* dram & gen_media event header */ 119 149 struct cxl_event_media_hdr media_hdr; 120 150 } __packed; ··· 165 131 CXL_CPER_EVENT_GEN_MEDIA, 166 132 CXL_CPER_EVENT_DRAM, 167 133 CXL_CPER_EVENT_MEM_MODULE, 134 + CXL_CPER_EVENT_MEM_SPARING, 168 135 }; 169 136 170 137 #define CPER_CXL_DEVICE_ID_VALID BIT(0)
+80 -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 + * DEFINE_GUARD_COND(pci_dev, _try, pci_dev_trylock(_T)) 68 + * ... 69 + * ACQUIRE(pci_dev_try, lock)(dev); 70 + * rc = ACQUIRE_ERR(pci_dev_try, &lock); 71 + * if (rc) 72 + * return rc; 73 + * // @lock is held 74 + * 75 + * Now, when a function uses both __free() and guard()/ACQUIRE(), or 76 + * multiple instances of __free(), the LIFO order of variable definition 77 + * order matters. GCC documentation says: 69 78 * 70 79 * "When multiple variables in the same scope have cleanup attributes, 71 80 * at exit from the scope their associated cleanup functions are run in ··· 326 313 * acquire fails. 327 314 * 328 315 * Only for conditional locks. 316 + * 317 + * ACQUIRE(name, var): 318 + * a named instance of the (guard) class, suitable for conditional 319 + * locks when paired with ACQUIRE_ERR(). 320 + * 321 + * ACQUIRE_ERR(name, &var): 322 + * a helper that is effectively a PTR_ERR() conversion of the guard 323 + * pointer. Returns 0 when the lock was acquired and a negative 324 + * error code otherwise. 329 325 */ 330 326 331 327 #define __DEFINE_CLASS_IS_CONDITIONAL(_name, _is_cond) \ 332 328 static __maybe_unused const bool class_##_name##_is_conditional = _is_cond 333 329 334 - #define __DEFINE_GUARD_LOCK_PTR(_name, _exp) \ 335 - static inline void * class_##_name##_lock_ptr(class_##_name##_t *_T) \ 336 - { return (void *)(__force unsigned long)*(_exp); } 330 + #define __GUARD_IS_ERR(_ptr) \ 331 + ({ \ 332 + unsigned long _rc = (__force unsigned long)(_ptr); \ 333 + unlikely((_rc - 1) >= -MAX_ERRNO - 1); \ 334 + }) 335 + 336 + #define __DEFINE_GUARD_LOCK_PTR(_name, _exp) \ 337 + static inline void *class_##_name##_lock_ptr(class_##_name##_t *_T) \ 338 + { \ 339 + void *_ptr = (void *)(__force unsigned long)*(_exp); \ 340 + if (IS_ERR(_ptr)) { \ 341 + _ptr = NULL; \ 342 + } \ 343 + return _ptr; \ 344 + } \ 345 + static inline int class_##_name##_lock_err(class_##_name##_t *_T) \ 346 + { \ 347 + long _rc = (__force unsigned long)*(_exp); \ 348 + if (!_rc) { \ 349 + _rc = -EBUSY; \ 350 + } \ 351 + if (!IS_ERR_VALUE(_rc)) { \ 352 + _rc = 0; \ 353 + } \ 354 + return _rc; \ 355 + } 337 356 338 357 #define DEFINE_CLASS_IS_GUARD(_name) \ 339 358 __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \ ··· 376 331 __DEFINE_GUARD_LOCK_PTR(_name, _T) 377 332 378 333 #define DEFINE_GUARD(_name, _type, _lock, _unlock) \ 379 - DEFINE_CLASS(_name, _type, if (_T) { _unlock; }, ({ _lock; _T; }), _type _T); \ 334 + DEFINE_CLASS(_name, _type, if (!__GUARD_IS_ERR(_T)) { _unlock; }, ({ _lock; _T; }), _type _T); \ 380 335 DEFINE_CLASS_IS_GUARD(_name) 381 336 382 - #define DEFINE_GUARD_COND(_name, _ext, _condlock) \ 337 + #define DEFINE_GUARD_COND_4(_name, _ext, _lock, _cond) \ 383 338 __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \ 384 339 EXTEND_CLASS(_name, _ext, \ 385 - ({ void *_t = _T; if (_T && !(_condlock)) _t = NULL; _t; }), \ 340 + ({ void *_t = _T; int _RET = (_lock); if (_T && !(_cond)) _t = ERR_PTR(_RET); _t; }), \ 386 341 class_##_name##_t _T) \ 387 342 static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \ 388 - { return class_##_name##_lock_ptr(_T); } 343 + { return class_##_name##_lock_ptr(_T); } \ 344 + static inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \ 345 + { return class_##_name##_lock_err(_T); } 346 + 347 + /* 348 + * Default binary condition; success on 'true'. 349 + */ 350 + #define DEFINE_GUARD_COND_3(_name, _ext, _lock) \ 351 + DEFINE_GUARD_COND_4(_name, _ext, _lock, _RET) 352 + 353 + #define DEFINE_GUARD_COND(X...) CONCATENATE(DEFINE_GUARD_COND_, COUNT_ARGS(X))(X) 389 354 390 355 #define guard(_name) \ 391 356 CLASS(_name, __UNIQUE_ID(guard)) 392 357 393 358 #define __guard_ptr(_name) class_##_name##_lock_ptr 359 + #define __guard_err(_name) class_##_name##_lock_err 394 360 #define __is_cond_ptr(_name) class_##_name##_is_conditional 361 + 362 + #define ACQUIRE(_name, _var) CLASS(_name, _var) 363 + #define ACQUIRE_ERR(_name, _var) __guard_err(_name)(_var) 395 364 396 365 /* 397 366 * Helper macro for scoped_guard(). ··· 468 409 \ 469 410 static inline void class_##_name##_destructor(class_##_name##_t *_T) \ 470 411 { \ 471 - if (_T->lock) { _unlock; } \ 412 + if (!__GUARD_IS_ERR(_T->lock)) { _unlock; } \ 472 413 } \ 473 414 \ 474 415 __DEFINE_GUARD_LOCK_PTR(_name, &_T->lock) ··· 500 441 __DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__) \ 501 442 __DEFINE_LOCK_GUARD_0(_name, _lock) 502 443 503 - #define DEFINE_LOCK_GUARD_1_COND(_name, _ext, _condlock) \ 444 + #define DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _cond) \ 504 445 __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \ 505 446 EXTEND_CLASS(_name, _ext, \ 506 447 ({ class_##_name##_t _t = { .lock = l }, *_T = &_t;\ 507 - if (_T->lock && !(_condlock)) _T->lock = NULL; \ 448 + int _RET = (_lock); \ 449 + if (_T->lock && !(_cond)) _T->lock = ERR_PTR(_RET);\ 508 450 _t; }), \ 509 451 typeof_member(class_##_name##_t, lock) l) \ 510 452 static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \ 511 - { return class_##_name##_lock_ptr(_T); } 453 + { return class_##_name##_lock_ptr(_T); } \ 454 + static inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \ 455 + { return class_##_name##_lock_err(_T); } 512 456 457 + #define DEFINE_LOCK_GUARD_1_COND_3(_name, _ext, _lock) \ 458 + DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _RET) 459 + 460 + #define DEFINE_LOCK_GUARD_1_COND(X...) CONCATENATE(DEFINE_LOCK_GUARD_1_COND_, COUNT_ARGS(X))(X) 513 461 514 462 #endif /* _LINUX_CLEANUP_H */
+1 -1
include/linux/mutex.h
··· 227 227 228 228 DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T)) 229 229 DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T)) 230 - DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) == 0) 230 + DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T), _RET == 0) 231 231 232 232 extern unsigned long mutex_get_owner(struct mutex *lock); 233 233
+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
-1
tools/testing/cxl/Kbuild
··· 62 62 cxl_core-y += $(CXL_CORE_SRC)/pmu.o 63 63 cxl_core-y += $(CXL_CORE_SRC)/cdat.o 64 64 cxl_core-y += $(CXL_CORE_SRC)/ras.o 65 - cxl_core-y += $(CXL_CORE_SRC)/acpi.o 66 65 cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o 67 66 cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o 68 67 cxl_core-$(CONFIG_CXL_MCE) += $(CXL_CORE_SRC)/mce.o
+1
tools/testing/cxl/config_check.c
··· 14 14 BUILD_BUG_ON(!IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)); 15 15 BUILD_BUG_ON(!IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST)); 16 16 BUILD_BUG_ON(!IS_ENABLED(CONFIG_DEBUG_FS)); 17 + BUILD_BUG_ON(!IS_ENABLED(CONFIG_MEMORY_HOTPLUG)); 17 18 }
+6 -1
tools/testing/cxl/test/cxl.c
··· 2 2 // Copyright(c) 2021 Intel Corporation. All rights reserved. 3 3 4 4 #include <linux/platform_device.h> 5 + #include <linux/memory_hotplug.h> 5 6 #include <linux/genalloc.h> 6 7 #include <linux/module.h> 7 8 #include <linux/mutex.h> ··· 1329 1328 static __init int cxl_test_init(void) 1330 1329 { 1331 1330 int rc, i; 1331 + struct range mappable; 1332 1332 1333 1333 cxl_acpi_test(); 1334 1334 cxl_core_test(); ··· 1344 1342 rc = -ENOMEM; 1345 1343 goto err_gen_pool_create; 1346 1344 } 1345 + mappable = mhp_get_pluggable_range(true); 1347 1346 1348 - rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G, 1347 + rc = gen_pool_add(cxl_mock_pool, 1348 + min(iomem_resource.end + 1 - SZ_64G, 1349 + mappable.end + 1 - SZ_64G), 1349 1350 SZ_64G, NUMA_NO_NODE); 1350 1351 if (rc) 1351 1352 goto err_gen_pool_add;