nexus.c revision 167308
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 167308 2007-03-07 21:13:51Z 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
96167308Smariusstatic int nexus_inlist(const char *, const char **);
97167308Smariusstatic struct nexus_devinfo * nexus_setup_dinfo(device_t, phandle_t);
98167308Smariusstatic void nexus_destroy_dinfo(struct nexus_devinfo *);
99167308Smariusstatic int nexus_print_res(struct nexus_devinfo *);
100167308Smarius
10186227Stmmstatic device_method_t nexus_methods[] = {
10286227Stmm	/* Device interface */
10386227Stmm	DEVMETHOD(device_probe,		nexus_probe),
104128776Stmm	DEVMETHOD(device_attach,	nexus_attach),
10586227Stmm	DEVMETHOD(device_detach,	bus_generic_detach),
10686227Stmm	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
10786227Stmm	DEVMETHOD(device_suspend,	bus_generic_suspend),
10886227Stmm	DEVMETHOD(device_resume,	bus_generic_resume),
10986227Stmm
110167308Smarius	/* Bus interface */
111167308Smarius	DEVMETHOD(bus_print_child,	nexus_print_child),
112167308Smarius	DEVMETHOD(bus_probe_nomatch,	nexus_probe_nomatch),
113167308Smarius	DEVMETHOD(bus_read_ivar,	bus_generic_read_ivar),
114167308Smarius	DEVMETHOD(bus_write_ivar,	bus_generic_write_ivar),
115146474Smarius	DEVMETHOD(bus_add_child,	nexus_add_child),
11686227Stmm	DEVMETHOD(bus_alloc_resource,	nexus_alloc_resource),
11786227Stmm	DEVMETHOD(bus_activate_resource,	nexus_activate_resource),
11886227Stmm	DEVMETHOD(bus_deactivate_resource,	nexus_deactivate_resource),
11986227Stmm	DEVMETHOD(bus_release_resource,	nexus_release_resource),
120167308Smarius	DEVMETHOD(bus_setup_intr,	nexus_setup_intr),
121167308Smarius	DEVMETHOD(bus_teardown_intr,	nexus_teardown_intr),
122167308Smarius	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
123167308Smarius	DEVMETHOD(bus_get_resource_list, nexus_get_resource_list),
124167308Smarius	DEVMETHOD(bus_get_dma_tag,	nexus_get_dma_tag),
12586227Stmm
126167308Smarius	/* ofw_bus interface */
127167308Smarius	DEVMETHOD(ofw_bus_get_devinfo,	nexus_get_devinfo),
128167308Smarius	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
129167308Smarius	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
130167308Smarius	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
131167308Smarius	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
132167308Smarius	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
133167308Smarius
13486227Stmm	{ 0, 0 }
13586227Stmm};
13686227Stmm
13786227Stmmstatic devclass_t nexus_devclass;
13886227Stmm
139167308SmariusDEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, sizeof(struct nexus_softc));
14086227StmmDRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
14186227Stmm
142167308Smariusstatic const char *nexus_excl_name[] = {
14390622Stmm	"aliases",
144167308Smarius	"associations",
14590622Stmm	"chosen",
14690622Stmm	"counter-timer",	/* No separate device; handled by psycho/sbus */
14786227Stmm	"memory",
14890622Stmm	"openprom",
14986227Stmm	"options",
15086227Stmm	"packages",
151167308Smarius	"rsc",
15290622Stmm	"virtual-memory",
15386227Stmm	NULL
15486227Stmm};
15586227Stmm
156167308Smariusstatic const char *nexus_excl_type[] = {
15786227Stmm	"cpu",
15886227Stmm	NULL
15986227Stmm};
16086227Stmm
16186227Stmmextern struct bus_space_tag nexus_bustag;
16286227Stmmextern struct bus_dma_tag nexus_dmatag;
16386227Stmm
16486227Stmmstatic int
165167308Smariusnexus_inlist(const char *name, const char **list)
16686227Stmm{
16786227Stmm	int i;
16886227Stmm
169167308Smarius	if (name == NULL)
170167308Smarius		return (0);
17186227Stmm	for (i = 0; list[i] != NULL; i++)
17286227Stmm		if (strcmp(name, list[i]) == 0)
17386227Stmm			return (1);
17486227Stmm	return (0);
17586227Stmm}
17686227Stmm
17786227Stmm#define	NEXUS_EXCLUDED(name, type)					\
17886227Stmm	(nexus_inlist((name), nexus_excl_name) ||			\
17986227Stmm	((type) != NULL && nexus_inlist((type), nexus_excl_type)))
18086227Stmm
18186227Stmmstatic int
18286227Stmmnexus_probe(device_t dev)
18386227Stmm{
184128776Stmm
185128776Stmm	/* Nexus does always match. */
186133862Smarius	device_set_desc(dev, "Open Firmware Nexus device");
187128776Stmm	return (0);
188128776Stmm}
189128776Stmm
190128776Stmmstatic int
191128776Stmmnexus_attach(device_t dev)
192128776Stmm{
193167308Smarius	struct nexus_devinfo *ndi;
194167308Smarius	struct nexus_softc *sc;
19586227Stmm	device_t cdev;
196167308Smarius	phandle_t node;
19786227Stmm
198167308Smarius	node = OF_peer(0);
199167308Smarius	if (node == -1)
200167308Smarius		panic("%s: OF_peer failed.", __func__);
20186227Stmm
20288823Stmm	sc = device_get_softc(dev);
20388823Stmm	sc->sc_intr_rman.rm_type = RMAN_ARRAY;
20488823Stmm	sc->sc_intr_rman.rm_descr = "Interrupts";
20588823Stmm	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
206167308Smarius	sc->sc_mem_rman.rm_descr = "Device Memory";
20788823Stmm	if (rman_init(&sc->sc_intr_rman) != 0 ||
20888823Stmm	    rman_init(&sc->sc_mem_rman) != 0 ||
20997265Sjake	    rman_manage_region(&sc->sc_intr_rman, 0, IV_MAX - 1) != 0 ||
210167308Smarius	    rman_manage_region(&sc->sc_mem_rman, 0ULL, ~0ULL) != 0)
211167308Smarius		panic("%s: failed to set up rmans.", __func__);
212146474Smarius
213146474Smarius	/*
214146474Smarius	 * Allow devices to identify.
215146474Smarius	 */
216146474Smarius	bus_generic_probe(dev);
217146474Smarius
218146474Smarius	/*
219146474Smarius	 * Now walk the OFW tree and attach top-level devices.
220146474Smarius	 */
221167308Smarius	for (node = OF_child(node); node > 0; node = OF_peer(node)) {
222167308Smarius		if ((ndi = nexus_setup_dinfo(dev, node)) == NULL)
22386227Stmm			continue;
224167308Smarius		cdev = device_add_child(dev, NULL, -1);
225167308Smarius		if (cdev == NULL) {
226167308Smarius			device_printf(dev, "<%s>: device_add_child failed\n",
227167308Smarius			    ndi->ndi_obdinfo.obd_name);
228167308Smarius			nexus_destroy_dinfo(ndi);
22986227Stmm			continue;
23088823Stmm		}
231167308Smarius		device_set_ivars(cdev, ndi);
23286227Stmm	}
233128776Stmm	return (bus_generic_attach(dev));
23486227Stmm}
23586227Stmm
236146474Smariusstatic device_t
237146474Smariusnexus_add_child(device_t dev, int order, const char *name, int unit)
238146474Smarius{
239146474Smarius	device_t cdev;
240167308Smarius	struct nexus_devinfo *ndi;
241146474Smarius
242146474Smarius	cdev = device_add_child_ordered(dev, order, name, unit);
243146474Smarius	if (cdev == NULL)
244146474Smarius		return (NULL);
245146474Smarius
246167308Smarius	ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
247167308Smarius	ndi->ndi_obdinfo.obd_node = -1;
248167308Smarius	ndi->ndi_obdinfo.obd_name = strdup(name, M_OFWPROP);
249167308Smarius	resource_list_init(&ndi->ndi_rl);
250167308Smarius	device_set_ivars(cdev, ndi);
251146474Smarius
252146474Smarius	return (cdev);
253146474Smarius}
254146474Smarius
255167308Smariusstatic int
256167308Smariusnexus_print_child(device_t dev, device_t child)
25786227Stmm{
258167308Smarius	int rv;
25986227Stmm
260167308Smarius	rv = bus_print_child_header(dev, child);
261167308Smarius	rv += nexus_print_res(device_get_ivars(child));
262167308Smarius	rv += bus_print_child_footer(dev, child);
263167308Smarius	return (rv);
26486227Stmm}
26586227Stmm
266167308Smariusstatic void
267167308Smariusnexus_probe_nomatch(device_t dev, device_t child)
26886227Stmm{
269167308Smarius	const char *type;
27086227Stmm
271167308Smarius	device_printf(dev, "<%s>", ofw_bus_get_name(child));
272167308Smarius	nexus_print_res(device_get_ivars(child));
273167308Smarius	type = ofw_bus_get_type(child);
274167308Smarius	printf(" type %s (no driver attached)\n",
275167308Smarius	    type != NULL ? type : "unknown");
27686227Stmm}
27786227Stmm
27886227Stmmstatic int
27986227Stmmnexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
280166901Spiso    driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
28186227Stmm{
28286227Stmm	int error;
28388823Stmm
28486227Stmm	if (res == NULL)
285167308Smarius		panic("%s: NULL interrupt resource!", __func__);
28686227Stmm
287131535Simp	if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
28886227Stmm		flags |= INTR_EXCL;
28986227Stmm
290128776Stmm	/* We depend here on rman_activate_resource() being idempotent. */
29186227Stmm	error = rman_activate_resource(res);
29286227Stmm	if (error)
29386227Stmm		return (error);
29486227Stmm
295131535Simp	error = inthand_add(device_get_nameunit(child), rman_get_start(res),
296166901Spiso	    filt, intr, arg, flags, cookiep);
29786227Stmm
298167308Smarius	/*
299167308Smarius	 * XXX in case of the AFB/FFB interrupt and a Psycho, Sabre or U2S
300167308Smarius	 * bridge enable the interrupt in the respective bridge.
301167308Smarius	 */
302167308Smarius
30386227Stmm	return (error);
30486227Stmm}
30586227Stmm
30686227Stmmstatic int
30786227Stmmnexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
30886227Stmm{
309146474Smarius
310131535Simp	inthand_remove(rman_get_start(r), ih);
31186227Stmm	return (0);
31286227Stmm}
31386227Stmm
31486227Stmmstatic struct resource *
31586227Stmmnexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
31686227Stmm    u_long start, u_long end, u_long count, u_int flags)
31786227Stmm{
318167308Smarius	struct nexus_softc *sc;
319167308Smarius	struct rman *rm;
320167308Smarius	struct resource *rv;
321167308Smarius	struct resource_list_entry *rle;
322167308Smarius	int isdefault, needactivate, passthrough;
32386227Stmm
324167308Smarius	isdefault = (start == 0UL && end == ~0UL);
325167308Smarius	needactivate = flags & RF_ACTIVE;
326167308Smarius	passthrough = (device_get_parent(child) != bus);
327167308Smarius	sc = device_get_softc(bus);
328167308Smarius	rle = NULL;
32986227Stmm
330167308Smarius	if (!passthrough) {
331167308Smarius		rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child),
332167308Smarius		    type, *rid);
333167308Smarius		if (rle == NULL)
334167308Smarius			return (NULL);
335167308Smarius		if (rle->res != NULL)
336167308Smarius			panic("%s: resource entry is busy", __func__);
337167308Smarius		if (isdefault) {
338167308Smarius			start = rle->start;
339167308Smarius			count = ulmax(count, rle->count);
340167308Smarius			end = ulmax(rle->end, start + count - 1);
341167308Smarius		}
342167308Smarius	}
343167308Smarius
34486227Stmm	switch (type) {
34586227Stmm	case SYS_RES_IRQ:
34688823Stmm		rm = &sc->sc_intr_rman;
34786227Stmm		break;
34888823Stmm	case SYS_RES_MEMORY:
34988823Stmm		rm = &sc->sc_mem_rman;
35088823Stmm		break;
35186227Stmm	default:
35286227Stmm		return (NULL);
35386227Stmm	}
35486227Stmm
355167308Smarius	flags &= ~RF_ACTIVE;
35686227Stmm	rv = rman_reserve_resource(rm, start, end, count, flags, child);
35786227Stmm	if (rv == NULL)
35886227Stmm		return (NULL);
359157896Simp	rman_set_rid(rv, *rid);
36088823Stmm	if (type == SYS_RES_MEMORY) {
36188823Stmm		rman_set_bustag(rv, &nexus_bustag);
36288823Stmm		rman_set_bushandle(rv, rman_get_start(rv));
36388823Stmm	}
36486227Stmm
36586227Stmm	if (needactivate) {
366128776Stmm		if (bus_activate_resource(child, type, *rid, rv) != 0) {
36786227Stmm			rman_release_resource(rv);
36886227Stmm			return (NULL);
36986227Stmm		}
37086227Stmm	}
37188823Stmm
372167308Smarius	if (!passthrough) {
373167308Smarius		rle->res = rv;
374167308Smarius		rle->start = rman_get_start(rv);
375167308Smarius		rle->end = rman_get_end(rv);
376167308Smarius		rle->count = rle->end - rle->start + 1;
377167308Smarius	}
378167308Smarius
37986227Stmm	return (rv);
38086227Stmm}
38186227Stmm
38286227Stmmstatic int
38386227Stmmnexus_activate_resource(device_t bus, device_t child, int type, int rid,
38486227Stmm    struct resource *r)
38586227Stmm{
38686227Stmm
38786227Stmm	/* Not much to be done yet... */
38886227Stmm	return (rman_activate_resource(r));
38986227Stmm}
39086227Stmm
39186227Stmmstatic int
39286227Stmmnexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
39386227Stmm    struct resource *r)
39486227Stmm{
39588823Stmm
39686227Stmm	/* Not much to be done yet... */
39786227Stmm	return (rman_deactivate_resource(r));
39886227Stmm}
39986227Stmm
40086227Stmmstatic int
40186227Stmmnexus_release_resource(device_t bus, device_t child, int type, int rid,
402167308Smarius    struct resource *r)
40386227Stmm{
40486227Stmm	int error;
40586227Stmm
40686227Stmm	if (rman_get_flags(r) & RF_ACTIVE) {
40786227Stmm		error = bus_deactivate_resource(child, type, rid, r);
40886227Stmm		if (error)
409128776Stmm			return (error);
41086227Stmm	}
41186227Stmm	return (rman_release_resource(r));
41286227Stmm}
413167308Smarius
414167308Smariusstatic struct resource_list *
415167308Smariusnexus_get_resource_list(device_t dev, device_t child)
416167308Smarius{
417167308Smarius	struct nexus_devinfo *ndi;
418167308Smarius
419167308Smarius	ndi = device_get_ivars(child);
420167308Smarius	return (&ndi->ndi_rl);
421167308Smarius}
422167308Smarius
423167308Smariusstatic bus_dma_tag_t
424167308Smariusnexus_get_dma_tag(device_t bus, device_t child)
425167308Smarius{
426167308Smarius
427167308Smarius	return (&nexus_dmatag);
428167308Smarius}
429167308Smarius
430167308Smariusstatic const struct ofw_bus_devinfo *
431167308Smariusnexus_get_devinfo(device_t dev, device_t child)
432167308Smarius{
433167308Smarius	struct nexus_devinfo *ndi;
434167308Smarius
435167308Smarius	ndi = device_get_ivars(child);
436167308Smarius	return (&ndi->ndi_obdinfo);
437167308Smarius}
438167308Smarius
439167308Smariusstatic struct nexus_devinfo *
440167308Smariusnexus_setup_dinfo(device_t dev, phandle_t node)
441167308Smarius{
442167308Smarius	struct nexus_devinfo *ndi;
443167308Smarius	struct nexus_regs *reg;
444167308Smarius	bus_addr_t phys;
445167308Smarius	bus_size_t size;
446167308Smarius	uint32_t ign;
447167308Smarius	uint32_t *intr;
448167308Smarius	int i;
449167308Smarius	int nintr;
450167308Smarius	int nreg;
451167308Smarius
452167308Smarius	ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
453167308Smarius	if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) {
454167308Smarius		free(ndi, M_DEVBUF);
455167308Smarius		return (NULL);
456167308Smarius	}
457167308Smarius	if (NEXUS_EXCLUDED(ndi->ndi_obdinfo.obd_name,
458167308Smarius	    ndi->ndi_obdinfo.obd_type)) {
459167308Smarius		ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo);
460167308Smarius		free(ndi, M_DEVBUF);
461167308Smarius		return (NULL);
462167308Smarius	}
463167308Smarius	resource_list_init(&ndi->ndi_rl);
464167308Smarius	nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
465167308Smarius	if (nreg == -1) {
466167308Smarius		device_printf(dev, "<%s>: incomplete\n",
467167308Smarius		    ndi->ndi_obdinfo.obd_name);
468167308Smarius		goto fail;
469167308Smarius	}
470167308Smarius	for (i = 0; i < nreg; i++) {
471167308Smarius		phys = NEXUS_REG_PHYS(&reg[i]);
472167308Smarius		size = NEXUS_REG_SIZE(&reg[i]);
473167308Smarius		resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, phys,
474167308Smarius		    phys + size - 1, size);
475167308Smarius	}
476167308Smarius	free(reg, M_OFWPROP);
477167308Smarius
478167308Smarius	nintr = OF_getprop_alloc(node, "interrupts",  sizeof(*intr),
479167308Smarius	    (void **)&intr);
480167308Smarius	if (nintr > 0) {
481167308Smarius		if (OF_getprop(node, cpu_impl < CPU_IMPL_ULTRASPARCIII ?
482167308Smarius		    "upa-portid" : "portid", &ign, sizeof(ign)) <= 0) {
483167308Smarius			device_printf(dev, "<%s>: could not determine portid\n",
484167308Smarius			    ndi->ndi_obdinfo.obd_name);
485167308Smarius			free(intr, M_OFWPROP);
486167308Smarius			goto fail;
487167308Smarius		}
488167308Smarius
489167308Smarius		/* XXX 7-bit MID on Starfire */
490167308Smarius		ign = (ign << INTMAP_IGN_SHIFT) & INTMAP_IGN_MASK;
491167308Smarius		for (i = 0; i < nintr; i++) {
492167308Smarius			intr[i] |= ign;
493167308Smarius			resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i],
494167308Smarius			    intr[i], 1);
495167308Smarius		}
496167308Smarius		free(intr, M_OFWPROP);
497167308Smarius	}
498167308Smarius
499167308Smarius	return (ndi);
500167308Smarius
501167308Smarius fail:
502167308Smarius	nexus_destroy_dinfo(ndi);
503167308Smarius	return (NULL);
504167308Smarius}
505167308Smarius
506167308Smariusstatic void
507167308Smariusnexus_destroy_dinfo(struct nexus_devinfo *ndi)
508167308Smarius{
509167308Smarius
510167308Smarius	resource_list_free(&ndi->ndi_rl);
511167308Smarius	ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo);
512167308Smarius	free(ndi, M_DEVBUF);
513167308Smarius}
514167308Smarius
515167308Smariusstatic int
516167308Smariusnexus_print_res(struct nexus_devinfo *ndi)
517167308Smarius{
518167308Smarius	int rv;
519167308Smarius
520167308Smarius	rv = 0;
521167308Smarius	rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY,
522167308Smarius	    "%#lx");
523167308Smarius	rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ,
524167308Smarius	    "%ld");
525167308Smarius	return (rv);
526167308Smarius}
527