1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright © 2021-2022 Dmitry Salychev 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 /* 30 * The DPAA2 Management Complex (MC) bus driver. 31 * 32 * MC is a hardware resource manager which can be found in several NXP 33 * SoCs (LX2160A, for example) and provides an access to the specialized 34 * hardware objects used in network-oriented packet processing applications. 35 */ 36 37 #include "opt_acpi.h" 38 #include "opt_platform.h" 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/bus.h> 43 #include <sys/rman.h> 44 #include <sys/lock.h> 45 #include <sys/module.h> 46 #include <sys/malloc.h> 47 #include <sys/mutex.h> 48 #include <sys/queue.h> 49 50 #include <vm/vm.h> 51 52 #include <machine/bus.h> 53 #include <machine/resource.h> 54 55 #ifdef DEV_ACPI 56 #include <contrib/dev/acpica/include/acpi.h> 57 #include <dev/acpica/acpivar.h> 58 #endif 59 60 #ifdef FDT 61 #include <dev/ofw/openfirm.h> 62 #include <dev/ofw/ofw_bus.h> 63 #include <dev/ofw/ofw_bus_subr.h> 64 #include <dev/ofw/ofw_pci.h> 65 #endif 66 67 #include "pcib_if.h" 68 #include "pci_if.h" 69 70 #include "dpaa2_mc.h" 71 72 /* Macros to read/write MC registers */ 73 #define mcreg_read_4(_sc, _r) bus_read_4(&(_sc)->map[1], (_r)) 74 #define mcreg_write_4(_sc, _r, _v) bus_write_4(&(_sc)->map[1], (_r), (_v)) 75 76 #define IORT_DEVICE_NAME "MCE" 77 78 /* MC Registers */ 79 #define MC_REG_GCR1 0x0000u 80 #define MC_REG_GCR2 0x0004u /* TODO: Does it exist? */ 81 #define MC_REG_GSR 0x0008u 82 #define MC_REG_FAPR 0x0028u 83 84 /* General Control Register 1 (GCR1) */ 85 #define GCR1_P1_STOP 0x80000000u 86 #define GCR1_P2_STOP 0x40000000u 87 88 /* General Status Register (GSR) */ 89 #define GSR_HW_ERR(v) (((v) & 0x80000000u) >> 31) 90 #define GSR_CAT_ERR(v) (((v) & 0x40000000u) >> 30) 91 #define GSR_DPL_OFFSET(v) (((v) & 0x3FFFFF00u) >> 8) 92 #define GSR_MCS(v) (((v) & 0xFFu) >> 0) 93 94 /* Timeouts to wait for the MC status. */ 95 #define MC_STAT_TIMEOUT 1000u /* us */ 96 #define MC_STAT_ATTEMPTS 100u 97 98 /** 99 * @brief Structure to describe a DPAA2 device as a managed resource. 100 */ 101 struct dpaa2_mc_devinfo { 102 STAILQ_ENTRY(dpaa2_mc_devinfo) link; 103 device_t dpaa2_dev; 104 uint32_t flags; 105 uint32_t owners; 106 }; 107 108 MALLOC_DEFINE(M_DPAA2_MC, "dpaa2_mc", "DPAA2 Management Complex"); 109 110 static struct resource_spec dpaa2_mc_spec[] = { 111 { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_UNMAPPED }, 112 { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL }, 113 RESOURCE_SPEC_END 114 }; 115 116 static u_int dpaa2_mc_get_xref(device_t, device_t); 117 static u_int dpaa2_mc_map_id(device_t, device_t, uintptr_t *); 118 static struct rman *dpaa2_mc_rman(device_t, int); 119 120 static int dpaa2_mc_alloc_msi_impl(device_t, device_t, int, int, int *); 121 static int dpaa2_mc_release_msi_impl(device_t, device_t, int, int *); 122 static int dpaa2_mc_map_msi_impl(device_t, device_t, int, uint64_t *, 123 uint32_t *); 124 125 /* 126 * For device interface. 127 */ 128 129 int 130 dpaa2_mc_attach(device_t dev) 131 { 132 struct dpaa2_mc_softc *sc; 133 struct resource_map_request req; 134 uint32_t val; 135 int error; 136 137 sc = device_get_softc(dev); 138 sc->dev = dev; 139 sc->msi_allocated = false; 140 sc->msi_owner = NULL; 141 142 error = bus_alloc_resources(sc->dev, dpaa2_mc_spec, sc->res); 143 if (error) { 144 device_printf(dev, "%s: failed to allocate resources\n", 145 __func__); 146 return (ENXIO); 147 } 148 149 if (sc->res[1]) { 150 resource_init_map_request(&req); 151 req.memattr = VM_MEMATTR_DEVICE; 152 error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[1], 153 &req, &sc->map[1]); 154 if (error) { 155 device_printf(dev, "%s: failed to map control " 156 "registers\n", __func__); 157 dpaa2_mc_detach(dev); 158 return (ENXIO); 159 } 160 161 if (bootverbose) 162 device_printf(dev, 163 "GCR1=0x%x, GCR2=0x%x, GSR=0x%x, FAPR=0x%x\n", 164 mcreg_read_4(sc, MC_REG_GCR1), 165 mcreg_read_4(sc, MC_REG_GCR2), 166 mcreg_read_4(sc, MC_REG_GSR), 167 mcreg_read_4(sc, MC_REG_FAPR)); 168 169 /* Reset P1_STOP and P2_STOP bits to resume MC processor. */ 170 val = mcreg_read_4(sc, MC_REG_GCR1) & 171 ~(GCR1_P1_STOP | GCR1_P2_STOP); 172 mcreg_write_4(sc, MC_REG_GCR1, val); 173 174 /* Poll MC status. */ 175 if (bootverbose) 176 device_printf(dev, "polling MC status...\n"); 177 for (int i = 0; i < MC_STAT_ATTEMPTS; i++) { 178 val = mcreg_read_4(sc, MC_REG_GSR); 179 if (GSR_MCS(val) != 0u) 180 break; 181 DELAY(MC_STAT_TIMEOUT); 182 } 183 184 if (bootverbose) 185 device_printf(dev, 186 "GCR1=0x%x, GCR2=0x%x, GSR=0x%x, FAPR=0x%x\n", 187 mcreg_read_4(sc, MC_REG_GCR1), 188 mcreg_read_4(sc, MC_REG_GCR2), 189 mcreg_read_4(sc, MC_REG_GSR), 190 mcreg_read_4(sc, MC_REG_FAPR)); 191 } 192 193 /* At least 64 bytes of the command portal should be available. */ 194 if (rman_get_size(sc->res[0]) < DPAA2_MCP_MEM_WIDTH) { 195 device_printf(dev, "%s: MC portal memory region too small: " 196 "%jd\n", __func__, rman_get_size(sc->res[0])); 197 dpaa2_mc_detach(dev); 198 return (ENXIO); 199 } 200 201 /* Map MC portal memory resource. */ 202 resource_init_map_request(&req); 203 req.memattr = VM_MEMATTR_DEVICE; 204 error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[0], 205 &req, &sc->map[0]); 206 if (error) { 207 device_printf(dev, "Failed to map MC portal memory\n"); 208 dpaa2_mc_detach(dev); 209 return (ENXIO); 210 } 211 212 /* Initialize a resource manager for the DPAA2 I/O objects. */ 213 sc->dpio_rman.rm_type = RMAN_ARRAY; 214 sc->dpio_rman.rm_descr = "DPAA2 DPIO objects"; 215 error = rman_init(&sc->dpio_rman); 216 if (error) { 217 device_printf(dev, "Failed to initialize a resource manager for " 218 "the DPAA2 I/O objects: error=%d\n", error); 219 dpaa2_mc_detach(dev); 220 return (ENXIO); 221 } 222 223 /* Initialize a resource manager for the DPAA2 buffer pools. */ 224 sc->dpbp_rman.rm_type = RMAN_ARRAY; 225 sc->dpbp_rman.rm_descr = "DPAA2 DPBP objects"; 226 error = rman_init(&sc->dpbp_rman); 227 if (error) { 228 device_printf(dev, "Failed to initialize a resource manager for " 229 "the DPAA2 buffer pools: error=%d\n", error); 230 dpaa2_mc_detach(dev); 231 return (ENXIO); 232 } 233 234 /* Initialize a resource manager for the DPAA2 concentrators. */ 235 sc->dpcon_rman.rm_type = RMAN_ARRAY; 236 sc->dpcon_rman.rm_descr = "DPAA2 DPCON objects"; 237 error = rman_init(&sc->dpcon_rman); 238 if (error) { 239 device_printf(dev, "Failed to initialize a resource manager for " 240 "the DPAA2 concentrators: error=%d\n", error); 241 dpaa2_mc_detach(dev); 242 return (ENXIO); 243 } 244 245 /* Initialize a resource manager for the DPAA2 MC portals. */ 246 sc->dpmcp_rman.rm_type = RMAN_ARRAY; 247 sc->dpmcp_rman.rm_descr = "DPAA2 DPMCP objects"; 248 error = rman_init(&sc->dpmcp_rman); 249 if (error) { 250 device_printf(dev, "Failed to initialize a resource manager for " 251 "the DPAA2 MC portals: error=%d\n", error); 252 dpaa2_mc_detach(dev); 253 return (ENXIO); 254 } 255 256 /* Initialize a list of non-allocatable DPAA2 devices. */ 257 mtx_init(&sc->mdev_lock, "MC portal mdev lock", NULL, MTX_DEF); 258 STAILQ_INIT(&sc->mdev_list); 259 260 mtx_init(&sc->msi_lock, "MC MSI lock", NULL, MTX_DEF); 261 262 /* 263 * Add a root resource container as the only child of the bus. All of 264 * the direct descendant containers will be attached to the root one 265 * instead of the MC device. 266 */ 267 sc->rcdev = device_add_child(dev, "dpaa2_rc", 0); 268 if (sc->rcdev == NULL) { 269 dpaa2_mc_detach(dev); 270 return (ENXIO); 271 } 272 bus_generic_probe(dev); 273 bus_generic_attach(dev); 274 275 return (0); 276 } 277 278 int 279 dpaa2_mc_detach(device_t dev) 280 { 281 struct dpaa2_mc_softc *sc; 282 struct dpaa2_devinfo *dinfo = NULL; 283 int error; 284 285 bus_generic_detach(dev); 286 287 sc = device_get_softc(dev); 288 if (sc->rcdev) 289 device_delete_child(dev, sc->rcdev); 290 bus_release_resources(dev, dpaa2_mc_spec, sc->res); 291 292 dinfo = device_get_ivars(dev); 293 if (dinfo) 294 free(dinfo, M_DPAA2_MC); 295 296 error = bus_generic_detach(dev); 297 if (error != 0) 298 return (error); 299 300 return (device_delete_children(dev)); 301 } 302 303 /* 304 * For bus interface. 305 */ 306 307 struct resource * 308 dpaa2_mc_alloc_resource(device_t mcdev, device_t child, int type, int *rid, 309 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 310 { 311 struct resource *res; 312 struct rman *rm; 313 int error; 314 315 rm = dpaa2_mc_rman(mcdev, type); 316 if (!rm) 317 return (BUS_ALLOC_RESOURCE(device_get_parent(mcdev), child, 318 type, rid, start, end, count, flags)); 319 320 /* 321 * Skip managing DPAA2-specific resource. It must be provided to MC by 322 * calling DPAA2_MC_MANAGE_DEV() beforehand. 323 */ 324 if (type <= DPAA2_DEV_MC) { 325 error = rman_manage_region(rm, start, end); 326 if (error) { 327 device_printf(mcdev, "rman_manage_region() failed: " 328 "start=%#jx, end=%#jx, error=%d\n", start, end, 329 error); 330 goto fail; 331 } 332 } 333 334 res = rman_reserve_resource(rm, start, end, count, flags, child); 335 if (!res) { 336 device_printf(mcdev, "rman_reserve_resource() failed: " 337 "start=%#jx, end=%#jx, count=%#jx\n", start, end, count); 338 goto fail; 339 } 340 341 rman_set_rid(res, *rid); 342 343 if (flags & RF_ACTIVE) { 344 if (bus_activate_resource(child, type, *rid, res)) { 345 device_printf(mcdev, "bus_activate_resource() failed: " 346 "rid=%d, res=%#jx\n", *rid, (uintmax_t) res); 347 rman_release_resource(res); 348 goto fail; 349 } 350 } 351 352 return (res); 353 fail: 354 device_printf(mcdev, "%s() failed: type=%d, rid=%d, start=%#jx, " 355 "end=%#jx, count=%#jx, flags=%x\n", __func__, type, *rid, start, end, 356 count, flags); 357 return (NULL); 358 } 359 360 int 361 dpaa2_mc_adjust_resource(device_t mcdev, device_t child, int type, 362 struct resource *r, rman_res_t start, rman_res_t end) 363 { 364 struct rman *rm; 365 366 rm = dpaa2_mc_rman(mcdev, type); 367 if (rm) 368 return (rman_adjust_resource(r, start, end)); 369 return (bus_generic_adjust_resource(mcdev, child, type, r, start, end)); 370 } 371 372 int 373 dpaa2_mc_release_resource(device_t mcdev, device_t child, int type, int rid, 374 struct resource *r) 375 { 376 struct rman *rm; 377 378 rm = dpaa2_mc_rman(mcdev, type); 379 if (rm) { 380 KASSERT(rman_is_region_manager(r, rm), ("rman mismatch")); 381 rman_release_resource(r); 382 } 383 384 return (bus_generic_release_resource(mcdev, child, type, rid, r)); 385 } 386 387 int 388 dpaa2_mc_activate_resource(device_t mcdev, device_t child, int type, int rid, 389 struct resource *r) 390 { 391 int rc; 392 393 if ((rc = rman_activate_resource(r)) != 0) 394 return (rc); 395 396 return (BUS_ACTIVATE_RESOURCE(device_get_parent(mcdev), child, type, 397 rid, r)); 398 } 399 400 int 401 dpaa2_mc_deactivate_resource(device_t mcdev, device_t child, int type, int rid, 402 struct resource *r) 403 { 404 int rc; 405 406 if ((rc = rman_deactivate_resource(r)) != 0) 407 return (rc); 408 409 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(mcdev), child, type, 410 rid, r)); 411 } 412 413 /* 414 * For pseudo-pcib interface. 415 */ 416 417 int 418 dpaa2_mc_alloc_msi(device_t mcdev, device_t child, int count, int maxcount, 419 int *irqs) 420 { 421 #if defined(INTRNG) 422 return (dpaa2_mc_alloc_msi_impl(mcdev, child, count, maxcount, irqs)); 423 #else 424 return (ENXIO); 425 #endif 426 } 427 428 int 429 dpaa2_mc_release_msi(device_t mcdev, device_t child, int count, int *irqs) 430 { 431 #if defined(INTRNG) 432 return (dpaa2_mc_release_msi_impl(mcdev, child, count, irqs)); 433 #else 434 return (ENXIO); 435 #endif 436 } 437 438 int 439 dpaa2_mc_map_msi(device_t mcdev, device_t child, int irq, uint64_t *addr, 440 uint32_t *data) 441 { 442 #if defined(INTRNG) 443 return (dpaa2_mc_map_msi_impl(mcdev, child, irq, addr, data)); 444 #else 445 return (ENXIO); 446 #endif 447 } 448 449 int 450 dpaa2_mc_get_id(device_t mcdev, device_t child, enum pci_id_type type, 451 uintptr_t *id) 452 { 453 struct dpaa2_devinfo *dinfo; 454 455 dinfo = device_get_ivars(child); 456 457 if (strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 458 return (ENXIO); 459 460 if (type == PCI_ID_MSI) 461 return (dpaa2_mc_map_id(mcdev, child, id)); 462 463 *id = dinfo->icid; 464 return (0); 465 } 466 467 /* 468 * For DPAA2 Management Complex bus driver interface. 469 */ 470 471 int 472 dpaa2_mc_manage_dev(device_t mcdev, device_t dpaa2_dev, uint32_t flags) 473 { 474 struct dpaa2_mc_softc *sc; 475 struct dpaa2_devinfo *dinfo; 476 struct dpaa2_mc_devinfo *di; 477 struct rman *rm; 478 int error; 479 480 sc = device_get_softc(mcdev); 481 dinfo = device_get_ivars(dpaa2_dev); 482 483 if (!sc || !dinfo || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 484 return (EINVAL); 485 486 di = malloc(sizeof(*di), M_DPAA2_MC, M_WAITOK | M_ZERO); 487 if (!di) 488 return (ENOMEM); 489 di->dpaa2_dev = dpaa2_dev; 490 di->flags = flags; 491 di->owners = 0; 492 493 /* Append a new managed DPAA2 device to the queue. */ 494 mtx_assert(&sc->mdev_lock, MA_NOTOWNED); 495 mtx_lock(&sc->mdev_lock); 496 STAILQ_INSERT_TAIL(&sc->mdev_list, di, link); 497 mtx_unlock(&sc->mdev_lock); 498 499 if (flags & DPAA2_MC_DEV_ALLOCATABLE) { 500 /* Select rman based on a type of the DPAA2 device. */ 501 rm = dpaa2_mc_rman(mcdev, dinfo->dtype); 502 if (!rm) 503 return (ENOENT); 504 /* Manage DPAA2 device as an allocatable resource. */ 505 error = rman_manage_region(rm, (rman_res_t) dpaa2_dev, 506 (rman_res_t) dpaa2_dev); 507 if (error) 508 return (error); 509 } 510 511 return (0); 512 } 513 514 int 515 dpaa2_mc_get_free_dev(device_t mcdev, device_t *dpaa2_dev, 516 enum dpaa2_dev_type devtype) 517 { 518 struct rman *rm; 519 rman_res_t start, end; 520 int error; 521 522 if (strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 523 return (EINVAL); 524 525 /* Select resource manager based on a type of the DPAA2 device. */ 526 rm = dpaa2_mc_rman(mcdev, devtype); 527 if (!rm) 528 return (ENOENT); 529 /* Find first free DPAA2 device of the given type. */ 530 error = rman_first_free_region(rm, &start, &end); 531 if (error) 532 return (error); 533 534 KASSERT(start == end, ("start != end, but should be the same pointer " 535 "to the DPAA2 device: start=%jx, end=%jx", start, end)); 536 537 *dpaa2_dev = (device_t) start; 538 539 return (0); 540 } 541 542 int 543 dpaa2_mc_get_dev(device_t mcdev, device_t *dpaa2_dev, 544 enum dpaa2_dev_type devtype, uint32_t obj_id) 545 { 546 struct dpaa2_mc_softc *sc; 547 struct dpaa2_devinfo *dinfo; 548 struct dpaa2_mc_devinfo *di; 549 int error = ENOENT; 550 551 sc = device_get_softc(mcdev); 552 553 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 554 return (EINVAL); 555 556 mtx_assert(&sc->mdev_lock, MA_NOTOWNED); 557 mtx_lock(&sc->mdev_lock); 558 559 STAILQ_FOREACH(di, &sc->mdev_list, link) { 560 dinfo = device_get_ivars(di->dpaa2_dev); 561 if (dinfo->dtype == devtype && dinfo->id == obj_id) { 562 *dpaa2_dev = di->dpaa2_dev; 563 error = 0; 564 break; 565 } 566 } 567 568 mtx_unlock(&sc->mdev_lock); 569 570 return (error); 571 } 572 573 int 574 dpaa2_mc_get_shared_dev(device_t mcdev, device_t *dpaa2_dev, 575 enum dpaa2_dev_type devtype) 576 { 577 struct dpaa2_mc_softc *sc; 578 struct dpaa2_devinfo *dinfo; 579 struct dpaa2_mc_devinfo *di; 580 device_t dev = NULL; 581 uint32_t owners = UINT32_MAX; 582 int error = ENOENT; 583 584 sc = device_get_softc(mcdev); 585 586 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 587 return (EINVAL); 588 589 mtx_assert(&sc->mdev_lock, MA_NOTOWNED); 590 mtx_lock(&sc->mdev_lock); 591 592 STAILQ_FOREACH(di, &sc->mdev_list, link) { 593 dinfo = device_get_ivars(di->dpaa2_dev); 594 595 if ((dinfo->dtype == devtype) && 596 (di->flags & DPAA2_MC_DEV_SHAREABLE) && 597 (di->owners < owners)) { 598 dev = di->dpaa2_dev; 599 owners = di->owners; 600 } 601 } 602 if (dev) { 603 *dpaa2_dev = dev; 604 error = 0; 605 } 606 607 mtx_unlock(&sc->mdev_lock); 608 609 return (error); 610 } 611 612 int 613 dpaa2_mc_reserve_dev(device_t mcdev, device_t dpaa2_dev, 614 enum dpaa2_dev_type devtype) 615 { 616 struct dpaa2_mc_softc *sc; 617 struct dpaa2_mc_devinfo *di; 618 int error = ENOENT; 619 620 sc = device_get_softc(mcdev); 621 622 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 623 return (EINVAL); 624 625 mtx_assert(&sc->mdev_lock, MA_NOTOWNED); 626 mtx_lock(&sc->mdev_lock); 627 628 STAILQ_FOREACH(di, &sc->mdev_list, link) { 629 if (di->dpaa2_dev == dpaa2_dev && 630 (di->flags & DPAA2_MC_DEV_SHAREABLE)) { 631 di->owners++; 632 error = 0; 633 break; 634 } 635 } 636 637 mtx_unlock(&sc->mdev_lock); 638 639 return (error); 640 } 641 642 int 643 dpaa2_mc_release_dev(device_t mcdev, device_t dpaa2_dev, 644 enum dpaa2_dev_type devtype) 645 { 646 struct dpaa2_mc_softc *sc; 647 struct dpaa2_mc_devinfo *di; 648 int error = ENOENT; 649 650 sc = device_get_softc(mcdev); 651 652 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0) 653 return (EINVAL); 654 655 mtx_assert(&sc->mdev_lock, MA_NOTOWNED); 656 mtx_lock(&sc->mdev_lock); 657 658 STAILQ_FOREACH(di, &sc->mdev_list, link) { 659 if (di->dpaa2_dev == dpaa2_dev && 660 (di->flags & DPAA2_MC_DEV_SHAREABLE)) { 661 di->owners -= di->owners > 0 ? 1 : 0; 662 error = 0; 663 break; 664 } 665 } 666 667 mtx_unlock(&sc->mdev_lock); 668 669 return (error); 670 } 671 672 /** 673 * @internal 674 */ 675 static u_int 676 dpaa2_mc_get_xref(device_t mcdev, device_t child) 677 { 678 struct dpaa2_mc_softc *sc = device_get_softc(mcdev); 679 struct dpaa2_devinfo *dinfo = device_get_ivars(child); 680 #ifdef DEV_ACPI 681 u_int xref, devid; 682 #endif 683 #ifdef FDT 684 phandle_t msi_parent; 685 #endif 686 int error; 687 688 if (sc && dinfo) { 689 #ifdef DEV_ACPI 690 if (sc->acpi_based) { 691 /* 692 * NOTE: The first named component from the IORT table 693 * with the given name (as a substring) will be used. 694 */ 695 error = acpi_iort_map_named_msi(IORT_DEVICE_NAME, 696 dinfo->icid, &xref, &devid); 697 if (error) 698 return (0); 699 return (xref); 700 } 701 #endif 702 #ifdef FDT 703 if (!sc->acpi_based) { 704 /* FDT-based driver. */ 705 error = ofw_bus_msimap(sc->ofw_node, dinfo->icid, 706 &msi_parent, NULL); 707 if (error) 708 return (0); 709 return ((u_int) msi_parent); 710 } 711 #endif 712 } 713 return (0); 714 } 715 716 /** 717 * @internal 718 */ 719 static u_int 720 dpaa2_mc_map_id(device_t mcdev, device_t child, uintptr_t *id) 721 { 722 struct dpaa2_devinfo *dinfo; 723 #ifdef DEV_ACPI 724 u_int xref, devid; 725 int error; 726 #endif 727 728 dinfo = device_get_ivars(child); 729 if (dinfo) { 730 /* 731 * The first named components from IORT table with the given 732 * name (as a substring) will be used. 733 */ 734 #ifdef DEV_ACPI 735 error = acpi_iort_map_named_msi(IORT_DEVICE_NAME, dinfo->icid, 736 &xref, &devid); 737 if (error == 0) 738 *id = devid; 739 else 740 #endif 741 *id = dinfo->icid; /* RID not in IORT, likely FW bug */ 742 743 return (0); 744 } 745 return (ENXIO); 746 } 747 748 /** 749 * @internal 750 * @brief Obtain a resource manager based on the given type of the resource. 751 */ 752 static struct rman * 753 dpaa2_mc_rman(device_t mcdev, int type) 754 { 755 struct dpaa2_mc_softc *sc; 756 757 sc = device_get_softc(mcdev); 758 759 switch (type) { 760 case DPAA2_DEV_IO: 761 return (&sc->dpio_rman); 762 case DPAA2_DEV_BP: 763 return (&sc->dpbp_rman); 764 case DPAA2_DEV_CON: 765 return (&sc->dpcon_rman); 766 case DPAA2_DEV_MCP: 767 return (&sc->dpmcp_rman); 768 default: 769 break; 770 } 771 772 return (NULL); 773 } 774 775 #if defined(INTRNG) && !defined(IOMMU) 776 777 /** 778 * @internal 779 * @brief Allocates requested number of MSIs. 780 * 781 * NOTE: This function is a part of fallback solution when IOMMU isn't available. 782 * Total number of IRQs is limited to 32. 783 */ 784 static int 785 dpaa2_mc_alloc_msi_impl(device_t mcdev, device_t child, int count, int maxcount, 786 int *irqs) 787 { 788 struct dpaa2_mc_softc *sc = device_get_softc(mcdev); 789 int msi_irqs[DPAA2_MC_MSI_COUNT]; 790 int error; 791 792 /* Pre-allocate a bunch of MSIs for MC to be used by its children. */ 793 if (!sc->msi_allocated) { 794 error = intr_alloc_msi(mcdev, child, dpaa2_mc_get_xref(mcdev, 795 child), DPAA2_MC_MSI_COUNT, DPAA2_MC_MSI_COUNT, msi_irqs); 796 if (error) { 797 device_printf(mcdev, "failed to pre-allocate %d MSIs: " 798 "error=%d\n", DPAA2_MC_MSI_COUNT, error); 799 return (error); 800 } 801 802 mtx_assert(&sc->msi_lock, MA_NOTOWNED); 803 mtx_lock(&sc->msi_lock); 804 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) { 805 sc->msi[i].child = NULL; 806 sc->msi[i].irq = msi_irqs[i]; 807 } 808 sc->msi_owner = child; 809 sc->msi_allocated = true; 810 mtx_unlock(&sc->msi_lock); 811 } 812 813 error = ENOENT; 814 815 /* Find the first free MSIs from the pre-allocated pool. */ 816 mtx_assert(&sc->msi_lock, MA_NOTOWNED); 817 mtx_lock(&sc->msi_lock); 818 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) { 819 if (sc->msi[i].child != NULL) 820 continue; 821 error = 0; 822 for (int j = 0; j < count; j++) { 823 if (i + j >= DPAA2_MC_MSI_COUNT) { 824 device_printf(mcdev, "requested %d MSIs exceed " 825 "limit of %d available\n", count, 826 DPAA2_MC_MSI_COUNT); 827 error = E2BIG; 828 break; 829 } 830 sc->msi[i + j].child = child; 831 irqs[j] = sc->msi[i + j].irq; 832 } 833 break; 834 } 835 mtx_unlock(&sc->msi_lock); 836 837 return (error); 838 } 839 840 /** 841 * @internal 842 * @brief Marks IRQs as free in the pre-allocated pool of MSIs. 843 * 844 * NOTE: This function is a part of fallback solution when IOMMU isn't available. 845 * Total number of IRQs is limited to 32. 846 * NOTE: MSIs are kept allocated in the kernel as a part of the pool. 847 */ 848 static int 849 dpaa2_mc_release_msi_impl(device_t mcdev, device_t child, int count, int *irqs) 850 { 851 struct dpaa2_mc_softc *sc = device_get_softc(mcdev); 852 853 mtx_assert(&sc->msi_lock, MA_NOTOWNED); 854 mtx_lock(&sc->msi_lock); 855 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) { 856 if (sc->msi[i].child != child) 857 continue; 858 for (int j = 0; j < count; j++) { 859 if (sc->msi[i].irq == irqs[j]) { 860 sc->msi[i].child = NULL; 861 break; 862 } 863 } 864 } 865 mtx_unlock(&sc->msi_lock); 866 867 return (0); 868 } 869 870 /** 871 * @internal 872 * @brief Provides address to write to and data according to the given MSI from 873 * the pre-allocated pool. 874 * 875 * NOTE: This function is a part of fallback solution when IOMMU isn't available. 876 * Total number of IRQs is limited to 32. 877 */ 878 static int 879 dpaa2_mc_map_msi_impl(device_t mcdev, device_t child, int irq, uint64_t *addr, 880 uint32_t *data) 881 { 882 struct dpaa2_mc_softc *sc = device_get_softc(mcdev); 883 int error = EINVAL; 884 885 mtx_assert(&sc->msi_lock, MA_NOTOWNED); 886 mtx_lock(&sc->msi_lock); 887 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) { 888 if (sc->msi[i].child == child && sc->msi[i].irq == irq) { 889 error = 0; 890 break; 891 } 892 } 893 mtx_unlock(&sc->msi_lock); 894 if (error) 895 return (error); 896 897 return (intr_map_msi(mcdev, sc->msi_owner, dpaa2_mc_get_xref(mcdev, 898 sc->msi_owner), irq, addr, data)); 899 } 900 901 #endif /* defined(INTRNG) && !defined(IOMMU) */ 902 903 static device_method_t dpaa2_mc_methods[] = { 904 DEVMETHOD_END 905 }; 906 907 DEFINE_CLASS_0(dpaa2_mc, dpaa2_mc_driver, dpaa2_mc_methods, 908 sizeof(struct dpaa2_mc_softc)); 909