xref: /freebsd/sys/dev/bhnd/siba/siba_erom.c (revision d9a42747950146bf03cda7f6e25d219253f8a57a)
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, &region_addr, &region_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