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