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