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