diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-12 15:57:59 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-12 15:57:59 -0800 |
commit | 362f533a2a1098fe95020cb59340023e9b11d062 (patch) | |
tree | 12e1162a0c973ff480c789e3f2b3066e42e0ac6a /tools | |
parent | 3acbdbf42e943d85174401357a6b6243479d4c76 (diff) | |
parent | be185c2988b48db65348d94168c793bdbc8d23c3 (diff) | |
download | linux-362f533a2a1098fe95020cb59340023e9b11d062.tar.gz |
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
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/cxl/Kbuild | 3 | ||||
-rw-r--r-- | tools/testing/cxl/test/cxl.c | 68 | ||||
-rw-r--r-- | tools/testing/cxl/test/mem.c | 99 | ||||
-rw-r--r-- | tools/testing/cxl/test/mock.c | 30 | ||||
-rw-r--r-- | tools/testing/cxl/test/mock.h | 6 |
5 files changed, 133 insertions, 73 deletions
diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 86deba8308a1..1acdf2fc31c5 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +ldflags-y += --wrap=acpi_table_parse_cedt ldflags-y += --wrap=is_acpi_device_node -ldflags-y += --wrap=acpi_get_table -ldflags-y += --wrap=acpi_put_table ldflags-y += --wrap=acpi_evaluate_integer ldflags-y += --wrap=acpi_pci_find_root ldflags-y += --wrap=pci_walk_bus diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index cb32f9e27d5d..736d99006fb7 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -182,6 +182,13 @@ static struct { }, }; +struct acpi_cedt_cfmws *mock_cfmws[4] = { + [0] = &mock_cedt.cfmws0.cfmws, + [1] = &mock_cedt.cfmws1.cfmws, + [2] = &mock_cedt.cfmws2.cfmws, + [3] = &mock_cedt.cfmws3.cfmws, +}; + struct cxl_mock_res { struct list_head list; struct range range; @@ -232,12 +239,6 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size) static int populate_cedt(void) { - struct acpi_cedt_cfmws *cfmws[4] = { - [0] = &mock_cedt.cfmws0.cfmws, - [1] = &mock_cedt.cfmws1.cfmws, - [2] = &mock_cedt.cfmws2.cfmws, - [3] = &mock_cedt.cfmws3.cfmws, - }; struct cxl_mock_res *res; int i; @@ -257,8 +258,8 @@ static int populate_cedt(void) chbs->length = size; } - for (i = 0; i < ARRAY_SIZE(cfmws); i++) { - struct acpi_cedt_cfmws *window = cfmws[i]; + for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) { + struct acpi_cedt_cfmws *window = mock_cfmws[i]; res = alloc_mock_res(window->window_size); if (!res) @@ -269,21 +270,44 @@ static int populate_cedt(void) return 0; } -static acpi_status mock_acpi_get_table(char *signature, u32 instance, - struct acpi_table_header **out_table) +/* + * WARNING, this hack assumes the format of 'struct + * cxl_cfmws_context' and 'struct cxl_chbs_context' share the property that + * the first struct member is the device being probed by the cxl_acpi + * driver. + */ +struct cxl_cedt_context { + struct device *dev; +}; + +static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id, + acpi_tbl_entry_handler_arg handler_arg, + void *arg) { - if (instance < U32_MAX || strcmp(signature, ACPI_SIG_CEDT) != 0) - return acpi_get_table(signature, instance, out_table); + struct cxl_cedt_context *ctx = arg; + struct device *dev = ctx->dev; + union acpi_subtable_headers *h; + unsigned long end; + int i; - *out_table = (struct acpi_table_header *) &mock_cedt; - return AE_OK; -} + if (dev != &cxl_acpi->dev) + return acpi_table_parse_cedt(id, handler_arg, arg); -static void mock_acpi_put_table(struct acpi_table_header *table) -{ - if (table == (struct acpi_table_header *) &mock_cedt) - return; - acpi_put_table(table); + if (id == ACPI_CEDT_TYPE_CHBS) + for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) { + h = (union acpi_subtable_headers *)&mock_cedt.chbs[i]; + end = (unsigned long)&mock_cedt.chbs[i + 1]; + handler_arg(h, arg, end); + } + + if (id == ACPI_CEDT_TYPE_CFMWS) + for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) { + h = (union acpi_subtable_headers *) mock_cfmws[i]; + end = (unsigned long) h + mock_cfmws[i]->header.length; + handler_arg(h, arg, end); + } + + return 0; } static bool is_mock_bridge(struct device *dev) @@ -388,8 +412,7 @@ static struct cxl_mock_ops cxl_mock_ops = { .is_mock_port = is_mock_port, .is_mock_dev = is_mock_dev, .mock_port = mock_cxl_root_port, - .acpi_get_table = mock_acpi_get_table, - .acpi_put_table = mock_acpi_put_table, + .acpi_table_parse_cedt = mock_acpi_table_parse_cedt, .acpi_evaluate_integer = mock_acpi_evaluate_integer, .acpi_pci_find_root = mock_acpi_pci_find_root, .list = LIST_HEAD_INIT(cxl_mock_ops.list), @@ -574,3 +597,4 @@ static __exit void cxl_test_exit(void) module_init(cxl_test_init); module_exit(cxl_test_exit); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(ACPI); diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index 12a8437a9ca0..8c2086c4caef 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -28,8 +28,24 @@ static struct cxl_cel_entry mock_cel[] = { .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA), .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)), }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO), + .effect = cpu_to_le16(0), + }, }; +/* See CXL 2.0 Table 181 Get Health Info Output Payload */ +struct cxl_mbox_health_info { + u8 health_status; + u8 media_status; + u8 ext_status; + u8 life_used; + __le16 temperature; + __le32 dirty_shutdowns; + __le32 volatile_errors; + __le32 pmem_errors; +} __packed; + static struct { struct cxl_mbox_get_supported_logs gsl; struct cxl_gsl_entry entry; @@ -54,7 +70,7 @@ static int mock_gsl(struct cxl_mbox_cmd *cmd) return 0; } -static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) { struct cxl_mbox_get_log *gl = cmd->payload_in; u32 offset = le32_to_cpu(gl->offset); @@ -64,7 +80,7 @@ static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) if (cmd->size_in < sizeof(*gl)) return -EINVAL; - if (length > cxlm->payload_size) + if (length > cxlds->payload_size) return -EINVAL; if (offset + length > sizeof(mock_cel)) return -EINVAL; @@ -78,9 +94,9 @@ static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) return 0; } -static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) { - struct platform_device *pdev = to_platform_device(cxlm->dev); + struct platform_device *pdev = to_platform_device(cxlds->dev); struct cxl_mbox_identify id = { .fw_revision = { "mock fw v1 " }, .lsa_size = cpu_to_le32(LSA_SIZE), @@ -120,10 +136,10 @@ static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) return 0; } -static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) { struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in; - void *lsa = dev_get_drvdata(cxlm->dev); + void *lsa = dev_get_drvdata(cxlds->dev); u32 offset, length; if (sizeof(*get_lsa) > cmd->size_in) @@ -139,10 +155,10 @@ static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) return 0; } -static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) { struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in; - void *lsa = dev_get_drvdata(cxlm->dev); + void *lsa = dev_get_drvdata(cxlds->dev); u32 offset, length; if (sizeof(*set_lsa) > cmd->size_in) @@ -156,9 +172,39 @@ static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) return 0; } -static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +static int mock_health_info(struct cxl_dev_state *cxlds, + struct cxl_mbox_cmd *cmd) { - struct device *dev = cxlm->dev; + struct cxl_mbox_health_info health_info = { + /* set flags for maint needed, perf degraded, hw replacement */ + .health_status = 0x7, + /* set media status to "All Data Lost" */ + .media_status = 0x3, + /* + * set ext_status flags for: + * ext_life_used: normal, + * ext_temperature: critical, + * ext_corrected_volatile: warning, + * ext_corrected_persistent: normal, + */ + .ext_status = 0x18, + .life_used = 15, + .temperature = cpu_to_le16(25), + .dirty_shutdowns = cpu_to_le32(10), + .volatile_errors = cpu_to_le32(20), + .pmem_errors = cpu_to_le32(30), + }; + + if (cmd->size_out < sizeof(health_info)) + return -EINVAL; + + memcpy(cmd->payload_out, &health_info, sizeof(health_info)); + return 0; +} + +static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) +{ + struct device *dev = cxlds->dev; int rc = -EIO; switch (cmd->opcode) { @@ -166,16 +212,19 @@ static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) rc = mock_gsl(cmd); break; case CXL_MBOX_OP_GET_LOG: - rc = mock_get_log(cxlm, cmd); + rc = mock_get_log(cxlds, cmd); break; case CXL_MBOX_OP_IDENTIFY: - rc = mock_id(cxlm, cmd); + rc = mock_id(cxlds, cmd); break; case CXL_MBOX_OP_GET_LSA: - rc = mock_get_lsa(cxlm, cmd); + rc = mock_get_lsa(cxlds, cmd); break; case CXL_MBOX_OP_SET_LSA: - rc = mock_set_lsa(cxlm, cmd); + rc = mock_set_lsa(cxlds, cmd); + break; + case CXL_MBOX_OP_GET_HEALTH_INFO: + rc = mock_health_info(cxlds, cmd); break; default: break; @@ -196,7 +245,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cxl_memdev *cxlmd; - struct cxl_mem *cxlm; + struct cxl_dev_state *cxlds; void *lsa; int rc; @@ -208,30 +257,30 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) return rc; dev_set_drvdata(dev, lsa); - cxlm = cxl_mem_create(dev); - if (IS_ERR(cxlm)) - return PTR_ERR(cxlm); + cxlds = cxl_dev_state_create(dev); + if (IS_ERR(cxlds)) + return PTR_ERR(cxlds); - cxlm->mbox_send = cxl_mock_mbox_send; - cxlm->payload_size = SZ_4K; + cxlds->mbox_send = cxl_mock_mbox_send; + cxlds->payload_size = SZ_4K; - rc = cxl_mem_enumerate_cmds(cxlm); + rc = cxl_enumerate_cmds(cxlds); if (rc) return rc; - rc = cxl_mem_identify(cxlm); + rc = cxl_dev_state_identify(cxlds); if (rc) return rc; - rc = cxl_mem_create_range_info(cxlm); + rc = cxl_mem_create_range_info(cxlds); if (rc) return rc; - cxlmd = devm_cxl_add_memdev(cxlm); + cxlmd = devm_cxl_add_memdev(cxlds); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); - if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) + if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) rc = devm_cxl_add_nvdimm(dev, cxlmd); return 0; diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index b8c108abcf07..17408f892df4 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -58,36 +58,23 @@ bool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode) } EXPORT_SYMBOL(__wrap_is_acpi_device_node); -acpi_status __wrap_acpi_get_table(char *signature, u32 instance, - struct acpi_table_header **out_table) +int __wrap_acpi_table_parse_cedt(enum acpi_cedt_type id, + acpi_tbl_entry_handler_arg handler_arg, + void *arg) { - int index; + int index, rc; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - acpi_status status; if (ops) - status = ops->acpi_get_table(signature, instance, out_table); + rc = ops->acpi_table_parse_cedt(id, handler_arg, arg); else - status = acpi_get_table(signature, instance, out_table); + rc = acpi_table_parse_cedt(id, handler_arg, arg); put_cxl_mock_ops(index); - return status; -} -EXPORT_SYMBOL(__wrap_acpi_get_table); - -void __wrap_acpi_put_table(struct acpi_table_header *table) -{ - int index; - struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - - if (ops) - ops->acpi_put_table(table); - else - acpi_put_table(table); - put_cxl_mock_ops(index); + return rc; } -EXPORT_SYMBOL(__wrap_acpi_put_table); +EXPORT_SYMBOL_NS_GPL(__wrap_acpi_table_parse_cedt, ACPI); acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, @@ -169,3 +156,4 @@ __wrap_nvdimm_bus_register(struct device *dev, EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(ACPI); diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h index 805a94cb3fbe..15ed0fd877e4 100644 --- a/tools/testing/cxl/test/mock.h +++ b/tools/testing/cxl/test/mock.h @@ -6,9 +6,9 @@ struct cxl_mock_ops { struct list_head list; bool (*is_mock_adev)(struct acpi_device *dev); - acpi_status (*acpi_get_table)(char *signature, u32 instance, - struct acpi_table_header **out_table); - void (*acpi_put_table)(struct acpi_table_header *table); + int (*acpi_table_parse_cedt)(enum acpi_cedt_type id, + acpi_tbl_entry_handler_arg handler_arg, + void *arg); bool (*is_mock_bridge)(struct device *dev); acpi_status (*acpi_evaluate_integer)(acpi_handle handle, acpi_string pathname, |