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