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

cxl/core/hdm: Add CXL standard decoder enumeration to the core

Unlike the decoder enumeration for "root decoders" described by platform
firmware, standard decoders can be enumerated from the component
registers space once the base address has been identified (via PCI,
ACPI, or another mechanism).

Add common infrastructure for HDM (Host-managed-Device-Memory) Decoder
enumeration and share it between host-bridge, upstream switch port, and
cxl_test defined decoders.

The locking model for switch level decoders is to hold the port lock
over the enumeration. This facilitates moving the dport and decoder
enumeration to a 'port' driver. For now, the only enumerator of decoder
resources is the cxl_acpi root driver.

Co-developed-by: Ben Widawsky <ben.widawsky@intel.com>
Signed-off-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/164374688404.395335.9239248252443123526.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+434 -49
+15 -28
drivers/cxl/acpi.c
··· 168 168 struct device *host = root_port->dev.parent; 169 169 struct acpi_device *bridge = to_cxl_host_bridge(host, match); 170 170 struct acpi_pci_root *pci_root; 171 - int single_port_map[1], rc; 172 - struct cxl_decoder *cxld; 173 171 struct cxl_dport *dport; 172 + struct cxl_hdm *cxlhdm; 174 173 struct cxl_port *port; 174 + int rc; 175 175 176 176 if (!bridge) 177 177 return 0; ··· 200 200 rc = devm_cxl_port_enumerate_dports(host, port); 201 201 if (rc < 0) 202 202 return rc; 203 - if (rc > 1) 204 - return 0; 205 - 206 - /* TODO: Scan CHBCR for HDM Decoder resources */ 207 - 208 - /* 209 - * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability 210 - * Structure) single ported host-bridges need not publish a decoder 211 - * capability when a passthrough decode can be assumed, i.e. all 212 - * transactions that the uport sees are claimed and passed to the single 213 - * dport. Disable the range until the first CXL region is enumerated / 214 - * activated. 215 - */ 216 - cxld = cxl_switch_decoder_alloc(port, 1); 217 - if (IS_ERR(cxld)) 218 - return PTR_ERR(cxld); 219 - 220 203 cxl_device_lock(&port->dev); 221 - dport = list_first_entry(&port->dports, typeof(*dport), list); 222 - cxl_device_unlock(&port->dev); 204 + if (rc == 1) { 205 + rc = devm_cxl_add_passthrough_decoder(host, port); 206 + goto out; 207 + } 223 208 224 - single_port_map[0] = dport->port_id; 209 + cxlhdm = devm_cxl_setup_hdm(host, port); 210 + if (IS_ERR(cxlhdm)) { 211 + rc = PTR_ERR(cxlhdm); 212 + goto out; 213 + } 225 214 226 - rc = cxl_decoder_add(cxld, single_port_map); 215 + rc = devm_cxl_enumerate_decoders(host, cxlhdm); 227 216 if (rc) 228 - put_device(&cxld->dev); 229 - else 230 - rc = cxl_decoder_autoremove(host, cxld); 217 + dev_err(&port->dev, "Couldn't enumerate decoders (%d)\n", rc); 231 218 232 - if (rc == 0) 233 - dev_dbg(host, "add: %s\n", dev_name(&cxld->dev)); 219 + out: 220 + cxl_device_unlock(&port->dev); 234 221 return rc; 235 222 } 236 223
+1
drivers/cxl/core/Makefile
··· 8 8 cxl_core-y += memdev.o 9 9 cxl_core-y += mbox.o 10 10 cxl_core-y += pci.o 11 + cxl_core-y += hdm.o
+2
drivers/cxl/core/core.h
··· 14 14 int cxl_query_cmd(struct cxl_memdev *cxlmd, 15 15 struct cxl_mem_query_commands __user *q); 16 16 int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s); 17 + void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, 18 + resource_size_t length); 17 19 18 20 int cxl_memdev_init(void); 19 21 void cxl_memdev_exit(void);
+248
drivers/cxl/core/hdm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 + #include <linux/io-64-nonatomic-hi-lo.h> 4 + #include <linux/device.h> 5 + #include <linux/delay.h> 6 + 7 + #include "cxlmem.h" 8 + #include "core.h" 9 + 10 + /** 11 + * DOC: cxl core hdm 12 + * 13 + * Compute Express Link Host Managed Device Memory, starting with the 14 + * CXL 2.0 specification, is managed by an array of HDM Decoder register 15 + * instances per CXL port and per CXL endpoint. Define common helpers 16 + * for enumerating these registers and capabilities. 17 + */ 18 + 19 + static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, 20 + int *target_map) 21 + { 22 + int rc; 23 + 24 + rc = cxl_decoder_add_locked(cxld, target_map); 25 + if (rc) { 26 + put_device(&cxld->dev); 27 + dev_err(&port->dev, "Failed to add decoder\n"); 28 + return rc; 29 + } 30 + 31 + rc = cxl_decoder_autoremove(&port->dev, cxld); 32 + if (rc) 33 + return rc; 34 + 35 + dev_dbg(&cxld->dev, "Added to port %s\n", dev_name(&port->dev)); 36 + 37 + return 0; 38 + } 39 + 40 + /* 41 + * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) 42 + * single ported host-bridges need not publish a decoder capability when a 43 + * passthrough decode can be assumed, i.e. all transactions that the uport sees 44 + * are claimed and passed to the single dport. Disable the range until the first 45 + * CXL region is enumerated / activated. 46 + */ 47 + int devm_cxl_add_passthrough_decoder(struct device *host, struct cxl_port *port) 48 + { 49 + struct cxl_decoder *cxld; 50 + struct cxl_dport *dport; 51 + int single_port_map[1]; 52 + 53 + cxld = cxl_switch_decoder_alloc(port, 1); 54 + if (IS_ERR(cxld)) 55 + return PTR_ERR(cxld); 56 + 57 + device_lock_assert(&port->dev); 58 + 59 + dport = list_first_entry(&port->dports, typeof(*dport), list); 60 + single_port_map[0] = dport->port_id; 61 + 62 + return add_hdm_decoder(port, cxld, single_port_map); 63 + } 64 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, CXL); 65 + 66 + static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm) 67 + { 68 + u32 hdm_cap; 69 + 70 + hdm_cap = readl(cxlhdm->regs.hdm_decoder + CXL_HDM_DECODER_CAP_OFFSET); 71 + cxlhdm->decoder_count = cxl_hdm_decoder_count(hdm_cap); 72 + cxlhdm->target_count = 73 + FIELD_GET(CXL_HDM_DECODER_TARGET_COUNT_MASK, hdm_cap); 74 + if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_11_8, hdm_cap)) 75 + cxlhdm->interleave_mask |= GENMASK(11, 8); 76 + if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_14_12, hdm_cap)) 77 + cxlhdm->interleave_mask |= GENMASK(14, 12); 78 + } 79 + 80 + static void __iomem *map_hdm_decoder_regs(struct cxl_port *port, 81 + void __iomem *crb) 82 + { 83 + struct cxl_component_reg_map map; 84 + 85 + cxl_probe_component_regs(&port->dev, crb, &map); 86 + if (!map.hdm_decoder.valid) { 87 + dev_err(&port->dev, "HDM decoder registers invalid\n"); 88 + return IOMEM_ERR_PTR(-ENXIO); 89 + } 90 + 91 + return crb + map.hdm_decoder.offset; 92 + } 93 + 94 + /** 95 + * devm_cxl_setup_hdm - map HDM decoder component registers 96 + * @host: devm context for allocations 97 + * @port: cxl_port to map 98 + */ 99 + struct cxl_hdm *devm_cxl_setup_hdm(struct device *host, struct cxl_port *port) 100 + { 101 + struct device *dev = &port->dev; 102 + void __iomem *crb, *hdm; 103 + struct cxl_hdm *cxlhdm; 104 + 105 + cxlhdm = devm_kzalloc(host, sizeof(*cxlhdm), GFP_KERNEL); 106 + if (!cxlhdm) 107 + return ERR_PTR(-ENOMEM); 108 + 109 + cxlhdm->port = port; 110 + crb = devm_cxl_iomap_block(host, port->component_reg_phys, 111 + CXL_COMPONENT_REG_BLOCK_SIZE); 112 + if (!crb) { 113 + dev_err(dev, "No component registers mapped\n"); 114 + return ERR_PTR(-ENXIO); 115 + } 116 + 117 + hdm = map_hdm_decoder_regs(port, crb); 118 + if (IS_ERR(hdm)) 119 + return ERR_CAST(hdm); 120 + cxlhdm->regs.hdm_decoder = hdm; 121 + 122 + parse_hdm_decoder_caps(cxlhdm); 123 + if (cxlhdm->decoder_count == 0) { 124 + dev_err(dev, "Spec violation. Caps invalid\n"); 125 + return ERR_PTR(-ENXIO); 126 + } 127 + 128 + return cxlhdm; 129 + } 130 + EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, CXL); 131 + 132 + static int to_interleave_granularity(u32 ctrl) 133 + { 134 + int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl); 135 + 136 + return 256 << val; 137 + } 138 + 139 + static int to_interleave_ways(u32 ctrl) 140 + { 141 + int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl); 142 + 143 + switch (val) { 144 + case 0 ... 4: 145 + return 1 << val; 146 + case 8 ... 10: 147 + return 3 << (val - 8); 148 + default: 149 + return 0; 150 + } 151 + } 152 + 153 + static void init_hdm_decoder(struct cxl_decoder *cxld, int *target_map, 154 + void __iomem *hdm, int which) 155 + { 156 + u64 size, base; 157 + u32 ctrl; 158 + int i; 159 + union { 160 + u64 value; 161 + unsigned char target_id[8]; 162 + } target_list; 163 + 164 + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which)); 165 + base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which)); 166 + size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which)); 167 + 168 + if (!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED)) 169 + size = 0; 170 + 171 + cxld->decoder_range = (struct range) { 172 + .start = base, 173 + .end = base + size - 1, 174 + }; 175 + 176 + /* switch decoders are always enabled if committed */ 177 + if (ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED) { 178 + cxld->flags |= CXL_DECODER_F_ENABLE; 179 + if (ctrl & CXL_HDM_DECODER0_CTRL_LOCK) 180 + cxld->flags |= CXL_DECODER_F_LOCK; 181 + } 182 + cxld->interleave_ways = to_interleave_ways(ctrl); 183 + cxld->interleave_granularity = to_interleave_granularity(ctrl); 184 + 185 + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl)) 186 + cxld->target_type = CXL_DECODER_EXPANDER; 187 + else 188 + cxld->target_type = CXL_DECODER_ACCELERATOR; 189 + 190 + target_list.value = 191 + ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which)); 192 + for (i = 0; i < cxld->interleave_ways; i++) 193 + target_map[i] = target_list.target_id[i]; 194 + } 195 + 196 + /** 197 + * devm_cxl_enumerate_decoders - add decoder objects per HDM register set 198 + * @host: devm allocation context 199 + * @cxlhdm: Structure to populate with HDM capabilities 200 + */ 201 + int devm_cxl_enumerate_decoders(struct device *host, struct cxl_hdm *cxlhdm) 202 + { 203 + void __iomem *hdm = cxlhdm->regs.hdm_decoder; 204 + struct cxl_port *port = cxlhdm->port; 205 + int i, committed; 206 + u32 ctrl; 207 + 208 + /* 209 + * Since the register resource was recently claimed via request_region() 210 + * be careful about trusting the "not-committed" status until the commit 211 + * timeout has elapsed. The commit timeout is 10ms (CXL 2.0 212 + * 8.2.5.12.20), but double it to be tolerant of any clock skew between 213 + * host and target. 214 + */ 215 + for (i = 0, committed = 0; i < cxlhdm->decoder_count; i++) { 216 + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); 217 + if (ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED) 218 + committed++; 219 + } 220 + 221 + /* ensure that future checks of committed can be trusted */ 222 + if (committed != cxlhdm->decoder_count) 223 + msleep(20); 224 + 225 + for (i = 0; i < cxlhdm->decoder_count; i++) { 226 + int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 }; 227 + int rc, target_count = cxlhdm->target_count; 228 + struct cxl_decoder *cxld; 229 + 230 + cxld = cxl_switch_decoder_alloc(port, target_count); 231 + if (IS_ERR(cxld)) { 232 + dev_warn(&port->dev, 233 + "Failed to allocate the decoder\n"); 234 + return PTR_ERR(cxld); 235 + } 236 + 237 + init_hdm_decoder(cxld, target_map, cxlhdm->regs.hdm_decoder, i); 238 + rc = add_hdm_decoder(port, cxld, target_map); 239 + if (rc) { 240 + dev_warn(&port->dev, 241 + "Failed to add decoder to port\n"); 242 + return rc; 243 + } 244 + } 245 + 246 + return 0; 247 + } 248 + EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, CXL);
+45 -12
drivers/cxl/core/port.c
··· 594 594 static int decoder_populate_targets(struct cxl_decoder *cxld, 595 595 struct cxl_port *port, int *target_map) 596 596 { 597 - int rc = 0, i; 597 + int i, rc = 0; 598 598 599 599 if (!target_map) 600 600 return 0; 601 601 602 - cxl_device_lock(&port->dev); 603 - if (list_empty(&port->dports)) { 604 - rc = -EINVAL; 605 - goto out_unlock; 606 - } 602 + device_lock_assert(&port->dev); 603 + 604 + if (list_empty(&port->dports)) 605 + return -EINVAL; 607 606 608 607 write_seqlock(&cxld->target_lock); 609 608 for (i = 0; i < cxld->nr_targets; i++) { ··· 615 616 cxld->target[i] = dport; 616 617 } 617 618 write_sequnlock(&cxld->target_lock); 618 - 619 - out_unlock: 620 - cxl_device_unlock(&port->dev); 621 619 622 620 return rc; 623 621 } ··· 717 721 EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, CXL); 718 722 719 723 /** 720 - * cxl_decoder_add - Add a decoder with targets 724 + * cxl_decoder_add_locked - Add a decoder with targets 721 725 * @cxld: The cxl decoder allocated by cxl_decoder_alloc() 722 726 * @target_map: A list of downstream ports that this decoder can direct memory 723 727 * traffic to. These numbers should correspond with the port number ··· 727 731 * is an endpoint device. A more awkward example is a hostbridge whose root 728 732 * ports get hot added (technically possible, though unlikely). 729 733 * 730 - * Context: Process context. Takes and releases the cxld's device lock. 734 + * This is the locked variant of cxl_decoder_add(). 735 + * 736 + * Context: Process context. Expects the device lock of the port that owns the 737 + * @cxld to be held. 731 738 * 732 739 * Return: Negative error code if the decoder wasn't properly configured; else 733 740 * returns 0. 734 741 */ 735 - int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) 742 + int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map) 736 743 { 737 744 struct cxl_port *port; 738 745 struct device *dev; ··· 768 769 cxld->platform_res.name = dev_name(dev); 769 770 770 771 return device_add(dev); 772 + } 773 + EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL); 774 + 775 + /** 776 + * cxl_decoder_add - Add a decoder with targets 777 + * @cxld: The cxl decoder allocated by cxl_decoder_alloc() 778 + * @target_map: A list of downstream ports that this decoder can direct memory 779 + * traffic to. These numbers should correspond with the port number 780 + * in the PCIe Link Capabilities structure. 781 + * 782 + * This is the unlocked variant of cxl_decoder_add_locked(). 783 + * See cxl_decoder_add_locked(). 784 + * 785 + * Context: Process context. Takes and releases the device lock of the port that 786 + * owns the @cxld. 787 + */ 788 + int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) 789 + { 790 + struct cxl_port *port; 791 + int rc; 792 + 793 + if (WARN_ON_ONCE(!cxld)) 794 + return -EINVAL; 795 + 796 + if (WARN_ON_ONCE(IS_ERR(cxld))) 797 + return PTR_ERR(cxld); 798 + 799 + port = to_cxl_port(cxld->dev.parent); 800 + 801 + cxl_device_lock(&port->dev); 802 + rc = cxl_decoder_add_locked(cxld, target_map); 803 + cxl_device_unlock(&port->dev); 804 + 805 + return rc; 771 806 } 772 807 EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL); 773 808
+2 -3
drivers/cxl/core/regs.c
··· 159 159 } 160 160 EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL); 161 161 162 - static void __iomem *devm_cxl_iomap_block(struct device *dev, 163 - resource_size_t addr, 164 - resource_size_t length) 162 + void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, 163 + resource_size_t length) 165 164 { 166 165 void __iomem *ret_val; 167 166 struct resource *res;
+27 -6
drivers/cxl/cxl.h
··· 17 17 * (port-driver, region-driver, nvdimm object-drivers... etc). 18 18 */ 19 19 20 + /* CXL 2.0 8.2.4 CXL Component Register Layout and Definition */ 21 + #define CXL_COMPONENT_REG_BLOCK_SIZE SZ_64K 22 + 20 23 /* CXL 2.0 8.2.5 CXL.cache and CXL.mem Registers*/ 21 24 #define CXL_CM_OFFSET 0x1000 22 25 #define CXL_CM_CAP_HDR_OFFSET 0x0 ··· 39 36 #define CXL_HDM_DECODER_CAP_OFFSET 0x0 40 37 #define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0) 41 38 #define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4) 42 - #define CXL_HDM_DECODER0_BASE_LOW_OFFSET 0x10 43 - #define CXL_HDM_DECODER0_BASE_HIGH_OFFSET 0x14 44 - #define CXL_HDM_DECODER0_SIZE_LOW_OFFSET 0x18 45 - #define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET 0x1c 46 - #define CXL_HDM_DECODER0_CTRL_OFFSET 0x20 39 + #define CXL_HDM_DECODER_INTERLEAVE_11_8 BIT(8) 40 + #define CXL_HDM_DECODER_INTERLEAVE_14_12 BIT(9) 41 + #define CXL_HDM_DECODER_CTRL_OFFSET 0x4 42 + #define CXL_HDM_DECODER_ENABLE BIT(1) 43 + #define CXL_HDM_DECODER0_BASE_LOW_OFFSET(i) (0x20 * (i) + 0x10) 44 + #define CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i) (0x20 * (i) + 0x14) 45 + #define CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i) (0x20 * (i) + 0x18) 46 + #define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i) (0x20 * (i) + 0x1c) 47 + #define CXL_HDM_DECODER0_CTRL_OFFSET(i) (0x20 * (i) + 0x20) 48 + #define CXL_HDM_DECODER0_CTRL_IG_MASK GENMASK(3, 0) 49 + #define CXL_HDM_DECODER0_CTRL_IW_MASK GENMASK(7, 4) 50 + #define CXL_HDM_DECODER0_CTRL_LOCK BIT(8) 51 + #define CXL_HDM_DECODER0_CTRL_COMMIT BIT(9) 52 + #define CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10) 53 + #define CXL_HDM_DECODER0_CTRL_TYPE BIT(12) 54 + #define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24) 55 + #define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28) 47 56 48 57 static inline int cxl_hdm_decoder_count(u32 cap_hdr) 49 58 { ··· 177 162 #define CXL_DECODER_F_TYPE2 BIT(2) 178 163 #define CXL_DECODER_F_TYPE3 BIT(3) 179 164 #define CXL_DECODER_F_LOCK BIT(4) 180 - #define CXL_DECODER_F_MASK GENMASK(4, 0) 165 + #define CXL_DECODER_F_ENABLE BIT(5) 166 + #define CXL_DECODER_F_MASK GENMASK(5, 0) 181 167 182 168 enum cxl_decoder_type { 183 169 CXL_DECODER_ACCELERATOR = 2, ··· 322 306 struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, 323 307 unsigned int nr_targets); 324 308 int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map); 309 + int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map); 325 310 int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld); 311 + struct cxl_hdm; 312 + struct cxl_hdm *devm_cxl_setup_hdm(struct device *host, struct cxl_port *port); 313 + int devm_cxl_enumerate_decoders(struct device *host, struct cxl_hdm *cxlhdm); 314 + int devm_cxl_add_passthrough_decoder(struct device *host, struct cxl_port *port); 326 315 327 316 extern struct bus_type cxl_bus_type; 328 317
+8
drivers/cxl/cxlmem.h
··· 264 264 struct cxl_dev_state *cxl_dev_state_create(struct device *dev); 265 265 void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds); 266 266 void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds); 267 + 268 + struct cxl_hdm { 269 + struct cxl_component_regs regs; 270 + unsigned int decoder_count; 271 + unsigned int target_count; 272 + unsigned int interleave_mask; 273 + struct cxl_port *port; 274 + }; 267 275 #endif /* __CXL_MEM_H__ */
+4
tools/testing/cxl/Kbuild
··· 5 5 ldflags-y += --wrap=acpi_pci_find_root 6 6 ldflags-y += --wrap=nvdimm_bus_register 7 7 ldflags-y += --wrap=devm_cxl_port_enumerate_dports 8 + ldflags-y += --wrap=devm_cxl_setup_hdm 9 + ldflags-y += --wrap=devm_cxl_add_passthrough_decoder 10 + ldflags-y += --wrap=devm_cxl_enumerate_decoders 8 11 9 12 DRIVERS := ../../../drivers 10 13 CXL_SRC := $(DRIVERS)/cxl ··· 34 31 cxl_core-y += $(CXL_CORE_SRC)/memdev.o 35 32 cxl_core-y += $(CXL_CORE_SRC)/mbox.o 36 33 cxl_core-y += $(CXL_CORE_SRC)/pci.o 34 + cxl_core-y += $(CXL_CORE_SRC)/hdm.o 37 35 cxl_core-y += config_check.o 38 36 39 37 obj-m += test/
+29
tools/testing/cxl/test/cxl.c
··· 8 8 #include <linux/acpi.h> 9 9 #include <linux/pci.h> 10 10 #include <linux/mm.h> 11 + #include <cxlmem.h> 11 12 #include "mock.h" 12 13 13 14 #define NR_CXL_HOST_BRIDGES 4 ··· 399 398 return &mock_pci_root[host_bridge_index(adev)]; 400 399 } 401 400 401 + static struct cxl_hdm *mock_cxl_setup_hdm(struct device *host, 402 + struct cxl_port *port) 403 + { 404 + struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL); 405 + 406 + if (!cxlhdm) 407 + return ERR_PTR(-ENOMEM); 408 + 409 + cxlhdm->port = port; 410 + return cxlhdm; 411 + } 412 + 413 + static int mock_cxl_add_passthrough_decoder(struct device *host, 414 + struct cxl_port *port) 415 + { 416 + dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n"); 417 + return -EOPNOTSUPP; 418 + } 419 + 420 + static int mock_cxl_enumerate_decoders(struct device *host, 421 + struct cxl_hdm *cxlhdm) 422 + { 423 + return 0; 424 + } 425 + 402 426 static int mock_cxl_port_enumerate_dports(struct device *host, 403 427 struct cxl_port *port) 404 428 { ··· 465 439 .acpi_evaluate_integer = mock_acpi_evaluate_integer, 466 440 .acpi_pci_find_root = mock_acpi_pci_find_root, 467 441 .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports, 442 + .devm_cxl_setup_hdm = mock_cxl_setup_hdm, 443 + .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder, 444 + .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders, 468 445 .list = LIST_HEAD_INIT(cxl_mock_ops.list), 469 446 }; 470 447
+50
tools/testing/cxl/test/mock.c
··· 131 131 } 132 132 EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); 133 133 134 + struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct device *host, 135 + struct cxl_port *port) 136 + { 137 + int index; 138 + struct cxl_hdm *cxlhdm; 139 + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 140 + 141 + if (ops && ops->is_mock_port(port->uport)) 142 + cxlhdm = ops->devm_cxl_setup_hdm(host, port); 143 + else 144 + cxlhdm = devm_cxl_setup_hdm(host, port); 145 + put_cxl_mock_ops(index); 146 + 147 + return cxlhdm; 148 + } 149 + EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL); 150 + 151 + int __wrap_devm_cxl_add_passthrough_decoder(struct device *host, 152 + struct cxl_port *port) 153 + { 154 + int rc, index; 155 + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 156 + 157 + if (ops && ops->is_mock_port(port->uport)) 158 + rc = ops->devm_cxl_add_passthrough_decoder(host, port); 159 + else 160 + rc = devm_cxl_add_passthrough_decoder(host, port); 161 + put_cxl_mock_ops(index); 162 + 163 + return rc; 164 + } 165 + EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, CXL); 166 + 167 + int __wrap_devm_cxl_enumerate_decoders(struct device *host, 168 + struct cxl_hdm *cxlhdm) 169 + { 170 + int rc, index; 171 + struct cxl_port *port = cxlhdm->port; 172 + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 173 + 174 + if (ops && ops->is_mock_port(port->uport)) 175 + rc = ops->devm_cxl_enumerate_decoders(host, cxlhdm); 176 + else 177 + rc = devm_cxl_enumerate_decoders(host, cxlhdm); 178 + put_cxl_mock_ops(index); 179 + 180 + return rc; 181 + } 182 + EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, CXL); 183 + 134 184 int __wrap_devm_cxl_port_enumerate_dports(struct device *host, 135 185 struct cxl_port *port) 136 186 {
+3
tools/testing/cxl/test/mock.h
··· 21 21 bool (*is_mock_dev)(struct device *dev); 22 22 int (*devm_cxl_port_enumerate_dports)(struct device *host, 23 23 struct cxl_port *port); 24 + struct cxl_hdm *(*devm_cxl_setup_hdm)(struct device *host, struct cxl_port *port); 25 + int (*devm_cxl_add_passthrough_decoder)(struct device *host, struct cxl_port *port); 26 + int (*devm_cxl_enumerate_decoders)(struct device *host, struct cxl_hdm *hdm); 24 27 }; 25 28 26 29 void register_cxl_mock_ops(struct cxl_mock_ops *ops);