xref: /freebsd/sys/dev/bhnd/siba/siba_erom.c (revision 5bf5ca772c6de2d53344a78cf461447cc322ccea)
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_erom.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 	uint32_t		idreg;
394 	int			error;
395 
396 	/* Identify the chipcommon core */
397 	if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
398 		return (error);
399 
400 	if (ccid.core_info.vendor != BHND_MFGID_BCM ||
401 	    ccid.core_info.device != BHND_COREID_CC)
402 	{
403 		if (bootverbose) {
404 			EROM_LOG(io, "first core not chipcommon "
405 			    "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
406 			    ccid.core_info.device);
407 		}
408 		return (ENXIO);
409 	}
410 
411 	/* Identify the chipset */
412 	idreg = siba_eio_read_4(io, 0, CHIPC_ID);
413 	*cid = bhnd_parse_chipid(idreg, enum_addr);
414 
415 	/* Fix up the core count in-place */
416 	return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev,
417 	    &cid->ncores));
418 }
419 
420 static int
421 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
422     struct bhnd_core_info *core)
423 {
424 	struct siba_erom	*sc;
425 	struct bhnd_core_match	 imatch;
426 	int			 error;
427 
428 	sc = (struct siba_erom *)erom;
429 
430 	/* We can't determine a core's unit number during the initial scan. */
431 	imatch = *desc;
432 	imatch.m.match.core_unit = 0;
433 
434 	/* Locate the first matching core */
435 	for (u_int i = 0; i < sc->io.ncores; i++) {
436 		struct siba_core_id	sid;
437 		struct bhnd_core_info	ci;
438 
439 		/* Read the core info */
440 		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
441 			return (error);
442 
443 		ci = sid.core_info;
444 
445 		/* Check for initial match */
446 		if (!bhnd_core_matches(&ci, &imatch))
447 			continue;
448 
449 		/* Re-scan preceding cores to determine the unit number. */
450 		for (u_int j = 0; j < i; j++) {
451 			error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
452 			if (error)
453 				return (error);
454 
455 			/* Bump the unit number? */
456 			if (sid.core_info.vendor == ci.vendor &&
457 			    sid.core_info.device == ci.device)
458 				ci.unit++;
459 		}
460 
461 		/* Check for full match against now-valid unit number */
462 		if (!bhnd_core_matches(&ci, desc))
463 			continue;
464 
465 		/* Matching core found */
466 		*core = ci;
467 		return (0);
468 	}
469 
470 	/* Not found */
471 	return (ENOENT);
472 }
473 
474 static int
475 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
476     bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
477     bhnd_addr_t *addr, bhnd_size_t *size)
478 {
479 	struct siba_erom	*sc;
480 	struct bhnd_core_info	 core;
481 	struct siba_core_id	 sid;
482 	struct siba_admatch	 admatch;
483 	uint32_t		 am;
484 	u_int			 am_offset;
485 	u_int			 addrspace, cfg;
486 
487 	int			 error;
488 
489 	sc = (struct siba_erom *)erom;
490 
491 	/* Locate the requested core */
492 	if ((error = siba_erom_lookup_core(erom, desc, &core)))
493 		return (error);
494 
495 	/* Fetch full siba core ident */
496 	error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
497 	if (error)
498 		return (error);
499 
500 	/* Is port valid? */
501 	if (!siba_is_port_valid(&sid, type, port))
502 		return (ENOENT);
503 
504 	/* Is region valid? */
505 	if (region >= siba_port_region_count(&sid, type, port))
506 		return (ENOENT);
507 
508 	/* Is this a siba configuration region? If so, this is mapped to an
509 	 * offset within the device0.0 port */
510 	error = siba_cfg_index(&sid, type, port, region, &cfg);
511 	if (!error) {
512 		bhnd_addr_t	region_addr;
513 		bhnd_addr_t	region_size;
514 		bhnd_size_t	cfg_offset, cfg_size;
515 
516 		cfg_offset = SIBA_CFG_OFFSET(cfg);
517 		cfg_size = SIBA_CFG_SIZE;
518 
519 		/* Fetch the device0.0 addr/size */
520 		error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
521 		    0, 0, NULL, &region_addr, &region_size);
522 		if (error)
523 			return (error);
524 
525 		/* Verify that our offset fits within the region */
526 		if (region_size < cfg_size) {
527 			printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
528 			    bhnd_port_type_name(type), port, region, cfg_offset,
529 			    bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
530 
531 			return (ENXIO);
532 		}
533 
534 		if (BHND_ADDR_MAX - region_addr < cfg_offset) {
535 			printf("%s%u.%u offset %ju would overflow %s0.0 addr "
536 			    "%ju\n", bhnd_port_type_name(type), port, region,
537 			    cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
538 			    region_addr);
539 
540 			return (ENXIO);
541 		}
542 
543 		if (info != NULL)
544 			*info = core;
545 
546 		*addr = region_addr + cfg_offset;
547 		*size = cfg_size;
548 		return (0);
549 	}
550 
551 	/*
552 	 * Otherwise, must be a device port.
553 	 *
554 	 * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
555 	 * bus drivers, we do not exclude the siba(4) configuration blocks from
556 	 * the first device port.
557 	 */
558 	error = siba_addrspace_index(&sid, type, port, region, &addrspace);
559 	if (error)
560 		return (error);
561 
562 	/* Determine the register offset */
563 	am_offset = siba_admatch_offset(addrspace);
564 	if (am_offset == 0) {
565 		printf("addrspace %u is unsupported", addrspace);
566 		return (ENODEV);
567 	}
568 
569 	/* Read and parse the address match register */
570 	am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
571 
572 	if ((error = siba_parse_admatch(am, &admatch))) {
573 		printf("failed to decode address match register value 0x%x\n",
574 		    am);
575 		return (error);
576 	}
577 
578 	if (info != NULL)
579 		*info = core;
580 
581 	*addr = admatch.am_base;
582 	*size = admatch.am_size;
583 
584 	return (0);
585 }
586 
587 /* BHND_EROM_GET_CORE_TABLE() */
588 static int
589 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
590     u_int *num_cores)
591 {
592 	struct siba_erom	*sc;
593 	struct bhnd_core_info	*out;
594 	int			 error;
595 
596 	sc = (struct siba_erom *)erom;
597 
598 	/* Allocate our core array */
599 	out = mallocarray(sc->io.ncores, sizeof(*out), M_BHND, M_NOWAIT);
600 	if (out == NULL)
601 		return (ENOMEM);
602 
603 	*cores = out;
604 	*num_cores = sc->io.ncores;
605 
606 	/* Enumerate all cores. */
607 	for (u_int i = 0; i < sc->io.ncores; i++) {
608 		struct siba_core_id sid;
609 
610 		/* Read the core info */
611 		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
612 			return (error);
613 
614 		out[i] = sid.core_info;
615 
616 		/* Determine unit number */
617 		for (u_int j = 0; j < i; j++) {
618 			if (out[j].vendor == out[i].vendor &&
619 			    out[j].device == out[i].device)
620 				out[i].unit++;
621 		}
622 	}
623 
624 	return (0);
625 }
626 
627 /* BHND_EROM_FREE_CORE_TABLE() */
628 static void
629 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
630 {
631 	free(cores, M_BHND);
632 }
633 
634 /* BHND_EROM_DUMP() */
635 static int
636 siba_erom_dump(bhnd_erom_t *erom)
637 {
638 	struct siba_erom	*sc;
639 	int			 error;
640 
641 	sc = (struct siba_erom *)erom;
642 
643 	/* Enumerate all cores. */
644 	for (u_int i = 0; i < sc->io.ncores; i++) {
645 		uint32_t idhigh, idlow;
646 		uint32_t nraddr;
647 
648 		idhigh = siba_eio_read_4(&sc->io, i,
649 		    SB0_REG_ABS(SIBA_CFG0_IDHIGH));
650 		idlow = siba_eio_read_4(&sc->io, i,
651 		    SB0_REG_ABS(SIBA_CFG0_IDLOW));
652 
653 		printf("siba core %u:\n", i);
654 		printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
655 		printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
656 		printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
657 		printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
658 
659 		/* Enumerate the address match registers */
660 		nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
661 		printf("\tnraddr\t0x%04x\n", nraddr);
662 
663 		for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
664 			struct siba_admatch	admatch;
665 			uint32_t		am;
666 			u_int			am_offset;
667 
668 			/* Determine the register offset */
669 			am_offset = siba_admatch_offset(addrspace);
670 			if (am_offset == 0) {
671 				printf("addrspace %zu unsupported",
672 				    addrspace);
673 				break;
674 			}
675 
676 			/* Read and parse the address match register */
677 			am = siba_eio_read_4(&sc->io, i, am_offset);
678 			if ((error = siba_parse_admatch(am, &admatch))) {
679 				printf("failed to decode address match "
680 				    "register value 0x%x\n", am);
681 				continue;
682 			}
683 
684 			printf("\taddrspace %zu\n", addrspace);
685 			printf("\t\taddr: 0x%08x\n", admatch.am_base);
686 			printf("\t\tsize: 0x%08x\n", admatch.am_size);
687 		}
688 	}
689 
690 	return (0);
691 }
692 
693 static kobj_method_t siba_erom_methods[] = {
694 	KOBJMETHOD(bhnd_erom_probe,		siba_erom_probe),
695 	KOBJMETHOD(bhnd_erom_init,		siba_erom_init),
696 	KOBJMETHOD(bhnd_erom_fini,		siba_erom_fini),
697 	KOBJMETHOD(bhnd_erom_get_core_table,	siba_erom_get_core_table),
698 	KOBJMETHOD(bhnd_erom_free_core_table,	siba_erom_free_core_table),
699 	KOBJMETHOD(bhnd_erom_lookup_core,	siba_erom_lookup_core),
700 	KOBJMETHOD(bhnd_erom_lookup_core_addr,	siba_erom_lookup_core_addr),
701 	KOBJMETHOD(bhnd_erom_dump,		siba_erom_dump),
702 
703 	KOBJMETHOD_END
704 };
705 
706 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));
707