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