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