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 <dev/acpica/acpivar.h> 50 51 #include "acpi_bus_if.h" 52 #include "pcib_if.h" 53 #include "pci_if.h" 54 55 #include "dpaa2_mcp.h" 56 #include "dpaa2_mc.h" 57 #include "dpaa2_mc_if.h" 58 59 struct dpaa2_mac_dev_softc { 60 int uid; 61 uint64_t reg; 62 char managed[64]; 63 char phy_conn_type[64]; 64 char phy_mode[64]; 65 ACPI_HANDLE phy_channel; 66 }; 67 68 static int 69 dpaa2_mac_dev_probe(device_t dev) 70 { 71 uint64_t reg; 72 ssize_t s; 73 74 s = device_get_property(dev, "reg", ®, sizeof(reg), 75 DEVICE_PROP_UINT64); 76 if (s == -1) 77 return (ENXIO); 78 79 device_set_desc(dev, "DPAA2 MAC DEV"); 80 return (BUS_PROBE_DEFAULT); 81 } 82 83 static int 84 dpaa2_mac_dev_attach(device_t dev) 85 { 86 struct dpaa2_mac_dev_softc *sc; 87 ACPI_HANDLE h; 88 ssize_t s; 89 90 sc = device_get_softc(dev); 91 h = acpi_get_handle(dev); 92 if (h == NULL) 93 return (ENXIO); 94 95 s = acpi_GetInteger(h, "_UID", &sc->uid); 96 if (ACPI_FAILURE(s)) { 97 device_printf(dev, "Cannot find '_UID' property: %zd\n", s); 98 return (ENXIO); 99 } 100 101 s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg), 102 DEVICE_PROP_UINT64); 103 if (s == -1) { 104 device_printf(dev, "Cannot find 'reg' property: %zd\n", s); 105 return (ENXIO); 106 } 107 108 s = device_get_property(dev, "managed", sc->managed, 109 sizeof(sc->managed), DEVICE_PROP_ANY); 110 s = device_get_property(dev, "phy-connection-type", sc->phy_conn_type, 111 sizeof(sc->phy_conn_type), DEVICE_PROP_ANY); 112 s = device_get_property(dev, "phy-mode", sc->phy_mode, 113 sizeof(sc->phy_mode), DEVICE_PROP_ANY); 114 s = device_get_property(dev, "phy-handle", &sc->phy_channel, 115 sizeof(sc->phy_channel), DEVICE_PROP_HANDLE); 116 117 if (bootverbose) 118 device_printf(dev, "UID %#04x reg %#04jx managed '%s' " 119 "phy-connection-type '%s' phy-mode '%s' phy-handle '%s'\n", 120 sc->uid, sc->reg, sc->managed[0] != '\0' ? sc->managed : "", 121 sc->phy_conn_type[0] != '\0' ? sc->phy_conn_type : "", 122 sc->phy_mode[0] != '\0' ? sc->phy_mode : "", 123 sc->phy_channel != NULL ? acpi_name(sc->phy_channel) : ""); 124 125 return (0); 126 } 127 128 static bool 129 dpaa2_mac_dev_match_id(device_t dev, uint32_t id) 130 { 131 struct dpaa2_mac_dev_softc *sc; 132 133 if (dev == NULL) 134 return (false); 135 136 sc = device_get_softc(dev); 137 if (sc->uid == id) 138 return (true); 139 140 return (false); 141 } 142 143 static device_t 144 dpaa2_mac_dev_get_phy_dev(device_t dev) 145 { 146 struct dpaa2_mac_dev_softc *sc; 147 148 if (dev == NULL) 149 return (NULL); 150 151 sc = device_get_softc(dev); 152 if (sc->phy_channel == NULL) 153 return (NULL); 154 155 return (acpi_get_device(sc->phy_channel)); 156 } 157 158 static device_method_t dpaa2_mac_dev_methods[] = { 159 /* Device interface */ 160 DEVMETHOD(device_probe, dpaa2_mac_dev_probe), 161 DEVMETHOD(device_attach, dpaa2_mac_dev_attach), 162 DEVMETHOD(device_detach, bus_generic_detach), 163 164 DEVMETHOD_END 165 }; 166 167 DEFINE_CLASS_0(dpaa2_mac_dev, dpaa2_mac_dev_driver, dpaa2_mac_dev_methods, 168 sizeof(struct dpaa2_mac_dev_softc)); 169 170 DRIVER_MODULE(dpaa2_mac_dev, dpaa2_mc, dpaa2_mac_dev_driver, 0, 0); 171 172 MODULE_DEPEND(dpaa2_mac_dev, memac_mdio_acpi, 1, 1, 1); 173 174 /* 175 * Device interface. 176 */ 177 178 static int 179 dpaa2_mc_acpi_probe(device_t dev) 180 { 181 static char *dpaa2_mc_ids[] = { "NXP0008", NULL }; 182 int rc; 183 184 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 185 186 rc = ACPI_ID_PROBE(device_get_parent(dev), dev, dpaa2_mc_ids, NULL); 187 if (rc <= 0) 188 device_set_desc(dev, "DPAA2 Management Complex"); 189 190 return (rc); 191 } 192 193 /* Context for walking PRxx child devices. */ 194 struct dpaa2_mc_acpi_prxx_walk_ctx { 195 device_t dev; 196 int count; 197 int countok; 198 }; 199 200 static ACPI_STATUS 201 dpaa2_mc_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg) 202 { 203 struct dpaa2_mc_acpi_prxx_walk_ctx *ctx; 204 struct acpi_device *ad; 205 device_t child; 206 uint32_t uid; 207 208 ctx = (struct dpaa2_mc_acpi_prxx_walk_ctx *)arg; 209 ctx->count++; 210 211 #if 0 212 device_printf(ctx->dev, "%s: %s level %d count %d\n", __func__, 213 acpi_name(h), level, ctx->count); 214 #endif 215 216 if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &uid))) 217 return (AE_OK); 218 #if 0 219 if (bootverbose) 220 device_printf(ctx->dev, "%s: Found child Ports _UID %u\n", 221 __func__, uid); 222 #endif 223 224 /* Technically M_ACPIDEV */ 225 if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) 226 return (AE_OK); 227 228 child = device_add_child(ctx->dev, "dpaa2_mac_dev", -1); 229 if (child == NULL) { 230 free(ad, M_DEVBUF); 231 return (AE_OK); 232 } 233 ad->ad_handle = h; 234 ad->ad_cls_class = 0xffffff; 235 resource_list_init(&ad->ad_rl); 236 device_set_ivars(child, ad); 237 *dev = child; 238 239 ctx->countok++; 240 return (AE_OK); 241 } 242 243 static int 244 dpaa2_mc_acpi_attach(device_t dev) 245 { 246 struct dpaa2_mc_softc *sc; 247 248 sc = device_get_softc(dev); 249 sc->acpi_based = true; 250 251 struct dpaa2_mc_acpi_prxx_walk_ctx ctx; 252 ctx.dev = dev; 253 ctx.count = 0; 254 ctx.countok = 0; 255 ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 2, 256 dpaa2_mc_acpi_probe_child, &ctx); 257 258 #if 0 259 device_printf(dev, "Found %d child Ports in ASL, %d ok\n", 260 ctx.count, ctx.countok); 261 #endif 262 263 return (dpaa2_mc_attach(dev)); 264 } 265 266 /* 267 * ACPI compat layer. 268 */ 269 270 static device_t 271 dpaa2_mc_acpi_find_dpaa2_mac_dev(device_t dev, uint32_t id) 272 { 273 int devcount, error, i, len; 274 device_t *devlist, mdev; 275 const char *mdevname; 276 277 error = device_get_children(dev, &devlist, &devcount); 278 if (error != 0) 279 return (NULL); 280 281 for (i = 0; i < devcount; i++) { 282 mdev = devlist[i]; 283 mdevname = device_get_name(mdev); 284 if (mdevname != NULL) { 285 len = strlen(mdevname); 286 if (strncmp("dpaa2_mac_dev", mdevname, len) != 0) 287 continue; 288 } else { 289 continue; 290 } 291 if (!device_is_attached(mdev)) 292 continue; 293 294 if (dpaa2_mac_dev_match_id(mdev, id)) 295 return (mdev); 296 } 297 298 return (NULL); 299 } 300 301 static int 302 dpaa2_mc_acpi_get_phy_dev(device_t dev, device_t *phy_dev, uint32_t id) 303 { 304 device_t mdev, pdev; 305 306 mdev = dpaa2_mc_acpi_find_dpaa2_mac_dev(dev, id); 307 if (mdev == NULL) { 308 device_printf(dev, "%s: error finding dpmac device with id=%u\n", 309 __func__, id); 310 return (ENXIO); 311 } 312 313 pdev = dpaa2_mac_dev_get_phy_dev(mdev); 314 if (pdev == NULL) { 315 device_printf(dev, "%s: error getting MDIO device for dpamc %s " 316 "(id=%u)\n", __func__, device_get_nameunit(mdev), id); 317 return (ENXIO); 318 } 319 320 if (phy_dev != NULL) 321 *phy_dev = pdev; 322 323 return (0); 324 } 325 326 static ssize_t 327 dpaa2_mc_acpi_get_property(device_t dev, device_t child, const char *propname, 328 void *propvalue, size_t size, device_property_type_t type) 329 { 330 return (bus_generic_get_property(dev, child, propname, propvalue, size, 331 type)); 332 } 333 334 static int 335 dpaa2_mc_acpi_read_ivar(device_t dev, device_t child, int index, 336 uintptr_t *result) 337 { 338 /* 339 * This is special in that it passes "child" as second argument rather 340 * than "dev". acpi_get_handle() in dpaa2_mac_dev_attach() calls the 341 * read on parent(dev), dev and gets us here not to ACPI. Hence we 342 * need to keep child as-is and pass it to our parent which is ACPI. 343 * Only that gives the desired result. 344 */ 345 return (BUS_READ_IVAR(device_get_parent(dev), child, index, result)); 346 } 347 348 static device_method_t dpaa2_mc_acpi_methods[] = { 349 /* Device interface */ 350 DEVMETHOD(device_probe, dpaa2_mc_acpi_probe), 351 DEVMETHOD(device_attach, dpaa2_mc_acpi_attach), 352 DEVMETHOD(device_detach, dpaa2_mc_detach), 353 354 /* Bus interface */ 355 DEVMETHOD(bus_get_rman, dpaa2_mc_rman), 356 DEVMETHOD(bus_alloc_resource, dpaa2_mc_alloc_resource), 357 DEVMETHOD(bus_adjust_resource, dpaa2_mc_adjust_resource), 358 DEVMETHOD(bus_release_resource, dpaa2_mc_release_resource), 359 DEVMETHOD(bus_activate_resource, dpaa2_mc_activate_resource), 360 DEVMETHOD(bus_deactivate_resource, dpaa2_mc_deactivate_resource), 361 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 362 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 363 364 /* Pseudo-PCIB interface */ 365 DEVMETHOD(pcib_alloc_msi, dpaa2_mc_alloc_msi), 366 DEVMETHOD(pcib_release_msi, dpaa2_mc_release_msi), 367 DEVMETHOD(pcib_map_msi, dpaa2_mc_map_msi), 368 DEVMETHOD(pcib_get_id, dpaa2_mc_get_id), 369 370 /* DPAA2 MC bus interface */ 371 DEVMETHOD(dpaa2_mc_manage_dev, dpaa2_mc_manage_dev), 372 DEVMETHOD(dpaa2_mc_get_free_dev,dpaa2_mc_get_free_dev), 373 DEVMETHOD(dpaa2_mc_get_dev, dpaa2_mc_get_dev), 374 DEVMETHOD(dpaa2_mc_get_shared_dev, dpaa2_mc_get_shared_dev), 375 DEVMETHOD(dpaa2_mc_reserve_dev, dpaa2_mc_reserve_dev), 376 DEVMETHOD(dpaa2_mc_release_dev, dpaa2_mc_release_dev), 377 DEVMETHOD(dpaa2_mc_get_phy_dev, dpaa2_mc_acpi_get_phy_dev), 378 379 /* ACPI compar layer. */ 380 DEVMETHOD(bus_read_ivar, dpaa2_mc_acpi_read_ivar), 381 DEVMETHOD(bus_get_property, dpaa2_mc_acpi_get_property), 382 383 DEVMETHOD_END 384 }; 385 386 DEFINE_CLASS_1(dpaa2_mc, dpaa2_mc_acpi_driver, dpaa2_mc_acpi_methods, 387 sizeof(struct dpaa2_mc_softc), dpaa2_mc_driver); 388 389 /* Make sure miibus gets procesed first. */ 390 DRIVER_MODULE_ORDERED(dpaa2_mc, acpi, dpaa2_mc_acpi_driver, NULL, NULL, 391 SI_ORDER_ANY); 392 MODULE_DEPEND(dpaa2_mc, memac_mdio_acpi, 1, 1, 1); 393