xref: /freebsd/sys/dev/bhnd/siba/siba.c (revision f3e7afe2d7b262ab55ab818445d4dfdb6e0c70a9)
1 /*-
2  * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/systm.h>
39 
40 #include <machine/bus.h>
41 
42 #include <dev/bhnd/cores/chipc/chipcreg.h>
43 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
44 
45 #include "sibareg.h"
46 #include "sibavar.h"
47 
48 static bhnd_erom_class_t *
49 siba_get_erom_class(driver_t *driver)
50 {
51 	return (&siba_erom_parser);
52 }
53 
54 int
55 siba_probe(device_t dev)
56 {
57 	device_set_desc(dev, "SIBA BHND bus");
58 	return (BUS_PROBE_DEFAULT);
59 }
60 
61 /**
62  * Default siba(4) bus driver implementation of DEVICE_ATTACH().
63  *
64  * This implementation initializes internal siba(4) state and performs
65  * bus enumeration, and must be called by subclassing drivers in
66  * DEVICE_ATTACH() before any other bus methods.
67  */
68 int
69 siba_attach(device_t dev)
70 {
71 	struct siba_softc	*sc;
72 	int			 error;
73 
74 	sc = device_get_softc(dev);
75 	sc->dev = dev;
76 
77 	/* Enumerate children */
78 	if ((error = siba_add_children(dev))) {
79 		device_delete_children(dev);
80 		return (error);
81 	}
82 
83 	return (0);
84 }
85 
86 int
87 siba_detach(device_t dev)
88 {
89 	return (bhnd_generic_detach(dev));
90 }
91 
92 int
93 siba_resume(device_t dev)
94 {
95 	return (bhnd_generic_resume(dev));
96 }
97 
98 int
99 siba_suspend(device_t dev)
100 {
101 	return (bhnd_generic_suspend(dev));
102 }
103 
104 static int
105 siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
106 {
107 	const struct siba_devinfo *dinfo;
108 	const struct bhnd_core_info *cfg;
109 
110 	dinfo = device_get_ivars(child);
111 	cfg = &dinfo->core_id.core_info;
112 
113 	switch (index) {
114 	case BHND_IVAR_VENDOR:
115 		*result = cfg->vendor;
116 		return (0);
117 	case BHND_IVAR_DEVICE:
118 		*result = cfg->device;
119 		return (0);
120 	case BHND_IVAR_HWREV:
121 		*result = cfg->hwrev;
122 		return (0);
123 	case BHND_IVAR_DEVICE_CLASS:
124 		*result = bhnd_core_class(cfg);
125 		return (0);
126 	case BHND_IVAR_VENDOR_NAME:
127 		*result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
128 		return (0);
129 	case BHND_IVAR_DEVICE_NAME:
130 		*result = (uintptr_t) bhnd_core_name(cfg);
131 		return (0);
132 	case BHND_IVAR_CORE_INDEX:
133 		*result = cfg->core_idx;
134 		return (0);
135 	case BHND_IVAR_CORE_UNIT:
136 		*result = cfg->unit;
137 		return (0);
138 	case BHND_IVAR_PMU_INFO:
139 		*result = (uintptr_t) dinfo->pmu_info;
140 		return (0);
141 	default:
142 		return (ENOENT);
143 	}
144 }
145 
146 static int
147 siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
148 {
149 	struct siba_devinfo *dinfo;
150 
151 	dinfo = device_get_ivars(child);
152 
153 	switch (index) {
154 	case BHND_IVAR_VENDOR:
155 	case BHND_IVAR_DEVICE:
156 	case BHND_IVAR_HWREV:
157 	case BHND_IVAR_DEVICE_CLASS:
158 	case BHND_IVAR_VENDOR_NAME:
159 	case BHND_IVAR_DEVICE_NAME:
160 	case BHND_IVAR_CORE_INDEX:
161 	case BHND_IVAR_CORE_UNIT:
162 		return (EINVAL);
163 	case BHND_IVAR_PMU_INFO:
164 		dinfo->pmu_info = (struct bhnd_core_pmu_info *) value;
165 		return (0);
166 	default:
167 		return (ENOENT);
168 	}
169 }
170 
171 static struct resource_list *
172 siba_get_resource_list(device_t dev, device_t child)
173 {
174 	struct siba_devinfo *dinfo = device_get_ivars(child);
175 	return (&dinfo->resources);
176 }
177 
178 static int
179 siba_read_iost(device_t dev, device_t child, uint16_t *iost)
180 {
181 	uint32_t	tmhigh;
182 	int		error;
183 
184 	error = bhnd_read_config(child, SIBA_CFG0_TMSTATEHIGH, &tmhigh, 4);
185 	if (error)
186 		return (error);
187 
188 	*iost = (SIBA_REG_GET(tmhigh, TMH_SISF));
189 	return (0);
190 }
191 
192 static int
193 siba_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
194 {
195 	uint32_t	ts_low;
196 	int		error;
197 
198 	if ((error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4)))
199 		return (error);
200 
201 	*ioctl = (SIBA_REG_GET(ts_low, TML_SICF));
202 	return (0);
203 }
204 
205 static int
206 siba_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
207 {
208 	struct siba_devinfo	*dinfo;
209 	struct bhnd_resource	*r;
210 	uint32_t		 ts_low, ts_mask;
211 
212 	if (device_get_parent(child) != dev)
213 		return (EINVAL);
214 
215 	/* Fetch CFG0 mapping */
216 	dinfo = device_get_ivars(child);
217 	if ((r = dinfo->cfg[0]) == NULL)
218 		return (ENODEV);
219 
220 	/* Mask and set TMSTATELOW core flag bits */
221 	ts_mask = (mask << SIBA_TML_SICF_SHIFT) & SIBA_TML_SICF_MASK;
222 	ts_low = (value << SIBA_TML_SICF_SHIFT) & ts_mask;
223 
224 	return (siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
225 	    ts_low, ts_mask));
226 }
227 
228 static bool
229 siba_is_hw_suspended(device_t dev, device_t child)
230 {
231 	uint32_t		ts_low;
232 	uint16_t		ioctl;
233 	int			error;
234 
235 	/* Fetch target state */
236 	error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4);
237 	if (error) {
238 		device_printf(child, "error reading HW reset state: %d\n",
239 		    error);
240 		return (true);
241 	}
242 
243 	/* Is core held in RESET? */
244 	if (ts_low & SIBA_TML_RESET)
245 		return (true);
246 
247 	/* Is core clocked? */
248 	ioctl = SIBA_REG_GET(ts_low, TML_SICF);
249 	if (!(ioctl & BHND_IOCTL_CLK_EN))
250 		return (true);
251 
252 	return (false);
253 }
254 
255 static int
256 siba_reset_hw(device_t dev, device_t child, uint16_t ioctl)
257 {
258 	struct siba_devinfo		*dinfo;
259 	struct bhnd_resource		*r;
260 	uint32_t			 ts_low, imstate;
261 	int				 error;
262 
263 	if (device_get_parent(child) != dev)
264 		return (EINVAL);
265 
266 	dinfo = device_get_ivars(child);
267 
268 	/* Can't suspend the core without access to the CFG0 registers */
269 	if ((r = dinfo->cfg[0]) == NULL)
270 		return (ENODEV);
271 
272 	/* We require exclusive control over BHND_IOCTL_CLK_EN and
273 	 * BHND_IOCTL_CLK_FORCE. */
274 	if (ioctl & (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE))
275 		return (EINVAL);
276 
277 	/* Place core into known RESET state */
278 	if ((error = BHND_BUS_SUSPEND_HW(dev, child)))
279 		return (error);
280 
281 	/* Leaving the core in reset, set the caller's IOCTL flags and
282 	 * enable the core's clocks. */
283 	ts_low = (ioctl | BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) <<
284 	    SIBA_TML_SICF_SHIFT;
285 	error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
286 	    ts_low, SIBA_TML_SICF_MASK);
287 	if (error)
288 		return (error);
289 
290 	/* Clear any target errors */
291 	if (bhnd_bus_read_4(r, SIBA_CFG0_TMSTATEHIGH) & SIBA_TMH_SERR) {
292 		error = siba_write_target_state(child, dinfo,
293 		    SIBA_CFG0_TMSTATEHIGH, 0, SIBA_TMH_SERR);
294 		if (error)
295 			return (error);
296 	}
297 
298 	/* Clear any initiator errors */
299 	imstate = bhnd_bus_read_4(r, SIBA_CFG0_IMSTATE);
300 	if (imstate & (SIBA_IM_IBE|SIBA_IM_TO)) {
301 		error = siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
302 		    0, SIBA_IM_IBE|SIBA_IM_TO);
303 		if (error)
304 			return (error);
305 	}
306 
307 	/* Release from RESET while leaving clocks forced, ensuring the
308 	 * signal propagates throughout the core */
309 	error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
310 	    0x0, SIBA_TML_RESET);
311 	if (error)
312 		return (error);
313 
314 	/* The core should now be active; we can clear the BHND_IOCTL_CLK_FORCE
315 	 * bit and allow the core to manage clock gating. */
316 	error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
317 	    0x0, (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT));
318 	if (error)
319 		return (error);
320 
321 	return (0);
322 }
323 
324 static int
325 siba_suspend_hw(device_t dev, device_t child)
326 {
327 	struct siba_devinfo		*dinfo;
328 	struct bhnd_core_pmu_info	*pm;
329 	struct bhnd_resource		*r;
330 	uint32_t			 idl, ts_low;
331 	uint16_t			 ioctl;
332 	int				 error;
333 
334 	if (device_get_parent(child) != dev)
335 		return (EINVAL);
336 
337 	dinfo = device_get_ivars(child);
338 	pm = dinfo->pmu_info;
339 
340 	/* Can't suspend the core without access to the CFG0 registers */
341 	if ((r = dinfo->cfg[0]) == NULL)
342 		return (ENODEV);
343 
344 	/* Already in RESET? */
345 	ts_low = bhnd_bus_read_4(r, SIBA_CFG0_TMSTATELOW);
346 	if (ts_low & SIBA_TML_RESET) {
347 		/* Clear IOCTL flags, ensuring the clock is disabled */
348 		return (siba_write_target_state(child, dinfo,
349 		    SIBA_CFG0_TMSTATELOW, 0x0, SIBA_TML_SICF_MASK));
350 
351 		return (0);
352 	}
353 
354 	/* If clocks are already disabled, we can put the core directly
355 	 * into RESET */
356 	ioctl = SIBA_REG_GET(ts_low, TML_SICF);
357 	if (!(ioctl & BHND_IOCTL_CLK_EN)) {
358 		/* Set RESET and clear IOCTL flags */
359 		return (siba_write_target_state(child, dinfo,
360 		    SIBA_CFG0_TMSTATELOW,
361 		    SIBA_TML_RESET,
362 		    SIBA_TML_RESET | SIBA_TML_SICF_MASK));
363 	}
364 
365 	/* Reject any further target backplane transactions */
366 	error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
367 	    SIBA_TML_REJ, SIBA_TML_REJ);
368 	if (error)
369 		return (error);
370 
371 	/* If this is an initiator core, we need to reject initiator
372 	 * transactions too. */
373 	idl = bhnd_bus_read_4(r, SIBA_CFG0_IDLOW);
374 	if (idl & SIBA_IDL_INIT) {
375 		error = siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
376 		    SIBA_IM_RJ, SIBA_IM_RJ);
377 		if (error)
378 			return (error);
379 	}
380 
381 	/* Put the core into RESET|REJECT, forcing clocks to ensure the RESET
382 	 * signal propagates throughout the core, leaving REJECT asserted. */
383 	ts_low = SIBA_TML_RESET;
384 	ts_low |= (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) <<
385 	    SIBA_TML_SICF_SHIFT;
386 
387 	error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
388 		ts_low, ts_low);
389 	if (error)
390 		return (error);
391 
392 	/* Give RESET ample time */
393 	DELAY(10);
394 
395 	/* Leaving core in reset, disable all clocks, clear REJ flags and
396 	 * IOCTL state */
397 	error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
398 		SIBA_TML_RESET,
399 		SIBA_TML_RESET | SIBA_TML_REJ | SIBA_TML_SICF_MASK);
400 	if (error)
401 		return (error);
402 
403 	/* Clear previously asserted initiator reject */
404 	if (idl & SIBA_IDL_INIT) {
405 		error = siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
406 		    0, SIBA_IM_RJ);
407 		if (error)
408 			return (error);
409 	}
410 
411 	/* Core is now in RESET, with clocks disabled and REJ not asserted.
412 	 *
413 	 * We lastly need to inform the PMU, releasing any outstanding per-core
414 	 * PMU requests */
415 	if (pm != NULL) {
416 		if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm)))
417 			return (error);
418 	}
419 
420 	return (0);
421 }
422 
423 static int
424 siba_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
425     u_int width)
426 {
427 	struct siba_devinfo	*dinfo;
428 	rman_res_t		 r_size;
429 
430 	/* Must be directly attached */
431 	if (device_get_parent(child) != dev)
432 		return (EINVAL);
433 
434 	/* CFG0 registers must be available */
435 	dinfo = device_get_ivars(child);
436 	if (dinfo->cfg[0] == NULL)
437 		return (ENODEV);
438 
439 	/* Offset must fall within CFG0 */
440 	r_size = rman_get_size(dinfo->cfg[0]->res);
441 	if (r_size < offset || r_size - offset < width)
442 		return (EFAULT);
443 
444 	switch (width) {
445 	case 1:
446 		*((uint8_t *)value) = bhnd_bus_read_1(dinfo->cfg[0], offset);
447 		return (0);
448 	case 2:
449 		*((uint16_t *)value) = bhnd_bus_read_2(dinfo->cfg[0], offset);
450 		return (0);
451 	case 4:
452 		*((uint32_t *)value) = bhnd_bus_read_4(dinfo->cfg[0], offset);
453 		return (0);
454 	default:
455 		return (EINVAL);
456 	}
457 }
458 
459 static int
460 siba_write_config(device_t dev, device_t child, bus_size_t offset,
461     const void *value, u_int width)
462 {
463 	struct siba_devinfo	*dinfo;
464 	struct bhnd_resource	*r;
465 	rman_res_t		 r_size;
466 
467 	/* Must be directly attached */
468 	if (device_get_parent(child) != dev)
469 		return (EINVAL);
470 
471 	/* CFG0 registers must be available */
472 	dinfo = device_get_ivars(child);
473 	if ((r = dinfo->cfg[0]) == NULL)
474 		return (ENODEV);
475 
476 	/* Offset must fall within CFG0 */
477 	r_size = rman_get_size(r->res);
478 	if (r_size < offset || r_size - offset < width)
479 		return (EFAULT);
480 
481 	switch (width) {
482 	case 1:
483 		bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
484 		return (0);
485 	case 2:
486 		bhnd_bus_write_2(r, offset, *(const uint8_t *)value);
487 		return (0);
488 	case 4:
489 		bhnd_bus_write_4(r, offset, *(const uint8_t *)value);
490 		return (0);
491 	default:
492 		return (EINVAL);
493 	}
494 }
495 
496 static u_int
497 siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
498 {
499 	struct siba_devinfo *dinfo;
500 
501 	/* delegate non-bus-attached devices to our parent */
502 	if (device_get_parent(child) != dev)
503 		return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
504 		    type));
505 
506 	dinfo = device_get_ivars(child);
507 	return (siba_addrspace_port_count(dinfo->core_id.num_addrspace));
508 }
509 
510 static u_int
511 siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
512     u_int port)
513 {
514 	struct siba_devinfo	*dinfo;
515 
516 	/* delegate non-bus-attached devices to our parent */
517 	if (device_get_parent(child) != dev)
518 		return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
519 		    type, port));
520 
521 	dinfo = device_get_ivars(child);
522 	if (!siba_is_port_valid(dinfo->core_id.num_addrspace, type, port))
523 		return (0);
524 
525 	return (siba_addrspace_region_count(dinfo->core_id.num_addrspace,
526 	    port));
527 }
528 
529 static int
530 siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
531     u_int port_num, u_int region_num)
532 {
533 	struct siba_devinfo	*dinfo;
534 	struct siba_addrspace	*addrspace;
535 
536 	/* delegate non-bus-attached devices to our parent */
537 	if (device_get_parent(child) != dev)
538 		return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
539 		    port_type, port_num, region_num));
540 
541 	dinfo = device_get_ivars(child);
542 	addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
543 	if (addrspace == NULL)
544 		return (-1);
545 
546 	return (addrspace->sa_rid);
547 }
548 
549 static int
550 siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
551     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
552 {
553 	struct siba_devinfo	*dinfo;
554 
555 	/* delegate non-bus-attached devices to our parent */
556 	if (device_get_parent(child) != dev)
557 		return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
558 		    type, rid, port_type, port_num, region_num));
559 
560 	dinfo = device_get_ivars(child);
561 
562 	/* Ports are always memory mapped */
563 	if (type != SYS_RES_MEMORY)
564 		return (EINVAL);
565 
566 	for (int i = 0; i < dinfo->core_id.num_addrspace; i++) {
567 		if (dinfo->addrspace[i].sa_rid != rid)
568 			continue;
569 
570 		*port_type = BHND_PORT_DEVICE;
571 		*port_num = siba_addrspace_port(i);
572 		*region_num = siba_addrspace_region(i);
573 		return (0);
574 	}
575 
576 	/* Not found */
577 	return (ENOENT);
578 }
579 
580 static int
581 siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
582     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
583 {
584 	struct siba_devinfo	*dinfo;
585 	struct siba_addrspace	*addrspace;
586 
587 	/* delegate non-bus-attached devices to our parent */
588 	if (device_get_parent(child) != dev) {
589 		return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
590 		    port_type, port_num, region_num, addr, size));
591 	}
592 
593 	dinfo = device_get_ivars(child);
594 	addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
595 	if (addrspace == NULL)
596 		return (ENOENT);
597 
598 	*addr = addrspace->sa_base;
599 	*size = addrspace->sa_size - addrspace->sa_bus_reserved;
600 	return (0);
601 }
602 
603 /**
604  * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
605  *
606  * This implementation consults @p child's configuration block mapping,
607  * returning SIBA_CORE_NUM_INTR if a valid CFG0 block is mapped.
608  */
609 int
610 siba_get_intr_count(device_t dev, device_t child)
611 {
612 	struct siba_devinfo *dinfo;
613 
614 	/* delegate non-bus-attached devices to our parent */
615 	if (device_get_parent(child) != dev)
616 		return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
617 
618 	dinfo = device_get_ivars(child);
619 
620 	/* We can get/set interrupt sbflags on any core with a valid cfg0
621 	 * block; whether the core actually makes use of it is another matter
622 	 * entirely */
623 	if (dinfo->cfg[0] == NULL)
624 		return (0);
625 
626 	return (SIBA_CORE_NUM_INTR);
627 }
628 
629 /**
630  * Default siba(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
631  *
632  * This implementation consults @p child's CFG0 register block,
633  * returning the interrupt flag assigned to @p child.
634  */
635 int
636 siba_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
637 {
638 	struct siba_devinfo	*dinfo;
639 	uint32_t		 tpsflag;
640 
641 	/* delegate non-bus-attached devices to our parent */
642 	if (device_get_parent(child) != dev)
643 		return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), child,
644 		    intr, ivec));
645 
646 	/* Must be a valid interrupt ID */
647 	if (intr >= siba_get_intr_count(dev, child))
648 		return (ENXIO);
649 
650 	/* Fetch sbflag number */
651 	dinfo = device_get_ivars(child);
652 	tpsflag = bhnd_bus_read_4(dinfo->cfg[0], SIBA_CFG0_TPSFLAG);
653 	*ivec = SIBA_REG_GET(tpsflag, TPS_NUM0);
654 
655 	return (0);
656 }
657 
658 /**
659  * Register all address space mappings for @p di.
660  *
661  * @param dev The siba bus device.
662  * @param di The device info instance on which to register all address
663  * space entries.
664  * @param r A resource mapping the enumeration table block for @p di.
665  */
666 static int
667 siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
668     struct bhnd_resource *r)
669 {
670 	struct siba_core_id	*cid;
671 	uint32_t		 addr;
672 	uint32_t		 size;
673 	int			 error;
674 
675 	cid = &di->core_id;
676 
677 
678 	/* Register the device address space entries */
679 	for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
680 		uint32_t	adm;
681 		u_int		adm_offset;
682 		uint32_t	bus_reserved;
683 
684 		/* Determine the register offset */
685 		adm_offset = siba_admatch_offset(i);
686 		if (adm_offset == 0) {
687 		    device_printf(dev, "addrspace %hhu is unsupported", i);
688 		    return (ENODEV);
689 		}
690 
691 		/* Fetch the address match register value */
692 		adm = bhnd_bus_read_4(r, adm_offset);
693 
694 		/* Parse the value */
695 		if ((error = siba_parse_admatch(adm, &addr, &size))) {
696 			device_printf(dev, "failed to decode address "
697 			    " match register value 0x%x\n", adm);
698 			return (error);
699 		}
700 
701 		/* If this is the device's core/enumeration addrespace,
702 		 * reserve the Sonics configuration register blocks for the
703 		 * use of our bus. */
704 		bus_reserved = 0;
705 		if (i == SIBA_CORE_ADDRSPACE)
706 			bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
707 
708 		/* Append the region info */
709 		error = siba_append_dinfo_region(di, i, addr, size,
710 		    bus_reserved);
711 		if (error)
712 			return (error);
713 	}
714 
715 	return (0);
716 }
717 
718 /**
719  * Map per-core configuration blocks for @p dinfo.
720  *
721  * @param dev The siba bus device.
722  * @param dinfo The device info instance on which to map all per-core
723  * configuration blocks.
724  */
725 static int
726 siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo)
727 {
728 	struct siba_addrspace	*addrspace;
729 	rman_res_t		 r_start, r_count, r_end;
730 	uint8_t			 num_cfg;
731 
732 	num_cfg = dinfo->core_id.num_cfg_blocks;
733 	if (num_cfg > SIBA_MAX_CFG) {
734 		device_printf(dev, "config block count %hhu out of range\n",
735 		    num_cfg);
736 		return (ENXIO);
737 	}
738 
739 	/* Fetch the core register address space */
740 	addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
741 	if (addrspace == NULL) {
742 		device_printf(dev, "missing device registers\n");
743 		return (ENXIO);
744 	}
745 
746 	/*
747 	 * Map the per-core configuration blocks
748 	 */
749 	for (uint8_t i = 0; i < num_cfg; i++) {
750 		/* Determine the config block's address range; configuration
751 		 * blocks are allocated starting at SIBA_CFG0_OFFSET,
752 		 * growing downwards. */
753 		r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
754 		r_start -= i * SIBA_CFG_SIZE;
755 
756 		r_count = SIBA_CFG_SIZE;
757 		r_end = r_start + r_count - 1;
758 
759 		/* Allocate the config resource */
760 		dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i);
761 		dinfo->cfg[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
762 		    SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end,
763 		    r_count, RF_ACTIVE);
764 
765 		if (dinfo->cfg[i] == NULL) {
766 			device_printf(dev, "failed to allocate SIBA_CFG%hhu\n",
767 			    i);
768 			return (ENXIO);
769 		}
770 	}
771 
772 	return (0);
773 }
774 
775 static device_t
776 siba_add_child(device_t dev, u_int order, const char *name, int unit)
777 {
778 	struct siba_devinfo	*dinfo;
779 	device_t		 child;
780 
781 	child = device_add_child_ordered(dev, order, name, unit);
782 	if (child == NULL)
783 		return (NULL);
784 
785 	if ((dinfo = siba_alloc_dinfo(dev)) == NULL) {
786 		device_delete_child(dev, child);
787 		return (NULL);
788 	}
789 
790 	device_set_ivars(child, dinfo);
791 
792 	return (child);
793 }
794 
795 static void
796 siba_child_deleted(device_t dev, device_t child)
797 {
798 	struct bhnd_softc	*sc;
799 	struct siba_devinfo	*dinfo;
800 
801 	sc = device_get_softc(dev);
802 
803 	/* Call required bhnd(4) implementation */
804 	bhnd_generic_child_deleted(dev, child);
805 
806 	/* Free siba device info */
807 	if ((dinfo = device_get_ivars(child)) != NULL)
808 		siba_free_dinfo(dev, dinfo);
809 
810 	device_set_ivars(child, NULL);
811 }
812 
813 /**
814  * Scan the core table and add all valid discovered cores to
815  * the bus.
816  *
817  * @param dev The siba bus device.
818  */
819 int
820 siba_add_children(device_t dev)
821 {
822 	const struct bhnd_chipid	*chipid;
823 	struct bhnd_core_info		*cores;
824 	struct siba_devinfo		*dinfo;
825 	struct bhnd_resource		*r;
826 	int				 rid;
827 	int				 error;
828 
829 	dinfo = NULL;
830 	cores = NULL;
831 	r = NULL;
832 
833 	chipid = BHND_BUS_GET_CHIPID(dev, dev);
834 
835 	/* Allocate our temporary core table and enumerate all cores */
836 	cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
837 	if (cores == NULL)
838 		return (ENOMEM);
839 
840 	/* Add all cores. */
841 	for (u_int i = 0; i < chipid->ncores; i++) {
842 		struct siba_core_id	 cid;
843 		device_t		 child;
844 		uint32_t		 idhigh, idlow;
845 		rman_res_t		 r_count, r_end, r_start;
846 		int			 nintr;
847 
848 		/* Map the core's register block */
849 		rid = 0;
850 		r_start = SIBA_CORE_ADDR(i);
851 		r_count = SIBA_CORE_SIZE;
852 		r_end = r_start + SIBA_CORE_SIZE - 1;
853 		r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
854 		    r_end, r_count, RF_ACTIVE);
855 		if (r == NULL) {
856 			error = ENXIO;
857 			goto cleanup;
858 		}
859 
860 		/* Add the child device */
861 		child = BUS_ADD_CHILD(dev, 0, NULL, -1);
862 		if (child == NULL) {
863 			error = ENXIO;
864 			goto cleanup;
865 		}
866 
867 		/* Read the core info */
868 		idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
869 		idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
870 
871 		cid = siba_parse_core_id(idhigh, idlow, i, 0);
872 		cores[i] = cid.core_info;
873 
874 		/* Determine unit number */
875 		for (u_int j = 0; j < i; j++) {
876 			if (cores[j].vendor == cores[i].vendor &&
877 			    cores[j].device == cores[i].device)
878 				cores[i].unit++;
879 		}
880 
881 		/* Initialize per-device bus info */
882 		if ((dinfo = device_get_ivars(child)) == NULL) {
883 			error = ENXIO;
884 			goto cleanup;
885 		}
886 
887 		if ((error = siba_init_dinfo(dev, dinfo, &cid)))
888 			goto cleanup;
889 
890 		/* Register the core's address space(s). */
891 		if ((error = siba_register_addrspaces(dev, dinfo, r)))
892 			goto cleanup;
893 
894 		/* Release our resource covering the register blocks
895 		 * we're about to map */
896 		bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
897 		r = NULL;
898 
899 		/* Map the core's config blocks */
900 		if ((error = siba_map_cfg_resources(dev, dinfo)))
901 			goto cleanup;
902 
903 		/* Assign interrupts */
904 		nintr = bhnd_get_intr_count(child);
905 		for (int rid = 0; rid < nintr; rid++) {
906 			error = BHND_BUS_ASSIGN_INTR(dev, child, rid);
907 			if (error) {
908 				device_printf(dev, "failed to assign interrupt "
909 				    "%d to core %u: %d\n", rid, i, error);
910 			}
911 		}
912 
913 		/* If pins are floating or the hardware is otherwise
914 		 * unpopulated, the device shouldn't be used. */
915 		if (bhnd_is_hw_disabled(child))
916 			device_disable(child);
917 
918 		/* Issue bus callback for fully initialized child. */
919 		BHND_BUS_CHILD_ADDED(dev, child);
920 	}
921 
922 cleanup:
923 	if (cores != NULL)
924 		free(cores, M_BHND);
925 
926 	if (r != NULL)
927 		bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
928 
929 	return (error);
930 }
931 
932 static device_method_t siba_methods[] = {
933 	/* Device interface */
934 	DEVMETHOD(device_probe,			siba_probe),
935 	DEVMETHOD(device_attach,		siba_attach),
936 	DEVMETHOD(device_detach,		siba_detach),
937 	DEVMETHOD(device_resume,		siba_resume),
938 	DEVMETHOD(device_suspend,		siba_suspend),
939 
940 	/* Bus interface */
941 	DEVMETHOD(bus_add_child,		siba_add_child),
942 	DEVMETHOD(bus_child_deleted,		siba_child_deleted),
943 	DEVMETHOD(bus_read_ivar,		siba_read_ivar),
944 	DEVMETHOD(bus_write_ivar,		siba_write_ivar),
945 	DEVMETHOD(bus_get_resource_list,	siba_get_resource_list),
946 
947 	/* BHND interface */
948 	DEVMETHOD(bhnd_bus_get_erom_class,	siba_get_erom_class),
949 	DEVMETHOD(bhnd_bus_read_ioctl,		siba_read_ioctl),
950 	DEVMETHOD(bhnd_bus_write_ioctl,		siba_write_ioctl),
951 	DEVMETHOD(bhnd_bus_read_iost,		siba_read_iost),
952 	DEVMETHOD(bhnd_bus_is_hw_suspended,	siba_is_hw_suspended),
953 	DEVMETHOD(bhnd_bus_reset_hw,		siba_reset_hw),
954 	DEVMETHOD(bhnd_bus_suspend_hw,		siba_suspend_hw),
955 	DEVMETHOD(bhnd_bus_read_config,		siba_read_config),
956 	DEVMETHOD(bhnd_bus_write_config,	siba_write_config),
957 	DEVMETHOD(bhnd_bus_get_port_count,	siba_get_port_count),
958 	DEVMETHOD(bhnd_bus_get_region_count,	siba_get_region_count),
959 	DEVMETHOD(bhnd_bus_get_port_rid,	siba_get_port_rid),
960 	DEVMETHOD(bhnd_bus_decode_port_rid,	siba_decode_port_rid),
961 	DEVMETHOD(bhnd_bus_get_region_addr,	siba_get_region_addr),
962 	DEVMETHOD(bhnd_bus_get_intr_count,	siba_get_intr_count),
963 	DEVMETHOD(bhnd_bus_get_core_ivec,	siba_get_core_ivec),
964 
965 	DEVMETHOD_END
966 };
967 
968 DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
969 
970 MODULE_VERSION(siba, 1);
971 MODULE_DEPEND(siba, bhnd, 1, 1, 1);
972