1 /*- 2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> 3 * Copyright (c) 2017 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Landon Fuller 7 * under sponsorship from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer, 14 * without modification. 15 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 17 * redistribution must be conditioned upon including a substantially 18 * similar Disclaimer requirement for further binary redistribution. 19 * 20 * NO WARRANTY 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 24 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGES. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 43 #include <machine/bus.h> 44 45 #include <dev/bhnd/bhnd_eromvar.h> 46 47 #include <dev/bhnd/cores/chipc/chipcreg.h> 48 49 #include "sibareg.h" 50 #include "sibavar.h" 51 52 #include "siba_eromvar.h" 53 54 struct siba_erom; 55 struct siba_erom_io; 56 57 static int siba_eio_init(struct siba_erom_io *io, 58 struct bhnd_erom_io *eio, u_int ncores); 59 60 static uint32_t siba_eio_read_4(struct siba_erom_io *io, 61 u_int core_idx, bus_size_t offset); 62 63 static int siba_eio_read_core_id(struct siba_erom_io *io, 64 u_int core_idx, int unit, 65 struct siba_core_id *sid); 66 67 static int siba_eio_read_chipid(struct siba_erom_io *io, 68 bus_addr_t enum_addr, 69 struct bhnd_chipid *cid); 70 71 /** 72 * SIBA EROM generic I/O context 73 */ 74 struct siba_erom_io { 75 struct bhnd_erom_io *eio; /**< erom I/O callbacks */ 76 bhnd_addr_t base_addr; /**< address of first core */ 77 u_int ncores; /**< core count */ 78 }; 79 80 /** 81 * SIBA EROM per-instance state. 82 */ 83 struct siba_erom { 84 struct bhnd_erom obj; 85 struct siba_erom_io io; /**< i/o context */ 86 }; 87 88 #define EROM_LOG(io, fmt, ...) do { \ 89 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \ 90 } while(0) 91 92 /* SIBA implementation of BHND_EROM_PROBE() */ 93 static int 94 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio, 95 const struct bhnd_chipid *hint, struct bhnd_chipid *cid) 96 { 97 struct siba_erom_io io; 98 uint32_t idreg; 99 int error; 100 101 /* Initialize I/O context, assuming at least the first core is mapped */ 102 if ((error = siba_eio_init(&io, eio, 1))) 103 return (error); 104 105 /* Try using the provided hint. */ 106 if (hint != NULL) { 107 struct siba_core_id sid; 108 109 /* Validate bus type */ 110 if (hint->chip_type != BHND_CHIPTYPE_SIBA) 111 return (ENXIO); 112 113 /* 114 * Verify the first core's IDHIGH/IDLOW identification. 115 * 116 * The core must be a Broadcom core, but must *not* be 117 * a chipcommon core; those shouldn't be hinted. 118 * 119 * The first core on EXTIF-equipped devices varies, but on the 120 * BCM4710, it's a SDRAM core (0x803). 121 */ 122 123 if ((error = siba_eio_read_core_id(&io, 0, 0, &sid))) 124 return (error); 125 126 if (sid.core_info.vendor != BHND_MFGID_BCM) 127 return (ENXIO); 128 129 if (sid.core_info.device == BHND_COREID_CC) 130 return (EINVAL); 131 132 *cid = *hint; 133 } else { 134 /* Validate bus type */ 135 idreg = siba_eio_read_4(&io, 0, CHIPC_ID); 136 if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA) 137 return (ENXIO); 138 139 /* Identify the chipset */ 140 if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid))) 141 return (error); 142 143 /* Verify the chip type */ 144 if (cid->chip_type != BHND_CHIPTYPE_SIBA) 145 return (ENXIO); 146 } 147 148 /* 149 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES 150 * without triggering build failure due to -Wtype-limits 151 * 152 * if (cid.ncores > SIBA_MAX_CORES) 153 * return (EINVAL) 154 */ 155 _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES, 156 "ncores could result in over-read of backing resource"); 157 158 return (0); 159 } 160 161 /* SIBA implementation of BHND_EROM_INIT() */ 162 static int 163 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid, 164 struct bhnd_erom_io *eio) 165 { 166 struct siba_erom *sc; 167 int error; 168 169 sc = (struct siba_erom *)erom; 170 171 /* Attempt to map the full core enumeration space */ 172 error = bhnd_erom_io_map(eio, cid->enum_addr, 173 cid->ncores * SIBA_CORE_SIZE); 174 if (error) { 175 printf("%s: failed to map %u cores: %d\n", __FUNCTION__, 176 cid->ncores, error); 177 return (error); 178 } 179 180 /* Initialize I/O context */ 181 return (siba_eio_init(&sc->io, eio, cid->ncores)); 182 } 183 184 /* SIBA implementation of BHND_EROM_FINI() */ 185 static void 186 siba_erom_fini(bhnd_erom_t *erom) 187 { 188 struct siba_erom *sc = (struct siba_erom *)erom; 189 190 bhnd_erom_io_fini(sc->io.eio); 191 } 192 193 /* Initialize siba_erom resource I/O context */ 194 static int 195 siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores) 196 { 197 io->eio = eio; 198 io->ncores = ncores; 199 return (0); 200 } 201 202 /** 203 * Read a 32-bit value from @p offset relative to the base address of 204 * the given @p core_idx. 205 * 206 * @param io EROM I/O context. 207 * @param core_idx Core index. 208 * @param offset Core register offset. 209 */ 210 static uint32_t 211 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset) 212 { 213 /* Sanity check core index and offset */ 214 if (core_idx >= io->ncores) 215 panic("core index %u out of range (ncores=%u)", core_idx, 216 io->ncores); 217 218 if (offset > SIBA_CORE_SIZE - sizeof(uint32_t)) 219 panic("invalid core offset %#jx", (uintmax_t)offset); 220 221 /* Perform read */ 222 return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset, 223 4)); 224 } 225 226 /** 227 * Read and parse identification registers for the given @p core_index. 228 * 229 * @param io EROM I/O context. 230 * @param core_idx The core index. 231 * @param unit The caller-specified unit number to be included in the return 232 * value. 233 * @param[out] sid On success, the parsed siba core id. 234 * 235 * @retval 0 success 236 * @retval non-zero if reading or parsing the identification registers 237 * otherwise fails, a regular unix error code will be 238 * returned. 239 */ 240 static int 241 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit, 242 struct siba_core_id *sid) 243 { 244 struct siba_admatch admatch[SIBA_MAX_ADDRSPACE]; 245 uint32_t idhigh, idlow; 246 uint32_t tpsflag; 247 uint16_t ocp_vendor; 248 uint8_t sonics_rev; 249 uint8_t num_admatch; 250 uint8_t num_admatch_en; 251 uint8_t num_cfg; 252 bool intr_en; 253 u_int intr_flag; 254 int error; 255 256 idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); 257 idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW)); 258 tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG)); 259 260 ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR); 261 sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV); 262 num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */; 263 if (num_admatch > nitems(admatch)) { 264 printf("core%u: invalid admatch count %hhu\n", core_idx, 265 num_admatch); 266 return (EINVAL); 267 } 268 269 /* Determine backplane interrupt distribution configuration */ 270 intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0); 271 intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0); 272 273 /* Determine the number of sonics config register blocks */ 274 num_cfg = SIBA_CFG_NUM_2_2; 275 if (sonics_rev >= SIBA_IDL_SBREV_2_3) 276 num_cfg = SIBA_CFG_NUM_2_3; 277 278 /* Parse all admatch descriptors */ 279 num_admatch_en = 0; 280 for (uint8_t i = 0; i < num_admatch; i++) { 281 uint32_t am_value; 282 u_int am_offset; 283 284 KASSERT(i < nitems(admatch), ("invalid admatch index")); 285 286 /* Determine the register offset */ 287 am_offset = siba_admatch_offset(i); 288 if (am_offset == 0) { 289 printf("core%u: addrspace %hhu is unsupported", 290 core_idx, i); 291 return (ENODEV); 292 } 293 294 /* Read and parse the address match register */ 295 am_value = siba_eio_read_4(io, core_idx, am_offset); 296 error = siba_parse_admatch(am_value, &admatch[num_admatch_en]); 297 if (error) { 298 printf("core%u: failed to decode admatch[%hhu] " 299 "register value 0x%x\n", core_idx, i, am_value); 300 return (error); 301 } 302 303 /* Skip disabled entries */ 304 if (!admatch[num_admatch_en].am_enabled) 305 continue; 306 307 /* Reject unsupported negative matches. These are not used on 308 * any known devices */ 309 if (admatch[num_admatch_en].am_negative) { 310 printf("core%u: unsupported negative admatch[%hhu] " 311 "value 0x%x\n", core_idx, i, am_value); 312 return (ENXIO); 313 } 314 315 num_admatch_en++; 316 } 317 318 /* Populate the result */ 319 *sid = (struct siba_core_id) { 320 .core_info = { 321 .vendor = siba_get_bhnd_mfgid(ocp_vendor), 322 .device = SIBA_REG_GET(idhigh, IDH_DEVICE), 323 .hwrev = SIBA_IDH_CORE_REV(idhigh), 324 .core_idx = core_idx, 325 .unit = unit 326 }, 327 .sonics_vendor = ocp_vendor, 328 .sonics_rev = sonics_rev, 329 .intr_en = intr_en, 330 .intr_flag = intr_flag, 331 .num_admatch = num_admatch_en, 332 .num_cfg_blocks = num_cfg 333 }; 334 memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0])); 335 336 return (0); 337 } 338 339 /** 340 * Read and parse the SSB identification registers for the given @p core_index, 341 * returning the siba(4) core identification in @p sid. 342 * 343 * @param sc A siba EROM instance. 344 * @param core_idx The index of the core to be identified. 345 * @param[out] result On success, the parsed siba core id. 346 * 347 * @retval 0 success 348 * @retval non-zero if reading or parsing the identification registers 349 * otherwise fails, a regular unix error code will be 350 * returned. 351 */ 352 int 353 siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx, 354 struct siba_core_id *result) 355 { 356 struct siba_core_id sid; 357 int error; 358 359 /* Fetch the core info, assuming a unit number of 0 */ 360 if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid))) 361 return (error); 362 363 /* Scan preceding cores to determine the real unit number. */ 364 for (u_int i = 0; i < core_idx; i++) { 365 struct siba_core_id prev; 366 367 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev))) 368 return (error); 369 370 /* Bump the unit number? */ 371 if (sid.core_info.vendor == prev.core_info.vendor && 372 sid.core_info.device == prev.core_info.device) 373 sid.core_info.unit++; 374 } 375 376 *result = sid; 377 return (0); 378 } 379 380 /** 381 * Read and parse the chip identification register from the ChipCommon core. 382 * 383 * @param io EROM I/O context. 384 * @param enum_addr The physical address mapped by @p io. 385 * @param cid On success, the parsed chip identifier. 386 */ 387 static int 388 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr, 389 struct bhnd_chipid *cid) 390 { 391 struct siba_core_id ccid; 392 int error; 393 394 /* Identify the chipcommon core */ 395 if ((error = siba_eio_read_core_id(io, 0, 0, &ccid))) 396 return (error); 397 398 if (ccid.core_info.vendor != BHND_MFGID_BCM || 399 ccid.core_info.device != BHND_COREID_CC) 400 { 401 if (bootverbose) { 402 EROM_LOG(io, "first core not chipcommon " 403 "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor, 404 ccid.core_info.device); 405 } 406 return (ENXIO); 407 } 408 409 /* Identify the chipset */ 410 if ((error = bhnd_erom_read_chipid(io->eio, cid))) 411 return (error); 412 413 /* Do we need to fix up the core count? */ 414 if (CHIPC_NCORES_MIN_HWREV(ccid.core_info.hwrev)) 415 return (0); 416 417 switch (cid->chip_id) { 418 case BHND_CHIPID_BCM4306: 419 cid->ncores = 6; 420 break; 421 case BHND_CHIPID_BCM4704: 422 cid->ncores = 9; 423 break; 424 case BHND_CHIPID_BCM5365: 425 /* 426 * BCM5365 does support ID_NUMCORE in at least 427 * some of its revisions, but for unknown 428 * reasons, Broadcom's drivers always exclude 429 * the ChipCommon revision (0x5) used by BCM5365 430 * from the set of revisions supporting 431 * ID_NUMCORE, and instead supply a fixed value. 432 * 433 * Presumably, at least some of these devices 434 * shipped with a broken ID_NUMCORE value. 435 */ 436 cid->ncores = 7; 437 break; 438 default: 439 return (EINVAL); 440 } 441 442 return (0); 443 } 444 445 static int 446 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc, 447 struct bhnd_core_info *core) 448 { 449 struct siba_erom *sc; 450 struct bhnd_core_match imatch; 451 int error; 452 453 sc = (struct siba_erom *)erom; 454 455 /* We can't determine a core's unit number during the initial scan. */ 456 imatch = *desc; 457 imatch.m.match.core_unit = 0; 458 459 /* Locate the first matching core */ 460 for (u_int i = 0; i < sc->io.ncores; i++) { 461 struct siba_core_id sid; 462 struct bhnd_core_info ci; 463 464 /* Read the core info */ 465 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid))) 466 return (error); 467 468 ci = sid.core_info; 469 470 /* Check for initial match */ 471 if (!bhnd_core_matches(&ci, &imatch)) 472 continue; 473 474 /* Re-scan preceding cores to determine the unit number. */ 475 for (u_int j = 0; j < i; j++) { 476 error = siba_eio_read_core_id(&sc->io, j, 0, &sid); 477 if (error) 478 return (error); 479 480 /* Bump the unit number? */ 481 if (sid.core_info.vendor == ci.vendor && 482 sid.core_info.device == ci.device) 483 ci.unit++; 484 } 485 486 /* Check for full match against now-valid unit number */ 487 if (!bhnd_core_matches(&ci, desc)) 488 continue; 489 490 /* Matching core found */ 491 *core = ci; 492 return (0); 493 } 494 495 /* Not found */ 496 return (ENOENT); 497 } 498 499 static int 500 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc, 501 bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info, 502 bhnd_addr_t *addr, bhnd_size_t *size) 503 { 504 struct siba_erom *sc; 505 struct bhnd_core_info core; 506 struct siba_core_id sid; 507 struct siba_admatch admatch; 508 uint32_t am; 509 u_int am_offset; 510 u_int addrspace, cfg; 511 512 int error; 513 514 sc = (struct siba_erom *)erom; 515 516 /* Locate the requested core */ 517 if ((error = siba_erom_lookup_core(erom, desc, &core))) 518 return (error); 519 520 /* Fetch full siba core ident */ 521 error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid); 522 if (error) 523 return (error); 524 525 /* Is port valid? */ 526 if (!siba_is_port_valid(&sid, type, port)) 527 return (ENOENT); 528 529 /* Is region valid? */ 530 if (region >= siba_port_region_count(&sid, type, port)) 531 return (ENOENT); 532 533 /* Is this a siba configuration region? If so, this is mapped to an 534 * offset within the device0.0 port */ 535 error = siba_cfg_index(&sid, type, port, region, &cfg); 536 if (!error) { 537 bhnd_addr_t region_addr; 538 bhnd_addr_t region_size; 539 bhnd_size_t cfg_offset, cfg_size; 540 541 cfg_offset = SIBA_CFG_OFFSET(cfg); 542 cfg_size = SIBA_CFG_SIZE; 543 544 /* Fetch the device0.0 addr/size */ 545 error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE, 546 0, 0, NULL, ®ion_addr, ®ion_size); 547 if (error) 548 return (error); 549 550 /* Verify that our offset fits within the region */ 551 if (region_size < cfg_size) { 552 printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n", 553 bhnd_port_type_name(type), port, region, cfg_offset, 554 bhnd_port_type_name(BHND_PORT_DEVICE), region_size); 555 556 return (ENXIO); 557 } 558 559 if (BHND_ADDR_MAX - region_addr < cfg_offset) { 560 printf("%s%u.%u offset %ju would overflow %s0.0 addr " 561 "%ju\n", bhnd_port_type_name(type), port, region, 562 cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE), 563 region_addr); 564 565 return (ENXIO); 566 } 567 568 if (info != NULL) 569 *info = core; 570 571 *addr = region_addr + cfg_offset; 572 *size = cfg_size; 573 return (0); 574 } 575 576 /* 577 * Otherwise, must be a device port. 578 * 579 * Map the bhnd device port to a siba addrspace index. Unlike siba(4) 580 * bus drivers, we do not exclude the siba(4) configuration blocks from 581 * the first device port. 582 */ 583 error = siba_addrspace_index(&sid, type, port, region, &addrspace); 584 if (error) 585 return (error); 586 587 /* Determine the register offset */ 588 am_offset = siba_admatch_offset(addrspace); 589 if (am_offset == 0) { 590 printf("addrspace %u is unsupported", addrspace); 591 return (ENODEV); 592 } 593 594 /* Read and parse the address match register */ 595 am = siba_eio_read_4(&sc->io, core.core_idx, am_offset); 596 597 if ((error = siba_parse_admatch(am, &admatch))) { 598 printf("failed to decode address match register value 0x%x\n", 599 am); 600 return (error); 601 } 602 603 if (info != NULL) 604 *info = core; 605 606 *addr = admatch.am_base; 607 *size = admatch.am_size; 608 609 return (0); 610 } 611 612 /* BHND_EROM_GET_CORE_TABLE() */ 613 static int 614 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores, 615 u_int *num_cores) 616 { 617 struct siba_erom *sc; 618 struct bhnd_core_info *out; 619 int error; 620 621 sc = (struct siba_erom *)erom; 622 623 /* Allocate our core array */ 624 out = mallocarray(sc->io.ncores, sizeof(*out), M_BHND, M_NOWAIT); 625 if (out == NULL) 626 return (ENOMEM); 627 628 *cores = out; 629 *num_cores = sc->io.ncores; 630 631 /* Enumerate all cores. */ 632 for (u_int i = 0; i < sc->io.ncores; i++) { 633 struct siba_core_id sid; 634 635 /* Read the core info */ 636 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid))) 637 return (error); 638 639 out[i] = sid.core_info; 640 641 /* Determine unit number */ 642 for (u_int j = 0; j < i; j++) { 643 if (out[j].vendor == out[i].vendor && 644 out[j].device == out[i].device) 645 out[i].unit++; 646 } 647 } 648 649 return (0); 650 } 651 652 /* BHND_EROM_FREE_CORE_TABLE() */ 653 static void 654 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores) 655 { 656 free(cores, M_BHND); 657 } 658 659 /* BHND_EROM_DUMP() */ 660 static int 661 siba_erom_dump(bhnd_erom_t *erom) 662 { 663 struct siba_erom *sc; 664 int error; 665 666 sc = (struct siba_erom *)erom; 667 668 /* Enumerate all cores. */ 669 for (u_int i = 0; i < sc->io.ncores; i++) { 670 uint32_t idhigh, idlow; 671 uint32_t nraddr; 672 673 idhigh = siba_eio_read_4(&sc->io, i, 674 SB0_REG_ABS(SIBA_CFG0_IDHIGH)); 675 idlow = siba_eio_read_4(&sc->io, i, 676 SB0_REG_ABS(SIBA_CFG0_IDLOW)); 677 678 printf("siba core %u:\n", i); 679 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR)); 680 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE)); 681 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh)); 682 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV)); 683 684 /* Enumerate the address match registers */ 685 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR); 686 printf("\tnraddr\t0x%04x\n", nraddr); 687 688 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) { 689 struct siba_admatch admatch; 690 uint32_t am; 691 u_int am_offset; 692 693 /* Determine the register offset */ 694 am_offset = siba_admatch_offset(addrspace); 695 if (am_offset == 0) { 696 printf("addrspace %zu unsupported", 697 addrspace); 698 break; 699 } 700 701 /* Read and parse the address match register */ 702 am = siba_eio_read_4(&sc->io, i, am_offset); 703 if ((error = siba_parse_admatch(am, &admatch))) { 704 printf("failed to decode address match " 705 "register value 0x%x\n", am); 706 continue; 707 } 708 709 printf("\taddrspace %zu\n", addrspace); 710 printf("\t\taddr: 0x%08x\n", admatch.am_base); 711 printf("\t\tsize: 0x%08x\n", admatch.am_size); 712 } 713 } 714 715 return (0); 716 } 717 718 static kobj_method_t siba_erom_methods[] = { 719 KOBJMETHOD(bhnd_erom_probe, siba_erom_probe), 720 KOBJMETHOD(bhnd_erom_init, siba_erom_init), 721 KOBJMETHOD(bhnd_erom_fini, siba_erom_fini), 722 KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table), 723 KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table), 724 KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core), 725 KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr), 726 KOBJMETHOD(bhnd_erom_dump, siba_erom_dump), 727 728 KOBJMETHOD_END 729 }; 730 731 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom)); 732