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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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