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