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

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull CXL updates from Dave Jiang:
"Core:

- A CXL maturity map has been added to the documentation to detail
the current state of CXL enabling.

It provides the status of the current state of various CXL features
to inform current and future contributors of where things are and
which areas need contribution.

- A notifier handler has been added in order for a newly created CXL
memory region to trigger the abstract distance metrics calculation.

This should bring parity for CXL memory to the same level vs
hotplugged DRAM for NUMA abstract distance calculation. The
abstract distance reflects relative performance used for memory
tiering handling.

- An addition for XOR math has been added to address the CXL DPA to
SPA translation.

CXL address translation did not support address interleave math
with XOR prior to this change.

Fixes:

- Fix to address race condition in the CXL memory hotplug notifier

- Add missing MODULE_DESCRIPTION() for CXL modules

- Fix incorrect vendor debug UUID define

Misc:

- A warning has been added to inform users of an unsupported
configuration when mixing CXL VH and RCH/RCD hierarchies

- The ENXIO error code has been replaced with EBUSY for inject poison
limit reached via debugfs and cxl-test support

- Moving the PCI config read in cxl_dvsec_rr_decode() to avoid
unnecessary PCI config reads

- A refactor to a common struct for DRAM and general media CXL
events"

* tag 'cxl-for-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
cxl/core/pci: Move reading of control register to immediately before usage
cxl: Remove defunct code calculating host bridge target positions
cxl/region: Verify target positions using the ordered target list
cxl: Restore XOR'd position bits during address translation
cxl/core: Fold cxl_trace_hpa() into cxl_dpa_to_hpa()
cxl/test: Replace ENXIO with EBUSY for inject poison limit reached
cxl/memdev: Replace ENXIO with EBUSY for inject poison limit reached
cxl/acpi: Warn on mixed CXL VH and RCH/RCD Hierarchy
cxl/core: Fix incorrect vendor debug UUID define
Documentation: CXL Maturity Map
cxl/region: Simplify cxl_region_nid()
cxl/region: Support to calculate memory tier abstract distance
cxl/region: Fix a race condition in memory hotplug notifier
cxl: add missing MODULE_DESCRIPTION() macros
cxl/events: Use a common struct for DRAM and General Media events

+442 -212
+4 -3
Documentation/ABI/testing/debugfs-cxl
··· 14 14 event to its internal Informational Event log, updates the 15 15 Event Status register, and if configured, interrupts the host. 16 16 It is not an error to inject poison into an address that 17 - already has poison present and no error is returned. The 18 - inject_poison attribute is only visible for devices supporting 19 - the capability. 17 + already has poison present and no error is returned. If the 18 + device returns 'Inject Poison Limit Reached' an -EBUSY error 19 + is returned to the user. The inject_poison attribute is only 20 + visible for devices supporting the capability. 20 21 21 22 22 23 What: /sys/kernel/debug/memX/clear_poison
+2
Documentation/driver-api/cxl/index.rst
··· 9 9 10 10 memory-devices 11 11 12 + maturity-map 13 + 12 14 .. only:: subproject and html
+202
Documentation/driver-api/cxl/maturity-map.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + .. include:: <isonum.txt> 3 + 4 + =========================================== 5 + Compute Express Link Subsystem Maturity Map 6 + =========================================== 7 + 8 + The Linux CXL subsystem tracks the dynamic `CXL specification 9 + <https://computeexpresslink.org/cxl-specification-landing-page>`_ that 10 + continues to respond to new use cases with new features, capability 11 + updates and fixes. At any given point some aspects of the subsystem are 12 + more mature than others. While the periodic pull requests summarize the 13 + `work being incorporated each merge window 14 + <https://lore.kernel.org/linux-cxl/?q=s%3APULL+s%3ACXL+tc%3Atorvalds+NOT+s%3ARe>`_, 15 + those do not always convey progress relative to a starting point and a 16 + future end goal. 17 + 18 + What follows is a coarse breakdown of the subsystem's major 19 + responsibilities along with a maturity score. The expectation is that 20 + the change-history of this document provides an overview summary of the 21 + subsystem maturation over time. 22 + 23 + The maturity scores are: 24 + 25 + - [3] Mature: Work in this area is complete and no changes on the horizon. 26 + Note that this score can regress from one kernel release to the next 27 + based on new test results or end user reports. 28 + 29 + - [2] Stabilizing: Major functionality operational, common cases are 30 + mature, but known corner cases are still a work in progress. 31 + 32 + - [1] Initial: Capability that has exited the Proof of Concept phase, but 33 + may still have significant gaps to close and fixes to apply as real 34 + world testing occurs. 35 + 36 + - [0] Known gap: Feature is on a medium to long term horizon to 37 + implement. If the specification has a feature that does not even have 38 + a '0' score in this document, there is a good chance that no one in 39 + the linux-cxl@vger.kernel.org community has started to look at it. 40 + 41 + - X: Out of scope for kernel enabling, or kernel enabling not required 42 + 43 + Feature and Capabilities 44 + ======================== 45 + 46 + Enumeration / Provisioning 47 + -------------------------- 48 + All of the fundamental enumeration an object model of the subsystem is 49 + in place, but there are several corner cases that are pending closure. 50 + 51 + 52 + * [2] CXL Window Enumeration 53 + 54 + * [0] :ref:`Extended-linear memory-side cache <extended-linear>` 55 + * [0] Low Memory-hole 56 + * [0] Hetero-interleave 57 + 58 + * [2] Switch Enumeration 59 + 60 + * [0] CXL register enumeration link-up dependency 61 + 62 + * [2] HDM Decoder Configuration 63 + 64 + * [0] Decoder target and granularity constraints 65 + 66 + * [2] Performance enumeration 67 + 68 + * [3] Endpoint CDAT 69 + * [3] Switch CDAT 70 + * [1] CDAT to Core-mm integration 71 + 72 + * [1] x86 73 + * [0] Arm64 74 + * [0] All other arch. 75 + 76 + * [0] Shared link 77 + 78 + * [2] Hotplug 79 + (see CXL Window Enumeration) 80 + 81 + * [0] Handle Soft Reserved conflicts 82 + 83 + * [0] :ref:`RCH link status <rch-link-status>` 84 + * [0] Fabrics / G-FAM (chapter 7) 85 + * [0] Global Access Endpoint 86 + 87 + 88 + RAS 89 + --- 90 + In many ways CXL can be seen as a standardization of what would normally 91 + be handled by custom EDAC drivers. The open development here is 92 + mainly caused by the enumeration corner cases above. 93 + 94 + * [3] Component events (OS) 95 + * [2] Component events (FFM) 96 + * [1] Endpoint protocol errors (OS) 97 + * [1] Endpoint protocol errors (FFM) 98 + * [0] Switch protocol errors (OS) 99 + * [1] Switch protocol errors (FFM) 100 + * [2] DPA->HPA Address translation 101 + 102 + * [1] XOR Interleave translation 103 + (see CXL Window Enumeration) 104 + 105 + * [1] Memory Failure coordination 106 + * [0] Scrub control 107 + * [2] ACPI error injection EINJ 108 + 109 + * [0] EINJ v2 110 + * [X] Compliance DOE 111 + 112 + * [2] Native error injection 113 + * [3] RCH error handling 114 + * [1] VH error handling 115 + * [0] PPR 116 + * [0] Sparing 117 + * [0] Device built in test 118 + 119 + 120 + Mailbox commands 121 + ---------------- 122 + 123 + * [3] Firmware update 124 + * [3] Health / Alerts 125 + * [1] :ref:`Background commands <background-commands>` 126 + * [3] Sanitization 127 + * [3] Security commands 128 + * [3] RAW Command Debug Passthrough 129 + * [0] CEL-only-validation Passthrough 130 + * [0] Switch CCI 131 + * [3] Timestamp 132 + * [1] PMEM labels 133 + * [0] PMEM GPF / Dirty Shutdown 134 + * [0] Scan Media 135 + 136 + PMU 137 + --- 138 + * [1] Type 3 PMU 139 + * [0] Switch USP/ DSP, Root Port 140 + 141 + Security 142 + -------- 143 + 144 + * [X] CXL Trusted Execution Environment Security Protocol (TSP) 145 + * [X] CXL IDE (subsumed by TSP) 146 + 147 + Memory-pooling 148 + -------------- 149 + 150 + * [1] Hotplug of LDs (via PCI hotplug) 151 + * [0] Dynamic Capacity Device (DCD) Support 152 + 153 + Multi-host sharing 154 + ------------------ 155 + 156 + * [0] Hardware coherent shared memory 157 + * [0] Software managed coherency shared memory 158 + 159 + Multi-host memory 160 + ----------------- 161 + 162 + * [0] Dynamic Capacity Device Support 163 + * [0] Sharing 164 + 165 + Accelerator 166 + ----------- 167 + 168 + * [0] Accelerator memory enumeration HDM-D (CXL 1.1/2.0 Type-2) 169 + * [0] Accelerator memory enumeration HDM-DB (CXL 3.0 Type-2) 170 + * [0] CXL.cache 68b (CXL 2.0) 171 + * [0] CXL.cache 256b Cache IDs (CXL 3.0) 172 + 173 + User Flow Support 174 + ----------------- 175 + 176 + * [0] HPA->DPA Address translation (need xormaps export solution) 177 + 178 + Details 179 + ======= 180 + 181 + .. _extended-linear: 182 + 183 + * **Extended-linear memory-side cache**: An HMAT proposal to enumerate the presence of a 184 + memory-side cache where the cache capacity extends the SRAT address 185 + range capacity. `See the ECN 186 + <https://lore.kernel.org/linux-cxl/6650e4f835a0e_195e294a8@dwillia2-mobl3.amr.corp.intel.com.notmuch/>`_ 187 + for more details: 188 + 189 + .. _rch-link-status: 190 + 191 + * **RCH Link Status**: RCH (Restricted CXL Host) topologies, end up 192 + hiding some standard registers like PCIe Link Status / Capabilities in 193 + the CXL RCRB (Root Complex Register Block). 194 + 195 + .. _background-commands: 196 + 197 + * **Background commands**: The CXL background command mechanism is 198 + awkward as the single slot is monopolized potentially indefinitely by 199 + various commands. A `cancel on conflict 200 + <http://lore.kernel.org/r/66035c2e8ba17_770232948b@dwillia2-xfh.jf.intel.com.notmuch>`_ 201 + facility is needed to make sure the kernel can ensure forward progress 202 + of priority commands.
+1
MAINTAINERS
··· 5613 5613 M: Dan Williams <dan.j.williams@intel.com> 5614 5614 L: linux-cxl@vger.kernel.org 5615 5615 S: Maintained 5616 + F: Documentation/driver-api/cxl 5616 5617 F: drivers/cxl/ 5617 5618 F: include/linux/einj-cxl.h 5618 5619 F: include/linux/cxl-event.h
+65 -60
drivers/cxl/acpi.c
··· 22 22 GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071, 23 23 0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52); 24 24 25 - /* 26 - * Find a targets entry (n) in the host bridge interleave list. 27 - * CXL Specification 3.0 Table 9-22 28 - */ 29 - static int cxl_xor_calc_n(u64 hpa, struct cxl_cxims_data *cximsd, int iw, 30 - int ig) 31 - { 32 - int i = 0, n = 0; 33 - u8 eiw; 34 25 35 - /* IW: 2,4,6,8,12,16 begin building 'n' using xormaps */ 36 - if (iw != 3) { 37 - for (i = 0; i < cximsd->nr_maps; i++) 38 - n |= (hweight64(hpa & cximsd->xormaps[i]) & 1) << i; 39 - } 40 - /* IW: 3,6,12 add a modulo calculation to 'n' */ 41 - if (!is_power_of_2(iw)) { 42 - if (ways_to_eiw(iw, &eiw)) 43 - return -1; 44 - hpa &= GENMASK_ULL(51, eiw + ig); 45 - n |= do_div(hpa, 3) << i; 46 - } 47 - return n; 48 - } 49 - 50 - static struct cxl_dport *cxl_hb_xor(struct cxl_root_decoder *cxlrd, int pos) 26 + static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa) 51 27 { 52 28 struct cxl_cxims_data *cximsd = cxlrd->platform_data; 53 - struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd; 54 - struct cxl_decoder *cxld = &cxlsd->cxld; 55 - int ig = cxld->interleave_granularity; 56 - int iw = cxld->interleave_ways; 57 - int n = 0; 58 - u64 hpa; 29 + int hbiw = cxlrd->cxlsd.nr_targets; 30 + u64 val; 31 + int pos; 59 32 60 - if (dev_WARN_ONCE(&cxld->dev, 61 - cxld->interleave_ways != cxlsd->nr_targets, 62 - "misconfigured root decoder\n")) 63 - return NULL; 33 + /* No xormaps for host bridge interleave ways of 1 or 3 */ 34 + if (hbiw == 1 || hbiw == 3) 35 + return hpa; 64 36 65 - hpa = cxlrd->res->start + pos * ig; 37 + /* 38 + * For root decoders using xormaps (hbiw: 2,4,6,8,12,16) restore 39 + * the position bit to its value before the xormap was applied at 40 + * HPA->DPA translation. 41 + * 42 + * pos is the lowest set bit in an XORMAP 43 + * val is the XORALLBITS(HPA & XORMAP) 44 + * 45 + * XORALLBITS: The CXL spec (3.1 Table 9-22) defines XORALLBITS 46 + * as an operation that outputs a single bit by XORing all the 47 + * bits in the input (hpa & xormap). Implement XORALLBITS using 48 + * hweight64(). If the hamming weight is even the XOR of those 49 + * bits results in val==0, if odd the XOR result is val==1. 50 + */ 66 51 67 - /* Entry (n) is 0 for no interleave (iw == 1) */ 68 - if (iw != 1) 69 - n = cxl_xor_calc_n(hpa, cximsd, iw, ig); 52 + for (int i = 0; i < cximsd->nr_maps; i++) { 53 + if (!cximsd->xormaps[i]) 54 + continue; 55 + pos = __ffs(cximsd->xormaps[i]); 56 + val = (hweight64(hpa & cximsd->xormaps[i]) & 1); 57 + hpa = (hpa & ~(1ULL << pos)) | (val << pos); 58 + } 70 59 71 - if (n < 0) 72 - return NULL; 73 - 74 - return cxlrd->cxlsd.target[n]; 60 + return hpa; 75 61 } 76 62 77 63 struct cxl_cxims_context { ··· 347 361 struct cxl_port *root_port = ctx->root_port; 348 362 struct cxl_cxims_context cxims_ctx; 349 363 struct device *dev = ctx->dev; 350 - cxl_calc_hb_fn cxl_calc_hb; 351 364 struct cxl_decoder *cxld; 352 365 unsigned int ways, i, ig; 353 366 int rc; ··· 374 389 if (rc) 375 390 return rc; 376 391 377 - if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) 378 - cxl_calc_hb = cxl_hb_modulo; 379 - else 380 - cxl_calc_hb = cxl_hb_xor; 381 - 382 392 struct cxl_root_decoder *cxlrd __free(put_cxlrd) = 383 - cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb); 393 + cxl_root_decoder_alloc(root_port, ways); 394 + 384 395 if (IS_ERR(cxlrd)) 385 396 return PTR_ERR(cxlrd); 386 397 ··· 414 433 } 415 434 416 435 cxlrd->qos_class = cfmws->qtg_id; 436 + 437 + if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) 438 + cxlrd->hpa_to_spa = cxl_xor_hpa_to_spa; 417 439 418 440 rc = cxl_decoder_add(cxld, target_map); 419 441 if (rc) ··· 466 482 unsigned long long uid; 467 483 resource_size_t base; 468 484 u32 cxl_version; 485 + int nr_versions; 486 + u32 saved_version; 469 487 }; 470 488 471 489 static int cxl_get_chbs_iter(union acpi_subtable_headers *header, void *arg, ··· 476 490 struct cxl_chbs_context *ctx = arg; 477 491 struct acpi_cedt_chbs *chbs; 478 492 479 - if (ctx->base != CXL_RESOURCE_NONE) 480 - return 0; 481 - 482 493 chbs = (struct acpi_cedt_chbs *) header; 483 - 484 - if (ctx->uid != chbs->uid) 485 - return 0; 486 - 487 - ctx->cxl_version = chbs->cxl_version; 488 - if (!chbs->base) 489 - return 0; 490 494 491 495 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11 && 492 496 chbs->length != CXL_RCRB_SIZE) 493 497 return 0; 494 498 499 + if (!chbs->base) 500 + return 0; 501 + 502 + if (ctx->saved_version != chbs->cxl_version) { 503 + /* 504 + * cxl_version cannot be overwritten before the next two 505 + * checks, then use saved_version 506 + */ 507 + ctx->saved_version = chbs->cxl_version; 508 + ctx->nr_versions++; 509 + } 510 + 511 + if (ctx->base != CXL_RESOURCE_NONE) 512 + return 0; 513 + 514 + if (ctx->uid != chbs->uid) 515 + return 0; 516 + 517 + ctx->cxl_version = chbs->cxl_version; 495 518 ctx->base = chbs->base; 496 519 497 520 return 0; ··· 524 529 .uid = uid, 525 530 .base = CXL_RESOURCE_NONE, 526 531 .cxl_version = UINT_MAX, 532 + .saved_version = UINT_MAX, 527 533 }; 528 534 529 535 acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbs_iter, ctx); 536 + 537 + if (ctx->nr_versions > 1) { 538 + /* 539 + * Disclaim eRCD support given some component register may 540 + * only be found via CHBCR 541 + */ 542 + dev_info(dev, "Unsupported platform config, mixed Virtual Host and Restricted CXL Host hierarchy."); 543 + } 530 544 531 545 return 0; 532 546 } ··· 925 921 /* load before dax_hmem sees 'Soft Reserved' CXL ranges */ 926 922 subsys_initcall(cxl_acpi_init); 927 923 module_exit(cxl_acpi_exit); 924 + MODULE_DESCRIPTION("CXL ACPI: Platform Support"); 928 925 MODULE_LICENSE("GPL v2"); 929 926 MODULE_IMPORT_NS(CXL); 930 927 MODULE_IMPORT_NS(ACPI);
+4 -4
drivers/cxl/core/core.h
··· 28 28 void cxl_region_exit(void); 29 29 int cxl_get_poison_by_endpoint(struct cxl_port *port); 30 30 struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa); 31 - u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, 32 - u64 dpa); 31 + u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, 32 + u64 dpa); 33 33 34 34 #else 35 - static inline u64 36 - cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa) 35 + static inline u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, 36 + const struct cxl_memdev *cxlmd, u64 dpa) 37 37 { 38 38 return ULLONG_MAX; 39 39 }
+2 -2
drivers/cxl/core/mbox.c
··· 875 875 guard(rwsem_read)(&cxl_region_rwsem); 876 876 guard(rwsem_read)(&cxl_dpa_rwsem); 877 877 878 - dpa = le64_to_cpu(evt->common.phys_addr) & CXL_DPA_MASK; 878 + dpa = le64_to_cpu(evt->media_hdr.phys_addr) & CXL_DPA_MASK; 879 879 cxlr = cxl_dpa_to_region(cxlmd, dpa); 880 880 if (cxlr) 881 - hpa = cxl_trace_hpa(cxlr, cxlmd, dpa); 881 + hpa = cxl_dpa_to_hpa(cxlr, cxlmd, dpa); 882 882 883 883 if (event_type == CXL_CPER_EVENT_GEN_MEDIA) 884 884 trace_cxl_general_media(cxlmd, type, cxlr, hpa,
+4 -4
drivers/cxl/core/pci.c
··· 338 338 if (rc) 339 339 return rc; 340 340 341 - rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl); 342 - if (rc) 343 - return rc; 344 - 345 341 if (!(cap & CXL_DVSEC_MEM_CAPABLE)) { 346 342 dev_dbg(dev, "Not MEM Capable\n"); 347 343 return -ENXIO; ··· 364 368 * disabled, and they will remain moot after the HDM Decoder 365 369 * capability is enabled. 366 370 */ 371 + rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl); 372 + if (rc) 373 + return rc; 374 + 367 375 info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl); 368 376 if (!info->mem_enabled) 369 377 return 0;
+2 -19
drivers/cxl/core/port.c
··· 1733 1733 return 0; 1734 1734 } 1735 1735 1736 - struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos) 1737 - { 1738 - struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd; 1739 - struct cxl_decoder *cxld = &cxlsd->cxld; 1740 - int iw; 1741 - 1742 - iw = cxld->interleave_ways; 1743 - if (dev_WARN_ONCE(&cxld->dev, iw != cxlsd->nr_targets, 1744 - "misconfigured root decoder\n")) 1745 - return NULL; 1746 - 1747 - return cxlrd->cxlsd.target[pos % iw]; 1748 - } 1749 - EXPORT_SYMBOL_NS_GPL(cxl_hb_modulo, CXL); 1750 - 1751 1736 static struct lock_class_key cxl_decoder_key; 1752 1737 1753 1738 /** ··· 1792 1807 * cxl_root_decoder_alloc - Allocate a root level decoder 1793 1808 * @port: owning CXL root of this decoder 1794 1809 * @nr_targets: static number of downstream targets 1795 - * @calc_hb: which host bridge covers the n'th position by granularity 1796 1810 * 1797 1811 * Return: A new cxl decoder to be registered by cxl_decoder_add(). A 1798 1812 * 'CXL root' decoder is one that decodes from a top-level / static platform ··· 1799 1815 * topology. 1800 1816 */ 1801 1817 struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, 1802 - unsigned int nr_targets, 1803 - cxl_calc_hb_fn calc_hb) 1818 + unsigned int nr_targets) 1804 1819 { 1805 1820 struct cxl_root_decoder *cxlrd; 1806 1821 struct cxl_switch_decoder *cxlsd; ··· 1821 1838 return ERR_PTR(rc); 1822 1839 } 1823 1840 1824 - cxlrd->calc_hb = calc_hb; 1825 1841 mutex_init(&cxlrd->range_lock); 1826 1842 1827 1843 cxld = &cxlsd->cxld; ··· 2338 2356 2339 2357 subsys_initcall(cxl_core_init); 2340 2358 module_exit(cxl_core_exit); 2359 + MODULE_DESCRIPTION("CXL: Core Compute Express Link support"); 2341 2360 MODULE_LICENSE("GPL v2"); 2342 2361 MODULE_IMPORT_NS(CXL);
+71 -34
drivers/cxl/core/region.c
··· 9 9 #include <linux/uuid.h> 10 10 #include <linux/sort.h> 11 11 #include <linux/idr.h> 12 + #include <linux/memory-tiers.h> 12 13 #include <cxlmem.h> 13 14 #include <cxl.h> 14 15 #include "core.h" ··· 1633 1632 const struct cxl_dport *dport, int pos) 1634 1633 { 1635 1634 struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 1635 + struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd; 1636 + struct cxl_decoder *cxld = &cxlsd->cxld; 1637 + int iw = cxld->interleave_ways; 1636 1638 struct cxl_port *iter; 1637 1639 int rc; 1638 1640 1639 - if (cxlrd->calc_hb(cxlrd, pos) != dport) { 1641 + if (dport != cxlrd->cxlsd.target[pos % iw]) { 1640 1642 dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n", 1641 1643 dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 1642 1644 dev_name(&cxlrd->cxlsd.cxld.dev)); ··· 2314 2310 int i; 2315 2311 2316 2312 unregister_memory_notifier(&cxlr->memory_notifier); 2313 + unregister_mt_adistance_algorithm(&cxlr->adist_notifier); 2317 2314 device_del(&cxlr->dev); 2318 2315 2319 2316 /* ··· 2391 2386 return true; 2392 2387 } 2393 2388 2389 + static int cxl_region_nid(struct cxl_region *cxlr) 2390 + { 2391 + struct cxl_region_params *p = &cxlr->params; 2392 + struct resource *res; 2393 + 2394 + guard(rwsem_read)(&cxl_region_rwsem); 2395 + res = p->res; 2396 + if (!res) 2397 + return NUMA_NO_NODE; 2398 + return phys_to_target_node(res->start); 2399 + } 2400 + 2394 2401 static int cxl_region_perf_attrs_callback(struct notifier_block *nb, 2395 2402 unsigned long action, void *arg) 2396 2403 { 2397 2404 struct cxl_region *cxlr = container_of(nb, struct cxl_region, 2398 2405 memory_notifier); 2399 - struct cxl_region_params *p = &cxlr->params; 2400 - struct cxl_endpoint_decoder *cxled = p->targets[0]; 2401 - struct cxl_decoder *cxld = &cxled->cxld; 2402 2406 struct memory_notify *mnb = arg; 2403 2407 int nid = mnb->status_change_nid; 2404 2408 int region_nid; ··· 2415 2401 if (nid == NUMA_NO_NODE || action != MEM_ONLINE) 2416 2402 return NOTIFY_DONE; 2417 2403 2418 - region_nid = phys_to_target_node(cxld->hpa_range.start); 2404 + region_nid = cxl_region_nid(cxlr); 2419 2405 if (nid != region_nid) 2420 2406 return NOTIFY_DONE; 2421 2407 ··· 2423 2409 return NOTIFY_DONE; 2424 2410 2425 2411 return NOTIFY_OK; 2412 + } 2413 + 2414 + static int cxl_region_calculate_adistance(struct notifier_block *nb, 2415 + unsigned long nid, void *data) 2416 + { 2417 + struct cxl_region *cxlr = container_of(nb, struct cxl_region, 2418 + adist_notifier); 2419 + struct access_coordinate *perf; 2420 + int *adist = data; 2421 + int region_nid; 2422 + 2423 + region_nid = cxl_region_nid(cxlr); 2424 + if (nid != region_nid) 2425 + return NOTIFY_OK; 2426 + 2427 + perf = &cxlr->coord[ACCESS_COORDINATE_CPU]; 2428 + 2429 + if (mt_perf_to_adistance(perf, adist)) 2430 + return NOTIFY_OK; 2431 + 2432 + return NOTIFY_STOP; 2426 2433 } 2427 2434 2428 2435 /** ··· 2487 2452 cxlr->memory_notifier.notifier_call = cxl_region_perf_attrs_callback; 2488 2453 cxlr->memory_notifier.priority = CXL_CALLBACK_PRI; 2489 2454 register_memory_notifier(&cxlr->memory_notifier); 2455 + 2456 + cxlr->adist_notifier.notifier_call = cxl_region_calculate_adistance; 2457 + cxlr->adist_notifier.priority = 100; 2458 + register_mt_adistance_algorithm(&cxlr->adist_notifier); 2490 2459 2491 2460 rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr); 2492 2461 if (rc) ··· 2855 2816 return ctx.cxlr; 2856 2817 } 2857 2818 2858 - static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos) 2819 + static bool cxl_is_hpa_in_chunk(u64 hpa, struct cxl_region *cxlr, int pos) 2859 2820 { 2860 2821 struct cxl_region_params *p = &cxlr->params; 2861 2822 int gran = p->interleave_granularity; 2862 2823 int ways = p->interleave_ways; 2863 2824 u64 offset; 2864 - 2865 - /* Is the hpa within this region at all */ 2866 - if (hpa < p->res->start || hpa > p->res->end) { 2867 - dev_dbg(&cxlr->dev, 2868 - "Addr trans fail: hpa 0x%llx not in region\n", hpa); 2869 - return false; 2870 - } 2871 2825 2872 2826 /* Is the hpa in an expected chunk for its pos(-ition) */ 2873 2827 offset = hpa - p->res->start; ··· 2874 2842 return false; 2875 2843 } 2876 2844 2877 - static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, 2878 - struct cxl_endpoint_decoder *cxled) 2845 + u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, 2846 + u64 dpa) 2879 2847 { 2848 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); 2880 2849 u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; 2881 2850 struct cxl_region_params *p = &cxlr->params; 2882 - int pos = cxled->pos; 2851 + struct cxl_endpoint_decoder *cxled = NULL; 2883 2852 u16 eig = 0; 2884 2853 u8 eiw = 0; 2854 + int pos; 2885 2855 2856 + for (int i = 0; i < p->nr_targets; i++) { 2857 + cxled = p->targets[i]; 2858 + if (cxlmd == cxled_to_memdev(cxled)) 2859 + break; 2860 + } 2861 + if (!cxled || cxlmd != cxled_to_memdev(cxled)) 2862 + return ULLONG_MAX; 2863 + 2864 + pos = cxled->pos; 2886 2865 ways_to_eiw(p->interleave_ways, &eiw); 2887 2866 granularity_to_eig(p->interleave_granularity, &eig); 2888 2867 ··· 2927 2884 /* Apply the hpa_offset to the region base address */ 2928 2885 hpa = hpa_offset + p->res->start; 2929 2886 2930 - if (!cxl_is_hpa_in_range(hpa, cxlr, cxled->pos)) 2887 + /* Root decoder translation overrides typical modulo decode */ 2888 + if (cxlrd->hpa_to_spa) 2889 + hpa = cxlrd->hpa_to_spa(cxlrd, hpa); 2890 + 2891 + if (hpa < p->res->start || hpa > p->res->end) { 2892 + dev_dbg(&cxlr->dev, 2893 + "Addr trans fail: hpa 0x%llx not in region\n", hpa); 2894 + return ULLONG_MAX; 2895 + } 2896 + 2897 + /* Simple chunk check, by pos & gran, only applies to modulo decodes */ 2898 + if (!cxlrd->hpa_to_spa && (!cxl_is_hpa_in_chunk(hpa, cxlr, pos))) 2931 2899 return ULLONG_MAX; 2932 2900 2933 2901 return hpa; 2934 - } 2935 - 2936 - u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, 2937 - u64 dpa) 2938 - { 2939 - struct cxl_region_params *p = &cxlr->params; 2940 - struct cxl_endpoint_decoder *cxled = NULL; 2941 - 2942 - for (int i = 0; i < p->nr_targets; i++) { 2943 - cxled = p->targets[i]; 2944 - if (cxlmd == cxled_to_memdev(cxled)) 2945 - break; 2946 - } 2947 - if (!cxled || cxlmd != cxled_to_memdev(cxled)) 2948 - return ULLONG_MAX; 2949 - 2950 - return cxl_dpa_to_hpa(dpa, cxlr, cxled); 2951 2902 } 2952 2903 2953 2904 static struct lock_class_key cxl_pmem_region_key;
+18 -18
drivers/cxl/core/trace.h
··· 340 340 ), 341 341 342 342 TP_fast_assign( 343 - CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); 343 + CXL_EVT_TP_fast_assign(cxlmd, log, rec->media_hdr.hdr); 344 344 __entry->hdr_uuid = CXL_EVENT_GEN_MEDIA_UUID; 345 345 346 346 /* General Media */ 347 - __entry->dpa = le64_to_cpu(rec->phys_addr); 347 + __entry->dpa = le64_to_cpu(rec->media_hdr.phys_addr); 348 348 __entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK; 349 349 /* Mask after flags have been parsed */ 350 350 __entry->dpa &= CXL_DPA_MASK; 351 - __entry->descriptor = rec->descriptor; 352 - __entry->type = rec->type; 353 - __entry->transaction_type = rec->transaction_type; 354 - __entry->channel = rec->channel; 355 - __entry->rank = rec->rank; 351 + __entry->descriptor = rec->media_hdr.descriptor; 352 + __entry->type = rec->media_hdr.type; 353 + __entry->transaction_type = rec->media_hdr.transaction_type; 354 + __entry->channel = rec->media_hdr.channel; 355 + __entry->rank = rec->media_hdr.rank; 356 356 __entry->device = get_unaligned_le24(rec->device); 357 357 memcpy(__entry->comp_id, &rec->component_id, 358 358 CXL_EVENT_GEN_MED_COMP_ID_SIZE); 359 - __entry->validity_flags = get_unaligned_le16(&rec->validity_flags); 359 + __entry->validity_flags = get_unaligned_le16(&rec->media_hdr.validity_flags); 360 360 __entry->hpa = hpa; 361 361 if (cxlr) { 362 362 __assign_str(region_name); ··· 440 440 ), 441 441 442 442 TP_fast_assign( 443 - CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); 443 + CXL_EVT_TP_fast_assign(cxlmd, log, rec->media_hdr.hdr); 444 444 __entry->hdr_uuid = CXL_EVENT_DRAM_UUID; 445 445 446 446 /* DRAM */ 447 - __entry->dpa = le64_to_cpu(rec->phys_addr); 447 + __entry->dpa = le64_to_cpu(rec->media_hdr.phys_addr); 448 448 __entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK; 449 449 __entry->dpa &= CXL_DPA_MASK; 450 - __entry->descriptor = rec->descriptor; 451 - __entry->type = rec->type; 452 - __entry->transaction_type = rec->transaction_type; 453 - __entry->validity_flags = get_unaligned_le16(rec->validity_flags); 454 - __entry->channel = rec->channel; 455 - __entry->rank = rec->rank; 450 + __entry->descriptor = rec->media_hdr.descriptor; 451 + __entry->type = rec->media_hdr.type; 452 + __entry->transaction_type = rec->media_hdr.transaction_type; 453 + __entry->validity_flags = get_unaligned_le16(rec->media_hdr.validity_flags); 454 + __entry->channel = rec->media_hdr.channel; 455 + __entry->rank = rec->media_hdr.rank; 456 456 __entry->nibble_mask = get_unaligned_le24(rec->nibble_mask); 457 457 __entry->bank_group = rec->bank_group; 458 458 __entry->bank = rec->bank; ··· 704 704 if (cxlr) { 705 705 __assign_str(region); 706 706 memcpy(__entry->uuid, &cxlr->params.uuid, 16); 707 - __entry->hpa = cxl_trace_hpa(cxlr, cxlmd, 708 - __entry->dpa); 707 + __entry->hpa = cxl_dpa_to_hpa(cxlr, cxlmd, 708 + __entry->dpa); 709 709 } else { 710 710 __assign_str(region); 711 711 memset(__entry->uuid, 0, 16);
+6 -7
drivers/cxl/cxl.h
··· 434 434 }; 435 435 436 436 struct cxl_root_decoder; 437 - typedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd, 438 - int pos); 437 + typedef u64 (*cxl_hpa_to_spa_fn)(struct cxl_root_decoder *cxlrd, u64 hpa); 439 438 440 439 /** 441 440 * struct cxl_root_decoder - Static platform CXL address decoder 442 441 * @res: host / parent resource for region allocations 443 442 * @region_id: region id for next region provisioning event 444 - * @calc_hb: which host bridge covers the n'th position by granularity 443 + * @hpa_to_spa: translate CXL host-physical-address to Platform system-physical-address 445 444 * @platform_data: platform specific configuration data 446 445 * @range_lock: sync region autodiscovery by address range 447 446 * @qos_class: QoS performance class cookie ··· 449 450 struct cxl_root_decoder { 450 451 struct resource *res; 451 452 atomic_t region_id; 452 - cxl_calc_hb_fn calc_hb; 453 + cxl_hpa_to_spa_fn hpa_to_spa; 453 454 void *platform_data; 454 455 struct mutex range_lock; 455 456 int qos_class; ··· 523 524 * @params: active + config params for the region 524 525 * @coord: QoS access coordinates for the region 525 526 * @memory_notifier: notifier for setting the access coordinates to node 527 + * @adist_notifier: notifier for calculating the abstract distance of node 526 528 */ 527 529 struct cxl_region { 528 530 struct device dev; ··· 536 536 struct cxl_region_params params; 537 537 struct access_coordinate coord[ACCESS_COORDINATE_MAX]; 538 538 struct notifier_block memory_notifier; 539 + struct notifier_block adist_notifier; 539 540 }; 540 541 541 542 struct cxl_nvdimm_bridge { ··· 775 774 bool is_switch_decoder(struct device *dev); 776 775 bool is_endpoint_decoder(struct device *dev); 777 776 struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, 778 - unsigned int nr_targets, 779 - cxl_calc_hb_fn calc_hb); 780 - struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos); 777 + unsigned int nr_targets); 781 778 struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, 782 779 unsigned int nr_targets); 783 780 int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
+2 -2
drivers/cxl/cxlmem.h
··· 161 161 C(FWRESET, -ENXIO, "FW failed to activate, needs cold reset"), \ 162 162 C(HANDLE, -ENXIO, "one or more Event Record Handles were invalid"), \ 163 163 C(PADDR, -EFAULT, "physical address specified is invalid"), \ 164 - C(POISONLMT, -ENXIO, "poison injection limit has been reached"), \ 164 + C(POISONLMT, -EBUSY, "poison injection limit has been reached"), \ 165 165 C(MEDIAFAILURE, -ENXIO, "permanent issue with the media"), \ 166 166 C(ABORT, -ENXIO, "background cmd was aborted by device"), \ 167 167 C(SECURITY, -ENXIO, "not valid in the current security state"), \ ··· 563 563 0x3b, 0x3f, 0x17) 564 564 565 565 #define DEFINE_CXL_VENDOR_DEBUG_UUID \ 566 - UUID_INIT(0xe1819d9, 0x11a9, 0x400c, 0x81, 0x1f, 0xd6, 0x07, 0x19, \ 566 + UUID_INIT(0x5e1819d9, 0x11a9, 0x400c, 0x81, 0x1f, 0xd6, 0x07, 0x19, \ 567 567 0x40, 0x3d, 0x86) 568 568 569 569 struct cxl_mbox_get_supported_logs {
+1
drivers/cxl/mem.c
··· 253 253 254 254 module_cxl_driver(cxl_mem_driver); 255 255 256 + MODULE_DESCRIPTION("CXL: Memory Expansion"); 256 257 MODULE_LICENSE("GPL v2"); 257 258 MODULE_IMPORT_NS(CXL); 258 259 MODULE_ALIAS_CXL(CXL_DEVICE_MEMORY_EXPANDER);
+1
drivers/cxl/pci.c
··· 1066 1066 1067 1067 module_init(cxl_pci_driver_init); 1068 1068 module_exit(cxl_pci_driver_exit); 1069 + MODULE_DESCRIPTION("CXL: PCI manageability"); 1069 1070 MODULE_LICENSE("GPL v2"); 1070 1071 MODULE_IMPORT_NS(CXL);
+1
drivers/cxl/pmem.c
··· 453 453 cxl_driver_unregister(&cxl_nvdimm_bridge_driver); 454 454 } 455 455 456 + MODULE_DESCRIPTION("CXL PMEM: Persistent Memory Support"); 456 457 MODULE_LICENSE("GPL v2"); 457 458 module_init(cxl_pmem_init); 458 459 module_exit(cxl_pmem_exit);
+1
drivers/cxl/port.c
··· 209 209 }; 210 210 211 211 module_cxl_driver(cxl_port_driver); 212 + MODULE_DESCRIPTION("CXL: Port enumeration and services"); 212 213 MODULE_LICENSE("GPL v2"); 213 214 MODULE_IMPORT_NS(CXL); 214 215 MODULE_ALIAS_CXL(CXL_DEVICE_PORT);
+19 -26
include/linux/cxl-event.h
··· 21 21 u8 reserved[15]; 22 22 } __packed; 23 23 24 + struct cxl_event_media_hdr { 25 + struct cxl_event_record_hdr hdr; 26 + __le64 phys_addr; 27 + u8 descriptor; 28 + u8 type; 29 + u8 transaction_type; 30 + /* 31 + * The meaning of Validity Flags from bit 2 is 32 + * different across DRAM and General Media records 33 + */ 34 + u8 validity_flags[2]; 35 + u8 channel; 36 + u8 rank; 37 + } __packed; 38 + 24 39 #define CXL_EVENT_RECORD_DATA_LENGTH 0x50 25 40 struct cxl_event_generic { 26 41 struct cxl_event_record_hdr hdr; ··· 48 33 */ 49 34 #define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10 50 35 struct cxl_event_gen_media { 51 - struct cxl_event_record_hdr hdr; 52 - __le64 phys_addr; 53 - u8 descriptor; 54 - u8 type; 55 - u8 transaction_type; 56 - u8 validity_flags[2]; 57 - u8 channel; 58 - u8 rank; 36 + struct cxl_event_media_hdr media_hdr; 59 37 u8 device[3]; 60 38 u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; 61 39 u8 reserved[46]; ··· 60 52 */ 61 53 #define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20 62 54 struct cxl_event_dram { 63 - struct cxl_event_record_hdr hdr; 64 - __le64 phys_addr; 65 - u8 descriptor; 66 - u8 type; 67 - u8 transaction_type; 68 - u8 validity_flags[2]; 69 - u8 channel; 70 - u8 rank; 55 + struct cxl_event_media_hdr media_hdr; 71 56 u8 nibble_mask[3]; 72 57 u8 bank_group; 73 58 u8 bank; ··· 96 95 u8 reserved[0x3d]; 97 96 } __packed; 98 97 99 - /* 100 - * General Media or DRAM Event Common Fields 101 - * - provides common access to phys_addr 102 - */ 103 - struct cxl_event_common { 104 - struct cxl_event_record_hdr hdr; 105 - __le64 phys_addr; 106 - } __packed; 107 - 108 98 union cxl_event { 109 99 struct cxl_event_generic generic; 110 100 struct cxl_event_gen_media gen_media; 111 101 struct cxl_event_dram dram; 112 102 struct cxl_event_mem_module mem_module; 113 - struct cxl_event_common common; 103 + /* dram & gen_media event header */ 104 + struct cxl_event_media_hdr media_hdr; 114 105 } __packed; 115 106 116 107 /*
+36 -33
tools/testing/cxl/test/mem.c
··· 385 385 struct cxl_test_gen_media gen_media = { 386 386 .id = CXL_EVENT_GEN_MEDIA_UUID, 387 387 .rec = { 388 - .hdr = { 389 - .length = sizeof(struct cxl_test_gen_media), 390 - .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT, 391 - /* .handle = Set dynamically */ 392 - .related_handle = cpu_to_le16(0), 388 + .media_hdr = { 389 + .hdr = { 390 + .length = sizeof(struct cxl_test_gen_media), 391 + .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT, 392 + /* .handle = Set dynamically */ 393 + .related_handle = cpu_to_le16(0), 394 + }, 395 + .phys_addr = cpu_to_le64(0x2000), 396 + .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT, 397 + .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, 398 + .transaction_type = CXL_GMER_TRANS_HOST_WRITE, 399 + /* .validity_flags = <set below> */ 400 + .channel = 1, 401 + .rank = 30, 393 402 }, 394 - .phys_addr = cpu_to_le64(0x2000), 395 - .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT, 396 - .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, 397 - .transaction_type = CXL_GMER_TRANS_HOST_WRITE, 398 - /* .validity_flags = <set below> */ 399 - .channel = 1, 400 - .rank = 30 401 403 }, 402 404 }; 403 405 ··· 411 409 struct cxl_test_dram dram = { 412 410 .id = CXL_EVENT_DRAM_UUID, 413 411 .rec = { 414 - .hdr = { 415 - .length = sizeof(struct cxl_test_dram), 416 - .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, 417 - /* .handle = Set dynamically */ 418 - .related_handle = cpu_to_le16(0), 412 + .media_hdr = { 413 + .hdr = { 414 + .length = sizeof(struct cxl_test_dram), 415 + .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, 416 + /* .handle = Set dynamically */ 417 + .related_handle = cpu_to_le16(0), 418 + }, 419 + .phys_addr = cpu_to_le64(0x8000), 420 + .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT, 421 + .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR, 422 + .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB, 423 + /* .validity_flags = <set below> */ 424 + .channel = 1, 419 425 }, 420 - .phys_addr = cpu_to_le64(0x8000), 421 - .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT, 422 - .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR, 423 - .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB, 424 - /* .validity_flags = <set below> */ 425 - .channel = 1, 426 426 .bank_group = 5, 427 427 .bank = 2, 428 428 .column = {0xDE, 0xAD}, ··· 478 474 static void cxl_mock_add_event_logs(struct mock_event_store *mes) 479 475 { 480 476 put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK, 481 - &gen_media.rec.validity_flags); 477 + &gen_media.rec.media_hdr.validity_flags); 482 478 483 479 put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP | 484 480 CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN, 485 - &dram.rec.validity_flags); 481 + &dram.rec.media_hdr.validity_flags); 486 482 487 483 mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed); 488 484 mes_add_event(mes, CXL_EVENT_TYPE_INFO, ··· 1135 1131 return (count >= poison_inject_dev_max); 1136 1132 } 1137 1133 1138 - static bool mock_poison_add(struct cxl_dev_state *cxlds, u64 dpa) 1134 + static int mock_poison_add(struct cxl_dev_state *cxlds, u64 dpa) 1139 1135 { 1136 + /* Return EBUSY to match the CXL driver handling */ 1140 1137 if (mock_poison_dev_max_injected(cxlds)) { 1141 1138 dev_dbg(cxlds->dev, 1142 1139 "Device poison injection limit has been reached: %d\n", 1143 - MOCK_INJECT_DEV_MAX); 1144 - return false; 1140 + poison_inject_dev_max); 1141 + return -EBUSY; 1145 1142 } 1146 1143 1147 1144 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1148 1145 if (!mock_poison_list[i].cxlds) { 1149 1146 mock_poison_list[i].cxlds = cxlds; 1150 1147 mock_poison_list[i].dpa = dpa; 1151 - return true; 1148 + return 0; 1152 1149 } 1153 1150 } 1154 1151 dev_dbg(cxlds->dev, 1155 1152 "Mock test poison injection limit has been reached: %d\n", 1156 1153 MOCK_INJECT_TEST_MAX); 1157 1154 1158 - return false; 1155 + return -ENXIO; 1159 1156 } 1160 1157 1161 1158 static bool mock_poison_found(struct cxl_dev_state *cxlds, u64 dpa) ··· 1180 1175 dev_dbg(cxlds->dev, "DPA: 0x%llx already poisoned\n", dpa); 1181 1176 return 0; 1182 1177 } 1183 - if (!mock_poison_add(cxlds, dpa)) 1184 - return -ENXIO; 1185 1178 1186 - return 0; 1179 + return mock_poison_add(cxlds, dpa); 1187 1180 } 1188 1181 1189 1182 static bool mock_poison_del(struct cxl_dev_state *cxlds, u64 dpa)