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 struct acpi_pci_root *__wrap_acpi_pci_find_root(acpi_handle handle) 115 { 116 int index; 117 struct acpi_pci_root *root; 118 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 119 120 if (ops) 121 root = ops->acpi_pci_find_root(handle); 122 else 123 root = acpi_pci_find_root(handle); 124 125 put_cxl_mock_ops(index); 126 127 return root; 128 } 129 EXPORT_SYMBOL_GPL(__wrap_acpi_pci_find_root); 130 131 struct nvdimm_bus * 132 __wrap_nvdimm_bus_register(struct device *dev, 133 struct nvdimm_bus_descriptor *nd_desc) 134 { 135 int index; 136 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 137 138 if (ops && ops->is_mock_dev(dev->parent->parent)) 139 nd_desc->provider_name = "cxl_test"; 140 put_cxl_mock_ops(index); 141 142 return nvdimm_bus_register(dev, nd_desc); 143 } 144 EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); 145 146 int redirect_devm_cxl_switch_port_decoders_setup(struct cxl_port *port) 147 { 148 int rc, index; 149 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 150 151 if (ops && ops->is_mock_port(port->uport_dev)) 152 rc = ops->devm_cxl_switch_port_decoders_setup(port); 153 else 154 rc = __devm_cxl_switch_port_decoders_setup(port); 155 put_cxl_mock_ops(index); 156 157 return rc; 158 } 159 160 int __wrap_devm_cxl_endpoint_decoders_setup(struct cxl_port *port) 161 { 162 int rc, index; 163 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 164 165 if (ops && ops->is_mock_port(port->uport_dev)) 166 rc = ops->devm_cxl_endpoint_decoders_setup(port); 167 else 168 rc = devm_cxl_endpoint_decoders_setup(port); 169 put_cxl_mock_ops(index); 170 171 return rc; 172 } 173 EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_endpoint_decoders_setup, "CXL"); 174 175 int __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds) 176 { 177 int rc, index; 178 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 179 180 if (ops && ops->is_mock_dev(cxlds->dev)) 181 rc = 0; 182 else 183 rc = cxl_await_media_ready(cxlds); 184 put_cxl_mock_ops(index); 185 186 return rc; 187 } 188 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, "CXL"); 189 190 struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port, 191 struct device *dport_dev, 192 int port_id, 193 resource_size_t rcrb) 194 { 195 int index; 196 struct cxl_dport *dport; 197 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 198 199 if (ops && ops->is_mock_port(dport_dev)) { 200 dport = devm_cxl_add_dport(port, dport_dev, port_id, 201 CXL_RESOURCE_NONE); 202 if (!IS_ERR(dport)) { 203 dport->rcrb.base = rcrb; 204 dport->rch = true; 205 } 206 } else 207 dport = devm_cxl_add_rch_dport(port, dport_dev, port_id, rcrb); 208 put_cxl_mock_ops(index); 209 210 return dport; 211 } 212 EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_rch_dport, "CXL"); 213 214 void __wrap_cxl_endpoint_parse_cdat(struct cxl_port *port) 215 { 216 int index; 217 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 218 struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); 219 220 if (ops && ops->is_mock_dev(cxlmd->dev.parent)) 221 ops->cxl_endpoint_parse_cdat(port); 222 else 223 cxl_endpoint_parse_cdat(port); 224 put_cxl_mock_ops(index); 225 } 226 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_endpoint_parse_cdat, "CXL"); 227 228 void __wrap_cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host) 229 { 230 int index; 231 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 232 233 if (!ops || !ops->is_mock_port(dport->dport_dev)) 234 cxl_dport_init_ras_reporting(dport, host); 235 236 put_cxl_mock_ops(index); 237 } 238 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dport_init_ras_reporting, "CXL"); 239 240 struct cxl_dport *redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port, 241 struct device *dport_dev) 242 { 243 int index; 244 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 245 struct cxl_dport *dport; 246 247 if (ops && ops->is_mock_port(port->uport_dev)) 248 dport = ops->devm_cxl_add_dport_by_dev(port, dport_dev); 249 else 250 dport = __devm_cxl_add_dport_by_dev(port, dport_dev); 251 put_cxl_mock_ops(index); 252 253 return dport; 254 } 255 256 MODULE_LICENSE("GPL v2"); 257 MODULE_DESCRIPTION("cxl_test: emulation module"); 258 MODULE_IMPORT_NS("ACPI"); 259 MODULE_IMPORT_NS("CXL"); 260