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
54struct siba_erom;
55struct siba_erom_io;
56
57
58static int			siba_eio_init(struct siba_erom_io *io,
59				    struct bhnd_erom_io *eio, u_int ncores);
60
61static uint32_t			siba_eio_read_4(struct siba_erom_io *io,
62				    u_int core_idx, bus_size_t offset);
63
64static 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
68static 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 */
75struct 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 */
84struct 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() */
94static int
95siba_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() */
163static int
164siba_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() */
186static void
187siba_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 */
195static int
196siba_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 */
211static uint32_t
212siba_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 */
241static int
242siba_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 */
353int
354siba_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 */
388static int
389siba_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
446static int
447siba_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
500static int
501siba_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, &region_addr, &region_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() */
614static int
615siba_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() */
654static void
655siba_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() */
661static int
662siba_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
719static 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
732BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));
733