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