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

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

Pull CXL (Compute Express Link) updates from Dan Williams:
"The highlight is initial support for CXL memory hotplug. The static
NUMA node (ACPI SRAT Physical Address to Proximity Domain) information
known to platform firmware is extended to support the potential
performance-class / memory-target nodes dynamically created from
available CXL memory device capacity.

New unit test infrastructure is added for validating health
information payloads.

Fixes to module reload stress and stack usage from exposure in -next
are included. A symbol rename and some other miscellaneous fixups are
included as well.

Summary:

- Rework ACPI sub-table infrastructure to optionally be used outside
of __init scenarios and use it for CEDT.CFMWS sub-table parsing.

- Add support for extending num_possible_nodes by the potential
hotplug CXL memory ranges

- Extend tools/testing/cxl with mock memory device health information

- Fix a module-reload workqueue race

- Fix excessive stack-frame usage

- Rename the driver context data structure from "cxl_mem" since that
name collides with a proposed driver name

- Use EXPORT_SYMBOL_NS_GPL instead of -DDEFAULT_SYMBOL_NAMESPACE at
build time"

* tag 'cxl-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
cxl/core: Remove cxld_const_init in cxl_decoder_alloc()
cxl/pmem: Fix module reload vs workqueue state
ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT
cxl/test: Mock acpi_table_parse_cedt()
cxl/acpi: Convert CFMWS parsing to ACPI sub-table helpers
ACPI: Add a context argument for table parsing handlers
ACPI: Teach ACPI table parsing about the CEDT header format
ACPI: Keep sub-table parsing infrastructure available for modules
tools/testing/cxl: add mock output for the GET_HEALTH_INFO command
cxl/memdev: Remove unused cxlmd field
cxl/core: Convert to EXPORT_SYMBOL_NS_GPL
cxl/memdev: Change cxl_mem to a more descriptive name
cxl/mbox: Remove bad comment
cxl/pmem: Fix reference counting for delayed work

+682 -508
+3
drivers/acpi/Kconfig
··· 59 59 config ACPI_CCA_REQUIRED 60 60 bool 61 61 62 + config ACPI_TABLE_LIB 63 + bool 64 + 62 65 config ACPI_DEBUGGER 63 66 bool "AML debugger interface" 64 67 select ACPI_DEBUG
+58 -1
drivers/acpi/numa/srat.c
··· 297 297 out_err: 298 298 return -EINVAL; 299 299 } 300 + 301 + static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, 302 + void *arg, const unsigned long table_end) 303 + { 304 + struct acpi_cedt_cfmws *cfmws; 305 + int *fake_pxm = arg; 306 + u64 start, end; 307 + int node; 308 + 309 + cfmws = (struct acpi_cedt_cfmws *)header; 310 + start = cfmws->base_hpa; 311 + end = cfmws->base_hpa + cfmws->window_size; 312 + 313 + /* Skip if the SRAT already described the NUMA details for this HPA */ 314 + node = phys_to_target_node(start); 315 + if (node != NUMA_NO_NODE) 316 + return 0; 317 + 318 + node = acpi_map_pxm_to_node(*fake_pxm); 319 + 320 + if (node == NUMA_NO_NODE) { 321 + pr_err("ACPI NUMA: Too many proximity domains while processing CFMWS.\n"); 322 + return -EINVAL; 323 + } 324 + 325 + if (numa_add_memblk(node, start, end) < 0) { 326 + /* CXL driver must handle the NUMA_NO_NODE case */ 327 + pr_warn("ACPI NUMA: Failed to add memblk for CFMWS node %d [mem %#llx-%#llx]\n", 328 + node, start, end); 329 + } 330 + 331 + /* Set the next available fake_pxm value */ 332 + (*fake_pxm)++; 333 + return 0; 334 + } 335 + #else 336 + static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, 337 + void *arg, const unsigned long table_end) 338 + { 339 + return 0; 340 + } 300 341 #endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ 301 342 302 343 static int __init acpi_parse_slit(struct acpi_table_header *table) ··· 482 441 483 442 int __init acpi_numa_init(void) 484 443 { 485 - int cnt = 0; 444 + int i, fake_pxm, cnt = 0; 486 445 487 446 if (acpi_disabled) 488 447 return -EINVAL; ··· 517 476 518 477 /* SLIT: System Locality Information Table */ 519 478 acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); 479 + 480 + /* 481 + * CXL Fixed Memory Window Structures (CFMWS) must be parsed 482 + * after the SRAT. Create NUMA Nodes for CXL memory ranges that 483 + * are defined in the CFMWS and not already defined in the SRAT. 484 + * Initialize a fake_pxm as the first available PXM to emulate. 485 + */ 486 + 487 + /* fake_pxm is the next unused PXM value after SRAT parsing */ 488 + for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) { 489 + if (node_to_pxm_map[i] > fake_pxm) 490 + fake_pxm = node_to_pxm_map[i]; 491 + } 492 + fake_pxm++; 493 + acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, acpi_parse_cfmws, 494 + &fake_pxm); 520 495 521 496 if (cnt < 0) 522 497 return cnt;
+66 -21
drivers/acpi/tables.c
··· 35 35 36 36 static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; 37 37 38 - static int acpi_apic_instance __initdata; 38 + static int acpi_apic_instance __initdata_or_acpilib; 39 39 40 40 enum acpi_subtable_type { 41 41 ACPI_SUBTABLE_COMMON, 42 42 ACPI_SUBTABLE_HMAT, 43 43 ACPI_SUBTABLE_PRMT, 44 + ACPI_SUBTABLE_CEDT, 44 45 }; 45 46 46 47 struct acpi_subtable_entry { ··· 53 52 * Disable table checksum verification for the early stage due to the size 54 53 * limitation of the current x86 early mapping implementation. 55 54 */ 56 - static bool acpi_verify_table_checksum __initdata = false; 55 + static bool acpi_verify_table_checksum __initdata_or_acpilib = false; 57 56 58 57 void acpi_table_print_madt_entry(struct acpi_subtable_header *header) 59 58 { ··· 217 216 } 218 217 } 219 218 220 - static unsigned long __init 219 + static unsigned long __init_or_acpilib 221 220 acpi_get_entry_type(struct acpi_subtable_entry *entry) 222 221 { 223 222 switch (entry->type) { ··· 227 226 return entry->hdr->hmat.type; 228 227 case ACPI_SUBTABLE_PRMT: 229 228 return 0; 229 + case ACPI_SUBTABLE_CEDT: 230 + return entry->hdr->cedt.type; 230 231 } 231 232 return 0; 232 233 } 233 234 234 - static unsigned long __init 235 + static unsigned long __init_or_acpilib 235 236 acpi_get_entry_length(struct acpi_subtable_entry *entry) 236 237 { 237 238 switch (entry->type) { ··· 243 240 return entry->hdr->hmat.length; 244 241 case ACPI_SUBTABLE_PRMT: 245 242 return entry->hdr->prmt.length; 243 + case ACPI_SUBTABLE_CEDT: 244 + return entry->hdr->cedt.length; 246 245 } 247 246 return 0; 248 247 } 249 248 250 - static unsigned long __init 249 + static unsigned long __init_or_acpilib 251 250 acpi_get_subtable_header_length(struct acpi_subtable_entry *entry) 252 251 { 253 252 switch (entry->type) { ··· 259 254 return sizeof(entry->hdr->hmat); 260 255 case ACPI_SUBTABLE_PRMT: 261 256 return sizeof(entry->hdr->prmt); 257 + case ACPI_SUBTABLE_CEDT: 258 + return sizeof(entry->hdr->cedt); 262 259 } 263 260 return 0; 264 261 } 265 262 266 - static enum acpi_subtable_type __init 263 + static enum acpi_subtable_type __init_or_acpilib 267 264 acpi_get_subtable_type(char *id) 268 265 { 269 266 if (strncmp(id, ACPI_SIG_HMAT, 4) == 0) 270 267 return ACPI_SUBTABLE_HMAT; 271 268 if (strncmp(id, ACPI_SIG_PRMT, 4) == 0) 272 269 return ACPI_SUBTABLE_PRMT; 270 + if (strncmp(id, ACPI_SIG_CEDT, 4) == 0) 271 + return ACPI_SUBTABLE_CEDT; 273 272 return ACPI_SUBTABLE_COMMON; 273 + } 274 + 275 + static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc) 276 + { 277 + return proc->handler || proc->handler_arg; 278 + } 279 + 280 + static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc, 281 + union acpi_subtable_headers *hdr, 282 + unsigned long end) 283 + { 284 + if (proc->handler) 285 + return proc->handler(hdr, end); 286 + if (proc->handler_arg) 287 + return proc->handler_arg(hdr, proc->arg, end); 288 + return -EINVAL; 274 289 } 275 290 276 291 /** ··· 316 291 * On success returns sum of all matching entries for all proc handlers. 317 292 * Otherwise, -ENODEV or -EINVAL is returned. 318 293 */ 319 - static int __init acpi_parse_entries_array(char *id, unsigned long table_size, 320 - struct acpi_table_header *table_header, 321 - struct acpi_subtable_proc *proc, int proc_num, 322 - unsigned int max_entries) 294 + static int __init_or_acpilib acpi_parse_entries_array( 295 + char *id, unsigned long table_size, 296 + struct acpi_table_header *table_header, struct acpi_subtable_proc *proc, 297 + int proc_num, unsigned int max_entries) 323 298 { 324 299 struct acpi_subtable_entry entry; 325 300 unsigned long table_end, subtable_len, entry_len; ··· 343 318 for (i = 0; i < proc_num; i++) { 344 319 if (acpi_get_entry_type(&entry) != proc[i].id) 345 320 continue; 346 - if (!proc[i].handler || 347 - (!errs && proc[i].handler(entry.hdr, table_end))) { 321 + if (!has_handler(&proc[i]) || 322 + (!errs && 323 + call_handler(&proc[i], entry.hdr, table_end))) { 348 324 errs++; 349 325 continue; 350 326 } ··· 378 352 return errs ? -EINVAL : count; 379 353 } 380 354 381 - int __init acpi_table_parse_entries_array(char *id, 382 - unsigned long table_size, 383 - struct acpi_subtable_proc *proc, int proc_num, 384 - unsigned int max_entries) 355 + int __init_or_acpilib acpi_table_parse_entries_array( 356 + char *id, unsigned long table_size, struct acpi_subtable_proc *proc, 357 + int proc_num, unsigned int max_entries) 385 358 { 386 359 struct acpi_table_header *table_header = NULL; 387 360 int count; ··· 411 386 return count; 412 387 } 413 388 414 - int __init acpi_table_parse_entries(char *id, 415 - unsigned long table_size, 416 - int entry_id, 417 - acpi_tbl_entry_handler handler, 418 - unsigned int max_entries) 389 + static int __init_or_acpilib __acpi_table_parse_entries( 390 + char *id, unsigned long table_size, int entry_id, 391 + acpi_tbl_entry_handler handler, acpi_tbl_entry_handler_arg handler_arg, 392 + void *arg, unsigned int max_entries) 419 393 { 420 394 struct acpi_subtable_proc proc = { 421 395 .id = entry_id, 422 396 .handler = handler, 397 + .handler_arg = handler_arg, 398 + .arg = arg, 423 399 }; 424 400 425 401 return acpi_table_parse_entries_array(id, table_size, &proc, 1, 426 402 max_entries); 403 + } 404 + 405 + int __init_or_acpilib 406 + acpi_table_parse_cedt(enum acpi_cedt_type id, 407 + acpi_tbl_entry_handler_arg handler_arg, void *arg) 408 + { 409 + return __acpi_table_parse_entries(ACPI_SIG_CEDT, 410 + sizeof(struct acpi_table_cedt), id, 411 + NULL, handler_arg, arg, 0); 412 + } 413 + EXPORT_SYMBOL_ACPI_LIB(acpi_table_parse_cedt); 414 + 415 + int __init acpi_table_parse_entries(char *id, unsigned long table_size, 416 + int entry_id, 417 + acpi_tbl_entry_handler handler, 418 + unsigned int max_entries) 419 + { 420 + return __acpi_table_parse_entries(id, table_size, entry_id, handler, 421 + NULL, NULL, max_entries); 427 422 } 428 423 429 424 int __init acpi_table_parse_madt(enum acpi_madt_type id,
+1
drivers/cxl/Kconfig
··· 51 51 tristate "CXL ACPI: Platform Support" 52 52 depends on ACPI 53 53 default CXL_BUS 54 + select ACPI_TABLE_LIB 54 55 help 55 56 Enable support for host managed device memory (HDM) resources 56 57 published by a platform's ACPI CXL memory layout description. See
+94 -151
drivers/cxl/acpi.c
··· 8 8 #include <linux/pci.h> 9 9 #include "cxl.h" 10 10 11 - static struct acpi_table_header *acpi_cedt; 12 - 13 11 /* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */ 14 12 #define CFMWS_INTERLEAVE_WAYS(x) (1 << (x)->interleave_ways) 15 13 #define CFMWS_INTERLEAVE_GRANULARITY(x) ((x)->granularity + 8) ··· 72 74 return 0; 73 75 } 74 76 75 - static void cxl_add_cfmws_decoders(struct device *dev, 76 - struct cxl_port *root_port) 77 + struct cxl_cfmws_context { 78 + struct device *dev; 79 + struct cxl_port *root_port; 80 + }; 81 + 82 + static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, 83 + const unsigned long end) 77 84 { 78 85 int target_map[CXL_DECODER_MAX_INTERLEAVE]; 86 + struct cxl_cfmws_context *ctx = arg; 87 + struct cxl_port *root_port = ctx->root_port; 88 + struct device *dev = ctx->dev; 79 89 struct acpi_cedt_cfmws *cfmws; 80 90 struct cxl_decoder *cxld; 81 - acpi_size len, cur = 0; 82 - void *cedt_subtable; 83 - int rc; 91 + int rc, i; 84 92 85 - len = acpi_cedt->length - sizeof(*acpi_cedt); 86 - cedt_subtable = acpi_cedt + 1; 93 + cfmws = (struct acpi_cedt_cfmws *) header; 87 94 88 - while (cur < len) { 89 - struct acpi_cedt_header *c = cedt_subtable + cur; 90 - int i; 91 - 92 - if (c->type != ACPI_CEDT_TYPE_CFMWS) { 93 - cur += c->length; 94 - continue; 95 - } 96 - 97 - cfmws = cedt_subtable + cur; 98 - 99 - if (cfmws->header.length < sizeof(*cfmws)) { 100 - dev_warn_once(dev, 101 - "CFMWS entry skipped:invalid length:%u\n", 102 - cfmws->header.length); 103 - cur += c->length; 104 - continue; 105 - } 106 - 107 - rc = cxl_acpi_cfmws_verify(dev, cfmws); 108 - if (rc) { 109 - dev_err(dev, "CFMWS range %#llx-%#llx not registered\n", 110 - cfmws->base_hpa, cfmws->base_hpa + 111 - cfmws->window_size - 1); 112 - cur += c->length; 113 - continue; 114 - } 115 - 116 - for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) 117 - target_map[i] = cfmws->interleave_targets[i]; 118 - 119 - cxld = cxl_decoder_alloc(root_port, 120 - CFMWS_INTERLEAVE_WAYS(cfmws)); 121 - if (IS_ERR(cxld)) 122 - goto next; 123 - 124 - cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); 125 - cxld->target_type = CXL_DECODER_EXPANDER; 126 - cxld->range = (struct range) { 127 - .start = cfmws->base_hpa, 128 - .end = cfmws->base_hpa + cfmws->window_size - 1, 129 - }; 130 - cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws); 131 - cxld->interleave_granularity = 132 - CFMWS_INTERLEAVE_GRANULARITY(cfmws); 133 - 134 - rc = cxl_decoder_add(cxld, target_map); 135 - if (rc) 136 - put_device(&cxld->dev); 137 - else 138 - rc = cxl_decoder_autoremove(dev, cxld); 139 - if (rc) { 140 - dev_err(dev, "Failed to add decoder for %#llx-%#llx\n", 141 - cfmws->base_hpa, cfmws->base_hpa + 142 - cfmws->window_size - 1); 143 - goto next; 144 - } 145 - dev_dbg(dev, "add: %s range %#llx-%#llx\n", 146 - dev_name(&cxld->dev), cfmws->base_hpa, 95 + rc = cxl_acpi_cfmws_verify(dev, cfmws); 96 + if (rc) { 97 + dev_err(dev, "CFMWS range %#llx-%#llx not registered\n", 98 + cfmws->base_hpa, 147 99 cfmws->base_hpa + cfmws->window_size - 1); 148 - next: 149 - cur += c->length; 150 - } 151 - } 152 - 153 - static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid) 154 - { 155 - struct acpi_cedt_chbs *chbs, *chbs_match = NULL; 156 - acpi_size len, cur = 0; 157 - void *cedt_subtable; 158 - 159 - len = acpi_cedt->length - sizeof(*acpi_cedt); 160 - cedt_subtable = acpi_cedt + 1; 161 - 162 - while (cur < len) { 163 - struct acpi_cedt_header *c = cedt_subtable + cur; 164 - 165 - if (c->type != ACPI_CEDT_TYPE_CHBS) { 166 - cur += c->length; 167 - continue; 168 - } 169 - 170 - chbs = cedt_subtable + cur; 171 - 172 - if (chbs->header.length < sizeof(*chbs)) { 173 - dev_warn_once(dev, 174 - "CHBS entry skipped: invalid length:%u\n", 175 - chbs->header.length); 176 - cur += c->length; 177 - continue; 178 - } 179 - 180 - if (chbs->uid != uid) { 181 - cur += c->length; 182 - continue; 183 - } 184 - 185 - if (chbs_match) { 186 - dev_warn_once(dev, 187 - "CHBS entry skipped: duplicate UID:%u\n", 188 - uid); 189 - cur += c->length; 190 - continue; 191 - } 192 - 193 - chbs_match = chbs; 194 - cur += c->length; 100 + return 0; 195 101 } 196 102 197 - return chbs_match ? chbs_match : ERR_PTR(-ENODEV); 198 - } 103 + for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) 104 + target_map[i] = cfmws->interleave_targets[i]; 199 105 200 - static resource_size_t get_chbcr(struct acpi_cedt_chbs *chbs) 201 - { 202 - return IS_ERR(chbs) ? CXL_RESOURCE_NONE : chbs->base; 106 + cxld = cxl_decoder_alloc(root_port, CFMWS_INTERLEAVE_WAYS(cfmws)); 107 + if (IS_ERR(cxld)) 108 + return 0; 109 + 110 + cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); 111 + cxld->target_type = CXL_DECODER_EXPANDER; 112 + cxld->range = (struct range){ 113 + .start = cfmws->base_hpa, 114 + .end = cfmws->base_hpa + cfmws->window_size - 1, 115 + }; 116 + cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws); 117 + cxld->interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY(cfmws); 118 + 119 + rc = cxl_decoder_add(cxld, target_map); 120 + if (rc) 121 + put_device(&cxld->dev); 122 + else 123 + rc = cxl_decoder_autoremove(dev, cxld); 124 + if (rc) { 125 + dev_err(dev, "Failed to add decoder for %#llx-%#llx\n", 126 + cfmws->base_hpa, 127 + cfmws->base_hpa + cfmws->window_size - 1); 128 + return 0; 129 + } 130 + dev_dbg(dev, "add: %s node: %d range %#llx-%#llx\n", 131 + dev_name(&cxld->dev), phys_to_target_node(cxld->range.start), 132 + cfmws->base_hpa, cfmws->base_hpa + cfmws->window_size - 1); 133 + 134 + return 0; 203 135 } 204 136 205 137 __mock int match_add_root_ports(struct pci_dev *pdev, void *data) ··· 283 355 return rc; 284 356 } 285 357 358 + struct cxl_chbs_context { 359 + struct device *dev; 360 + unsigned long long uid; 361 + resource_size_t chbcr; 362 + }; 363 + 364 + static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg, 365 + const unsigned long end) 366 + { 367 + struct cxl_chbs_context *ctx = arg; 368 + struct acpi_cedt_chbs *chbs; 369 + 370 + if (ctx->chbcr) 371 + return 0; 372 + 373 + chbs = (struct acpi_cedt_chbs *) header; 374 + 375 + if (ctx->uid != chbs->uid) 376 + return 0; 377 + ctx->chbcr = chbs->base; 378 + 379 + return 0; 380 + } 381 + 286 382 static int add_host_bridge_dport(struct device *match, void *arg) 287 383 { 288 384 int rc; 289 385 acpi_status status; 290 386 unsigned long long uid; 291 - struct acpi_cedt_chbs *chbs; 387 + struct cxl_chbs_context ctx; 292 388 struct cxl_port *root_port = arg; 293 389 struct device *host = root_port->dev.parent; 294 390 struct acpi_device *bridge = to_cxl_host_bridge(host, match); ··· 328 376 return -ENODEV; 329 377 } 330 378 331 - chbs = cxl_acpi_match_chbs(host, uid); 332 - if (IS_ERR(chbs)) { 379 + ctx = (struct cxl_chbs_context) { 380 + .dev = host, 381 + .uid = uid, 382 + }; 383 + acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbcr, &ctx); 384 + 385 + if (ctx.chbcr == 0) { 333 386 dev_warn(host, "No CHBS found for Host Bridge: %s\n", 334 387 dev_name(match)); 335 388 return 0; 336 389 } 337 390 338 - rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs)); 391 + rc = cxl_add_dport(root_port, match, uid, ctx.chbcr); 339 392 if (rc) { 340 393 dev_err(host, "failed to add downstream port: %s\n", 341 394 dev_name(match)); ··· 374 417 return 1; 375 418 } 376 419 377 - static u32 cedt_instance(struct platform_device *pdev) 378 - { 379 - const bool *native_acpi0017 = acpi_device_get_match_data(&pdev->dev); 380 - 381 - if (native_acpi0017 && *native_acpi0017) 382 - return 0; 383 - 384 - /* for cxl_test request a non-canonical instance */ 385 - return U32_MAX; 386 - } 387 - 388 420 static int cxl_acpi_probe(struct platform_device *pdev) 389 421 { 390 422 int rc; 391 - acpi_status status; 392 423 struct cxl_port *root_port; 393 424 struct device *host = &pdev->dev; 394 425 struct acpi_device *adev = ACPI_COMPANION(host); 426 + struct cxl_cfmws_context ctx; 395 427 396 428 root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL); 397 429 if (IS_ERR(root_port)) 398 430 return PTR_ERR(root_port); 399 431 dev_dbg(host, "add: %s\n", dev_name(&root_port->dev)); 400 432 401 - status = acpi_get_table(ACPI_SIG_CEDT, cedt_instance(pdev), &acpi_cedt); 402 - if (ACPI_FAILURE(status)) 403 - return -ENXIO; 404 - 405 433 rc = bus_for_each_dev(adev->dev.bus, NULL, root_port, 406 434 add_host_bridge_dport); 407 - if (rc) 408 - goto out; 435 + if (rc < 0) 436 + return rc; 409 437 410 - cxl_add_cfmws_decoders(host, root_port); 438 + ctx = (struct cxl_cfmws_context) { 439 + .dev = host, 440 + .root_port = root_port, 441 + }; 442 + acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx); 411 443 412 444 /* 413 445 * Root level scanned with host-bridge as dports, now scan host-bridges ··· 404 458 */ 405 459 rc = bus_for_each_dev(adev->dev.bus, NULL, root_port, 406 460 add_host_bridge_uport); 407 - if (rc) 408 - goto out; 461 + if (rc < 0) 462 + return rc; 409 463 410 464 if (IS_ENABLED(CONFIG_CXL_PMEM)) 411 465 rc = device_for_each_child(&root_port->dev, root_port, 412 466 add_root_nvdimm_bridge); 413 - 414 - out: 415 - acpi_put_table(acpi_cedt); 416 467 if (rc < 0) 417 468 return rc; 469 + 418 470 return 0; 419 471 } 420 472 421 - static bool native_acpi0017 = true; 422 - 423 473 static const struct acpi_device_id cxl_acpi_ids[] = { 424 - { "ACPI0017", (unsigned long) &native_acpi0017 }, 474 + { "ACPI0017" }, 425 475 { }, 426 476 }; 427 477 MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids); ··· 433 491 module_platform_driver(cxl_acpi_driver); 434 492 MODULE_LICENSE("GPL v2"); 435 493 MODULE_IMPORT_NS(CXL); 494 + MODULE_IMPORT_NS(ACPI);
+1 -1
drivers/cxl/core/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_CXL_BUS) += cxl_core.o 3 3 4 - ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -I$(srctree)/drivers/cxl 4 + ccflags-y += -I$(srctree)/drivers/cxl 5 5 cxl_core-y := bus.o 6 6 cxl_core-y += pmem.o 7 7 cxl_core-y += regs.o
+12 -14
drivers/cxl/core/bus.c
··· 200 200 { 201 201 return dev->type == &cxl_decoder_root_type; 202 202 } 203 - EXPORT_SYMBOL_GPL(is_root_decoder); 203 + EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL); 204 204 205 205 struct cxl_decoder *to_cxl_decoder(struct device *dev) 206 206 { ··· 209 209 return NULL; 210 210 return container_of(dev, struct cxl_decoder, dev); 211 211 } 212 - EXPORT_SYMBOL_GPL(to_cxl_decoder); 212 + EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, CXL); 213 213 214 214 static void cxl_dport_release(struct cxl_dport *dport) 215 215 { ··· 376 376 put_device(dev); 377 377 return ERR_PTR(rc); 378 378 } 379 - EXPORT_SYMBOL_GPL(devm_cxl_add_port); 379 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL); 380 380 381 381 static struct cxl_dport *find_dport(struct cxl_port *port, int id) 382 382 { ··· 451 451 cxl_dport_release(dport); 452 452 return rc; 453 453 } 454 - EXPORT_SYMBOL_GPL(cxl_add_dport); 454 + EXPORT_SYMBOL_NS_GPL(cxl_add_dport, CXL); 455 455 456 456 static int decoder_populate_targets(struct cxl_decoder *cxld, 457 457 struct cxl_port *port, int *target_map) ··· 485 485 486 486 struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets) 487 487 { 488 - struct cxl_decoder *cxld, cxld_const_init = { 489 - .nr_targets = nr_targets, 490 - }; 488 + struct cxl_decoder *cxld; 491 489 struct device *dev; 492 490 int rc = 0; 493 491 ··· 495 497 cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL); 496 498 if (!cxld) 497 499 return ERR_PTR(-ENOMEM); 498 - memcpy(cxld, &cxld_const_init, sizeof(cxld_const_init)); 499 500 500 501 rc = ida_alloc(&port->decoder_ida, GFP_KERNEL); 501 502 if (rc < 0) 502 503 goto err; 503 504 504 505 cxld->id = rc; 506 + cxld->nr_targets = nr_targets; 505 507 dev = &cxld->dev; 506 508 device_initialize(dev); 507 509 device_set_pm_not_required(dev); ··· 519 521 kfree(cxld); 520 522 return ERR_PTR(rc); 521 523 } 522 - EXPORT_SYMBOL_GPL(cxl_decoder_alloc); 524 + EXPORT_SYMBOL_NS_GPL(cxl_decoder_alloc, CXL); 523 525 524 526 int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) 525 527 { ··· 548 550 549 551 return device_add(dev); 550 552 } 551 - EXPORT_SYMBOL_GPL(cxl_decoder_add); 553 + EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL); 552 554 553 555 static void cxld_unregister(void *dev) 554 556 { ··· 559 561 { 560 562 return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev); 561 563 } 562 - EXPORT_SYMBOL_GPL(cxl_decoder_autoremove); 564 + EXPORT_SYMBOL_NS_GPL(cxl_decoder_autoremove, CXL); 563 565 564 566 /** 565 567 * __cxl_driver_register - register a driver for the cxl bus ··· 592 594 593 595 return driver_register(&cxl_drv->drv); 594 596 } 595 - EXPORT_SYMBOL_GPL(__cxl_driver_register); 597 + EXPORT_SYMBOL_NS_GPL(__cxl_driver_register, CXL); 596 598 597 599 void cxl_driver_unregister(struct cxl_driver *cxl_drv) 598 600 { 599 601 driver_unregister(&cxl_drv->drv); 600 602 } 601 - EXPORT_SYMBOL_GPL(cxl_driver_unregister); 603 + EXPORT_SYMBOL_NS_GPL(cxl_driver_unregister, CXL); 602 604 603 605 static int cxl_device_id(struct device *dev) 604 606 { ··· 640 642 .probe = cxl_bus_probe, 641 643 .remove = cxl_bus_remove, 642 644 }; 643 - EXPORT_SYMBOL_GPL(cxl_bus_type); 645 + EXPORT_SYMBOL_NS_GPL(cxl_bus_type, CXL); 644 646 645 647 static __init int cxl_core_init(void) 646 648 {
+92 -94
drivers/cxl/core/mbox.c
··· 128 128 } 129 129 130 130 /** 131 - * cxl_mem_mbox_send_cmd() - Send a mailbox command to a memory device. 132 - * @cxlm: The CXL memory device to communicate with. 131 + * cxl_mbox_send_cmd() - Send a mailbox command to a device. 132 + * @cxlds: The device data for the operation 133 133 * @opcode: Opcode for the mailbox command. 134 134 * @in: The input payload for the mailbox command. 135 135 * @in_size: The length of the input payload ··· 148 148 * Mailbox commands may execute successfully yet the device itself reported an 149 149 * error. While this distinction can be useful for commands from userspace, the 150 150 * kernel will only be able to use results when both are successful. 151 - * 152 - * See __cxl_mem_mbox_send_cmd() 153 151 */ 154 - int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, 155 - size_t in_size, void *out, size_t out_size) 152 + int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in, 153 + size_t in_size, void *out, size_t out_size) 156 154 { 157 155 const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); 158 156 struct cxl_mbox_cmd mbox_cmd = { ··· 162 164 }; 163 165 int rc; 164 166 165 - if (out_size > cxlm->payload_size) 167 + if (out_size > cxlds->payload_size) 166 168 return -E2BIG; 167 169 168 - rc = cxlm->mbox_send(cxlm, &mbox_cmd); 170 + rc = cxlds->mbox_send(cxlds, &mbox_cmd); 169 171 if (rc) 170 172 return rc; 171 173 ··· 182 184 183 185 return 0; 184 186 } 185 - EXPORT_SYMBOL_GPL(cxl_mem_mbox_send_cmd); 187 + EXPORT_SYMBOL_NS_GPL(cxl_mbox_send_cmd, CXL); 186 188 187 189 static bool cxl_mem_raw_command_allowed(u16 opcode) 188 190 { ··· 209 211 210 212 /** 211 213 * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. 212 - * @cxlm: &struct cxl_mem device whose mailbox will be used. 214 + * @cxlds: The device data for the operation 213 215 * @send_cmd: &struct cxl_send_command copied in from userspace. 214 216 * @out_cmd: Sanitized and populated &struct cxl_mem_command. 215 217 * ··· 226 228 * 227 229 * See handle_mailbox_cmd_from_user() 228 230 */ 229 - static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, 231 + static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds, 230 232 const struct cxl_send_command *send_cmd, 231 233 struct cxl_mem_command *out_cmd) 232 234 { ··· 241 243 * supports, but output can be arbitrarily large (simply write out as 242 244 * much data as the hardware provides). 243 245 */ 244 - if (send_cmd->in.size > cxlm->payload_size) 246 + if (send_cmd->in.size > cxlds->payload_size) 245 247 return -EINVAL; 246 248 247 249 /* ··· 267 269 * gets passed along without further checking, so it must be 268 270 * validated here. 269 271 */ 270 - if (send_cmd->out.size > cxlm->payload_size) 272 + if (send_cmd->out.size > cxlds->payload_size) 271 273 return -EINVAL; 272 274 273 275 if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) ··· 292 294 info = &c->info; 293 295 294 296 /* Check that the command is enabled for hardware */ 295 - if (!test_bit(info->id, cxlm->enabled_cmds)) 297 + if (!test_bit(info->id, cxlds->enabled_cmds)) 296 298 return -ENOTTY; 297 299 298 300 /* Check that the command is not claimed for exclusive kernel use */ 299 - if (test_bit(info->id, cxlm->exclusive_cmds)) 301 + if (test_bit(info->id, cxlds->exclusive_cmds)) 300 302 return -EBUSY; 301 303 302 304 /* Check the input buffer is the expected size */ ··· 354 356 355 357 /** 356 358 * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. 357 - * @cxlm: The CXL memory device to communicate with. 359 + * @cxlds: The device data for the operation 358 360 * @cmd: The validated command. 359 361 * @in_payload: Pointer to userspace's input payload. 360 362 * @out_payload: Pointer to userspace's output payload. ··· 377 379 * 378 380 * See cxl_send_cmd(). 379 381 */ 380 - static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, 382 + static int handle_mailbox_cmd_from_user(struct cxl_dev_state *cxlds, 381 383 const struct cxl_mem_command *cmd, 382 384 u64 in_payload, u64 out_payload, 383 385 s32 *size_out, u32 *retval) 384 386 { 385 - struct device *dev = cxlm->dev; 387 + struct device *dev = cxlds->dev; 386 388 struct cxl_mbox_cmd mbox_cmd = { 387 389 .opcode = cmd->opcode, 388 390 .size_in = cmd->info.size_in, ··· 415 417 dev_WARN_ONCE(dev, cmd->info.id == CXL_MEM_COMMAND_ID_RAW, 416 418 "raw command path used\n"); 417 419 418 - rc = cxlm->mbox_send(cxlm, &mbox_cmd); 420 + rc = cxlds->mbox_send(cxlds, &mbox_cmd); 419 421 if (rc) 420 422 goto out; 421 423 ··· 445 447 446 448 int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) 447 449 { 448 - struct cxl_mem *cxlm = cxlmd->cxlm; 450 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 449 451 struct device *dev = &cxlmd->dev; 450 452 struct cxl_send_command send; 451 453 struct cxl_mem_command c; ··· 456 458 if (copy_from_user(&send, s, sizeof(send))) 457 459 return -EFAULT; 458 460 459 - rc = cxl_validate_cmd_from_user(cxlmd->cxlm, &send, &c); 461 + rc = cxl_validate_cmd_from_user(cxlmd->cxlds, &send, &c); 460 462 if (rc) 461 463 return rc; 462 464 463 465 /* Prepare to handle a full payload for variable sized output */ 464 466 if (c.info.size_out < 0) 465 - c.info.size_out = cxlm->payload_size; 467 + c.info.size_out = cxlds->payload_size; 466 468 467 - rc = handle_mailbox_cmd_from_user(cxlm, &c, send.in.payload, 469 + rc = handle_mailbox_cmd_from_user(cxlds, &c, send.in.payload, 468 470 send.out.payload, &send.out.size, 469 471 &send.retval); 470 472 if (rc) ··· 476 478 return 0; 477 479 } 478 480 479 - static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) 481 + static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8 *out) 480 482 { 481 483 u32 remaining = size; 482 484 u32 offset = 0; 483 485 484 486 while (remaining) { 485 - u32 xfer_size = min_t(u32, remaining, cxlm->payload_size); 487 + u32 xfer_size = min_t(u32, remaining, cxlds->payload_size); 486 488 struct cxl_mbox_get_log log = { 487 489 .uuid = *uuid, 488 490 .offset = cpu_to_le32(offset), ··· 490 492 }; 491 493 int rc; 492 494 493 - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LOG, &log, 494 - sizeof(log), out, xfer_size); 495 + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LOG, &log, sizeof(log), 496 + out, xfer_size); 495 497 if (rc < 0) 496 498 return rc; 497 499 ··· 505 507 506 508 /** 507 509 * cxl_walk_cel() - Walk through the Command Effects Log. 508 - * @cxlm: Device. 510 + * @cxlds: The device data for the operation 509 511 * @size: Length of the Command Effects Log. 510 512 * @cel: CEL 511 513 * 512 514 * Iterate over each entry in the CEL and determine if the driver supports the 513 515 * command. If so, the command is enabled for the device and can be used later. 514 516 */ 515 - static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) 517 + static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel) 516 518 { 517 519 struct cxl_cel_entry *cel_entry; 518 520 const int cel_entries = size / sizeof(*cel_entry); ··· 525 527 struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); 526 528 527 529 if (!cmd) { 528 - dev_dbg(cxlm->dev, 530 + dev_dbg(cxlds->dev, 529 531 "Opcode 0x%04x unsupported by driver", opcode); 530 532 continue; 531 533 } 532 534 533 - set_bit(cmd->info.id, cxlm->enabled_cmds); 535 + set_bit(cmd->info.id, cxlds->enabled_cmds); 534 536 } 535 537 } 536 538 537 - static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) 539 + static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_dev_state *cxlds) 538 540 { 539 541 struct cxl_mbox_get_supported_logs *ret; 540 542 int rc; 541 543 542 - ret = kvmalloc(cxlm->payload_size, GFP_KERNEL); 544 + ret = kvmalloc(cxlds->payload_size, GFP_KERNEL); 543 545 if (!ret) 544 546 return ERR_PTR(-ENOMEM); 545 547 546 - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, 547 - 0, ret, cxlm->payload_size); 548 + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, 0, ret, 549 + cxlds->payload_size); 548 550 if (rc < 0) { 549 551 kvfree(ret); 550 552 return ERR_PTR(rc); ··· 565 567 }; 566 568 567 569 /** 568 - * cxl_mem_enumerate_cmds() - Enumerate commands for a device. 569 - * @cxlm: The device. 570 + * cxl_enumerate_cmds() - Enumerate commands for a device. 571 + * @cxlds: The device data for the operation 570 572 * 571 573 * Returns 0 if enumerate completed successfully. 572 574 * 573 575 * CXL devices have optional support for certain commands. This function will 574 576 * determine the set of supported commands for the hardware and update the 575 - * enabled_cmds bitmap in the @cxlm. 577 + * enabled_cmds bitmap in the @cxlds. 576 578 */ 577 - int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) 579 + int cxl_enumerate_cmds(struct cxl_dev_state *cxlds) 578 580 { 579 581 struct cxl_mbox_get_supported_logs *gsl; 580 - struct device *dev = cxlm->dev; 582 + struct device *dev = cxlds->dev; 581 583 struct cxl_mem_command *cmd; 582 584 int i, rc; 583 585 584 - gsl = cxl_get_gsl(cxlm); 586 + gsl = cxl_get_gsl(cxlds); 585 587 if (IS_ERR(gsl)) 586 588 return PTR_ERR(gsl); 587 589 ··· 602 604 goto out; 603 605 } 604 606 605 - rc = cxl_xfer_log(cxlm, &uuid, size, log); 607 + rc = cxl_xfer_log(cxlds, &uuid, size, log); 606 608 if (rc) { 607 609 kvfree(log); 608 610 goto out; 609 611 } 610 612 611 - cxl_walk_cel(cxlm, size, log); 613 + cxl_walk_cel(cxlds, size, log); 612 614 kvfree(log); 613 615 614 616 /* In case CEL was bogus, enable some default commands. */ 615 617 cxl_for_each_cmd(cmd) 616 618 if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE) 617 - set_bit(cmd->info.id, cxlm->enabled_cmds); 619 + set_bit(cmd->info.id, cxlds->enabled_cmds); 618 620 619 621 /* Found the required CEL */ 620 622 rc = 0; ··· 624 626 kvfree(gsl); 625 627 return rc; 626 628 } 627 - EXPORT_SYMBOL_GPL(cxl_mem_enumerate_cmds); 629 + EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL); 628 630 629 631 /** 630 632 * cxl_mem_get_partition_info - Get partition info 631 - * @cxlm: cxl_mem instance to update partition info 633 + * @cxlds: The device data for the operation 632 634 * 633 635 * Retrieve the current partition info for the device specified. The active 634 636 * values are the current capacity in bytes. If not 0, the 'next' values are ··· 638 640 * 639 641 * See CXL @8.2.9.5.2.1 Get Partition Info 640 642 */ 641 - static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) 643 + static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds) 642 644 { 643 645 struct cxl_mbox_get_partition_info { 644 646 __le64 active_volatile_cap; ··· 648 650 } __packed pi; 649 651 int rc; 650 652 651 - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_PARTITION_INFO, 652 - NULL, 0, &pi, sizeof(pi)); 653 + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_PARTITION_INFO, NULL, 0, 654 + &pi, sizeof(pi)); 653 655 654 656 if (rc) 655 657 return rc; 656 658 657 - cxlm->active_volatile_bytes = 659 + cxlds->active_volatile_bytes = 658 660 le64_to_cpu(pi.active_volatile_cap) * CXL_CAPACITY_MULTIPLIER; 659 - cxlm->active_persistent_bytes = 661 + cxlds->active_persistent_bytes = 660 662 le64_to_cpu(pi.active_persistent_cap) * CXL_CAPACITY_MULTIPLIER; 661 - cxlm->next_volatile_bytes = 663 + cxlds->next_volatile_bytes = 662 664 le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; 663 - cxlm->next_persistent_bytes = 665 + cxlds->next_persistent_bytes = 664 666 le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; 665 667 666 668 return 0; 667 669 } 668 670 669 671 /** 670 - * cxl_mem_identify() - Send the IDENTIFY command to the device. 671 - * @cxlm: The device to identify. 672 + * cxl_dev_state_identify() - Send the IDENTIFY command to the device. 673 + * @cxlds: The device data for the operation 672 674 * 673 675 * Return: 0 if identify was executed successfully. 674 676 * 675 677 * This will dispatch the identify command to the device and on success populate 676 678 * structures to be exported to sysfs. 677 679 */ 678 - int cxl_mem_identify(struct cxl_mem *cxlm) 680 + int cxl_dev_state_identify(struct cxl_dev_state *cxlds) 679 681 { 680 682 /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ 681 683 struct cxl_mbox_identify id; 682 684 int rc; 683 685 684 - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id, 685 - sizeof(id)); 686 + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id, 687 + sizeof(id)); 686 688 if (rc < 0) 687 689 return rc; 688 690 689 - cxlm->total_bytes = 691 + cxlds->total_bytes = 690 692 le64_to_cpu(id.total_capacity) * CXL_CAPACITY_MULTIPLIER; 691 - cxlm->volatile_only_bytes = 693 + cxlds->volatile_only_bytes = 692 694 le64_to_cpu(id.volatile_capacity) * CXL_CAPACITY_MULTIPLIER; 693 - cxlm->persistent_only_bytes = 695 + cxlds->persistent_only_bytes = 694 696 le64_to_cpu(id.persistent_capacity) * CXL_CAPACITY_MULTIPLIER; 695 - cxlm->partition_align_bytes = 697 + cxlds->partition_align_bytes = 696 698 le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER; 697 699 698 - dev_dbg(cxlm->dev, 700 + dev_dbg(cxlds->dev, 699 701 "Identify Memory Device\n" 700 702 " total_bytes = %#llx\n" 701 703 " volatile_only_bytes = %#llx\n" 702 704 " persistent_only_bytes = %#llx\n" 703 705 " partition_align_bytes = %#llx\n", 704 - cxlm->total_bytes, cxlm->volatile_only_bytes, 705 - cxlm->persistent_only_bytes, cxlm->partition_align_bytes); 706 + cxlds->total_bytes, cxlds->volatile_only_bytes, 707 + cxlds->persistent_only_bytes, cxlds->partition_align_bytes); 706 708 707 - cxlm->lsa_size = le32_to_cpu(id.lsa_size); 708 - memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); 709 + cxlds->lsa_size = le32_to_cpu(id.lsa_size); 710 + memcpy(cxlds->firmware_version, id.fw_revision, sizeof(id.fw_revision)); 709 711 710 712 return 0; 711 713 } 712 - EXPORT_SYMBOL_GPL(cxl_mem_identify); 714 + EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); 713 715 714 - int cxl_mem_create_range_info(struct cxl_mem *cxlm) 716 + int cxl_mem_create_range_info(struct cxl_dev_state *cxlds) 715 717 { 716 718 int rc; 717 719 718 - if (cxlm->partition_align_bytes == 0) { 719 - cxlm->ram_range.start = 0; 720 - cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; 721 - cxlm->pmem_range.start = cxlm->volatile_only_bytes; 722 - cxlm->pmem_range.end = cxlm->volatile_only_bytes + 723 - cxlm->persistent_only_bytes - 1; 720 + if (cxlds->partition_align_bytes == 0) { 721 + cxlds->ram_range.start = 0; 722 + cxlds->ram_range.end = cxlds->volatile_only_bytes - 1; 723 + cxlds->pmem_range.start = cxlds->volatile_only_bytes; 724 + cxlds->pmem_range.end = cxlds->volatile_only_bytes + 725 + cxlds->persistent_only_bytes - 1; 724 726 return 0; 725 727 } 726 728 727 - rc = cxl_mem_get_partition_info(cxlm); 729 + rc = cxl_mem_get_partition_info(cxlds); 728 730 if (rc) { 729 - dev_err(cxlm->dev, "Failed to query partition information\n"); 731 + dev_err(cxlds->dev, "Failed to query partition information\n"); 730 732 return rc; 731 733 } 732 734 733 - dev_dbg(cxlm->dev, 735 + dev_dbg(cxlds->dev, 734 736 "Get Partition Info\n" 735 737 " active_volatile_bytes = %#llx\n" 736 738 " active_persistent_bytes = %#llx\n" 737 739 " next_volatile_bytes = %#llx\n" 738 740 " next_persistent_bytes = %#llx\n", 739 - cxlm->active_volatile_bytes, cxlm->active_persistent_bytes, 740 - cxlm->next_volatile_bytes, cxlm->next_persistent_bytes); 741 + cxlds->active_volatile_bytes, cxlds->active_persistent_bytes, 742 + cxlds->next_volatile_bytes, cxlds->next_persistent_bytes); 741 743 742 - cxlm->ram_range.start = 0; 743 - cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; 744 + cxlds->ram_range.start = 0; 745 + cxlds->ram_range.end = cxlds->active_volatile_bytes - 1; 744 746 745 - cxlm->pmem_range.start = cxlm->active_volatile_bytes; 746 - cxlm->pmem_range.end = 747 - cxlm->active_volatile_bytes + cxlm->active_persistent_bytes - 1; 747 + cxlds->pmem_range.start = cxlds->active_volatile_bytes; 748 + cxlds->pmem_range.end = 749 + cxlds->active_volatile_bytes + cxlds->active_persistent_bytes - 1; 748 750 749 751 return 0; 750 752 } 751 - EXPORT_SYMBOL_GPL(cxl_mem_create_range_info); 753 + EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL); 752 754 753 - struct cxl_mem *cxl_mem_create(struct device *dev) 755 + struct cxl_dev_state *cxl_dev_state_create(struct device *dev) 754 756 { 755 - struct cxl_mem *cxlm; 757 + struct cxl_dev_state *cxlds; 756 758 757 - cxlm = devm_kzalloc(dev, sizeof(*cxlm), GFP_KERNEL); 758 - if (!cxlm) { 759 + cxlds = devm_kzalloc(dev, sizeof(*cxlds), GFP_KERNEL); 760 + if (!cxlds) { 759 761 dev_err(dev, "No memory available\n"); 760 762 return ERR_PTR(-ENOMEM); 761 763 } 762 764 763 - mutex_init(&cxlm->mbox_mutex); 764 - cxlm->dev = dev; 765 + mutex_init(&cxlds->mbox_mutex); 766 + cxlds->dev = dev; 765 767 766 - return cxlm; 768 + return cxlds; 767 769 } 768 - EXPORT_SYMBOL_GPL(cxl_mem_create); 770 + EXPORT_SYMBOL_NS_GPL(cxl_dev_state_create, CXL); 769 771 770 772 static struct dentry *cxl_debugfs; 771 773
+27 -28
drivers/cxl/core/memdev.c
··· 37 37 struct device_attribute *attr, char *buf) 38 38 { 39 39 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 40 - struct cxl_mem *cxlm = cxlmd->cxlm; 40 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 41 41 42 - return sysfs_emit(buf, "%.16s\n", cxlm->firmware_version); 42 + return sysfs_emit(buf, "%.16s\n", cxlds->firmware_version); 43 43 } 44 44 static DEVICE_ATTR_RO(firmware_version); 45 45 ··· 47 47 struct device_attribute *attr, char *buf) 48 48 { 49 49 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 50 - struct cxl_mem *cxlm = cxlmd->cxlm; 50 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 51 51 52 - return sysfs_emit(buf, "%zu\n", cxlm->payload_size); 52 + return sysfs_emit(buf, "%zu\n", cxlds->payload_size); 53 53 } 54 54 static DEVICE_ATTR_RO(payload_max); 55 55 ··· 57 57 struct device_attribute *attr, char *buf) 58 58 { 59 59 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 60 - struct cxl_mem *cxlm = cxlmd->cxlm; 60 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 61 61 62 - return sysfs_emit(buf, "%zu\n", cxlm->lsa_size); 62 + return sysfs_emit(buf, "%zu\n", cxlds->lsa_size); 63 63 } 64 64 static DEVICE_ATTR_RO(label_storage_size); 65 65 ··· 67 67 char *buf) 68 68 { 69 69 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 70 - struct cxl_mem *cxlm = cxlmd->cxlm; 71 - unsigned long long len = range_len(&cxlm->ram_range); 70 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 71 + unsigned long long len = range_len(&cxlds->ram_range); 72 72 73 73 return sysfs_emit(buf, "%#llx\n", len); 74 74 } ··· 80 80 char *buf) 81 81 { 82 82 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 83 - struct cxl_mem *cxlm = cxlmd->cxlm; 84 - unsigned long long len = range_len(&cxlm->pmem_range); 83 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 84 + unsigned long long len = range_len(&cxlds->pmem_range); 85 85 86 86 return sysfs_emit(buf, "%#llx\n", len); 87 87 } ··· 136 136 137 137 /** 138 138 * set_exclusive_cxl_commands() - atomically disable user cxl commands 139 - * @cxlm: cxl_mem instance to modify 139 + * @cxlds: The device state to operate on 140 140 * @cmds: bitmap of commands to mark exclusive 141 141 * 142 142 * Grab the cxl_memdev_rwsem in write mode to flush in-flight 143 143 * invocations of the ioctl path and then disable future execution of 144 144 * commands with the command ids set in @cmds. 145 145 */ 146 - void set_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds) 146 + void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds) 147 147 { 148 148 down_write(&cxl_memdev_rwsem); 149 - bitmap_or(cxlm->exclusive_cmds, cxlm->exclusive_cmds, cmds, 149 + bitmap_or(cxlds->exclusive_cmds, cxlds->exclusive_cmds, cmds, 150 150 CXL_MEM_COMMAND_ID_MAX); 151 151 up_write(&cxl_memdev_rwsem); 152 152 } 153 - EXPORT_SYMBOL_GPL(set_exclusive_cxl_commands); 153 + EXPORT_SYMBOL_NS_GPL(set_exclusive_cxl_commands, CXL); 154 154 155 155 /** 156 156 * clear_exclusive_cxl_commands() - atomically enable user cxl commands 157 - * @cxlm: cxl_mem instance to modify 157 + * @cxlds: The device state to modify 158 158 * @cmds: bitmap of commands to mark available for userspace 159 159 */ 160 - void clear_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds) 160 + void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds) 161 161 { 162 162 down_write(&cxl_memdev_rwsem); 163 - bitmap_andnot(cxlm->exclusive_cmds, cxlm->exclusive_cmds, cmds, 163 + bitmap_andnot(cxlds->exclusive_cmds, cxlds->exclusive_cmds, cmds, 164 164 CXL_MEM_COMMAND_ID_MAX); 165 165 up_write(&cxl_memdev_rwsem); 166 166 } 167 - EXPORT_SYMBOL_GPL(clear_exclusive_cxl_commands); 167 + EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL); 168 168 169 169 static void cxl_memdev_shutdown(struct device *dev) 170 170 { 171 171 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 172 172 173 173 down_write(&cxl_memdev_rwsem); 174 - cxlmd->cxlm = NULL; 174 + cxlmd->cxlds = NULL; 175 175 up_write(&cxl_memdev_rwsem); 176 176 } 177 177 ··· 185 185 put_device(dev); 186 186 } 187 187 188 - static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, 188 + static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds, 189 189 const struct file_operations *fops) 190 190 { 191 191 struct cxl_memdev *cxlmd; ··· 204 204 205 205 dev = &cxlmd->dev; 206 206 device_initialize(dev); 207 - dev->parent = cxlm->dev; 207 + dev->parent = cxlds->dev; 208 208 dev->bus = &cxl_bus_type; 209 209 dev->devt = MKDEV(cxl_mem_major, cxlmd->id); 210 210 dev->type = &cxl_memdev_type; ··· 239 239 int rc = -ENXIO; 240 240 241 241 down_read(&cxl_memdev_rwsem); 242 - if (cxlmd->cxlm) 242 + if (cxlmd->cxlds) 243 243 rc = __cxl_memdev_ioctl(cxlmd, cmd, arg); 244 244 up_read(&cxl_memdev_rwsem); 245 245 ··· 276 276 .llseek = noop_llseek, 277 277 }; 278 278 279 - struct cxl_memdev * 280 - devm_cxl_add_memdev(struct cxl_mem *cxlm) 279 + struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds) 281 280 { 282 281 struct cxl_memdev *cxlmd; 283 282 struct device *dev; 284 283 struct cdev *cdev; 285 284 int rc; 286 285 287 - cxlmd = cxl_memdev_alloc(cxlm, &cxl_memdev_fops); 286 + cxlmd = cxl_memdev_alloc(cxlds, &cxl_memdev_fops); 288 287 if (IS_ERR(cxlmd)) 289 288 return cxlmd; 290 289 ··· 296 297 * Activate ioctl operations, no cxl_memdev_rwsem manipulation 297 298 * needed as this is ordered with cdev_add() publishing the device. 298 299 */ 299 - cxlmd->cxlm = cxlm; 300 + cxlmd->cxlds = cxlds; 300 301 301 302 cdev = &cxlmd->cdev; 302 303 rc = cdev_device_add(cdev, dev); 303 304 if (rc) 304 305 goto err; 305 306 306 - rc = devm_add_action_or_reset(cxlm->dev, cxl_memdev_unregister, cxlmd); 307 + rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd); 307 308 if (rc) 308 309 return ERR_PTR(rc); 309 310 return cxlmd; ··· 317 318 put_device(dev); 318 319 return ERR_PTR(rc); 319 320 } 320 - EXPORT_SYMBOL_GPL(devm_cxl_add_memdev); 321 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); 321 322 322 323 __init int cxl_memdev_init(void) 323 324 {
+13 -7
drivers/cxl/core/pmem.c
··· 49 49 return NULL; 50 50 return container_of(dev, struct cxl_nvdimm_bridge, dev); 51 51 } 52 - EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge); 52 + EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm_bridge, CXL); 53 + 54 + bool is_cxl_nvdimm_bridge(struct device *dev) 55 + { 56 + return dev->type == &cxl_nvdimm_bridge_type; 57 + } 58 + EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm_bridge, CXL); 53 59 54 60 __mock int match_nvdimm_bridge(struct device *dev, const void *data) 55 61 { 56 - return dev->type == &cxl_nvdimm_bridge_type; 62 + return is_cxl_nvdimm_bridge(dev); 57 63 } 58 64 59 65 struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd) ··· 71 65 return NULL; 72 66 return to_cxl_nvdimm_bridge(dev); 73 67 } 74 - EXPORT_SYMBOL_GPL(cxl_find_nvdimm_bridge); 68 + EXPORT_SYMBOL_NS_GPL(cxl_find_nvdimm_bridge, CXL); 75 69 76 70 static struct cxl_nvdimm_bridge * 77 71 cxl_nvdimm_bridge_alloc(struct cxl_port *port) ··· 173 167 put_device(dev); 174 168 return ERR_PTR(rc); 175 169 } 176 - EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm_bridge); 170 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, CXL); 177 171 178 172 static void cxl_nvdimm_release(struct device *dev) 179 173 { ··· 197 191 { 198 192 return dev->type == &cxl_nvdimm_type; 199 193 } 200 - EXPORT_SYMBOL_GPL(is_cxl_nvdimm); 194 + EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm, CXL); 201 195 202 196 struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) 203 197 { ··· 206 200 return NULL; 207 201 return container_of(dev, struct cxl_nvdimm, dev); 208 202 } 209 - EXPORT_SYMBOL_GPL(to_cxl_nvdimm); 203 + EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm, CXL); 210 204 211 205 static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd) 212 206 { ··· 268 262 put_device(dev); 269 263 return rc; 270 264 } 271 - EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm); 265 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm, CXL);
+4 -4
drivers/cxl/core/regs.c
··· 90 90 } 91 91 } 92 92 } 93 - EXPORT_SYMBOL_GPL(cxl_probe_component_regs); 93 + EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, CXL); 94 94 95 95 /** 96 96 * cxl_probe_device_regs() - Detect CXL Device register blocks ··· 156 156 } 157 157 } 158 158 } 159 - EXPORT_SYMBOL_GPL(cxl_probe_device_regs); 159 + EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL); 160 160 161 161 static void __iomem *devm_cxl_iomap_block(struct device *dev, 162 162 resource_size_t addr, ··· 199 199 200 200 return 0; 201 201 } 202 - EXPORT_SYMBOL_GPL(cxl_map_component_regs); 202 + EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL); 203 203 204 204 int cxl_map_device_regs(struct pci_dev *pdev, 205 205 struct cxl_device_regs *regs, ··· 246 246 247 247 return 0; 248 248 } 249 - EXPORT_SYMBOL_GPL(cxl_map_device_regs); 249 + EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL);
+9 -1
drivers/cxl/cxl.h
··· 191 191 int interleave_granularity; 192 192 enum cxl_decoder_type target_type; 193 193 unsigned long flags; 194 - const int nr_targets; 194 + int nr_targets; 195 195 struct cxl_dport *target[]; 196 196 }; 197 197 198 198 199 + /** 200 + * enum cxl_nvdimm_brige_state - state machine for managing bus rescans 201 + * @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed 202 + * @CXL_NVB_DEAD: Set at brige unregistration to preclude async probing 203 + * @CXL_NVB_ONLINE: Target state after successful ->probe() 204 + * @CXL_NVB_OFFLINE: Target state after ->remove() or failed ->probe() 205 + */ 199 206 enum cxl_nvdimm_brige_state { 200 207 CXL_NVB_NEW, 201 208 CXL_NVB_DEAD, ··· 315 308 struct cxl_port *port); 316 309 struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); 317 310 bool is_cxl_nvdimm(struct device *dev); 311 + bool is_cxl_nvdimm_bridge(struct device *dev); 318 312 int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); 319 313 struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd); 320 314
+20 -17
drivers/cxl/cxlmem.h
··· 33 33 * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device 34 34 * @dev: driver core device object 35 35 * @cdev: char dev core object for ioctl operations 36 - * @cxlm: pointer to the parent device driver data 36 + * @cxlds: The device state backing this device 37 37 * @id: id number of this memdev instance. 38 38 */ 39 39 struct cxl_memdev { 40 40 struct device dev; 41 41 struct cdev cdev; 42 - struct cxl_mem *cxlm; 42 + struct cxl_dev_state *cxlds; 43 43 int id; 44 44 }; 45 45 ··· 48 48 return container_of(dev, struct cxl_memdev, dev); 49 49 } 50 50 51 - struct cxl_memdev *devm_cxl_add_memdev(struct cxl_mem *cxlm); 51 + struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds); 52 52 53 53 /** 54 54 * struct cxl_mbox_cmd - A command to be submitted to hardware. ··· 90 90 #define CXL_CAPACITY_MULTIPLIER SZ_256M 91 91 92 92 /** 93 - * struct cxl_mem - A CXL memory device 94 - * @dev: The device associated with this CXL device. 95 - * @cxlmd: Logical memory device chardev / interface 93 + * struct cxl_dev_state - The driver device state 94 + * 95 + * cxl_dev_state represents the CXL driver/device state. It provides an 96 + * interface to mailbox commands as well as some cached data about the device. 97 + * Currently only memory devices are represented. 98 + * 99 + * @dev: The device associated with this CXL state 96 100 * @regs: Parsed register blocks 97 101 * @payload_size: Size of space for payload 98 102 * (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register) ··· 121 117 * See section 8.2.9.5.2 Capacity Configuration and Label Storage for 122 118 * details on capacity parameters. 123 119 */ 124 - struct cxl_mem { 120 + struct cxl_dev_state { 125 121 struct device *dev; 126 - struct cxl_memdev *cxlmd; 127 122 128 123 struct cxl_regs regs; 129 124 ··· 145 142 u64 next_volatile_bytes; 146 143 u64 next_persistent_bytes; 147 144 148 - int (*mbox_send)(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd); 145 + int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd); 149 146 }; 150 147 151 148 enum cxl_opcode { ··· 256 253 #define CXL_CMD_FLAG_FORCE_ENABLE BIT(0) 257 254 }; 258 255 259 - int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, 260 - size_t in_size, void *out, size_t out_size); 261 - int cxl_mem_identify(struct cxl_mem *cxlm); 262 - int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm); 263 - int cxl_mem_create_range_info(struct cxl_mem *cxlm); 264 - struct cxl_mem *cxl_mem_create(struct device *dev); 265 - void set_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds); 266 - void clear_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds); 256 + int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in, 257 + size_t in_size, void *out, size_t out_size); 258 + int cxl_dev_state_identify(struct cxl_dev_state *cxlds); 259 + int cxl_enumerate_cmds(struct cxl_dev_state *cxlds); 260 + int cxl_mem_create_range_info(struct cxl_dev_state *cxlds); 261 + struct cxl_dev_state *cxl_dev_state_create(struct device *dev); 262 + void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds); 263 + void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds); 267 264 #endif /* __CXL_MEM_H__ */
+60 -60
drivers/cxl/pci.c
··· 28 28 * - Registers a CXL mailbox with cxl_core. 29 29 */ 30 30 31 - #define cxl_doorbell_busy(cxlm) \ 32 - (readl((cxlm)->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET) & \ 31 + #define cxl_doorbell_busy(cxlds) \ 32 + (readl((cxlds)->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET) & \ 33 33 CXLDEV_MBOX_CTRL_DOORBELL) 34 34 35 35 /* CXL 2.0 - 8.2.8.4 */ 36 36 #define CXL_MAILBOX_TIMEOUT_MS (2 * HZ) 37 37 38 - static int cxl_pci_mbox_wait_for_doorbell(struct cxl_mem *cxlm) 38 + static int cxl_pci_mbox_wait_for_doorbell(struct cxl_dev_state *cxlds) 39 39 { 40 40 const unsigned long start = jiffies; 41 41 unsigned long end = start; 42 42 43 - while (cxl_doorbell_busy(cxlm)) { 43 + while (cxl_doorbell_busy(cxlds)) { 44 44 end = jiffies; 45 45 46 46 if (time_after(end, start + CXL_MAILBOX_TIMEOUT_MS)) { 47 47 /* Check again in case preempted before timeout test */ 48 - if (!cxl_doorbell_busy(cxlm)) 48 + if (!cxl_doorbell_busy(cxlds)) 49 49 break; 50 50 return -ETIMEDOUT; 51 51 } 52 52 cpu_relax(); 53 53 } 54 54 55 - dev_dbg(cxlm->dev, "Doorbell wait took %dms", 55 + dev_dbg(cxlds->dev, "Doorbell wait took %dms", 56 56 jiffies_to_msecs(end) - jiffies_to_msecs(start)); 57 57 return 0; 58 58 } 59 59 60 - static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm, 60 + static void cxl_pci_mbox_timeout(struct cxl_dev_state *cxlds, 61 61 struct cxl_mbox_cmd *mbox_cmd) 62 62 { 63 - struct device *dev = cxlm->dev; 63 + struct device *dev = cxlds->dev; 64 64 65 65 dev_dbg(dev, "Mailbox command (opcode: %#x size: %zub) timed out\n", 66 66 mbox_cmd->opcode, mbox_cmd->size_in); ··· 68 68 69 69 /** 70 70 * __cxl_pci_mbox_send_cmd() - Execute a mailbox command 71 - * @cxlm: The CXL memory device to communicate with. 71 + * @cxlds: The device state to communicate with. 72 72 * @mbox_cmd: Command to send to the memory device. 73 73 * 74 74 * Context: Any context. Expects mbox_mutex to be held. ··· 88 88 * not need to coordinate with each other. The driver only uses the primary 89 89 * mailbox. 90 90 */ 91 - static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, 91 + static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds, 92 92 struct cxl_mbox_cmd *mbox_cmd) 93 93 { 94 - void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET; 95 - struct device *dev = cxlm->dev; 94 + void __iomem *payload = cxlds->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET; 95 + struct device *dev = cxlds->dev; 96 96 u64 cmd_reg, status_reg; 97 97 size_t out_len; 98 98 int rc; 99 99 100 - lockdep_assert_held(&cxlm->mbox_mutex); 100 + lockdep_assert_held(&cxlds->mbox_mutex); 101 101 102 102 /* 103 103 * Here are the steps from 8.2.8.4 of the CXL 2.0 spec. ··· 117 117 */ 118 118 119 119 /* #1 */ 120 - if (cxl_doorbell_busy(cxlm)) { 120 + if (cxl_doorbell_busy(cxlds)) { 121 121 dev_err_ratelimited(dev, "Mailbox re-busy after acquiring\n"); 122 122 return -EBUSY; 123 123 } ··· 134 134 } 135 135 136 136 /* #2, #3 */ 137 - writeq(cmd_reg, cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); 137 + writeq(cmd_reg, cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); 138 138 139 139 /* #4 */ 140 140 dev_dbg(dev, "Sending command\n"); 141 141 writel(CXLDEV_MBOX_CTRL_DOORBELL, 142 - cxlm->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); 142 + cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); 143 143 144 144 /* #5 */ 145 - rc = cxl_pci_mbox_wait_for_doorbell(cxlm); 145 + rc = cxl_pci_mbox_wait_for_doorbell(cxlds); 146 146 if (rc == -ETIMEDOUT) { 147 - cxl_pci_mbox_timeout(cxlm, mbox_cmd); 147 + cxl_pci_mbox_timeout(cxlds, mbox_cmd); 148 148 return rc; 149 149 } 150 150 151 151 /* #6 */ 152 - status_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_STATUS_OFFSET); 152 + status_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_STATUS_OFFSET); 153 153 mbox_cmd->return_code = 154 154 FIELD_GET(CXLDEV_MBOX_STATUS_RET_CODE_MASK, status_reg); 155 155 ··· 159 159 } 160 160 161 161 /* #7 */ 162 - cmd_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); 162 + cmd_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); 163 163 out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg); 164 164 165 165 /* #8 */ ··· 171 171 * have requested less data than the hardware supplied even 172 172 * within spec. 173 173 */ 174 - size_t n = min3(mbox_cmd->size_out, cxlm->payload_size, out_len); 174 + size_t n = min3(mbox_cmd->size_out, cxlds->payload_size, out_len); 175 175 176 176 memcpy_fromio(mbox_cmd->payload_out, payload, n); 177 177 mbox_cmd->size_out = n; ··· 184 184 185 185 /** 186 186 * cxl_pci_mbox_get() - Acquire exclusive access to the mailbox. 187 - * @cxlm: The memory device to gain access to. 187 + * @cxlds: The device state to gain access to. 188 188 * 189 189 * Context: Any context. Takes the mbox_mutex. 190 190 * Return: 0 if exclusive access was acquired. 191 191 */ 192 - static int cxl_pci_mbox_get(struct cxl_mem *cxlm) 192 + static int cxl_pci_mbox_get(struct cxl_dev_state *cxlds) 193 193 { 194 - struct device *dev = cxlm->dev; 194 + struct device *dev = cxlds->dev; 195 195 u64 md_status; 196 196 int rc; 197 197 198 - mutex_lock_io(&cxlm->mbox_mutex); 198 + mutex_lock_io(&cxlds->mbox_mutex); 199 199 200 200 /* 201 201 * XXX: There is some amount of ambiguity in the 2.0 version of the spec ··· 214 214 * Mailbox Interface Ready bit. Therefore, waiting for the doorbell 215 215 * to be ready is sufficient. 216 216 */ 217 - rc = cxl_pci_mbox_wait_for_doorbell(cxlm); 217 + rc = cxl_pci_mbox_wait_for_doorbell(cxlds); 218 218 if (rc) { 219 219 dev_warn(dev, "Mailbox interface not ready\n"); 220 220 goto out; 221 221 } 222 222 223 - md_status = readq(cxlm->regs.memdev + CXLMDEV_STATUS_OFFSET); 223 + md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET); 224 224 if (!(md_status & CXLMDEV_MBOX_IF_READY && CXLMDEV_READY(md_status))) { 225 225 dev_err(dev, "mbox: reported doorbell ready, but not mbox ready\n"); 226 226 rc = -EBUSY; ··· 249 249 return 0; 250 250 251 251 out: 252 - mutex_unlock(&cxlm->mbox_mutex); 252 + mutex_unlock(&cxlds->mbox_mutex); 253 253 return rc; 254 254 } 255 255 256 256 /** 257 257 * cxl_pci_mbox_put() - Release exclusive access to the mailbox. 258 - * @cxlm: The CXL memory device to communicate with. 258 + * @cxlds: The device state to communicate with. 259 259 * 260 260 * Context: Any context. Expects mbox_mutex to be held. 261 261 */ 262 - static void cxl_pci_mbox_put(struct cxl_mem *cxlm) 262 + static void cxl_pci_mbox_put(struct cxl_dev_state *cxlds) 263 263 { 264 - mutex_unlock(&cxlm->mbox_mutex); 264 + mutex_unlock(&cxlds->mbox_mutex); 265 265 } 266 266 267 - static int cxl_pci_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) 267 + static int cxl_pci_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 268 268 { 269 269 int rc; 270 270 271 - rc = cxl_pci_mbox_get(cxlm); 271 + rc = cxl_pci_mbox_get(cxlds); 272 272 if (rc) 273 273 return rc; 274 274 275 - rc = __cxl_pci_mbox_send_cmd(cxlm, cmd); 276 - cxl_pci_mbox_put(cxlm); 275 + rc = __cxl_pci_mbox_send_cmd(cxlds, cmd); 276 + cxl_pci_mbox_put(cxlds); 277 277 278 278 return rc; 279 279 } 280 280 281 - static int cxl_pci_setup_mailbox(struct cxl_mem *cxlm) 281 + static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds) 282 282 { 283 - const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); 283 + const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); 284 284 285 - cxlm->mbox_send = cxl_pci_mbox_send; 286 - cxlm->payload_size = 285 + cxlds->mbox_send = cxl_pci_mbox_send; 286 + cxlds->payload_size = 287 287 1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap); 288 288 289 289 /* ··· 293 293 * there's no point in going forward. If the size is too large, there's 294 294 * no harm is soft limiting it. 295 295 */ 296 - cxlm->payload_size = min_t(size_t, cxlm->payload_size, SZ_1M); 297 - if (cxlm->payload_size < 256) { 298 - dev_err(cxlm->dev, "Mailbox is too small (%zub)", 299 - cxlm->payload_size); 296 + cxlds->payload_size = min_t(size_t, cxlds->payload_size, SZ_1M); 297 + if (cxlds->payload_size < 256) { 298 + dev_err(cxlds->dev, "Mailbox is too small (%zub)", 299 + cxlds->payload_size); 300 300 return -ENXIO; 301 301 } 302 302 303 - dev_dbg(cxlm->dev, "Mailbox payload sized %zu", 304 - cxlm->payload_size); 303 + dev_dbg(cxlds->dev, "Mailbox payload sized %zu", 304 + cxlds->payload_size); 305 305 306 306 return 0; 307 307 } ··· 379 379 return 0; 380 380 } 381 381 382 - static int cxl_map_regs(struct cxl_mem *cxlm, struct cxl_register_map *map) 382 + static int cxl_map_regs(struct cxl_dev_state *cxlds, struct cxl_register_map *map) 383 383 { 384 - struct device *dev = cxlm->dev; 384 + struct device *dev = cxlds->dev; 385 385 struct pci_dev *pdev = to_pci_dev(dev); 386 386 387 387 switch (map->reg_type) { 388 388 case CXL_REGLOC_RBI_COMPONENT: 389 - cxl_map_component_regs(pdev, &cxlm->regs.component, map); 389 + cxl_map_component_regs(pdev, &cxlds->regs.component, map); 390 390 dev_dbg(dev, "Mapping component registers...\n"); 391 391 break; 392 392 case CXL_REGLOC_RBI_MEMDEV: 393 - cxl_map_device_regs(pdev, &cxlm->regs.device_regs, map); 393 + cxl_map_device_regs(pdev, &cxlds->regs.device_regs, map); 394 394 dev_dbg(dev, "Probing device registers...\n"); 395 395 break; 396 396 default: ··· 475 475 { 476 476 struct cxl_register_map map; 477 477 struct cxl_memdev *cxlmd; 478 - struct cxl_mem *cxlm; 478 + struct cxl_dev_state *cxlds; 479 479 int rc; 480 480 481 481 /* ··· 489 489 if (rc) 490 490 return rc; 491 491 492 - cxlm = cxl_mem_create(&pdev->dev); 493 - if (IS_ERR(cxlm)) 494 - return PTR_ERR(cxlm); 492 + cxlds = cxl_dev_state_create(&pdev->dev); 493 + if (IS_ERR(cxlds)) 494 + return PTR_ERR(cxlds); 495 495 496 496 rc = cxl_setup_regs(pdev, CXL_REGLOC_RBI_MEMDEV, &map); 497 497 if (rc) 498 498 return rc; 499 499 500 - rc = cxl_map_regs(cxlm, &map); 500 + rc = cxl_map_regs(cxlds, &map); 501 501 if (rc) 502 502 return rc; 503 503 504 - rc = cxl_pci_setup_mailbox(cxlm); 504 + rc = cxl_pci_setup_mailbox(cxlds); 505 505 if (rc) 506 506 return rc; 507 507 508 - rc = cxl_mem_enumerate_cmds(cxlm); 508 + rc = cxl_enumerate_cmds(cxlds); 509 509 if (rc) 510 510 return rc; 511 511 512 - rc = cxl_mem_identify(cxlm); 512 + rc = cxl_dev_state_identify(cxlds); 513 513 if (rc) 514 514 return rc; 515 515 516 - rc = cxl_mem_create_range_info(cxlm); 516 + rc = cxl_mem_create_range_info(cxlds); 517 517 if (rc) 518 518 return rc; 519 519 520 - cxlmd = devm_cxl_add_memdev(cxlm); 520 + cxlmd = devm_cxl_add_memdev(cxlds); 521 521 if (IS_ERR(cxlmd)) 522 522 return PTR_ERR(cxlmd); 523 523 524 - if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) 524 + if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) 525 525 rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd); 526 526 527 527 return rc;
+59 -26
drivers/cxl/pmem.c
··· 19 19 20 20 static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); 21 21 22 - static void clear_exclusive(void *cxlm) 22 + static void clear_exclusive(void *cxlds) 23 23 { 24 - clear_exclusive_cxl_commands(cxlm, exclusive_cmds); 24 + clear_exclusive_cxl_commands(cxlds, exclusive_cmds); 25 25 } 26 26 27 27 static void unregister_nvdimm(void *nvdimm) ··· 34 34 struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); 35 35 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 36 36 unsigned long flags = 0, cmd_mask = 0; 37 - struct cxl_mem *cxlm = cxlmd->cxlm; 37 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 38 38 struct cxl_nvdimm_bridge *cxl_nvb; 39 39 struct nvdimm *nvdimm; 40 40 int rc; ··· 49 49 goto out; 50 50 } 51 51 52 - set_exclusive_cxl_commands(cxlm, exclusive_cmds); 53 - rc = devm_add_action_or_reset(dev, clear_exclusive, cxlm); 52 + set_exclusive_cxl_commands(cxlds, exclusive_cmds); 53 + rc = devm_add_action_or_reset(dev, clear_exclusive, cxlds); 54 54 if (rc) 55 55 goto out; 56 56 ··· 80 80 .id = CXL_DEVICE_NVDIMM, 81 81 }; 82 82 83 - static int cxl_pmem_get_config_size(struct cxl_mem *cxlm, 83 + static int cxl_pmem_get_config_size(struct cxl_dev_state *cxlds, 84 84 struct nd_cmd_get_config_size *cmd, 85 85 unsigned int buf_len) 86 86 { ··· 88 88 return -EINVAL; 89 89 90 90 *cmd = (struct nd_cmd_get_config_size) { 91 - .config_size = cxlm->lsa_size, 92 - .max_xfer = cxlm->payload_size, 91 + .config_size = cxlds->lsa_size, 92 + .max_xfer = cxlds->payload_size, 93 93 }; 94 94 95 95 return 0; 96 96 } 97 97 98 - static int cxl_pmem_get_config_data(struct cxl_mem *cxlm, 98 + static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds, 99 99 struct nd_cmd_get_config_data_hdr *cmd, 100 100 unsigned int buf_len) 101 101 { ··· 112 112 .length = cmd->in_length, 113 113 }; 114 114 115 - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LSA, &get_lsa, 116 - sizeof(get_lsa), cmd->out_buf, 117 - cmd->in_length); 115 + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LSA, &get_lsa, 116 + sizeof(get_lsa), cmd->out_buf, cmd->in_length); 118 117 cmd->status = 0; 119 118 120 119 return rc; 121 120 } 122 121 123 - static int cxl_pmem_set_config_data(struct cxl_mem *cxlm, 122 + static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds, 124 123 struct nd_cmd_set_config_hdr *cmd, 125 124 unsigned int buf_len) 126 125 { ··· 143 144 }; 144 145 memcpy(set_lsa->data, cmd->in_buf, cmd->in_length); 145 146 146 - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_SET_LSA, set_lsa, 147 - struct_size(set_lsa, data, cmd->in_length), 148 - NULL, 0); 147 + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_SET_LSA, set_lsa, 148 + struct_size(set_lsa, data, cmd->in_length), 149 + NULL, 0); 149 150 150 151 /* 151 152 * Set "firmware" status (4-packed bytes at the end of the input ··· 163 164 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 164 165 unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); 165 166 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 166 - struct cxl_mem *cxlm = cxlmd->cxlm; 167 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 167 168 168 169 if (!test_bit(cmd, &cmd_mask)) 169 170 return -ENOTTY; 170 171 171 172 switch (cmd) { 172 173 case ND_CMD_GET_CONFIG_SIZE: 173 - return cxl_pmem_get_config_size(cxlm, buf, buf_len); 174 + return cxl_pmem_get_config_size(cxlds, buf, buf_len); 174 175 case ND_CMD_GET_CONFIG_DATA: 175 - return cxl_pmem_get_config_data(cxlm, buf, buf_len); 176 + return cxl_pmem_get_config_data(cxlds, buf, buf_len); 176 177 case ND_CMD_SET_CONFIG_DATA: 177 - return cxl_pmem_set_config_data(cxlm, buf, buf_len); 178 + return cxl_pmem_set_config_data(cxlds, buf, buf_len); 178 179 default: 179 180 return -ENOTTY; 180 181 } ··· 265 266 put_device(&cxl_nvb->dev); 266 267 } 267 268 269 + static void cxl_nvdimm_bridge_state_work(struct cxl_nvdimm_bridge *cxl_nvb) 270 + { 271 + /* 272 + * Take a reference that the workqueue will drop if new work 273 + * gets queued. 274 + */ 275 + get_device(&cxl_nvb->dev); 276 + if (!queue_work(cxl_pmem_wq, &cxl_nvb->state_work)) 277 + put_device(&cxl_nvb->dev); 278 + } 279 + 268 280 static void cxl_nvdimm_bridge_remove(struct device *dev) 269 281 { 270 282 struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev); 271 283 272 284 if (cxl_nvb->state == CXL_NVB_ONLINE) 273 285 cxl_nvb->state = CXL_NVB_OFFLINE; 274 - if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work)) 275 - get_device(&cxl_nvb->dev); 286 + cxl_nvdimm_bridge_state_work(cxl_nvb); 276 287 } 277 288 278 289 static int cxl_nvdimm_bridge_probe(struct device *dev) ··· 303 294 } 304 295 305 296 cxl_nvb->state = CXL_NVB_ONLINE; 306 - if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work)) 307 - get_device(&cxl_nvb->dev); 297 + cxl_nvdimm_bridge_state_work(cxl_nvb); 308 298 309 299 return 0; 310 300 } ··· 314 306 .remove = cxl_nvdimm_bridge_remove, 315 307 .id = CXL_DEVICE_NVDIMM_BRIDGE, 316 308 }; 309 + 310 + /* 311 + * Return all bridges to the CXL_NVB_NEW state to invalidate any 312 + * ->state_work referring to the now destroyed cxl_pmem_wq. 313 + */ 314 + static int cxl_nvdimm_bridge_reset(struct device *dev, void *data) 315 + { 316 + struct cxl_nvdimm_bridge *cxl_nvb; 317 + 318 + if (!is_cxl_nvdimm_bridge(dev)) 319 + return 0; 320 + 321 + cxl_nvb = to_cxl_nvdimm_bridge(dev); 322 + device_lock(dev); 323 + cxl_nvb->state = CXL_NVB_NEW; 324 + device_unlock(dev); 325 + 326 + return 0; 327 + } 328 + 329 + static void destroy_cxl_pmem_wq(void) 330 + { 331 + destroy_workqueue(cxl_pmem_wq); 332 + bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_bridge_reset); 333 + } 317 334 318 335 static __init int cxl_pmem_init(void) 319 336 { ··· 365 332 err_nvdimm: 366 333 cxl_driver_unregister(&cxl_nvdimm_bridge_driver); 367 334 err_bridge: 368 - destroy_workqueue(cxl_pmem_wq); 335 + destroy_cxl_pmem_wq(); 369 336 return rc; 370 337 } 371 338 ··· 373 340 { 374 341 cxl_driver_unregister(&cxl_nvdimm_driver); 375 342 cxl_driver_unregister(&cxl_nvdimm_bridge_driver); 376 - destroy_workqueue(cxl_pmem_wq); 343 + destroy_cxl_pmem_wq(); 377 344 } 378 345 379 346 MODULE_LICENSE("GPL v2");
+27 -7
include/linux/acpi.h
··· 133 133 struct acpi_subtable_header common; 134 134 struct acpi_hmat_structure hmat; 135 135 struct acpi_prmt_module_header prmt; 136 + struct acpi_cedt_header cedt; 136 137 }; 137 138 138 139 typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table); 139 140 140 141 typedef int (*acpi_tbl_entry_handler)(union acpi_subtable_headers *header, 141 142 const unsigned long end); 143 + 144 + typedef int (*acpi_tbl_entry_handler_arg)(union acpi_subtable_headers *header, 145 + void *arg, const unsigned long end); 142 146 143 147 /* Debugger support */ 144 148 ··· 220 216 struct acpi_subtable_proc { 221 217 int id; 222 218 acpi_tbl_entry_handler handler; 219 + acpi_tbl_entry_handler_arg handler_arg; 220 + void *arg; 223 221 int count; 224 222 }; 225 223 ··· 238 232 void acpi_reserve_initial_tables (void); 239 233 void acpi_table_init_complete (void); 240 234 int acpi_table_init (void); 235 + 236 + #ifdef CONFIG_ACPI_TABLE_LIB 237 + #define EXPORT_SYMBOL_ACPI_LIB(x) EXPORT_SYMBOL_NS_GPL(x, ACPI) 238 + #define __init_or_acpilib 239 + #define __initdata_or_acpilib 240 + #else 241 + #define EXPORT_SYMBOL_ACPI_LIB(x) 242 + #define __init_or_acpilib __init 243 + #define __initdata_or_acpilib __initdata 244 + #endif 245 + 241 246 int acpi_table_parse(char *id, acpi_tbl_table_handler handler); 242 - int __init acpi_table_parse_entries(char *id, unsigned long table_size, 243 - int entry_id, 244 - acpi_tbl_entry_handler handler, 245 - unsigned int max_entries); 246 - int __init acpi_table_parse_entries_array(char *id, unsigned long table_size, 247 - struct acpi_subtable_proc *proc, int proc_num, 248 - unsigned int max_entries); 247 + int __init_or_acpilib acpi_table_parse_entries(char *id, 248 + unsigned long table_size, int entry_id, 249 + acpi_tbl_entry_handler handler, unsigned int max_entries); 250 + int __init_or_acpilib acpi_table_parse_entries_array(char *id, 251 + unsigned long table_size, struct acpi_subtable_proc *proc, 252 + int proc_num, unsigned int max_entries); 249 253 int acpi_table_parse_madt(enum acpi_madt_type id, 250 254 acpi_tbl_entry_handler handler, 251 255 unsigned int max_entries); 256 + int __init_or_acpilib 257 + acpi_table_parse_cedt(enum acpi_cedt_type id, 258 + acpi_tbl_entry_handler_arg handler_arg, void *arg); 259 + 252 260 int acpi_parse_mcfg (struct acpi_table_header *header); 253 261 void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); 254 262
+1 -2
tools/testing/cxl/Kbuild
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + ldflags-y += --wrap=acpi_table_parse_cedt 2 3 ldflags-y += --wrap=is_acpi_device_node 3 - ldflags-y += --wrap=acpi_get_table 4 - ldflags-y += --wrap=acpi_put_table 5 4 ldflags-y += --wrap=acpi_evaluate_integer 6 5 ldflags-y += --wrap=acpi_pci_find_root 7 6 ldflags-y += --wrap=pci_walk_bus
+47 -23
tools/testing/cxl/test/cxl.c
··· 182 182 }, 183 183 }; 184 184 185 + struct acpi_cedt_cfmws *mock_cfmws[4] = { 186 + [0] = &mock_cedt.cfmws0.cfmws, 187 + [1] = &mock_cedt.cfmws1.cfmws, 188 + [2] = &mock_cedt.cfmws2.cfmws, 189 + [3] = &mock_cedt.cfmws3.cfmws, 190 + }; 191 + 185 192 struct cxl_mock_res { 186 193 struct list_head list; 187 194 struct range range; ··· 239 232 240 233 static int populate_cedt(void) 241 234 { 242 - struct acpi_cedt_cfmws *cfmws[4] = { 243 - [0] = &mock_cedt.cfmws0.cfmws, 244 - [1] = &mock_cedt.cfmws1.cfmws, 245 - [2] = &mock_cedt.cfmws2.cfmws, 246 - [3] = &mock_cedt.cfmws3.cfmws, 247 - }; 248 235 struct cxl_mock_res *res; 249 236 int i; 250 237 ··· 258 257 chbs->length = size; 259 258 } 260 259 261 - for (i = 0; i < ARRAY_SIZE(cfmws); i++) { 262 - struct acpi_cedt_cfmws *window = cfmws[i]; 260 + for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) { 261 + struct acpi_cedt_cfmws *window = mock_cfmws[i]; 263 262 264 263 res = alloc_mock_res(window->window_size); 265 264 if (!res) ··· 270 269 return 0; 271 270 } 272 271 273 - static acpi_status mock_acpi_get_table(char *signature, u32 instance, 274 - struct acpi_table_header **out_table) 275 - { 276 - if (instance < U32_MAX || strcmp(signature, ACPI_SIG_CEDT) != 0) 277 - return acpi_get_table(signature, instance, out_table); 272 + /* 273 + * WARNING, this hack assumes the format of 'struct 274 + * cxl_cfmws_context' and 'struct cxl_chbs_context' share the property that 275 + * the first struct member is the device being probed by the cxl_acpi 276 + * driver. 277 + */ 278 + struct cxl_cedt_context { 279 + struct device *dev; 280 + }; 278 281 279 - *out_table = (struct acpi_table_header *) &mock_cedt; 280 - return AE_OK; 281 - } 282 - 283 - static void mock_acpi_put_table(struct acpi_table_header *table) 282 + static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id, 283 + acpi_tbl_entry_handler_arg handler_arg, 284 + void *arg) 284 285 { 285 - if (table == (struct acpi_table_header *) &mock_cedt) 286 - return; 287 - acpi_put_table(table); 286 + struct cxl_cedt_context *ctx = arg; 287 + struct device *dev = ctx->dev; 288 + union acpi_subtable_headers *h; 289 + unsigned long end; 290 + int i; 291 + 292 + if (dev != &cxl_acpi->dev) 293 + return acpi_table_parse_cedt(id, handler_arg, arg); 294 + 295 + if (id == ACPI_CEDT_TYPE_CHBS) 296 + for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) { 297 + h = (union acpi_subtable_headers *)&mock_cedt.chbs[i]; 298 + end = (unsigned long)&mock_cedt.chbs[i + 1]; 299 + handler_arg(h, arg, end); 300 + } 301 + 302 + if (id == ACPI_CEDT_TYPE_CFMWS) 303 + for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) { 304 + h = (union acpi_subtable_headers *) mock_cfmws[i]; 305 + end = (unsigned long) h + mock_cfmws[i]->header.length; 306 + handler_arg(h, arg, end); 307 + } 308 + 309 + return 0; 288 310 } 289 311 290 312 static bool is_mock_bridge(struct device *dev) ··· 412 388 .is_mock_port = is_mock_port, 413 389 .is_mock_dev = is_mock_dev, 414 390 .mock_port = mock_cxl_root_port, 415 - .acpi_get_table = mock_acpi_get_table, 416 - .acpi_put_table = mock_acpi_put_table, 391 + .acpi_table_parse_cedt = mock_acpi_table_parse_cedt, 417 392 .acpi_evaluate_integer = mock_acpi_evaluate_integer, 418 393 .acpi_pci_find_root = mock_acpi_pci_find_root, 419 394 .list = LIST_HEAD_INIT(cxl_mock_ops.list), ··· 597 574 module_init(cxl_test_init); 598 575 module_exit(cxl_test_exit); 599 576 MODULE_LICENSE("GPL v2"); 577 + MODULE_IMPORT_NS(ACPI);
+74 -25
tools/testing/cxl/test/mem.c
··· 28 28 .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA), 29 29 .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)), 30 30 }, 31 + { 32 + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO), 33 + .effect = cpu_to_le16(0), 34 + }, 31 35 }; 36 + 37 + /* See CXL 2.0 Table 181 Get Health Info Output Payload */ 38 + struct cxl_mbox_health_info { 39 + u8 health_status; 40 + u8 media_status; 41 + u8 ext_status; 42 + u8 life_used; 43 + __le16 temperature; 44 + __le32 dirty_shutdowns; 45 + __le32 volatile_errors; 46 + __le32 pmem_errors; 47 + } __packed; 32 48 33 49 static struct { 34 50 struct cxl_mbox_get_supported_logs gsl; ··· 70 54 return 0; 71 55 } 72 56 73 - static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) 57 + static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 74 58 { 75 59 struct cxl_mbox_get_log *gl = cmd->payload_in; 76 60 u32 offset = le32_to_cpu(gl->offset); ··· 80 64 81 65 if (cmd->size_in < sizeof(*gl)) 82 66 return -EINVAL; 83 - if (length > cxlm->payload_size) 67 + if (length > cxlds->payload_size) 84 68 return -EINVAL; 85 69 if (offset + length > sizeof(mock_cel)) 86 70 return -EINVAL; ··· 94 78 return 0; 95 79 } 96 80 97 - static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) 81 + static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 98 82 { 99 - struct platform_device *pdev = to_platform_device(cxlm->dev); 83 + struct platform_device *pdev = to_platform_device(cxlds->dev); 100 84 struct cxl_mbox_identify id = { 101 85 .fw_revision = { "mock fw v1 " }, 102 86 .lsa_size = cpu_to_le32(LSA_SIZE), ··· 136 120 return 0; 137 121 } 138 122 139 - static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) 123 + static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 140 124 { 141 125 struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in; 142 - void *lsa = dev_get_drvdata(cxlm->dev); 126 + void *lsa = dev_get_drvdata(cxlds->dev); 143 127 u32 offset, length; 144 128 145 129 if (sizeof(*get_lsa) > cmd->size_in) ··· 155 139 return 0; 156 140 } 157 141 158 - static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) 142 + static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 159 143 { 160 144 struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in; 161 - void *lsa = dev_get_drvdata(cxlm->dev); 145 + void *lsa = dev_get_drvdata(cxlds->dev); 162 146 u32 offset, length; 163 147 164 148 if (sizeof(*set_lsa) > cmd->size_in) ··· 172 156 return 0; 173 157 } 174 158 175 - static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) 159 + static int mock_health_info(struct cxl_dev_state *cxlds, 160 + struct cxl_mbox_cmd *cmd) 176 161 { 177 - struct device *dev = cxlm->dev; 162 + struct cxl_mbox_health_info health_info = { 163 + /* set flags for maint needed, perf degraded, hw replacement */ 164 + .health_status = 0x7, 165 + /* set media status to "All Data Lost" */ 166 + .media_status = 0x3, 167 + /* 168 + * set ext_status flags for: 169 + * ext_life_used: normal, 170 + * ext_temperature: critical, 171 + * ext_corrected_volatile: warning, 172 + * ext_corrected_persistent: normal, 173 + */ 174 + .ext_status = 0x18, 175 + .life_used = 15, 176 + .temperature = cpu_to_le16(25), 177 + .dirty_shutdowns = cpu_to_le32(10), 178 + .volatile_errors = cpu_to_le32(20), 179 + .pmem_errors = cpu_to_le32(30), 180 + }; 181 + 182 + if (cmd->size_out < sizeof(health_info)) 183 + return -EINVAL; 184 + 185 + memcpy(cmd->payload_out, &health_info, sizeof(health_info)); 186 + return 0; 187 + } 188 + 189 + static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 190 + { 191 + struct device *dev = cxlds->dev; 178 192 int rc = -EIO; 179 193 180 194 switch (cmd->opcode) { ··· 212 166 rc = mock_gsl(cmd); 213 167 break; 214 168 case CXL_MBOX_OP_GET_LOG: 215 - rc = mock_get_log(cxlm, cmd); 169 + rc = mock_get_log(cxlds, cmd); 216 170 break; 217 171 case CXL_MBOX_OP_IDENTIFY: 218 - rc = mock_id(cxlm, cmd); 172 + rc = mock_id(cxlds, cmd); 219 173 break; 220 174 case CXL_MBOX_OP_GET_LSA: 221 - rc = mock_get_lsa(cxlm, cmd); 175 + rc = mock_get_lsa(cxlds, cmd); 222 176 break; 223 177 case CXL_MBOX_OP_SET_LSA: 224 - rc = mock_set_lsa(cxlm, cmd); 178 + rc = mock_set_lsa(cxlds, cmd); 179 + break; 180 + case CXL_MBOX_OP_GET_HEALTH_INFO: 181 + rc = mock_health_info(cxlds, cmd); 225 182 break; 226 183 default: 227 184 break; ··· 245 196 { 246 197 struct device *dev = &pdev->dev; 247 198 struct cxl_memdev *cxlmd; 248 - struct cxl_mem *cxlm; 199 + struct cxl_dev_state *cxlds; 249 200 void *lsa; 250 201 int rc; 251 202 ··· 257 208 return rc; 258 209 dev_set_drvdata(dev, lsa); 259 210 260 - cxlm = cxl_mem_create(dev); 261 - if (IS_ERR(cxlm)) 262 - return PTR_ERR(cxlm); 211 + cxlds = cxl_dev_state_create(dev); 212 + if (IS_ERR(cxlds)) 213 + return PTR_ERR(cxlds); 263 214 264 - cxlm->mbox_send = cxl_mock_mbox_send; 265 - cxlm->payload_size = SZ_4K; 215 + cxlds->mbox_send = cxl_mock_mbox_send; 216 + cxlds->payload_size = SZ_4K; 266 217 267 - rc = cxl_mem_enumerate_cmds(cxlm); 218 + rc = cxl_enumerate_cmds(cxlds); 268 219 if (rc) 269 220 return rc; 270 221 271 - rc = cxl_mem_identify(cxlm); 222 + rc = cxl_dev_state_identify(cxlds); 272 223 if (rc) 273 224 return rc; 274 225 275 - rc = cxl_mem_create_range_info(cxlm); 226 + rc = cxl_mem_create_range_info(cxlds); 276 227 if (rc) 277 228 return rc; 278 229 279 - cxlmd = devm_cxl_add_memdev(cxlm); 230 + cxlmd = devm_cxl_add_memdev(cxlds); 280 231 if (IS_ERR(cxlmd)) 281 232 return PTR_ERR(cxlmd); 282 233 283 - if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) 234 + if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) 284 235 rc = devm_cxl_add_nvdimm(dev, cxlmd); 285 236 286 237 return 0;
+11 -23
tools/testing/cxl/test/mock.c
··· 58 58 } 59 59 EXPORT_SYMBOL(__wrap_is_acpi_device_node); 60 60 61 - acpi_status __wrap_acpi_get_table(char *signature, u32 instance, 62 - struct acpi_table_header **out_table) 61 + int __wrap_acpi_table_parse_cedt(enum acpi_cedt_type id, 62 + acpi_tbl_entry_handler_arg handler_arg, 63 + void *arg) 63 64 { 64 - int index; 65 - struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 66 - acpi_status status; 67 - 68 - if (ops) 69 - status = ops->acpi_get_table(signature, instance, out_table); 70 - else 71 - status = acpi_get_table(signature, instance, out_table); 72 - 73 - put_cxl_mock_ops(index); 74 - 75 - return status; 76 - } 77 - EXPORT_SYMBOL(__wrap_acpi_get_table); 78 - 79 - void __wrap_acpi_put_table(struct acpi_table_header *table) 80 - { 81 - int index; 65 + int index, rc; 82 66 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 83 67 84 68 if (ops) 85 - ops->acpi_put_table(table); 69 + rc = ops->acpi_table_parse_cedt(id, handler_arg, arg); 86 70 else 87 - acpi_put_table(table); 71 + rc = acpi_table_parse_cedt(id, handler_arg, arg); 72 + 88 73 put_cxl_mock_ops(index); 74 + 75 + return rc; 89 76 } 90 - EXPORT_SYMBOL(__wrap_acpi_put_table); 77 + EXPORT_SYMBOL_NS_GPL(__wrap_acpi_table_parse_cedt, ACPI); 91 78 92 79 acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle, 93 80 acpi_string pathname, ··· 156 169 EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); 157 170 158 171 MODULE_LICENSE("GPL v2"); 172 + MODULE_IMPORT_NS(ACPI);
+3 -3
tools/testing/cxl/test/mock.h
··· 6 6 struct cxl_mock_ops { 7 7 struct list_head list; 8 8 bool (*is_mock_adev)(struct acpi_device *dev); 9 - acpi_status (*acpi_get_table)(char *signature, u32 instance, 10 - struct acpi_table_header **out_table); 11 - void (*acpi_put_table)(struct acpi_table_header *table); 9 + int (*acpi_table_parse_cedt)(enum acpi_cedt_type id, 10 + acpi_tbl_entry_handler_arg handler_arg, 11 + void *arg); 12 12 bool (*is_mock_bridge)(struct device *dev); 13 13 acpi_status (*acpi_evaluate_integer)(acpi_handle handle, 14 14 acpi_string pathname,