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