162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci//Copyright(c) 2021 Intel Corporation. All rights reserved.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/libnvdimm.h>
562306a36Sopenharmony_ci#include <linux/rculist.h>
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/export.h>
862306a36Sopenharmony_ci#include <linux/acpi.h>
962306a36Sopenharmony_ci#include <linux/pci.h>
1062306a36Sopenharmony_ci#include <cxlmem.h>
1162306a36Sopenharmony_ci#include <cxlpci.h>
1262306a36Sopenharmony_ci#include "mock.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic LIST_HEAD(mock);
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_civoid register_cxl_mock_ops(struct cxl_mock_ops *ops)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	list_add_rcu(&ops->list, &mock);
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(register_cxl_mock_ops);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciDEFINE_STATIC_SRCU(cxl_mock_srcu);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_civoid unregister_cxl_mock_ops(struct cxl_mock_ops *ops)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	list_del_rcu(&ops->list);
2762306a36Sopenharmony_ci	synchronize_srcu(&cxl_mock_srcu);
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_cxl_mock_ops);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct cxl_mock_ops *get_cxl_mock_ops(int *index)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	*index = srcu_read_lock(&cxl_mock_srcu);
3462306a36Sopenharmony_ci	return list_first_or_null_rcu(&mock, struct cxl_mock_ops, list);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_cxl_mock_ops);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_civoid put_cxl_mock_ops(int index)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	srcu_read_unlock(&cxl_mock_srcu, index);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(put_cxl_mock_ops);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cibool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct acpi_device *adev =
4762306a36Sopenharmony_ci		container_of(fwnode, struct acpi_device, fwnode);
4862306a36Sopenharmony_ci	int index;
4962306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
5062306a36Sopenharmony_ci	bool retval = false;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (ops)
5362306a36Sopenharmony_ci		retval = ops->is_mock_adev(adev);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (!retval)
5662306a36Sopenharmony_ci		retval = is_acpi_device_node(fwnode);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	put_cxl_mock_ops(index);
5962306a36Sopenharmony_ci	return retval;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ciEXPORT_SYMBOL(__wrap_is_acpi_device_node);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciint __wrap_acpi_table_parse_cedt(enum acpi_cedt_type id,
6462306a36Sopenharmony_ci				 acpi_tbl_entry_handler_arg handler_arg,
6562306a36Sopenharmony_ci				 void *arg)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	int index, rc;
6862306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (ops)
7162306a36Sopenharmony_ci		rc = ops->acpi_table_parse_cedt(id, handler_arg, arg);
7262306a36Sopenharmony_ci	else
7362306a36Sopenharmony_ci		rc = acpi_table_parse_cedt(id, handler_arg, arg);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	put_cxl_mock_ops(index);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return rc;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_acpi_table_parse_cedt, ACPI);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciacpi_status __wrap_acpi_evaluate_integer(acpi_handle handle,
8262306a36Sopenharmony_ci					 acpi_string pathname,
8362306a36Sopenharmony_ci					 struct acpi_object_list *arguments,
8462306a36Sopenharmony_ci					 unsigned long long *data)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	int index;
8762306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
8862306a36Sopenharmony_ci	acpi_status status;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (ops)
9162306a36Sopenharmony_ci		status = ops->acpi_evaluate_integer(handle, pathname, arguments,
9262306a36Sopenharmony_ci						    data);
9362306a36Sopenharmony_ci	else
9462306a36Sopenharmony_ci		status = acpi_evaluate_integer(handle, pathname, arguments,
9562306a36Sopenharmony_ci					       data);
9662306a36Sopenharmony_ci	put_cxl_mock_ops(index);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return status;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ciEXPORT_SYMBOL(__wrap_acpi_evaluate_integer);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct acpi_pci_root *__wrap_acpi_pci_find_root(acpi_handle handle)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int index;
10562306a36Sopenharmony_ci	struct acpi_pci_root *root;
10662306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (ops)
10962306a36Sopenharmony_ci		root = ops->acpi_pci_find_root(handle);
11062306a36Sopenharmony_ci	else
11162306a36Sopenharmony_ci		root = acpi_pci_find_root(handle);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	put_cxl_mock_ops(index);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return root;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__wrap_acpi_pci_find_root);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct nvdimm_bus *
12062306a36Sopenharmony_ci__wrap_nvdimm_bus_register(struct device *dev,
12162306a36Sopenharmony_ci			   struct nvdimm_bus_descriptor *nd_desc)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	int index;
12462306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (ops && ops->is_mock_dev(dev->parent->parent))
12762306a36Sopenharmony_ci		nd_desc->provider_name = "cxl_test";
12862306a36Sopenharmony_ci	put_cxl_mock_ops(index);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return nvdimm_bus_register(dev, nd_desc);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistruct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
13562306a36Sopenharmony_ci					  struct cxl_endpoint_dvsec_info *info)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	int index;
13962306a36Sopenharmony_ci	struct cxl_hdm *cxlhdm;
14062306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (ops && ops->is_mock_port(port->uport_dev))
14362306a36Sopenharmony_ci		cxlhdm = ops->devm_cxl_setup_hdm(port, info);
14462306a36Sopenharmony_ci	else
14562306a36Sopenharmony_ci		cxlhdm = devm_cxl_setup_hdm(port, info);
14662306a36Sopenharmony_ci	put_cxl_mock_ops(index);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return cxlhdm;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ciint __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	int rc, index;
15562306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (ops && ops->is_mock_port(port->uport_dev))
15862306a36Sopenharmony_ci		rc = ops->devm_cxl_add_passthrough_decoder(port);
15962306a36Sopenharmony_ci	else
16062306a36Sopenharmony_ci		rc = devm_cxl_add_passthrough_decoder(port);
16162306a36Sopenharmony_ci	put_cxl_mock_ops(index);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return rc;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, CXL);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciint __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
16862306a36Sopenharmony_ci				       struct cxl_endpoint_dvsec_info *info)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	int rc, index;
17162306a36Sopenharmony_ci	struct cxl_port *port = cxlhdm->port;
17262306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (ops && ops->is_mock_port(port->uport_dev))
17562306a36Sopenharmony_ci		rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info);
17662306a36Sopenharmony_ci	else
17762306a36Sopenharmony_ci		rc = devm_cxl_enumerate_decoders(cxlhdm, info);
17862306a36Sopenharmony_ci	put_cxl_mock_ops(index);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return rc;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, CXL);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ciint __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	int rc, index;
18762306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (ops && ops->is_mock_port(port->uport_dev))
19062306a36Sopenharmony_ci		rc = ops->devm_cxl_port_enumerate_dports(port);
19162306a36Sopenharmony_ci	else
19262306a36Sopenharmony_ci		rc = devm_cxl_port_enumerate_dports(port);
19362306a36Sopenharmony_ci	put_cxl_mock_ops(index);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return rc;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_port_enumerate_dports, CXL);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciint __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	int rc, index;
20262306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (ops && ops->is_mock_dev(cxlds->dev))
20562306a36Sopenharmony_ci		rc = 0;
20662306a36Sopenharmony_ci	else
20762306a36Sopenharmony_ci		rc = cxl_await_media_ready(cxlds);
20862306a36Sopenharmony_ci	put_cxl_mock_ops(index);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	return rc;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, CXL);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciint __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
21562306a36Sopenharmony_ci			       struct cxl_hdm *cxlhdm,
21662306a36Sopenharmony_ci			       struct cxl_endpoint_dvsec_info *info)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	int rc = 0, index;
21962306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (ops && ops->is_mock_dev(cxlds->dev))
22262306a36Sopenharmony_ci		rc = 0;
22362306a36Sopenharmony_ci	else
22462306a36Sopenharmony_ci		rc = cxl_hdm_decode_init(cxlds, cxlhdm, info);
22562306a36Sopenharmony_ci	put_cxl_mock_ops(index);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return rc;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_cxl_hdm_decode_init, CXL);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ciint __wrap_cxl_dvsec_rr_decode(struct device *dev, int dvsec,
23262306a36Sopenharmony_ci			       struct cxl_endpoint_dvsec_info *info)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	int rc = 0, index;
23562306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (ops && ops->is_mock_dev(dev))
23862306a36Sopenharmony_ci		rc = 0;
23962306a36Sopenharmony_ci	else
24062306a36Sopenharmony_ci		rc = cxl_dvsec_rr_decode(dev, dvsec, info);
24162306a36Sopenharmony_ci	put_cxl_mock_ops(index);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return rc;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_cxl_dvsec_rr_decode, CXL);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistruct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port,
24862306a36Sopenharmony_ci						struct device *dport_dev,
24962306a36Sopenharmony_ci						int port_id,
25062306a36Sopenharmony_ci						resource_size_t rcrb)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	int index;
25362306a36Sopenharmony_ci	struct cxl_dport *dport;
25462306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (ops && ops->is_mock_port(dport_dev)) {
25762306a36Sopenharmony_ci		dport = devm_cxl_add_dport(port, dport_dev, port_id,
25862306a36Sopenharmony_ci					   CXL_RESOURCE_NONE);
25962306a36Sopenharmony_ci		if (!IS_ERR(dport)) {
26062306a36Sopenharmony_ci			dport->rcrb.base = rcrb;
26162306a36Sopenharmony_ci			dport->rch = true;
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci	} else
26462306a36Sopenharmony_ci		dport = devm_cxl_add_rch_dport(port, dport_dev, port_id, rcrb);
26562306a36Sopenharmony_ci	put_cxl_mock_ops(index);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	return dport;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_rch_dport, CXL);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ciresource_size_t __wrap_cxl_rcd_component_reg_phys(struct device *dev,
27262306a36Sopenharmony_ci						  struct cxl_dport *dport)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	int index;
27562306a36Sopenharmony_ci	resource_size_t component_reg_phys;
27662306a36Sopenharmony_ci	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (ops && ops->is_mock_port(dev))
27962306a36Sopenharmony_ci		component_reg_phys = CXL_RESOURCE_NONE;
28062306a36Sopenharmony_ci	else
28162306a36Sopenharmony_ci		component_reg_phys = cxl_rcd_component_reg_phys(dev, dport);
28262306a36Sopenharmony_ci	put_cxl_mock_ops(index);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return component_reg_phys;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcd_component_reg_phys, CXL);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
28962306a36Sopenharmony_ciMODULE_IMPORT_NS(ACPI);
29062306a36Sopenharmony_ciMODULE_IMPORT_NS(CXL);
291