1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015-2017 Landon Fuller <landonf@landonf.org>
5 * Copyright (c) 2017 The FreeBSD Foundation
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19 *    redistribution must be conditioned upon including a substantially
20 *    similar Disclaimer requirement for further binary redistribution.
21 *
22 * NO WARRANTY
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39#include <sys/param.h>
40#include <sys/bus.h>
41#include <sys/kernel.h>
42#include <sys/limits.h>
43#include <sys/systm.h>
44
45#include <machine/bus.h>
46#include <machine/resource.h>
47
48#include <dev/bhnd/bhnd_eromvar.h>
49
50#include "bcma_eromreg.h"
51#include "bcma_eromvar.h"
52
53/*
54 * BCMA Enumeration ROM (EROM) Table
55 *
56 * Provides auto-discovery of BCMA cores on Broadcom's HND SoC.
57 *
58 * The EROM core address can be found at BCMA_CC_EROM_ADDR within the
59 * ChipCommon registers. The table itself is comprised of 32-bit
60 * type-tagged entries, organized into an array of variable-length
61 * core descriptor records.
62 *
63 * The final core descriptor is followed by a 32-bit BCMA_EROM_TABLE_EOF (0xF)
64 * marker.
65 */
66
67static const char	*bcma_erom_entry_type_name (uint8_t entry);
68
69static int		 bcma_erom_read32(struct bcma_erom *erom,
70			     uint32_t *entry);
71static int		 bcma_erom_skip32(struct bcma_erom *erom);
72
73static int		 bcma_erom_skip_core(struct bcma_erom *erom);
74static int		 bcma_erom_skip_mport(struct bcma_erom *erom);
75static int		 bcma_erom_skip_sport_region(struct bcma_erom *erom);
76
77static int		 bcma_erom_seek_next(struct bcma_erom *erom,
78			     uint8_t etype);
79static int		 bcma_erom_region_to_port_type(struct bcma_erom *erom,
80			     uint8_t region_type, bhnd_port_type *port_type);
81
82
83static int		 bcma_erom_peek32(struct bcma_erom *erom,
84			     uint32_t *entry);
85
86static bus_size_t	 bcma_erom_tell(struct bcma_erom *erom);
87static void		 bcma_erom_seek(struct bcma_erom *erom,
88			     bus_size_t offset);
89static void		 bcma_erom_reset(struct bcma_erom *erom);
90
91static int		 bcma_erom_seek_matching_core(struct bcma_erom *sc,
92			     const struct bhnd_core_match *desc,
93			     struct bhnd_core_info *core);
94
95static int		 bcma_erom_parse_core(struct bcma_erom *erom,
96			     struct bcma_erom_core *core);
97
98static int		 bcma_erom_parse_mport(struct bcma_erom *erom,
99			     struct bcma_erom_mport *mport);
100
101static int		 bcma_erom_parse_sport_region(struct bcma_erom *erom,
102			     struct bcma_erom_sport_region *region);
103
104static void		 bcma_erom_to_core_info(const struct bcma_erom_core *core,
105			     u_int core_idx, int core_unit,
106			     struct bhnd_core_info *info);
107
108/**
109 * BCMA EROM per-instance state.
110 */
111struct bcma_erom {
112	struct bhnd_erom	 obj;
113	device_t	 	 dev;		/**< parent device, or NULL if none. */
114	struct bhnd_erom_io	*eio;		/**< bus I/O callbacks */
115	bhnd_size_t	 	 offset;	/**< current read offset */
116};
117
118#define	EROM_LOG(erom, fmt, ...)	do {			\
119	printf("%s erom[0x%llx]: " fmt, __FUNCTION__,		\
120	    (unsigned long long)(erom->offset), ##__VA_ARGS__);	\
121} while(0)
122
123/** Return the type name for an EROM entry */
124static const char *
125bcma_erom_entry_type_name (uint8_t entry)
126{
127	switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
128	case BCMA_EROM_ENTRY_TYPE_CORE:
129		return "core";
130	case BCMA_EROM_ENTRY_TYPE_MPORT:
131		return "mport";
132	case BCMA_EROM_ENTRY_TYPE_REGION:
133		return "region";
134	default:
135		return "unknown";
136	}
137}
138
139/* BCMA implementation of BHND_EROM_INIT() */
140static int
141bcma_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
142    struct bhnd_erom_io *eio)
143{
144	struct bcma_erom	*sc;
145	bhnd_addr_t		 table_addr;
146	int			 error;
147
148	sc = (struct bcma_erom *)erom;
149	sc->eio = eio;
150	sc->offset = 0;
151
152	/* Determine erom table address */
153	if (BHND_ADDR_MAX - BCMA_EROM_TABLE_START < cid->enum_addr)
154		return (ENXIO); /* would overflow */
155
156	table_addr = cid->enum_addr + BCMA_EROM_TABLE_START;
157
158	/* Try to map the erom table */
159	error = bhnd_erom_io_map(sc->eio, table_addr, BCMA_EROM_TABLE_SIZE);
160	if (error)
161		return (error);
162
163	return (0);
164}
165
166/* BCMA implementation of BHND_EROM_PROBE() */
167static int
168bcma_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
169    const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
170{
171	int error;
172
173	/* Hints aren't supported; all BCMA devices have a ChipCommon
174	 * core */
175	if (hint != NULL)
176		return (EINVAL);
177
178	/* Read and parse chip identification */
179	if ((error = bhnd_erom_read_chipid(eio, cid)))
180		return (error);
181
182	/* Verify chip type */
183	switch (cid->chip_type) {
184		case BHND_CHIPTYPE_BCMA:
185			return (BUS_PROBE_DEFAULT);
186
187		case BHND_CHIPTYPE_BCMA_ALT:
188		case BHND_CHIPTYPE_UBUS:
189			return (BUS_PROBE_GENERIC);
190
191		default:
192			return (ENXIO);
193	}
194}
195
196static void
197bcma_erom_fini(bhnd_erom_t *erom)
198{
199	struct bcma_erom *sc = (struct bcma_erom *)erom;
200
201	bhnd_erom_io_fini(sc->eio);
202}
203
204static int
205bcma_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
206    struct bhnd_core_info *core)
207{
208	struct bcma_erom *sc = (struct bcma_erom *)erom;
209
210	/* Search for the first matching core */
211	return (bcma_erom_seek_matching_core(sc, desc, core));
212}
213
214static int
215bcma_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
216    bhnd_port_type port_type, u_int port_num, u_int region_num,
217    struct bhnd_core_info *core, bhnd_addr_t *addr, bhnd_size_t *size)
218{
219	struct bcma_erom	*sc;
220	struct bcma_erom_core	 ec;
221	uint32_t		 entry;
222	uint8_t			 region_port, region_type;
223	bool			 found;
224	int			 error;
225
226	sc = (struct bcma_erom *)erom;
227
228	/* Seek to the first matching core and provide the core info
229	 * to the caller */
230	if ((error = bcma_erom_seek_matching_core(sc, desc, core)))
231		return (error);
232
233	if ((error = bcma_erom_parse_core(sc, &ec)))
234		return (error);
235
236	/* Skip master ports */
237	for (u_long i = 0; i < ec.num_mport; i++) {
238		if ((error = bcma_erom_skip_mport(sc)))
239			return (error);
240	}
241
242	/* Seek to the region block for the given port type */
243	found = false;
244	while (1) {
245		bhnd_port_type	p_type;
246		uint8_t		r_type;
247
248		if ((error = bcma_erom_peek32(sc, &entry)))
249			return (error);
250
251		if (!BCMA_EROM_ENTRY_IS(entry, REGION))
252			return (ENOENT);
253
254		/* Expected region type? */
255		r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
256		error = bcma_erom_region_to_port_type(sc, r_type, &p_type);
257		if (error)
258			return (error);
259
260		if (p_type == port_type) {
261			found = true;
262			break;
263		}
264
265		/* Skip to next entry */
266		if ((error = bcma_erom_skip_sport_region(sc)))
267			return (error);
268	}
269
270	if (!found)
271		return (ENOENT);
272
273	/* Found the appropriate port type block; now find the region records
274	 * for the given port number */
275	found = false;
276	for (u_int i = 0; i <= port_num; i++) {
277		bhnd_port_type	p_type;
278
279		if ((error = bcma_erom_peek32(sc, &entry)))
280			return (error);
281
282		if (!BCMA_EROM_ENTRY_IS(entry, REGION))
283			return (ENOENT);
284
285		/* Fetch the type/port of the first region entry */
286		region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
287		region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
288
289		/* Have we found the region entries for the desired port? */
290		if (i == port_num) {
291			error = bcma_erom_region_to_port_type(sc, region_type,
292			    &p_type);
293			if (error)
294				return (error);
295
296			if (p_type == port_type)
297				found = true;
298
299			break;
300		}
301
302		/* Otherwise, seek to next block of region records */
303		while (1) {
304			uint8_t	next_type, next_port;
305
306			if ((error = bcma_erom_skip_sport_region(sc)))
307				return (error);
308
309			if ((error = bcma_erom_peek32(sc, &entry)))
310				return (error);
311
312			if (!BCMA_EROM_ENTRY_IS(entry, REGION))
313				return (ENOENT);
314
315			next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
316			next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
317
318			if (next_type != region_type ||
319			    next_port != region_port)
320				break;
321		}
322	}
323
324	if (!found)
325		return (ENOENT);
326
327	/* Finally, search for the requested region number */
328	for (u_int i = 0; i <= region_num; i++) {
329		struct bcma_erom_sport_region	region;
330		uint8_t				next_port, next_type;
331
332		if ((error = bcma_erom_peek32(sc, &entry)))
333			return (error);
334
335		if (!BCMA_EROM_ENTRY_IS(entry, REGION))
336			return (ENOENT);
337
338		/* Check for the end of the region block */
339		next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
340		next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
341
342		if (next_type != region_type ||
343		    next_port != region_port)
344			break;
345
346		/* Parse the region */
347		if ((error = bcma_erom_parse_sport_region(sc, &region)))
348			return (error);
349
350		/* Is this our target region_num? */
351		if (i == region_num) {
352			/* Found */
353			*addr = region.base_addr;
354			*size = region.size;
355			return (0);
356		}
357	}
358
359	/* Not found */
360	return (ENOENT);
361};
362
363static int
364bcma_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
365    u_int *num_cores)
366{
367	struct bcma_erom	*sc;
368	struct bhnd_core_info	*buffer;
369	bus_size_t		 initial_offset;
370	u_int			 count;
371	int			 error;
372
373	sc = (struct bcma_erom *)erom;
374
375	buffer = NULL;
376	initial_offset = bcma_erom_tell(sc);
377
378	/* Determine the core count */
379	bcma_erom_reset(sc);
380	for (count = 0, error = 0; !error; count++) {
381		struct bcma_erom_core core;
382
383		/* Seek to the first readable core entry */
384		error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
385		if (error == ENOENT)
386			break;
387		else if (error)
388			goto cleanup;
389
390		/* Read past the core descriptor */
391		if ((error = bcma_erom_parse_core(sc, &core)))
392			goto cleanup;
393	}
394
395	/* Allocate our output buffer */
396	buffer = mallocarray(count, sizeof(struct bhnd_core_info), M_BHND,
397	    M_NOWAIT);
398	if (buffer == NULL) {
399		error = ENOMEM;
400		goto cleanup;
401	}
402
403	/* Parse all core descriptors */
404	bcma_erom_reset(sc);
405	for (u_int i = 0; i < count; i++) {
406		struct bcma_erom_core	core;
407		int			unit;
408
409		/* Parse the core */
410		error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
411		if (error)
412			goto cleanup;
413
414		error = bcma_erom_parse_core(sc, &core);
415		if (error)
416			goto cleanup;
417
418		/* Determine the unit number */
419		unit = 0;
420		for (u_int j = 0; j < i; j++) {
421			if (buffer[i].vendor == buffer[j].vendor &&
422			    buffer[i].device == buffer[j].device)
423				unit++;
424		}
425
426		/* Convert to a bhnd info record */
427		bcma_erom_to_core_info(&core, i, unit, &buffer[i]);
428	}
429
430cleanup:
431	if (!error) {
432		*cores = buffer;
433		*num_cores = count;
434	} else {
435		if (buffer != NULL)
436			free(buffer, M_BHND);
437	}
438
439	/* Restore the initial position */
440	bcma_erom_seek(sc, initial_offset);
441	return (error);
442}
443
444static void
445bcma_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
446{
447	free(cores, M_BHND);
448}
449
450/**
451 * Return the current read position.
452 */
453static bus_size_t
454bcma_erom_tell(struct bcma_erom *erom)
455{
456	return (erom->offset);
457}
458
459/**
460 * Seek to an absolute read position.
461 */
462static void
463bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset)
464{
465	erom->offset = offset;
466}
467
468/**
469 * Read a 32-bit entry value from the EROM table without advancing the
470 * read position.
471 *
472 * @param erom EROM read state.
473 * @param entry Will contain the read result on success.
474 * @retval 0 success
475 * @retval ENOENT The end of the EROM table was reached.
476 * @retval non-zero The read could not be completed.
477 */
478static int
479bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
480{
481	if (erom->offset >= (BCMA_EROM_TABLE_SIZE - sizeof(uint32_t))) {
482		EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n");
483		return (EINVAL);
484	}
485
486	*entry = bhnd_erom_io_read(erom->eio, erom->offset, 4);
487	return (0);
488}
489
490/**
491 * Read a 32-bit entry value from the EROM table.
492 *
493 * @param erom EROM read state.
494 * @param entry Will contain the read result on success.
495 * @retval 0 success
496 * @retval ENOENT The end of the EROM table was reached.
497 * @retval non-zero The read could not be completed.
498 */
499static int
500bcma_erom_read32(struct bcma_erom *erom, uint32_t *entry)
501{
502	int error;
503
504	if ((error = bcma_erom_peek32(erom, entry)) == 0)
505		erom->offset += 4;
506
507	return (error);
508}
509
510/**
511 * Read and discard 32-bit entry value from the EROM table.
512 *
513 * @param erom EROM read state.
514 * @retval 0 success
515 * @retval ENOENT The end of the EROM table was reached.
516 * @retval non-zero The read could not be completed.
517 */
518static int
519bcma_erom_skip32(struct bcma_erom *erom)
520{
521	uint32_t	entry;
522
523	return bcma_erom_read32(erom, &entry);
524}
525
526/**
527 * Read and discard a core descriptor from the EROM table.
528 *
529 * @param erom EROM read state.
530 * @retval 0 success
531 * @retval ENOENT The end of the EROM table was reached.
532 * @retval non-zero The read could not be completed.
533 */
534static int
535bcma_erom_skip_core(struct bcma_erom *erom)
536{
537	struct bcma_erom_core core;
538	return (bcma_erom_parse_core(erom, &core));
539}
540
541/**
542 * Read and discard a master port descriptor from the EROM table.
543 *
544 * @param erom EROM read state.
545 * @retval 0 success
546 * @retval ENOENT The end of the EROM table was reached.
547 * @retval non-zero The read could not be completed.
548 */
549static int
550bcma_erom_skip_mport(struct bcma_erom *erom)
551{
552	struct bcma_erom_mport mp;
553	return (bcma_erom_parse_mport(erom, &mp));
554}
555
556/**
557 * Read and discard a port region descriptor from the EROM table.
558 *
559 * @param erom EROM read state.
560 * @retval 0 success
561 * @retval ENOENT The end of the EROM table was reached.
562 * @retval non-zero The read could not be completed.
563 */
564static int
565bcma_erom_skip_sport_region(struct bcma_erom *erom)
566{
567	struct bcma_erom_sport_region r;
568	return (bcma_erom_parse_sport_region(erom, &r));
569}
570
571/**
572 * Seek to the next entry matching the given EROM entry type.
573 *
574 * @param erom EROM read state.
575 * @param etype  One of BCMA_EROM_ENTRY_TYPE_CORE,
576 * BCMA_EROM_ENTRY_TYPE_MPORT, or BCMA_EROM_ENTRY_TYPE_REGION.
577 * @retval 0 success
578 * @retval ENOENT The end of the EROM table was reached.
579 * @retval non-zero Reading or parsing the descriptor failed.
580 */
581static int
582bcma_erom_seek_next(struct bcma_erom *erom, uint8_t etype)
583{
584	uint32_t			entry;
585	int				error;
586
587	/* Iterate until we hit an entry matching the requested type. */
588	while (!(error = bcma_erom_peek32(erom, &entry))) {
589		/* Handle EOF */
590		if (entry == BCMA_EROM_TABLE_EOF)
591			return (ENOENT);
592
593		/* Invalid entry */
594		if (!BCMA_EROM_GET_ATTR(entry, ENTRY_ISVALID))
595			return (EINVAL);
596
597		/* Entry type matches? */
598		if (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE) == etype)
599			return (0);
600
601		/* Skip non-matching entry types. */
602		switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
603		case BCMA_EROM_ENTRY_TYPE_CORE:
604			if ((error = bcma_erom_skip_core(erom)))
605				return (error);
606
607			break;
608
609		case BCMA_EROM_ENTRY_TYPE_MPORT:
610			if ((error = bcma_erom_skip_mport(erom)))
611				return (error);
612
613			break;
614
615		case BCMA_EROM_ENTRY_TYPE_REGION:
616			if ((error = bcma_erom_skip_sport_region(erom)))
617				return (error);
618			break;
619
620		default:
621			/* Unknown entry type! */
622			return (EINVAL);
623		}
624	}
625
626	return (error);
627}
628
629/**
630 * Return the read position to the start of the EROM table.
631 *
632 * @param erom EROM read state.
633 */
634static void
635bcma_erom_reset(struct bcma_erom *erom)
636{
637	erom->offset = 0;
638}
639
640/**
641 * Seek to the first core entry matching @p desc.
642 *
643 * @param erom EROM read state.
644 * @param desc The core match descriptor.
645 * @param[out] core On success, the matching core info. If the core info
646 * is not desired, a NULL pointer may be provided.
647 * @retval 0 success
648 * @retval ENOENT The end of the EROM table was reached before @p index was
649 * found.
650 * @retval non-zero Reading or parsing failed.
651 */
652static int
653bcma_erom_seek_matching_core(struct bcma_erom *sc,
654    const struct bhnd_core_match *desc, struct bhnd_core_info *core)
655{
656	struct bhnd_core_match	 imatch;
657	bus_size_t		 core_offset, next_offset;
658	int			 error;
659
660	/* Seek to table start. */
661	bcma_erom_reset(sc);
662
663	/* We can't determine a core's unit number during the initial scan. */
664	imatch = *desc;
665	imatch.m.match.core_unit = 0;
666
667	/* Locate the first matching core */
668	for (u_int i = 0; i < UINT_MAX; i++) {
669		struct bcma_erom_core	ec;
670		struct bhnd_core_info	ci;
671
672		/* Seek to the next core */
673		error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
674		if (error)
675			return (error);
676
677		/* Save the core offset */
678		core_offset = bcma_erom_tell(sc);
679
680		/* Parse the core */
681		if ((error = bcma_erom_parse_core(sc, &ec)))
682			return (error);
683
684		bcma_erom_to_core_info(&ec, i, 0, &ci);
685
686		/* Check for initial match */
687		if (!bhnd_core_matches(&ci, &imatch))
688			continue;
689
690		/* Re-scan preceding cores to determine the unit number. */
691		next_offset = bcma_erom_tell(sc);
692		bcma_erom_reset(sc);
693		for (u_int j = 0; j < i; j++) {
694			/* Parse the core */
695			error = bcma_erom_seek_next(sc,
696			    BCMA_EROM_ENTRY_TYPE_CORE);
697			if (error)
698				return (error);
699
700			if ((error = bcma_erom_parse_core(sc, &ec)))
701				return (error);
702
703			/* Bump the unit number? */
704			if (ec.vendor == ci.vendor && ec.device == ci.device)
705				ci.unit++;
706		}
707
708		/* Check for full match against now-valid unit number */
709		if (!bhnd_core_matches(&ci, desc)) {
710			/* Reposition to allow reading the next core */
711			bcma_erom_seek(sc, next_offset);
712			continue;
713		}
714
715		/* Found; seek to the core's initial offset and provide
716		 * the core info to the caller */
717		bcma_erom_seek(sc, core_offset);
718		if (core != NULL)
719			*core = ci;
720
721		return (0);
722	}
723
724	/* Not found, or a parse error occured */
725	return (error);
726}
727
728/**
729 * Read the next core descriptor from the EROM table.
730 *
731 * @param erom EROM read state.
732 * @param[out] core On success, will be populated with the parsed core
733 * descriptor data.
734 * @retval 0 success
735 * @retval ENOENT The end of the EROM table was reached.
736 * @retval non-zero Reading or parsing the core descriptor failed.
737 */
738static int
739bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core)
740{
741	uint32_t	entry;
742	int		error;
743
744	/* Parse CoreDescA */
745	if ((error = bcma_erom_read32(erom, &entry)))
746		return (error);
747
748	/* Handle EOF */
749	if (entry == BCMA_EROM_TABLE_EOF)
750		return (ENOENT);
751
752	if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
753		EROM_LOG(erom, "Unexpected EROM entry 0x%x (type=%s)\n",
754                   entry, bcma_erom_entry_type_name(entry));
755
756		return (EINVAL);
757	}
758
759	core->vendor = BCMA_EROM_GET_ATTR(entry, COREA_DESIGNER);
760	core->device = BCMA_EROM_GET_ATTR(entry, COREA_ID);
761
762	/* Parse CoreDescB */
763	if ((error = bcma_erom_read32(erom, &entry)))
764		return (error);
765
766	if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
767		return (EINVAL);
768	}
769
770	core->rev = BCMA_EROM_GET_ATTR(entry, COREB_REV);
771	core->num_mport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_MP);
772	core->num_dport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_DP);
773	core->num_mwrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP);
774	core->num_swrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WSP);
775
776	return (0);
777}
778
779/**
780 * Read the next master port descriptor from the EROM table.
781 *
782 * @param erom EROM read state.
783 * @param[out] mport On success, will be populated with the parsed
784 * descriptor data.
785 * @retval 0 success
786 * @retval non-zero Reading or parsing the descriptor failed.
787 */
788static int
789bcma_erom_parse_mport(struct bcma_erom *erom, struct bcma_erom_mport *mport)
790{
791	uint32_t	entry;
792	int		error;
793
794	/* Parse the master port descriptor */
795	if ((error = bcma_erom_read32(erom, &entry)))
796		return (error);
797
798	if (!BCMA_EROM_ENTRY_IS(entry, MPORT))
799		return (EINVAL);
800
801	mport->port_vid = BCMA_EROM_GET_ATTR(entry, MPORT_ID);
802	mport->port_num = BCMA_EROM_GET_ATTR(entry, MPORT_NUM);
803
804	return (0);
805}
806
807/**
808 * Read the next slave port region descriptor from the EROM table.
809 *
810 * @param erom EROM read state.
811 * @param[out] mport On success, will be populated with the parsed
812 * descriptor data.
813 * @retval 0 success
814 * @retval ENOENT The end of the region descriptor table was reached.
815 * @retval non-zero Reading or parsing the descriptor failed.
816 */
817static int
818bcma_erom_parse_sport_region(struct bcma_erom *erom,
819    struct bcma_erom_sport_region *region)
820{
821	uint32_t	entry;
822	uint8_t		size_type;
823	int		error;
824
825	/* Peek at the region descriptor */
826	if (bcma_erom_peek32(erom, &entry))
827		return (EINVAL);
828
829	/* A non-region entry signals the end of the region table */
830	if (!BCMA_EROM_ENTRY_IS(entry, REGION)) {
831		return (ENOENT);
832	} else {
833		bcma_erom_skip32(erom);
834	}
835
836	region->base_addr = BCMA_EROM_GET_ATTR(entry, REGION_BASE);
837	region->region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
838	region->region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
839	size_type = BCMA_EROM_GET_ATTR(entry, REGION_SIZE);
840
841	/* If region address is 64-bit, fetch the high bits. */
842	if (BCMA_EROM_GET_ATTR(entry, REGION_64BIT)) {
843		if ((error = bcma_erom_read32(erom, &entry)))
844			return (error);
845
846		region->base_addr |= ((bhnd_addr_t) entry << 32);
847	}
848
849	/* Parse the region size; it's either encoded as the binary logarithm
850	 * of the number of 4K pages (i.e. log2 n), or its encoded as a
851	 * 32-bit/64-bit literal value directly following the current entry. */
852	if (size_type == BCMA_EROM_REGION_SIZE_OTHER) {
853		if ((error = bcma_erom_read32(erom, &entry)))
854			return (error);
855
856		region->size = BCMA_EROM_GET_ATTR(entry, RSIZE_VAL);
857
858		if (BCMA_EROM_GET_ATTR(entry, RSIZE_64BIT)) {
859			if ((error = bcma_erom_read32(erom, &entry)))
860				return (error);
861			region->size |= ((bhnd_size_t) entry << 32);
862		}
863	} else {
864		region->size = BCMA_EROM_REGION_SIZE_BASE << size_type;
865	}
866
867	/* Verify that addr+size does not overflow. */
868	if (region->size != 0 &&
869	    BHND_ADDR_MAX - (region->size - 1) < region->base_addr)
870	{
871		EROM_LOG(erom, "%s%u: invalid address map %llx:%llx\n",
872		    bcma_erom_entry_type_name(region->region_type),
873		    region->region_port,
874		    (unsigned long long) region->base_addr,
875		    (unsigned long long) region->size);
876
877		return (EINVAL);
878	}
879
880	return (0);
881}
882
883/**
884 * Convert a bcma_erom_core record to its bhnd_core_info representation.
885 *
886 * @param core EROM core record to convert.
887 * @param core_idx The core index of @p core.
888 * @param core_unit The core unit of @p core.
889 * @param[out] info The populated bhnd_core_info representation.
890 */
891static void
892bcma_erom_to_core_info(const struct bcma_erom_core *core, u_int core_idx,
893    int core_unit, struct bhnd_core_info *info)
894{
895	info->vendor = core->vendor;
896	info->device = core->device;
897	info->hwrev = core->rev;
898	info->core_idx = core_idx;
899	info->unit = core_unit;
900}
901
902/**
903 * Map an EROM region type to its corresponding port type.
904 *
905 * @param region_type Region type value.
906 * @param[out] port_type On success, the corresponding port type.
907 */
908static int
909bcma_erom_region_to_port_type(struct bcma_erom *erom, uint8_t region_type,
910    bhnd_port_type *port_type)
911{
912	switch (region_type) {
913	case BCMA_EROM_REGION_TYPE_DEVICE:
914		*port_type = BHND_PORT_DEVICE;
915		return (0);
916	case BCMA_EROM_REGION_TYPE_BRIDGE:
917		*port_type = BHND_PORT_BRIDGE;
918		return (0);
919	case BCMA_EROM_REGION_TYPE_MWRAP:
920	case BCMA_EROM_REGION_TYPE_SWRAP:
921		*port_type = BHND_PORT_AGENT;
922		return (0);
923	default:
924		EROM_LOG(erom, "unsupported region type %hhx\n",
925			region_type);
926		return (EINVAL);
927	}
928}
929
930/**
931 * Register all MMIO region descriptors for the given slave port.
932 *
933 * @param erom EROM read state.
934 * @param corecfg Core info to be populated with the scanned port regions.
935 * @param port_num Port index for which regions will be parsed.
936 * @param region_type The region type to be parsed.
937 * @param[out] offset The offset at which to perform parsing. On success, this
938 * will be updated to point to the next EROM table entry.
939 */
940static int
941bcma_erom_corecfg_fill_port_regions(struct bcma_erom *erom,
942    struct bcma_corecfg *corecfg, bcma_pid_t port_num,
943    uint8_t region_type)
944{
945	struct bcma_sport	*sport;
946	struct bcma_sport_list	*sports;
947	bus_size_t		 entry_offset;
948	int			 error;
949	bhnd_port_type		 port_type;
950
951	error = 0;
952
953	/* Determine the port type for this region type. */
954	error = bcma_erom_region_to_port_type(erom, region_type, &port_type);
955	if (error)
956		return (error);
957
958	/* Fetch the list to be populated */
959	sports = bcma_corecfg_get_port_list(corecfg, port_type);
960
961	/* Allocate a new port descriptor */
962	sport = bcma_alloc_sport(port_num, port_type);
963	if (sport == NULL)
964		return (ENOMEM);
965
966	/* Read all address regions defined for this port */
967	for (bcma_rmid_t region_num = 0;; region_num++) {
968		struct bcma_map			*map;
969		struct bcma_erom_sport_region	 spr;
970
971		/* No valid port definition should come anywhere near
972		 * BCMA_RMID_MAX. */
973		if (region_num == BCMA_RMID_MAX) {
974			EROM_LOG(erom, "core%u %s%u: region count reached "
975			    "upper limit of %u\n",
976			    corecfg->core_info.core_idx,
977			    bhnd_port_type_name(port_type),
978			    port_num, BCMA_RMID_MAX);
979
980			error = EINVAL;
981			goto cleanup;
982		}
983
984		/* Parse the next region entry. */
985		entry_offset = bcma_erom_tell(erom);
986		error = bcma_erom_parse_sport_region(erom, &spr);
987		if (error && error != ENOENT) {
988			EROM_LOG(erom, "core%u %s%u.%u: invalid slave port "
989			    "address region\n",
990			    corecfg->core_info.core_idx,
991			    bhnd_port_type_name(port_type),
992			    port_num, region_num);
993			goto cleanup;
994		}
995
996		/* ENOENT signals no further region entries */
997		if (error == ENOENT) {
998			/* No further entries */
999			error = 0;
1000			break;
1001		}
1002
1003		/* A region or type mismatch also signals no further region
1004		 * entries */
1005		if (spr.region_port != port_num ||
1006		    spr.region_type != region_type)
1007		{
1008			/* We don't want to consume this entry */
1009			bcma_erom_seek(erom, entry_offset);
1010
1011			error = 0;
1012			goto cleanup;
1013		}
1014
1015		/*
1016		 * Create the map entry.
1017		 */
1018		map = malloc(sizeof(struct bcma_map), M_BHND, M_NOWAIT);
1019		if (map == NULL) {
1020			error = ENOMEM;
1021			goto cleanup;
1022		}
1023
1024		map->m_region_num = region_num;
1025		map->m_base = spr.base_addr;
1026		map->m_size = spr.size;
1027		map->m_rid = -1;
1028
1029		/* Add the region map to the port */
1030		STAILQ_INSERT_TAIL(&sport->sp_maps, map, m_link);
1031		sport->sp_num_maps++;
1032	}
1033
1034cleanup:
1035	/* Append the new port descriptor on success, or deallocate the
1036	 * partially parsed descriptor on failure. */
1037	if (error == 0) {
1038		STAILQ_INSERT_TAIL(sports, sport, sp_link);
1039	} else if (sport != NULL) {
1040		bcma_free_sport(sport);
1041	}
1042
1043	return error;
1044}
1045
1046/**
1047 * Parse the next core entry from the EROM table and produce a bcma_corecfg
1048 * to be owned by the caller.
1049 *
1050 * @param erom A bcma EROM instance.
1051 * @param[out] result On success, the core's device info. The caller inherits
1052 * ownership of this allocation.
1053 *
1054 * @return If successful, returns 0. If the end of the EROM table is hit,
1055 * ENOENT will be returned. On error, returns a non-zero error value.
1056 */
1057int
1058bcma_erom_next_corecfg(struct bcma_erom *erom, struct bcma_corecfg **result)
1059{
1060	struct bcma_corecfg	*cfg;
1061	struct bcma_erom_core	 core;
1062	uint8_t			 first_region_type;
1063	bus_size_t		 initial_offset;
1064	u_int			 core_index;
1065	int			 core_unit;
1066	int			 error;
1067
1068	cfg = NULL;
1069	initial_offset = bcma_erom_tell(erom);
1070
1071	/* Parse the next core entry */
1072	if ((error = bcma_erom_parse_core(erom, &core)))
1073		return (error);
1074
1075	/* Determine the core's index and unit numbers */
1076	bcma_erom_reset(erom);
1077	core_unit = 0;
1078	core_index = 0;
1079	for (; bcma_erom_tell(erom) != initial_offset; core_index++) {
1080		struct bcma_erom_core prev_core;
1081
1082		/* Parse next core */
1083		error = bcma_erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
1084		if (error)
1085			return (error);
1086
1087		if ((error = bcma_erom_parse_core(erom, &prev_core)))
1088			return (error);
1089
1090		/* Is earlier unit? */
1091		if (core.vendor == prev_core.vendor &&
1092		    core.device == prev_core.device)
1093		{
1094			core_unit++;
1095		}
1096
1097		/* Seek to next core */
1098		error = bcma_erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
1099		if (error)
1100			return (error);
1101	}
1102
1103	/* We already parsed the core descriptor */
1104	if ((error = bcma_erom_skip_core(erom)))
1105		return (error);
1106
1107	/* Allocate our corecfg */
1108	cfg = bcma_alloc_corecfg(core_index, core_unit, core.vendor,
1109	    core.device, core.rev);
1110	if (cfg == NULL)
1111		return (ENOMEM);
1112
1113	/* These are 5-bit values in the EROM table, and should never be able
1114	 * to overflow BCMA_PID_MAX. */
1115	KASSERT(core.num_mport <= BCMA_PID_MAX, ("unsupported mport count"));
1116	KASSERT(core.num_dport <= BCMA_PID_MAX, ("unsupported dport count"));
1117	KASSERT(core.num_mwrap + core.num_swrap <= BCMA_PID_MAX,
1118	    ("unsupported wport count"));
1119
1120	if (bootverbose) {
1121		EROM_LOG(erom,
1122		    "core%u: %s %s (cid=%hx, rev=%hu, unit=%d)\n",
1123		    core_index,
1124		    bhnd_vendor_name(core.vendor),
1125		    bhnd_find_core_name(core.vendor, core.device),
1126		    core.device, core.rev, core_unit);
1127	}
1128
1129	cfg->num_master_ports = core.num_mport;
1130	cfg->num_dev_ports = 0;		/* determined below */
1131	cfg->num_bridge_ports = 0;	/* determined blow */
1132	cfg->num_wrapper_ports = core.num_mwrap + core.num_swrap;
1133
1134	/* Parse Master Port Descriptors */
1135	for (uint8_t i = 0; i < core.num_mport; i++) {
1136		struct bcma_mport	*mport;
1137		struct bcma_erom_mport	 mpd;
1138
1139		/* Parse the master port descriptor */
1140		error = bcma_erom_parse_mport(erom, &mpd);
1141		if (error)
1142			goto failed;
1143
1144		/* Initialize a new bus mport structure */
1145		mport = malloc(sizeof(struct bcma_mport), M_BHND, M_NOWAIT);
1146		if (mport == NULL) {
1147			error = ENOMEM;
1148			goto failed;
1149		}
1150
1151		mport->mp_vid = mpd.port_vid;
1152		mport->mp_num = mpd.port_num;
1153
1154		/* Update dinfo */
1155		STAILQ_INSERT_TAIL(&cfg->master_ports, mport, mp_link);
1156	}
1157
1158
1159	/*
1160	 * Determine whether this is a bridge device; if so, we can
1161	 * expect the first sequence of address region descriptors to
1162	 * be of EROM_REGION_TYPE_BRIDGE instead of
1163	 * BCMA_EROM_REGION_TYPE_DEVICE.
1164	 *
1165	 * It's unclear whether this is the correct mechanism by which we
1166	 * should detect/handle bridge devices, but this approach matches
1167	 * that of (some of) Broadcom's published drivers.
1168	 */
1169	if (core.num_dport > 0) {
1170		uint32_t entry;
1171
1172		if ((error = bcma_erom_peek32(erom, &entry)))
1173			goto failed;
1174
1175		if (BCMA_EROM_ENTRY_IS(entry, REGION) &&
1176		    BCMA_EROM_GET_ATTR(entry, REGION_TYPE) == BCMA_EROM_REGION_TYPE_BRIDGE)
1177		{
1178			first_region_type = BCMA_EROM_REGION_TYPE_BRIDGE;
1179			cfg->num_dev_ports = 0;
1180			cfg->num_bridge_ports = core.num_dport;
1181		} else {
1182			first_region_type = BCMA_EROM_REGION_TYPE_DEVICE;
1183			cfg->num_dev_ports = core.num_dport;
1184			cfg->num_bridge_ports = 0;
1185		}
1186	}
1187
1188	/* Device/bridge port descriptors */
1189	for (uint8_t sp_num = 0; sp_num < core.num_dport; sp_num++) {
1190		error = bcma_erom_corecfg_fill_port_regions(erom, cfg, sp_num,
1191		    first_region_type);
1192
1193		if (error)
1194			goto failed;
1195	}
1196
1197	/* Wrapper (aka device management) descriptors (for master ports). */
1198	for (uint8_t sp_num = 0; sp_num < core.num_mwrap; sp_num++) {
1199		error = bcma_erom_corecfg_fill_port_regions(erom, cfg, sp_num,
1200		    BCMA_EROM_REGION_TYPE_MWRAP);
1201
1202		if (error)
1203			goto failed;
1204	}
1205
1206
1207	/* Wrapper (aka device management) descriptors (for slave ports). */
1208	for (uint8_t i = 0; i < core.num_swrap; i++) {
1209		/* Slave wrapper ports are not numbered distinctly from master
1210		 * wrapper ports. */
1211
1212		/*
1213		 * Broadcom DDR1/DDR2 Memory Controller
1214		 * (cid=82e, rev=1, unit=0, d/mw/sw = 2/0/1 ) ->
1215		 * bhnd0: erom[0xdc]: core6 agent0.0: mismatch got: 0x1 (0x2)
1216		 *
1217		 * ARM BP135 AMBA3 AXI to APB Bridge
1218		 * (cid=135, rev=0, unit=0, d/mw/sw = 1/0/1 ) ->
1219		 * bhnd0: erom[0x124]: core9 agent1.0: mismatch got: 0x0 (0x2)
1220		 *
1221		 * core.num_mwrap
1222		 * ===>
1223		 * (core.num_mwrap > 0) ?
1224		 *           core.num_mwrap :
1225		 *           ((core.vendor == BHND_MFGID_BCM) ? 1 : 0)
1226		 */
1227		uint8_t sp_num;
1228		sp_num = (core.num_mwrap > 0) ?
1229				core.num_mwrap :
1230				((core.vendor == BHND_MFGID_BCM) ? 1 : 0) + i;
1231		error = bcma_erom_corecfg_fill_port_regions(erom, cfg, sp_num,
1232		    BCMA_EROM_REGION_TYPE_SWRAP);
1233
1234		if (error)
1235			goto failed;
1236	}
1237
1238	/*
1239	 * Seek to the next core entry (if any), skipping any dangling/invalid
1240	 * region entries.
1241	 *
1242	 * On the BCM4706, the EROM entry for the memory controller core
1243	 * (0x4bf/0x52E) contains a dangling/unused slave wrapper port region
1244	 * descriptor.
1245	 */
1246	if ((error = bcma_erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE))) {
1247		if (error != ENOENT)
1248			goto failed;
1249	}
1250
1251	*result = cfg;
1252	return (0);
1253
1254failed:
1255	if (cfg != NULL)
1256		bcma_free_corecfg(cfg);
1257
1258	return error;
1259}
1260
1261static int
1262bcma_erom_dump(bhnd_erom_t *erom)
1263{
1264	struct bcma_erom	*sc;
1265	uint32_t		entry;
1266	int			error;
1267
1268	sc = (struct bcma_erom *)erom;
1269
1270	bcma_erom_reset(sc);
1271
1272	while (!(error = bcma_erom_read32(sc, &entry))) {
1273		/* Handle EOF */
1274		if (entry == BCMA_EROM_TABLE_EOF) {
1275			EROM_LOG(sc, "EOF\n");
1276			return (0);
1277		}
1278
1279		/* Invalid entry */
1280		if (!BCMA_EROM_GET_ATTR(entry, ENTRY_ISVALID)) {
1281			EROM_LOG(sc, "invalid EROM entry %#x\n", entry);
1282			return (EINVAL);
1283		}
1284
1285		switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
1286		case BCMA_EROM_ENTRY_TYPE_CORE: {
1287			/* CoreDescA */
1288			EROM_LOG(sc, "coreA (0x%x)\n", entry);
1289			EROM_LOG(sc, "\tdesigner:\t0x%x\n",
1290			    BCMA_EROM_GET_ATTR(entry, COREA_DESIGNER));
1291			EROM_LOG(sc, "\tid:\t\t0x%x\n",
1292			    BCMA_EROM_GET_ATTR(entry, COREA_ID));
1293			EROM_LOG(sc, "\tclass:\t\t0x%x\n",
1294			    BCMA_EROM_GET_ATTR(entry, COREA_CLASS));
1295
1296			/* CoreDescB */
1297			if ((error = bcma_erom_read32(sc, &entry))) {
1298				EROM_LOG(sc, "error reading CoreDescB: %d\n",
1299				    error);
1300				return (error);
1301			}
1302
1303			if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
1304				EROM_LOG(sc, "invalid core descriptor; found "
1305				    "unexpected entry %#x (type=%s)\n",
1306				    entry, bcma_erom_entry_type_name(entry));
1307				return (EINVAL);
1308			}
1309
1310			EROM_LOG(sc, "coreB (0x%x)\n", entry);
1311			EROM_LOG(sc, "\trev:\t0x%x\n",
1312			    BCMA_EROM_GET_ATTR(entry, COREB_REV));
1313			EROM_LOG(sc, "\tnummp:\t0x%x\n",
1314			    BCMA_EROM_GET_ATTR(entry, COREB_NUM_MP));
1315			EROM_LOG(sc, "\tnumdp:\t0x%x\n",
1316			    BCMA_EROM_GET_ATTR(entry, COREB_NUM_DP));
1317			EROM_LOG(sc, "\tnumwmp:\t0x%x\n",
1318			    BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP));
1319			EROM_LOG(sc, "\tnumwsp:\t0x%x\n",
1320			    BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP));
1321
1322			break;
1323		}
1324		case BCMA_EROM_ENTRY_TYPE_MPORT:
1325			EROM_LOG(sc, "\tmport 0x%x\n", entry);
1326			EROM_LOG(sc, "\t\tport:\t0x%x\n",
1327			    BCMA_EROM_GET_ATTR(entry, MPORT_NUM));
1328			EROM_LOG(sc, "\t\tid:\t\t0x%x\n",
1329			    BCMA_EROM_GET_ATTR(entry, MPORT_ID));
1330			break;
1331
1332		case BCMA_EROM_ENTRY_TYPE_REGION: {
1333			bool	addr64;
1334			uint8_t	size_type;
1335
1336			addr64 = (BCMA_EROM_GET_ATTR(entry, REGION_64BIT) != 0);
1337			size_type = BCMA_EROM_GET_ATTR(entry, REGION_SIZE);
1338
1339			EROM_LOG(sc, "\tregion 0x%x:\n", entry);
1340			EROM_LOG(sc, "\t\t%s:\t0x%x\n",
1341			    addr64 ? "baselo" : "base",
1342			    BCMA_EROM_GET_ATTR(entry, REGION_BASE));
1343			EROM_LOG(sc, "\t\tport:\t0x%x\n",
1344			    BCMA_EROM_GET_ATTR(entry, REGION_PORT));
1345			EROM_LOG(sc, "\t\ttype:\t0x%x\n",
1346			    BCMA_EROM_GET_ATTR(entry, REGION_TYPE));
1347			EROM_LOG(sc, "\t\tsztype:\t0x%hhx\n", size_type);
1348
1349			/* Read the base address high bits */
1350			if (addr64) {
1351				if ((error = bcma_erom_read32(sc, &entry))) {
1352					EROM_LOG(sc, "error reading region "
1353					    "base address high bits %d\n",
1354					    error);
1355					return (error);
1356				}
1357
1358				EROM_LOG(sc, "\t\tbasehi:\t0x%x\n", entry);
1359			}
1360
1361			/* Read extended size descriptor */
1362			if (size_type == BCMA_EROM_REGION_SIZE_OTHER) {
1363				bool size64;
1364
1365				if ((error = bcma_erom_read32(sc, &entry))) {
1366					EROM_LOG(sc, "error reading region "
1367					    "size descriptor %d\n",
1368					    error);
1369					return (error);
1370				}
1371
1372				if (BCMA_EROM_GET_ATTR(entry, RSIZE_64BIT))
1373					size64 = true;
1374				else
1375					size64 = false;
1376
1377				EROM_LOG(sc, "\t\t%s:\t0x%x\n",
1378				    size64 ? "sizelo" : "size",
1379				    BCMA_EROM_GET_ATTR(entry, RSIZE_VAL));
1380
1381				if (size64) {
1382					error = bcma_erom_read32(sc, &entry);
1383					if (error) {
1384						EROM_LOG(sc, "error reading "
1385						    "region size high bits: "
1386						    "%d\n", error);
1387						return (error);
1388					}
1389
1390					EROM_LOG(sc, "\t\tsizehi:\t0x%x\n",
1391					    entry);
1392				}
1393			}
1394			break;
1395		}
1396
1397		default:
1398			EROM_LOG(sc, "unknown EROM entry 0x%x (type=%s)\n",
1399			    entry, bcma_erom_entry_type_name(entry));
1400			return (EINVAL);
1401		}
1402	}
1403
1404	if (error == ENOENT)
1405		EROM_LOG(sc, "BCMA EROM table missing terminating EOF\n");
1406	else if (error)
1407		EROM_LOG(sc, "EROM read failed: %d\n", error);
1408
1409	return (error);
1410}
1411
1412static kobj_method_t bcma_erom_methods[] = {
1413	KOBJMETHOD(bhnd_erom_probe,		bcma_erom_probe),
1414	KOBJMETHOD(bhnd_erom_init,		bcma_erom_init),
1415	KOBJMETHOD(bhnd_erom_fini,		bcma_erom_fini),
1416	KOBJMETHOD(bhnd_erom_get_core_table,	bcma_erom_get_core_table),
1417	KOBJMETHOD(bhnd_erom_free_core_table,	bcma_erom_free_core_table),
1418	KOBJMETHOD(bhnd_erom_lookup_core,	bcma_erom_lookup_core),
1419	KOBJMETHOD(bhnd_erom_lookup_core_addr,	bcma_erom_lookup_core_addr),
1420	KOBJMETHOD(bhnd_erom_dump,		bcma_erom_dump),
1421
1422	KOBJMETHOD_END
1423};
1424
1425BHND_EROM_DEFINE_CLASS(bcma_erom, bcma_erom_parser, bcma_erom_methods, sizeof(struct bcma_erom));
1426