1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright © 2021-2022 Dmitry Salychev 5 * Copyright © 2021 Bjoern A. Zeeb 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 /* 31 * The DPAA2 Management Complex (MC) Bus Driver (ACPI-based). 32 * 33 * MC is a hardware resource manager which can be found in several NXP 34 * SoCs (LX2160A, for example) and provides an access to the specialized 35 * hardware objects used in network-oriented packet processing applications. 36 */ 37 #include <sys/param.h> 38 #include <sys/kernel.h> 39 #include <sys/bus.h> 40 #include <sys/rman.h> 41 #include <sys/module.h> 42 #include <sys/malloc.h> 43 #include <sys/mutex.h> 44 45 #include <machine/bus.h> 46 #include <machine/resource.h> 47 48 #include <contrib/dev/acpica/include/acpi.h> 49 #include <contrib/dev/acpica/include/accommon.h> 50 #include <dev/acpica/acpivar.h> 51 52 #include "acpi_bus_if.h" 53 #include "pcib_if.h" 54 #include "pci_if.h" 55 56 #include "dpaa2_mcp.h" 57 #include "dpaa2_mc.h" 58 #include "dpaa2_mc_if.h" 59 60 #define _COMPONENT ACPI_BUS 61 ACPI_MODULE_NAME("DPAA2_MC") 62 63 struct dpaa2_mac_dev_softc { 64 int uid; 65 uint64_t reg; 66 char managed[64]; 67 char phy_conn_type[64]; 68 char phy_mode[64]; 69 ACPI_HANDLE phy_channel; 70 }; 71 72 static int 73 dpaa2_mac_dev_probe(device_t dev) 74 { 75 uint64_t reg; 76 ssize_t s; 77 78 s = device_get_property(dev, "reg", ®, sizeof(reg), 79 DEVICE_PROP_UINT64); 80 if (s == -1) 81 return (ENXIO); 82 83 device_set_desc(dev, "DPAA2 MAC DEV"); 84 return (BUS_PROBE_DEFAULT); 85 } 86 87 static int 88 dpaa2_mac_dev_attach(device_t dev) 89 { 90 struct dpaa2_mac_dev_softc *sc; 91 ACPI_HANDLE h; 92 ssize_t s; 93 94 sc = device_get_softc(dev); 95 h = acpi_get_handle(dev); 96 if (h == NULL) 97 return (ENXIO); 98 99 s = acpi_GetInteger(h, "_UID", &sc->uid); 100 if (ACPI_FAILURE(s)) { 101 device_printf(dev, "Cannot find '_UID' property: %zd\n", s); 102 return (ENXIO); 103 } 104 105 s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg), 106 DEVICE_PROP_UINT64); 107 if (s == -1) { 108 device_printf(dev, "Cannot find 'reg' property: %zd\n", s); 109 return (ENXIO); 110 } 111 112 s = device_get_property(dev, "managed", sc->managed, 113 sizeof(sc->managed), DEVICE_PROP_ANY); 114 s = device_get_property(dev, "phy-connection-type", sc->phy_conn_type, 115 sizeof(sc->phy_conn_type), DEVICE_PROP_ANY); 116 s = device_get_property(dev, "phy-mode", sc->phy_mode, 117 sizeof(sc->phy_mode), DEVICE_PROP_ANY); 118 s = device_get_property(dev, "phy-handle", &sc->phy_channel, 119 sizeof(sc->phy_channel), DEVICE_PROP_HANDLE); 120 121 if (bootverbose) 122 device_printf(dev, "UID %#04x reg %#04jx managed '%s' " 123 "phy-connection-type '%s' phy-mode '%s' phy-handle '%s'\n", 124 sc->uid, sc->reg, sc->managed[0] != '\0' ? sc->managed : "", 125 sc->phy_conn_type[0] != '\0' ? sc->phy_conn_type : "", 126 sc->phy_mode[0] != '\0' ? sc->phy_mode : "", 127 sc->phy_channel != NULL ? acpi_name(sc->phy_channel) : ""); 128 129 return (0); 130 } 131 132 static bool 133 dpaa2_mac_dev_match_id(device_t dev, uint32_t id) 134 { 135 struct dpaa2_mac_dev_softc *sc; 136 137 if (dev == NULL) 138 return (false); 139 140 sc = device_get_softc(dev); 141 if (sc->uid == id) 142 return (true); 143 144 return (false); 145 } 146 147 static device_t 148 dpaa2_mac_dev_get_phy_dev(device_t dev) 149 { 150 struct dpaa2_mac_dev_softc *sc; 151 152 if (dev == NULL) 153 return (NULL); 154 155 sc = device_get_softc(dev); 156 if (sc->phy_channel == NULL) 157 return (NULL); 158 159 return (acpi_get_device(sc->phy_channel)); 160 } 161 162 static device_method_t dpaa2_mac_dev_methods[] = { 163 /* Device interface */ 164 DEVMETHOD(device_probe, dpaa2_mac_dev_probe), 165 DEVMETHOD(device_attach, dpaa2_mac_dev_attach), 166 DEVMETHOD(device_detach, bus_generic_detach), 167 168 DEVMETHOD_END 169 }; 170 171 DEFINE_CLASS_0(dpaa2_mac_dev, dpaa2_mac_dev_driver, dpaa2_mac_dev_methods, 172 sizeof(struct dpaa2_mac_dev_softc)); 173 174 DRIVER_MODULE(dpaa2_mac_dev, dpaa2_mc, dpaa2_mac_dev_driver, 0, 0); 175 176 MODULE_DEPEND(dpaa2_mac_dev, memac_mdio_acpi, 1, 1, 1); 177 178 /* 179 * Device interface. 180 */ 181 182 static int 183 dpaa2_mc_acpi_probe(device_t dev) 184 { 185 static char *dpaa2_mc_ids[] = { "NXP0008", NULL }; 186 int rc; 187 188 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 189 190 rc = ACPI_ID_PROBE(device_get_parent(dev), dev, dpaa2_mc_ids, NULL); 191 if (rc <= 0) 192 device_set_desc(dev, "DPAA2 Management Complex"); 193 194 return (rc); 195 } 196 197 /* Context for walking PRxx child devices. */ 198 struct dpaa2_mc_acpi_prxx_walk_ctx { 199 device_t dev; 200 int count; 201 int countok; 202 }; 203 204 static ACPI_STATUS 205 dpaa2_mc_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg) 206 { 207 struct dpaa2_mc_acpi_prxx_walk_ctx *ctx; 208 struct acpi_device *ad; 209 device_t child; 210 uint32_t uid; 211 212 ctx = (struct dpaa2_mc_acpi_prxx_walk_ctx *)arg; 213 ctx->count++; 214 215 #if 0 216 device_printf(ctx->dev, "%s: %s level %d count %d\n", __func__, 217 acpi_name(h), level, ctx->count); 218 #endif 219 220 if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &uid))) 221 return (AE_OK); 222 #if 0 223 if (bootverbose) 224 device_printf(ctx->dev, "%s: Found child Ports _UID %u\n", 225 __func__, uid); 226 #endif 227 228 /* Technically M_ACPIDEV */ 229 if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) 230 return (AE_OK); 231 232 child = device_add_child(ctx->dev, "dpaa2_mac_dev", -1); 233 if (child == NULL) { 234 free(ad, M_DEVBUF); 235 return (AE_OK); 236 } 237 ad->ad_handle = h; 238 ad->ad_cls_class = 0xffffff; 239 resource_list_init(&ad->ad_rl); 240 device_set_ivars(child, ad); 241 *dev = child; 242 243 ctx->countok++; 244 return (AE_OK); 245 } 246 247 static int 248 dpaa2_mc_acpi_attach(device_t dev) 249 { 250 struct dpaa2_mc_softc *sc; 251 252 sc = device_get_softc(dev); 253 sc->acpi_based = true; 254 255 struct dpaa2_mc_acpi_prxx_walk_ctx ctx; 256 ctx.dev = dev; 257 ctx.count = 0; 258 ctx.countok = 0; 259 ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 2, 260 dpaa2_mc_acpi_probe_child, &ctx); 261 262 #if 0 263 device_printf(dev, "Found %d child Ports in ASL, %d ok\n", 264 ctx.count, ctx.countok); 265 #endif 266 267 return (dpaa2_mc_attach(dev)); 268 } 269 270 /* 271 * ACPI compat layer. 272 */ 273 274 static device_t 275 dpaa2_mc_acpi_find_dpaa2_mac_dev(device_t dev, uint32_t id) 276 { 277 int devcount, error, i, len; 278 device_t *devlist, mdev; 279 const char *mdevname; 280 281 error = device_get_children(dev, &devlist, &devcount); 282 if (error != 0) 283 return (NULL); 284 285 for (i = 0; i < devcount; i++) { 286 mdev = devlist[i]; 287 mdevname = device_get_name(mdev); 288 if (mdevname != NULL) { 289 len = strlen(mdevname); 290 if (strncmp("dpaa2_mac_dev", mdevname, len) != 0) 291 continue; 292 } else { 293 continue; 294 } 295 if (!device_is_attached(mdev)) 296 continue; 297 298 if (dpaa2_mac_dev_match_id(mdev, id)) 299 return (mdev); 300 } 301 302 return (NULL); 303 } 304 305 static int 306 dpaa2_mc_acpi_get_phy_dev(device_t dev, device_t *phy_dev, uint32_t id) 307 { 308 device_t mdev, pdev; 309 310 mdev = dpaa2_mc_acpi_find_dpaa2_mac_dev(dev, id); 311 if (mdev == NULL) { 312 device_printf(dev, "%s: error finding dpmac device with id=%u\n", 313 __func__, id); 314 return (ENXIO); 315 } 316 317 pdev = dpaa2_mac_dev_get_phy_dev(mdev); 318 if (pdev == NULL) { 319 device_printf(dev, "%s: error getting MDIO device for dpamc %s " 320 "(id=%u)\n", __func__, device_get_nameunit(mdev), id); 321 return (ENXIO); 322 } 323 324 if (phy_dev != NULL) 325 *phy_dev = pdev; 326 327 return (0); 328 } 329 330 static ssize_t 331 dpaa2_mc_acpi_get_property(device_t dev, device_t child, const char *propname, 332 void *propvalue, size_t size, device_property_type_t type) 333 { 334 return (bus_generic_get_property(dev, child, propname, propvalue, size, 335 type)); 336 } 337 338 static int 339 dpaa2_mc_acpi_read_ivar(device_t dev, device_t child, int index, 340 uintptr_t *result) 341 { 342 /* 343 * This is special in that it passes "child" as second argument rather 344 * than "dev". acpi_get_handle() in dpaa2_mac_dev_attach() calls the 345 * read on parent(dev), dev and gets us here not to ACPI. Hence we 346 * need to keep child as-is and pass it to our parent which is ACPI. 347 * Only that gives the desired result. 348 */ 349 return (BUS_READ_IVAR(device_get_parent(dev), child, index, result)); 350 } 351 352 static device_method_t dpaa2_mc_acpi_methods[] = { 353 /* Device interface */ 354 DEVMETHOD(device_probe, dpaa2_mc_acpi_probe), 355 DEVMETHOD(device_attach, dpaa2_mc_acpi_attach), 356 DEVMETHOD(device_detach, dpaa2_mc_detach), 357 358 /* Bus interface */ 359 DEVMETHOD(bus_get_rman, dpaa2_mc_rman), 360 DEVMETHOD(bus_alloc_resource, dpaa2_mc_alloc_resource), 361 DEVMETHOD(bus_adjust_resource, dpaa2_mc_adjust_resource), 362 DEVMETHOD(bus_release_resource, dpaa2_mc_release_resource), 363 DEVMETHOD(bus_activate_resource, dpaa2_mc_activate_resource), 364 DEVMETHOD(bus_deactivate_resource, dpaa2_mc_deactivate_resource), 365 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 366 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 367 368 /* Pseudo-PCIB interface */ 369 DEVMETHOD(pcib_alloc_msi, dpaa2_mc_alloc_msi), 370 DEVMETHOD(pcib_release_msi, dpaa2_mc_release_msi), 371 DEVMETHOD(pcib_map_msi, dpaa2_mc_map_msi), 372 DEVMETHOD(pcib_get_id, dpaa2_mc_get_id), 373 374 /* DPAA2 MC bus interface */ 375 DEVMETHOD(dpaa2_mc_manage_dev, dpaa2_mc_manage_dev), 376 DEVMETHOD(dpaa2_mc_get_free_dev,dpaa2_mc_get_free_dev), 377 DEVMETHOD(dpaa2_mc_get_dev, dpaa2_mc_get_dev), 378 DEVMETHOD(dpaa2_mc_get_shared_dev, dpaa2_mc_get_shared_dev), 379 DEVMETHOD(dpaa2_mc_reserve_dev, dpaa2_mc_reserve_dev), 380 DEVMETHOD(dpaa2_mc_release_dev, dpaa2_mc_release_dev), 381 DEVMETHOD(dpaa2_mc_get_phy_dev, dpaa2_mc_acpi_get_phy_dev), 382 383 /* ACPI compar layer. */ 384 DEVMETHOD(bus_read_ivar, dpaa2_mc_acpi_read_ivar), 385 DEVMETHOD(bus_get_property, dpaa2_mc_acpi_get_property), 386 387 DEVMETHOD_END 388 }; 389 390 DEFINE_CLASS_1(dpaa2_mc, dpaa2_mc_acpi_driver, dpaa2_mc_acpi_methods, 391 sizeof(struct dpaa2_mc_softc), dpaa2_mc_driver); 392 393 /* Make sure miibus gets procesed first. */ 394 DRIVER_MODULE_ORDERED(dpaa2_mc, acpi, dpaa2_mc_acpi_driver, NULL, NULL, 395 SI_ORDER_ANY); 396 MODULE_DEPEND(dpaa2_mc, memac_mdio_acpi, 1, 1, 1); 397