291 lines
7.0 KiB
C
291 lines
7.0 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);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_IMPORT_NS(ACPI);
|
|
MODULE_IMPORT_NS(CXL);
|