mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
The cxl_test unit test environment on qemu always hits below call trace
with KASAN enabled:
BUG: KASAN: slab-out-of-bounds in cxl_setup_parent_dport+0x480/0x530 [cxl_core]
Read of size 1 at addr ff110000676014f8 by task (udev-worker)/676[ 24.424403] CPU: 2 PID: 676 Comm: (udev-worker) Tainted: G O N 6.10.0-qemucxl #1
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS edk2-20240214-2.el9 02/14/2024
Call Trace:
<TASK>
dump_stack_lvl+0xea/0x150
print_report+0xce/0x610
? kasan_complete_mode_report_info+0x40/0x200
kasan_report+0xcc/0x110
__asan_report_load1_noabort+0x18/0x20
cxl_setup_parent_dport+0x480/0x530 [cxl_core]
cxl_mem_probe+0x49b/0xaa0 [cxl_mem]
cxl_test module models a CXL topology for testing, it creates some
emulated dports with platform devices in the CXL topology, so the
dport_dev of an emulated dport points to a platform device rather than a
pci device or a pci host bridge in the case. Currently,
cxl_setup_parent_dport() is used to set up RAS and AER capability on the
dport connected to the CXL memory device, but cxl_test does not support
RAS or AER functionality yet, so the fix is implementing a
__wrap_cxl_setup_parent_dport() to filter out all emulated dports,
guarantees only real dports can be handled by cxl_setup_parent_dport().
Fixes: f05fd10d13 ("cxl/pci: Add RCH downstream port AER register discovery")
Reported-by: Pengfei Xu <pengfei.xu@intel.com>
Closes: https://lore.kernel.org/linux-cxl/ZrHTBp2O+HtUe6kt@xpf.sh.intel.com/T/#t
Signed-off-by: Li Ming <ming4.li@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Ira Weiny <ira.weiny@intel.com>
Tested-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20240809082750.3015641-3-ming4.li@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
317 lines
7.7 KiB
C
317 lines
7.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
//Copyright(c) 2021 Intel Corporation. All rights reserved.
|
|
|
|
#include <linux/libnvdimm.h>
|
|
#include <linux/rculist.h>
|
|
#include <linux/device.h>
|
|
#include <linux/export.h>
|
|
#include <linux/acpi.h>
|
|
#include <linux/pci.h>
|
|
#include <cxlmem.h>
|
|
#include <cxlpci.h>
|
|
#include "mock.h"
|
|
|
|
static LIST_HEAD(mock);
|
|
|
|
void register_cxl_mock_ops(struct cxl_mock_ops *ops)
|
|
{
|
|
list_add_rcu(&ops->list, &mock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(register_cxl_mock_ops);
|
|
|
|
DEFINE_STATIC_SRCU(cxl_mock_srcu);
|
|
|
|
void unregister_cxl_mock_ops(struct cxl_mock_ops *ops)
|
|
{
|
|
list_del_rcu(&ops->list);
|
|
synchronize_srcu(&cxl_mock_srcu);
|
|
}
|
|
EXPORT_SYMBOL_GPL(unregister_cxl_mock_ops);
|
|
|
|
struct cxl_mock_ops *get_cxl_mock_ops(int *index)
|
|
{
|
|
*index = srcu_read_lock(&cxl_mock_srcu);
|
|
return list_first_or_null_rcu(&mock, struct cxl_mock_ops, list);
|
|
}
|
|
EXPORT_SYMBOL_GPL(get_cxl_mock_ops);
|
|
|
|
void put_cxl_mock_ops(int index)
|
|
{
|
|
srcu_read_unlock(&cxl_mock_srcu, index);
|
|
}
|
|
EXPORT_SYMBOL_GPL(put_cxl_mock_ops);
|
|
|
|
bool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode)
|
|
{
|
|
struct acpi_device *adev =
|
|
container_of(fwnode, struct acpi_device, fwnode);
|
|
int index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
bool retval = false;
|
|
|
|
if (ops)
|
|
retval = ops->is_mock_adev(adev);
|
|
|
|
if (!retval)
|
|
retval = is_acpi_device_node(fwnode);
|
|
|
|
put_cxl_mock_ops(index);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL(__wrap_is_acpi_device_node);
|
|
|
|
int __wrap_acpi_table_parse_cedt(enum acpi_cedt_type id,
|
|
acpi_tbl_entry_handler_arg handler_arg,
|
|
void *arg)
|
|
{
|
|
int index, rc;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops)
|
|
rc = ops->acpi_table_parse_cedt(id, handler_arg, arg);
|
|
else
|
|
rc = acpi_table_parse_cedt(id, handler_arg, arg);
|
|
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_acpi_table_parse_cedt, ACPI);
|
|
|
|
acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle,
|
|
acpi_string pathname,
|
|
struct acpi_object_list *arguments,
|
|
unsigned long long *data)
|
|
{
|
|
int index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
acpi_status status;
|
|
|
|
if (ops)
|
|
status = ops->acpi_evaluate_integer(handle, pathname, arguments,
|
|
data);
|
|
else
|
|
status = acpi_evaluate_integer(handle, pathname, arguments,
|
|
data);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return status;
|
|
}
|
|
EXPORT_SYMBOL(__wrap_acpi_evaluate_integer);
|
|
|
|
struct acpi_pci_root *__wrap_acpi_pci_find_root(acpi_handle handle)
|
|
{
|
|
int index;
|
|
struct acpi_pci_root *root;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops)
|
|
root = ops->acpi_pci_find_root(handle);
|
|
else
|
|
root = acpi_pci_find_root(handle);
|
|
|
|
put_cxl_mock_ops(index);
|
|
|
|
return root;
|
|
}
|
|
EXPORT_SYMBOL_GPL(__wrap_acpi_pci_find_root);
|
|
|
|
struct nvdimm_bus *
|
|
__wrap_nvdimm_bus_register(struct device *dev,
|
|
struct nvdimm_bus_descriptor *nd_desc)
|
|
{
|
|
int index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_dev(dev->parent->parent))
|
|
nd_desc->provider_name = "cxl_test";
|
|
put_cxl_mock_ops(index);
|
|
|
|
return nvdimm_bus_register(dev, nd_desc);
|
|
}
|
|
EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register);
|
|
|
|
struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
|
|
struct cxl_endpoint_dvsec_info *info)
|
|
|
|
{
|
|
int index;
|
|
struct cxl_hdm *cxlhdm;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_port(port->uport_dev))
|
|
cxlhdm = ops->devm_cxl_setup_hdm(port, info);
|
|
else
|
|
cxlhdm = devm_cxl_setup_hdm(port, info);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return cxlhdm;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL);
|
|
|
|
int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
|
|
{
|
|
int rc, index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_port(port->uport_dev))
|
|
rc = ops->devm_cxl_add_passthrough_decoder(port);
|
|
else
|
|
rc = devm_cxl_add_passthrough_decoder(port);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, CXL);
|
|
|
|
int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
|
|
struct cxl_endpoint_dvsec_info *info)
|
|
{
|
|
int rc, index;
|
|
struct cxl_port *port = cxlhdm->port;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_port(port->uport_dev))
|
|
rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info);
|
|
else
|
|
rc = devm_cxl_enumerate_decoders(cxlhdm, info);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, CXL);
|
|
|
|
int __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port)
|
|
{
|
|
int rc, index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_port(port->uport_dev))
|
|
rc = ops->devm_cxl_port_enumerate_dports(port);
|
|
else
|
|
rc = devm_cxl_port_enumerate_dports(port);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_port_enumerate_dports, CXL);
|
|
|
|
int __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds)
|
|
{
|
|
int rc, index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_dev(cxlds->dev))
|
|
rc = 0;
|
|
else
|
|
rc = cxl_await_media_ready(cxlds);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, CXL);
|
|
|
|
int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
|
|
struct cxl_hdm *cxlhdm,
|
|
struct cxl_endpoint_dvsec_info *info)
|
|
{
|
|
int rc = 0, index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_dev(cxlds->dev))
|
|
rc = 0;
|
|
else
|
|
rc = cxl_hdm_decode_init(cxlds, cxlhdm, info);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_hdm_decode_init, CXL);
|
|
|
|
int __wrap_cxl_dvsec_rr_decode(struct device *dev, int dvsec,
|
|
struct cxl_endpoint_dvsec_info *info)
|
|
{
|
|
int rc = 0, index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_dev(dev))
|
|
rc = 0;
|
|
else
|
|
rc = cxl_dvsec_rr_decode(dev, dvsec, info);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dvsec_rr_decode, CXL);
|
|
|
|
struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port,
|
|
struct device *dport_dev,
|
|
int port_id,
|
|
resource_size_t rcrb)
|
|
{
|
|
int index;
|
|
struct cxl_dport *dport;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_port(dport_dev)) {
|
|
dport = devm_cxl_add_dport(port, dport_dev, port_id,
|
|
CXL_RESOURCE_NONE);
|
|
if (!IS_ERR(dport)) {
|
|
dport->rcrb.base = rcrb;
|
|
dport->rch = true;
|
|
}
|
|
} else
|
|
dport = devm_cxl_add_rch_dport(port, dport_dev, port_id, rcrb);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return dport;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_rch_dport, CXL);
|
|
|
|
resource_size_t __wrap_cxl_rcd_component_reg_phys(struct device *dev,
|
|
struct cxl_dport *dport)
|
|
{
|
|
int index;
|
|
resource_size_t component_reg_phys;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (ops && ops->is_mock_port(dev))
|
|
component_reg_phys = CXL_RESOURCE_NONE;
|
|
else
|
|
component_reg_phys = cxl_rcd_component_reg_phys(dev, dport);
|
|
put_cxl_mock_ops(index);
|
|
|
|
return component_reg_phys;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcd_component_reg_phys, CXL);
|
|
|
|
void __wrap_cxl_endpoint_parse_cdat(struct cxl_port *port)
|
|
{
|
|
int index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
|
|
|
|
if (ops && ops->is_mock_dev(cxlmd->dev.parent))
|
|
ops->cxl_endpoint_parse_cdat(port);
|
|
else
|
|
cxl_endpoint_parse_cdat(port);
|
|
put_cxl_mock_ops(index);
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_endpoint_parse_cdat, CXL);
|
|
|
|
void __wrap_cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport)
|
|
{
|
|
int index;
|
|
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
|
|
|
|
if (!ops || !ops->is_mock_port(dport->dport_dev))
|
|
cxl_setup_parent_dport(host, dport);
|
|
|
|
put_cxl_mock_ops(index);
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_setup_parent_dport, CXL);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_IMPORT_NS(ACPI);
|
|
MODULE_IMPORT_NS(CXL);
|