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