nexus.c revision 200874
1139825Simp/*-
286227Stmm * Copyright 1998 Massachusetts Institute of Technology
3128776Stmm * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.
4167308Smarius * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>.
5128776Stmm * All rights reserved.
686227Stmm *
786227Stmm * Permission to use, copy, modify, and distribute this software and
886227Stmm * its documentation for any purpose and without fee is hereby
986227Stmm * granted, provided that both the above copyright notice and this
1086227Stmm * permission notice appear in all copies, that both the above
1186227Stmm * copyright notice and this permission notice appear in all
1286227Stmm * supporting documentation, and that the name of M.I.T. not be used
1386227Stmm * in advertising or publicity pertaining to distribution of the
1486227Stmm * software without specific, written prior permission.  M.I.T. makes
1586227Stmm * no representations about the suitability of this software for any
1686227Stmm * purpose.  It is provided "as is" without express or implied
1786227Stmm * warranty.
18128776Stmm *
1986227Stmm * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
2086227Stmm * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
2186227Stmm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2286227Stmm * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
2386227Stmm * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2486227Stmm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2586227Stmm * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2686227Stmm * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2786227Stmm * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2886227Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2986227Stmm * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3086227Stmm * SUCH DAMAGE.
3186227Stmm *
3286227Stmm * 	from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09
3386227Stmm */
3486227Stmm
35146474Smarius#include <sys/cdefs.h>
36146474Smarius__FBSDID("$FreeBSD: head/sys/sparc64/sparc64/nexus.c 200874 2009-12-22 21:02:46Z marius $");
37146474Smarius
3886227Stmm#include <sys/param.h>
3986227Stmm#include <sys/systm.h>
4086227Stmm#include <sys/bus.h>
4186227Stmm#include <sys/kernel.h>
4286227Stmm#include <sys/malloc.h>
43130068Sphk#include <sys/module.h>
4486227Stmm
45167308Smarius#include <dev/ofw/ofw_bus.h>
46167308Smarius#include <dev/ofw/ofw_bus_subr.h>
4786227Stmm#include <dev/ofw/openfirm.h>
4886227Stmm
4986227Stmm#include <machine/bus.h>
50167308Smarius#include <machine/bus_common.h>
5186227Stmm#include <machine/intr_machdep.h>
52167308Smarius#include <machine/ofw_nexus.h>
5386227Stmm#include <machine/resource.h>
54167308Smarius#include <machine/ver.h>
5586227Stmm
5686227Stmm#include <sys/rman.h>
5786227Stmm
5886227Stmm/*
5986227Stmm * The nexus (which is a pseudo-bus actually) iterates over the nodes that
60133862Smarius * hang from the Open Firmware root node and adds them as devices to this bus
6186227Stmm * (except some special nodes which are excluded) so that drivers can be
62128776Stmm * attached to them.
6386227Stmm *
6486227Stmm * Additionally, interrupt setup/teardown and some resource management are
6586227Stmm * done at this level.
6686227Stmm *
6786227Stmm * Maybe this code should get into dev/ofw to some extent, as some of it should
68133862Smarius * work for all Open Firmware based machines...
6986227Stmm */
7086227Stmm
7186227Stmmstruct nexus_devinfo {
72167308Smarius	struct ofw_bus_devinfo	ndi_obdinfo;
73167308Smarius	struct resource_list	ndi_rl;
7486227Stmm};
7586227Stmm
7688823Stmmstruct nexus_softc {
7788823Stmm	struct rman	sc_intr_rman;
7888823Stmm	struct rman	sc_mem_rman;
7988823Stmm};
8088823Stmm
81128776Stmmstatic device_probe_t nexus_probe;
82128776Stmmstatic device_attach_t nexus_attach;
83167308Smariusstatic bus_print_child_t nexus_print_child;
84146474Smariusstatic bus_add_child_t nexus_add_child;
85128776Stmmstatic bus_probe_nomatch_t nexus_probe_nomatch;
86128776Stmmstatic bus_setup_intr_t nexus_setup_intr;
87128776Stmmstatic bus_teardown_intr_t nexus_teardown_intr;
88128776Stmmstatic bus_alloc_resource_t nexus_alloc_resource;
89128776Stmmstatic bus_activate_resource_t nexus_activate_resource;
90128776Stmmstatic bus_deactivate_resource_t nexus_deactivate_resource;
91128776Stmmstatic bus_release_resource_t nexus_release_resource;
92167308Smariusstatic bus_get_resource_list_t nexus_get_resource_list;
93167308Smariusstatic bus_get_dma_tag_t nexus_get_dma_tag;
94167308Smariusstatic ofw_bus_get_devinfo_t nexus_get_devinfo;
9586227Stmm
96178443Smarius#ifdef SMP
97178443Smariusstatic int nexus_bind_intr(device_t, device_t, struct resource *, int);
98178443Smarius#endif
99185133Smariusstatic int nexus_inlist(const char *, const char *const *);
100167308Smariusstatic struct nexus_devinfo * nexus_setup_dinfo(device_t, phandle_t);
101167308Smariusstatic void nexus_destroy_dinfo(struct nexus_devinfo *);
102167308Smariusstatic int nexus_print_res(struct nexus_devinfo *);
103167308Smarius
10486227Stmmstatic device_method_t nexus_methods[] = {
10586227Stmm	/* Device interface */
10686227Stmm	DEVMETHOD(device_probe,		nexus_probe),
107128776Stmm	DEVMETHOD(device_attach,	nexus_attach),
10886227Stmm	DEVMETHOD(device_detach,	bus_generic_detach),
10986227Stmm	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
11086227Stmm	DEVMETHOD(device_suspend,	bus_generic_suspend),
11186227Stmm	DEVMETHOD(device_resume,	bus_generic_resume),
11286227Stmm
113167308Smarius	/* Bus interface */
114167308Smarius	DEVMETHOD(bus_print_child,	nexus_print_child),
115167308Smarius	DEVMETHOD(bus_probe_nomatch,	nexus_probe_nomatch),
116167308Smarius	DEVMETHOD(bus_read_ivar,	bus_generic_read_ivar),
117167308Smarius	DEVMETHOD(bus_write_ivar,	bus_generic_write_ivar),
118146474Smarius	DEVMETHOD(bus_add_child,	nexus_add_child),
11986227Stmm	DEVMETHOD(bus_alloc_resource,	nexus_alloc_resource),
12086227Stmm	DEVMETHOD(bus_activate_resource,	nexus_activate_resource),
12186227Stmm	DEVMETHOD(bus_deactivate_resource,	nexus_deactivate_resource),
12286227Stmm	DEVMETHOD(bus_release_resource,	nexus_release_resource),
123167308Smarius	DEVMETHOD(bus_setup_intr,	nexus_setup_intr),
124167308Smarius	DEVMETHOD(bus_teardown_intr,	nexus_teardown_intr),
125190099Smarius	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
126190099Smarius	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
127190099Smarius	DEVMETHOD(bus_get_resource_list, nexus_get_resource_list),
128178443Smarius#ifdef SMP
129178443Smarius	DEVMETHOD(bus_bind_intr,	nexus_bind_intr),
130178443Smarius#endif
131167308Smarius	DEVMETHOD(bus_get_dma_tag,	nexus_get_dma_tag),
13286227Stmm
133167308Smarius	/* ofw_bus interface */
134167308Smarius	DEVMETHOD(ofw_bus_get_devinfo,	nexus_get_devinfo),
135167308Smarius	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
136167308Smarius	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
137167308Smarius	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
138167308Smarius	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
139167308Smarius	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
140167308Smarius
141190099Smarius	KOBJMETHOD_END
14286227Stmm};
14386227Stmm
14486227Stmmstatic devclass_t nexus_devclass;
14586227Stmm
146167308SmariusDEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, sizeof(struct nexus_softc));
147200874SmariusEARLY_DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0,
148200874Smarius    BUS_PASS_BUS);
149200815SmariusMODULE_VERSION(nexus, 1);
15086227Stmm
151185133Smariusstatic const char *const nexus_excl_name[] = {
15290622Stmm	"aliases",
153167308Smarius	"associations",
15490622Stmm	"chosen",
15590622Stmm	"counter-timer",	/* No separate device; handled by psycho/sbus */
15686227Stmm	"memory",
15790622Stmm	"openprom",
15886227Stmm	"options",
15986227Stmm	"packages",
160167308Smarius	"rsc",
16190622Stmm	"virtual-memory",
16286227Stmm	NULL
16386227Stmm};
16486227Stmm
165185133Smariusstatic const char *const nexus_excl_type[] = {
16686227Stmm	"cpu",
16786227Stmm	NULL
16886227Stmm};
16986227Stmm
17086227Stmmextern struct bus_space_tag nexus_bustag;
17186227Stmmextern struct bus_dma_tag nexus_dmatag;
17286227Stmm
17386227Stmmstatic int
174185133Smariusnexus_inlist(const char *name, const char *const *list)
17586227Stmm{
17686227Stmm	int i;
17786227Stmm
178167308Smarius	if (name == NULL)
179167308Smarius		return (0);
18086227Stmm	for (i = 0; list[i] != NULL; i++)
18186227Stmm		if (strcmp(name, list[i]) == 0)
18286227Stmm			return (1);
18386227Stmm	return (0);
18486227Stmm}
18586227Stmm
18686227Stmm#define	NEXUS_EXCLUDED(name, type)					\
18786227Stmm	(nexus_inlist((name), nexus_excl_name) ||			\
18886227Stmm	((type) != NULL && nexus_inlist((type), nexus_excl_type)))
18986227Stmm
19086227Stmmstatic int
19186227Stmmnexus_probe(device_t dev)
19286227Stmm{
193128776Stmm
194128776Stmm	/* Nexus does always match. */
195133862Smarius	device_set_desc(dev, "Open Firmware Nexus device");
196128776Stmm	return (0);
197128776Stmm}
198128776Stmm
199128776Stmmstatic int
200128776Stmmnexus_attach(device_t dev)
201128776Stmm{
202167308Smarius	struct nexus_devinfo *ndi;
203167308Smarius	struct nexus_softc *sc;
20486227Stmm	device_t cdev;
205167308Smarius	phandle_t node;
20686227Stmm
207167308Smarius	node = OF_peer(0);
208167308Smarius	if (node == -1)
209167308Smarius		panic("%s: OF_peer failed.", __func__);
21086227Stmm
21188823Stmm	sc = device_get_softc(dev);
21288823Stmm	sc->sc_intr_rman.rm_type = RMAN_ARRAY;
21388823Stmm	sc->sc_intr_rman.rm_descr = "Interrupts";
21488823Stmm	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
215167308Smarius	sc->sc_mem_rman.rm_descr = "Device Memory";
21688823Stmm	if (rman_init(&sc->sc_intr_rman) != 0 ||
21788823Stmm	    rman_init(&sc->sc_mem_rman) != 0 ||
21897265Sjake	    rman_manage_region(&sc->sc_intr_rman, 0, IV_MAX - 1) != 0 ||
219167308Smarius	    rman_manage_region(&sc->sc_mem_rman, 0ULL, ~0ULL) != 0)
220167308Smarius		panic("%s: failed to set up rmans.", __func__);
221146474Smarius
222146474Smarius	/*
223146474Smarius	 * Allow devices to identify.
224146474Smarius	 */
225146474Smarius	bus_generic_probe(dev);
226146474Smarius
227146474Smarius	/*
228146474Smarius	 * Now walk the OFW tree and attach top-level devices.
229146474Smarius	 */
230167308Smarius	for (node = OF_child(node); node > 0; node = OF_peer(node)) {
231167308Smarius		if ((ndi = nexus_setup_dinfo(dev, node)) == NULL)
23286227Stmm			continue;
233167308Smarius		cdev = device_add_child(dev, NULL, -1);
234167308Smarius		if (cdev == NULL) {
235167308Smarius			device_printf(dev, "<%s>: device_add_child failed\n",
236167308Smarius			    ndi->ndi_obdinfo.obd_name);
237167308Smarius			nexus_destroy_dinfo(ndi);
23886227Stmm			continue;
23988823Stmm		}
240167308Smarius		device_set_ivars(cdev, ndi);
24186227Stmm	}
242128776Stmm	return (bus_generic_attach(dev));
24386227Stmm}
24486227Stmm
245146474Smariusstatic device_t
246146474Smariusnexus_add_child(device_t dev, int order, const char *name, int unit)
247146474Smarius{
248146474Smarius	device_t cdev;
249167308Smarius	struct nexus_devinfo *ndi;
250146474Smarius
251146474Smarius	cdev = device_add_child_ordered(dev, order, name, unit);
252146474Smarius	if (cdev == NULL)
253146474Smarius		return (NULL);
254146474Smarius
255167308Smarius	ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
256167308Smarius	ndi->ndi_obdinfo.obd_node = -1;
257167308Smarius	ndi->ndi_obdinfo.obd_name = strdup(name, M_OFWPROP);
258167308Smarius	resource_list_init(&ndi->ndi_rl);
259167308Smarius	device_set_ivars(cdev, ndi);
260146474Smarius
261146474Smarius	return (cdev);
262146474Smarius}
263146474Smarius
264167308Smariusstatic int
265167308Smariusnexus_print_child(device_t dev, device_t child)
26686227Stmm{
267167308Smarius	int rv;
26886227Stmm
269167308Smarius	rv = bus_print_child_header(dev, child);
270167308Smarius	rv += nexus_print_res(device_get_ivars(child));
271167308Smarius	rv += bus_print_child_footer(dev, child);
272167308Smarius	return (rv);
27386227Stmm}
27486227Stmm
275167308Smariusstatic void
276167308Smariusnexus_probe_nomatch(device_t dev, device_t child)
27786227Stmm{
278167308Smarius	const char *type;
27986227Stmm
280167308Smarius	device_printf(dev, "<%s>", ofw_bus_get_name(child));
281167308Smarius	nexus_print_res(device_get_ivars(child));
282167308Smarius	type = ofw_bus_get_type(child);
283167308Smarius	printf(" type %s (no driver attached)\n",
284167308Smarius	    type != NULL ? type : "unknown");
28586227Stmm}
28686227Stmm
28786227Stmmstatic int
28886227Stmmnexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
289166901Spiso    driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
29086227Stmm{
29186227Stmm	int error;
29288823Stmm
29386227Stmm	if (res == NULL)
294167308Smarius		panic("%s: NULL interrupt resource!", __func__);
29586227Stmm
296131535Simp	if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
29786227Stmm		flags |= INTR_EXCL;
29886227Stmm
299128776Stmm	/* We depend here on rman_activate_resource() being idempotent. */
30086227Stmm	error = rman_activate_resource(res);
30186227Stmm	if (error)
30286227Stmm		return (error);
30386227Stmm
304131535Simp	error = inthand_add(device_get_nameunit(child), rman_get_start(res),
305166901Spiso	    filt, intr, arg, flags, cookiep);
30686227Stmm
307167308Smarius	/*
308167308Smarius	 * XXX in case of the AFB/FFB interrupt and a Psycho, Sabre or U2S
309167308Smarius	 * bridge enable the interrupt in the respective bridge.
310167308Smarius	 */
311167308Smarius
31286227Stmm	return (error);
31386227Stmm}
31486227Stmm
31586227Stmmstatic int
31686227Stmmnexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
31786227Stmm{
318146474Smarius
319131535Simp	inthand_remove(rman_get_start(r), ih);
32086227Stmm	return (0);
32186227Stmm}
32286227Stmm
323178443Smarius#ifdef SMP
324178443Smariusstatic int
325178443Smariusnexus_bind_intr(device_t dev, device_t child, struct resource *r, int cpu)
326178443Smarius{
327178443Smarius
328178443Smarius	return (intr_bind(rman_get_start(r), cpu));
329178443Smarius}
330178443Smarius#endif
331178443Smarius
33286227Stmmstatic struct resource *
33386227Stmmnexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
33486227Stmm    u_long start, u_long end, u_long count, u_int flags)
33586227Stmm{
336167308Smarius	struct nexus_softc *sc;
337167308Smarius	struct rman *rm;
338167308Smarius	struct resource *rv;
339167308Smarius	struct resource_list_entry *rle;
340167308Smarius	int isdefault, needactivate, passthrough;
34186227Stmm
342167308Smarius	isdefault = (start == 0UL && end == ~0UL);
343167308Smarius	needactivate = flags & RF_ACTIVE;
344167308Smarius	passthrough = (device_get_parent(child) != bus);
345167308Smarius	sc = device_get_softc(bus);
346167308Smarius	rle = NULL;
34786227Stmm
348167308Smarius	if (!passthrough) {
349167308Smarius		rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child),
350167308Smarius		    type, *rid);
351167308Smarius		if (rle == NULL)
352167308Smarius			return (NULL);
353167308Smarius		if (rle->res != NULL)
354167308Smarius			panic("%s: resource entry is busy", __func__);
355167308Smarius		if (isdefault) {
356167308Smarius			start = rle->start;
357167308Smarius			count = ulmax(count, rle->count);
358167308Smarius			end = ulmax(rle->end, start + count - 1);
359167308Smarius		}
360167308Smarius	}
361167308Smarius
36286227Stmm	switch (type) {
36386227Stmm	case SYS_RES_IRQ:
36488823Stmm		rm = &sc->sc_intr_rman;
36586227Stmm		break;
36688823Stmm	case SYS_RES_MEMORY:
36788823Stmm		rm = &sc->sc_mem_rman;
36888823Stmm		break;
36986227Stmm	default:
37086227Stmm		return (NULL);
37186227Stmm	}
37286227Stmm
373167308Smarius	flags &= ~RF_ACTIVE;
37486227Stmm	rv = rman_reserve_resource(rm, start, end, count, flags, child);
37586227Stmm	if (rv == NULL)
37686227Stmm		return (NULL);
377157896Simp	rman_set_rid(rv, *rid);
37888823Stmm	if (type == SYS_RES_MEMORY) {
37988823Stmm		rman_set_bustag(rv, &nexus_bustag);
38088823Stmm		rman_set_bushandle(rv, rman_get_start(rv));
38188823Stmm	}
38286227Stmm
38386227Stmm	if (needactivate) {
384128776Stmm		if (bus_activate_resource(child, type, *rid, rv) != 0) {
38586227Stmm			rman_release_resource(rv);
38686227Stmm			return (NULL);
38786227Stmm		}
38886227Stmm	}
38988823Stmm
390167308Smarius	if (!passthrough) {
391167308Smarius		rle->res = rv;
392167308Smarius		rle->start = rman_get_start(rv);
393167308Smarius		rle->end = rman_get_end(rv);
394167308Smarius		rle->count = rle->end - rle->start + 1;
395167308Smarius	}
396167308Smarius
39786227Stmm	return (rv);
39886227Stmm}
39986227Stmm
40086227Stmmstatic int
40186227Stmmnexus_activate_resource(device_t bus, device_t child, int type, int rid,
40286227Stmm    struct resource *r)
40386227Stmm{
40486227Stmm
40586227Stmm	/* Not much to be done yet... */
40686227Stmm	return (rman_activate_resource(r));
40786227Stmm}
40886227Stmm
40986227Stmmstatic int
41086227Stmmnexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
41186227Stmm    struct resource *r)
41286227Stmm{
41388823Stmm
41486227Stmm	/* Not much to be done yet... */
41586227Stmm	return (rman_deactivate_resource(r));
41686227Stmm}
41786227Stmm
41886227Stmmstatic int
41986227Stmmnexus_release_resource(device_t bus, device_t child, int type, int rid,
420167308Smarius    struct resource *r)
42186227Stmm{
42286227Stmm	int error;
42386227Stmm
42486227Stmm	if (rman_get_flags(r) & RF_ACTIVE) {
42586227Stmm		error = bus_deactivate_resource(child, type, rid, r);
42686227Stmm		if (error)
427128776Stmm			return (error);
42886227Stmm	}
42986227Stmm	return (rman_release_resource(r));
43086227Stmm}
431167308Smarius
432167308Smariusstatic struct resource_list *
433167308Smariusnexus_get_resource_list(device_t dev, device_t child)
434167308Smarius{
435167308Smarius	struct nexus_devinfo *ndi;
436167308Smarius
437167308Smarius	ndi = device_get_ivars(child);
438167308Smarius	return (&ndi->ndi_rl);
439167308Smarius}
440167308Smarius
441167308Smariusstatic bus_dma_tag_t
442167308Smariusnexus_get_dma_tag(device_t bus, device_t child)
443167308Smarius{
444167308Smarius
445167308Smarius	return (&nexus_dmatag);
446167308Smarius}
447167308Smarius
448167308Smariusstatic const struct ofw_bus_devinfo *
449167308Smariusnexus_get_devinfo(device_t dev, device_t child)
450167308Smarius{
451167308Smarius	struct nexus_devinfo *ndi;
452167308Smarius
453167308Smarius	ndi = device_get_ivars(child);
454167308Smarius	return (&ndi->ndi_obdinfo);
455167308Smarius}
456167308Smarius
457167308Smariusstatic struct nexus_devinfo *
458167308Smariusnexus_setup_dinfo(device_t dev, phandle_t node)
459167308Smarius{
460167308Smarius	struct nexus_devinfo *ndi;
461167308Smarius	struct nexus_regs *reg;
462167308Smarius	bus_addr_t phys;
463167308Smarius	bus_size_t size;
464167308Smarius	uint32_t ign;
465167308Smarius	uint32_t *intr;
466167308Smarius	int i;
467167308Smarius	int nintr;
468167308Smarius	int nreg;
469167308Smarius
470167308Smarius	ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
471167308Smarius	if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) {
472167308Smarius		free(ndi, M_DEVBUF);
473167308Smarius		return (NULL);
474167308Smarius	}
475167308Smarius	if (NEXUS_EXCLUDED(ndi->ndi_obdinfo.obd_name,
476167308Smarius	    ndi->ndi_obdinfo.obd_type)) {
477167308Smarius		ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo);
478167308Smarius		free(ndi, M_DEVBUF);
479167308Smarius		return (NULL);
480167308Smarius	}
481167308Smarius	resource_list_init(&ndi->ndi_rl);
482167308Smarius	nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
483167308Smarius	if (nreg == -1) {
484167308Smarius		device_printf(dev, "<%s>: incomplete\n",
485167308Smarius		    ndi->ndi_obdinfo.obd_name);
486167308Smarius		goto fail;
487167308Smarius	}
488167308Smarius	for (i = 0; i < nreg; i++) {
489167308Smarius		phys = NEXUS_REG_PHYS(&reg[i]);
490167308Smarius		size = NEXUS_REG_SIZE(&reg[i]);
491167308Smarius		resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, phys,
492167308Smarius		    phys + size - 1, size);
493167308Smarius	}
494167308Smarius	free(reg, M_OFWPROP);
495167308Smarius
496167308Smarius	nintr = OF_getprop_alloc(node, "interrupts",  sizeof(*intr),
497167308Smarius	    (void **)&intr);
498167308Smarius	if (nintr > 0) {
499167308Smarius		if (OF_getprop(node, cpu_impl < CPU_IMPL_ULTRASPARCIII ?
500167308Smarius		    "upa-portid" : "portid", &ign, sizeof(ign)) <= 0) {
501167308Smarius			device_printf(dev, "<%s>: could not determine portid\n",
502167308Smarius			    ndi->ndi_obdinfo.obd_name);
503167308Smarius			free(intr, M_OFWPROP);
504167308Smarius			goto fail;
505167308Smarius		}
506167308Smarius
507167308Smarius		/* XXX 7-bit MID on Starfire */
508167308Smarius		ign = (ign << INTMAP_IGN_SHIFT) & INTMAP_IGN_MASK;
509167308Smarius		for (i = 0; i < nintr; i++) {
510167308Smarius			intr[i] |= ign;
511167308Smarius			resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i],
512167308Smarius			    intr[i], 1);
513167308Smarius		}
514167308Smarius		free(intr, M_OFWPROP);
515167308Smarius	}
516167308Smarius
517167308Smarius	return (ndi);
518167308Smarius
519167308Smarius fail:
520167308Smarius	nexus_destroy_dinfo(ndi);
521167308Smarius	return (NULL);
522167308Smarius}
523167308Smarius
524167308Smariusstatic void
525167308Smariusnexus_destroy_dinfo(struct nexus_devinfo *ndi)
526167308Smarius{
527167308Smarius
528167308Smarius	resource_list_free(&ndi->ndi_rl);
529167308Smarius	ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo);
530167308Smarius	free(ndi, M_DEVBUF);
531167308Smarius}
532167308Smarius
533167308Smariusstatic int
534167308Smariusnexus_print_res(struct nexus_devinfo *ndi)
535167308Smarius{
536167308Smarius	int rv;
537167308Smarius
538167308Smarius	rv = 0;
539167308Smarius	rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY,
540167308Smarius	    "%#lx");
541167308Smarius	rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ,
542167308Smarius	    "%ld");
543167308Smarius	return (rv);
544167308Smarius}
545