1// SPDX-License-Identifier: GPL-2.0-only
2//Copyright(c) 2021 Intel Corporation. All rights reserved.
3
4#include <linux/libnvdimm.h>
5#include <linux/rculist.h>
6#include <linux/device.h>
7#include <linux/export.h>
8#include <linux/acpi.h>
9#include <linux/pci.h>
10#include <cxlmem.h>
11#include <cxlpci.h>
12#include "mock.h"
13
14static LIST_HEAD(mock);
15
16void register_cxl_mock_ops(struct cxl_mock_ops *ops)
17{
18	list_add_rcu(&ops->list, &mock);
19}
20EXPORT_SYMBOL_GPL(register_cxl_mock_ops);
21
22DEFINE_STATIC_SRCU(cxl_mock_srcu);
23
24void unregister_cxl_mock_ops(struct cxl_mock_ops *ops)
25{
26	list_del_rcu(&ops->list);
27	synchronize_srcu(&cxl_mock_srcu);
28}
29EXPORT_SYMBOL_GPL(unregister_cxl_mock_ops);
30
31struct cxl_mock_ops *get_cxl_mock_ops(int *index)
32{
33	*index = srcu_read_lock(&cxl_mock_srcu);
34	return list_first_or_null_rcu(&mock, struct cxl_mock_ops, list);
35}
36EXPORT_SYMBOL_GPL(get_cxl_mock_ops);
37
38void put_cxl_mock_ops(int index)
39{
40	srcu_read_unlock(&cxl_mock_srcu, index);
41}
42EXPORT_SYMBOL_GPL(put_cxl_mock_ops);
43
44bool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode)
45{
46	struct acpi_device *adev =
47		container_of(fwnode, struct acpi_device, fwnode);
48	int index;
49	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
50	bool retval = false;
51
52	if (ops)
53		retval = ops->is_mock_adev(adev);
54
55	if (!retval)
56		retval = is_acpi_device_node(fwnode);
57
58	put_cxl_mock_ops(index);
59	return retval;
60}
61EXPORT_SYMBOL(__wrap_is_acpi_device_node);
62
63int __wrap_acpi_table_parse_cedt(enum acpi_cedt_type id,
64				 acpi_tbl_entry_handler_arg handler_arg,
65				 void *arg)
66{
67	int index, rc;
68	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
69
70	if (ops)
71		rc = ops->acpi_table_parse_cedt(id, handler_arg, arg);
72	else
73		rc = acpi_table_parse_cedt(id, handler_arg, arg);
74
75	put_cxl_mock_ops(index);
76
77	return rc;
78}
79EXPORT_SYMBOL_NS_GPL(__wrap_acpi_table_parse_cedt, ACPI);
80
81acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle,
82					 acpi_string pathname,
83					 struct acpi_object_list *arguments,
84					 unsigned long long *data)
85{
86	int index;
87	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
88	acpi_status status;
89
90	if (ops)
91		status = ops->acpi_evaluate_integer(handle, pathname, arguments,
92						    data);
93	else
94		status = acpi_evaluate_integer(handle, pathname, arguments,
95					       data);
96	put_cxl_mock_ops(index);
97
98	return status;
99}
100EXPORT_SYMBOL(__wrap_acpi_evaluate_integer);
101
102struct acpi_pci_root *__wrap_acpi_pci_find_root(acpi_handle handle)
103{
104	int index;
105	struct acpi_pci_root *root;
106	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
107
108	if (ops)
109		root = ops->acpi_pci_find_root(handle);
110	else
111		root = acpi_pci_find_root(handle);
112
113	put_cxl_mock_ops(index);
114
115	return root;
116}
117EXPORT_SYMBOL_GPL(__wrap_acpi_pci_find_root);
118
119struct nvdimm_bus *
120__wrap_nvdimm_bus_register(struct device *dev,
121			   struct nvdimm_bus_descriptor *nd_desc)
122{
123	int index;
124	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
125
126	if (ops && ops->is_mock_dev(dev->parent->parent))
127		nd_desc->provider_name = "cxl_test";
128	put_cxl_mock_ops(index);
129
130	return nvdimm_bus_register(dev, nd_desc);
131}
132EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register);
133
134struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
135					  struct cxl_endpoint_dvsec_info *info)
136
137{
138	int index;
139	struct cxl_hdm *cxlhdm;
140	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
141
142	if (ops && ops->is_mock_port(port->uport_dev))
143		cxlhdm = ops->devm_cxl_setup_hdm(port, info);
144	else
145		cxlhdm = devm_cxl_setup_hdm(port, info);
146	put_cxl_mock_ops(index);
147
148	return cxlhdm;
149}
150EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL);
151
152int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
153{
154	int rc, index;
155	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
156
157	if (ops && ops->is_mock_port(port->uport_dev))
158		rc = ops->devm_cxl_add_passthrough_decoder(port);
159	else
160		rc = devm_cxl_add_passthrough_decoder(port);
161	put_cxl_mock_ops(index);
162
163	return rc;
164}
165EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, CXL);
166
167int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
168				       struct cxl_endpoint_dvsec_info *info)
169{
170	int rc, index;
171	struct cxl_port *port = cxlhdm->port;
172	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
173
174	if (ops && ops->is_mock_port(port->uport_dev))
175		rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info);
176	else
177		rc = devm_cxl_enumerate_decoders(cxlhdm, info);
178	put_cxl_mock_ops(index);
179
180	return rc;
181}
182EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, CXL);
183
184int __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port)
185{
186	int rc, index;
187	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
188
189	if (ops && ops->is_mock_port(port->uport_dev))
190		rc = ops->devm_cxl_port_enumerate_dports(port);
191	else
192		rc = devm_cxl_port_enumerate_dports(port);
193	put_cxl_mock_ops(index);
194
195	return rc;
196}
197EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_port_enumerate_dports, CXL);
198
199int __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds)
200{
201	int rc, index;
202	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
203
204	if (ops && ops->is_mock_dev(cxlds->dev))
205		rc = 0;
206	else
207		rc = cxl_await_media_ready(cxlds);
208	put_cxl_mock_ops(index);
209
210	return rc;
211}
212EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, CXL);
213
214int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
215			       struct cxl_hdm *cxlhdm,
216			       struct cxl_endpoint_dvsec_info *info)
217{
218	int rc = 0, index;
219	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
220
221	if (ops && ops->is_mock_dev(cxlds->dev))
222		rc = 0;
223	else
224		rc = cxl_hdm_decode_init(cxlds, cxlhdm, info);
225	put_cxl_mock_ops(index);
226
227	return rc;
228}
229EXPORT_SYMBOL_NS_GPL(__wrap_cxl_hdm_decode_init, CXL);
230
231int __wrap_cxl_dvsec_rr_decode(struct device *dev, int dvsec,
232			       struct cxl_endpoint_dvsec_info *info)
233{
234	int rc = 0, index;
235	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
236
237	if (ops && ops->is_mock_dev(dev))
238		rc = 0;
239	else
240		rc = cxl_dvsec_rr_decode(dev, dvsec, info);
241	put_cxl_mock_ops(index);
242
243	return rc;
244}
245EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dvsec_rr_decode, CXL);
246
247struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port,
248						struct device *dport_dev,
249						int port_id,
250						resource_size_t rcrb)
251{
252	int index;
253	struct cxl_dport *dport;
254	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
255
256	if (ops && ops->is_mock_port(dport_dev)) {
257		dport = devm_cxl_add_dport(port, dport_dev, port_id,
258					   CXL_RESOURCE_NONE);
259		if (!IS_ERR(dport)) {
260			dport->rcrb.base = rcrb;
261			dport->rch = true;
262		}
263	} else
264		dport = devm_cxl_add_rch_dport(port, dport_dev, port_id, rcrb);
265	put_cxl_mock_ops(index);
266
267	return dport;
268}
269EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_rch_dport, CXL);
270
271resource_size_t __wrap_cxl_rcd_component_reg_phys(struct device *dev,
272						  struct cxl_dport *dport)
273{
274	int index;
275	resource_size_t component_reg_phys;
276	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
277
278	if (ops && ops->is_mock_port(dev))
279		component_reg_phys = CXL_RESOURCE_NONE;
280	else
281		component_reg_phys = cxl_rcd_component_reg_phys(dev, dport);
282	put_cxl_mock_ops(index);
283
284	return component_reg_phys;
285}
286EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcd_component_reg_phys, CXL);
287
288MODULE_LICENSE("GPL v2");
289MODULE_IMPORT_NS(ACPI);
290MODULE_IMPORT_NS(CXL);
291