| // 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); |
| |
| MODULE_LICENSE("GPL v2"); |
| MODULE_IMPORT_NS(ACPI); |
| MODULE_IMPORT_NS(CXL); |