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