1152683Smarius/*-
2186128Snwhitehorn * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
3152683Smarius * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
4152683Smarius * All rights reserved.
5152683Smarius *
6152683Smarius * Redistribution and use in source and binary forms, with or without
7152683Smarius * modification, are permitted provided that the following conditions
8152683Smarius * are met:
9152683Smarius * 1. Redistributions of source code must retain the above copyright
10152683Smarius *    notice, this list of conditions, and the following disclaimer,
11152683Smarius *    without modification, immediately at the beginning of the file.
12152683Smarius * 2. Redistributions in binary form must reproduce the above copyright
13152683Smarius *    notice, this list of conditions and the following disclaimer in
14152683Smarius *    the documentation and/or other materials provided with the
15152683Smarius *    distribution.
16152683Smarius *
17152683Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18152683Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19152683Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20152683Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21152683Smarius * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22152683Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23152683Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24152683Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25152683Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26152683Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27152683Smarius * SUCH DAMAGE.
28152683Smarius */
29152683Smarius
30152683Smarius#include <sys/cdefs.h>
31152683Smarius__FBSDID("$FreeBSD: releng/10.3/sys/dev/ofw/ofw_bus_subr.c 283334 2015-05-23 22:36:41Z ian $");
32152683Smarius
33208614Sraj#include "opt_platform.h"
34152683Smarius#include <sys/param.h>
35152683Smarius#include <sys/systm.h>
36152683Smarius#include <sys/bus.h>
37152683Smarius#include <sys/errno.h>
38186128Snwhitehorn#include <sys/libkern.h>
39152683Smarius
40273675Sian#include <machine/resource.h>
41273675Sian
42186128Snwhitehorn#include <dev/ofw/ofw_bus.h>
43152683Smarius#include <dev/ofw/ofw_bus_subr.h>
44152683Smarius#include <dev/ofw/openfirm.h>
45152683Smarius
46152683Smarius#include "ofw_bus_if.h"
47152683Smarius
48152683Smariusint
49152683Smariusofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
50152683Smarius{
51152683Smarius
52152683Smarius	if (obd == NULL)
53152683Smarius		return (ENOMEM);
54152683Smarius	/* The 'name' property is considered mandatory. */
55152683Smarius	if ((OF_getprop_alloc(node, "name", 1, (void **)&obd->obd_name)) == -1)
56152683Smarius		return (EINVAL);
57152683Smarius	OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat);
58152683Smarius	OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type);
59152683Smarius	OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model);
60266128Sian	OF_getprop_alloc(node, "status", 1, (void **)&obd->obd_status);
61152683Smarius	obd->obd_node = node;
62152683Smarius	return (0);
63152683Smarius}
64152683Smarius
65152683Smariusvoid
66152683Smariusofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
67152683Smarius{
68152683Smarius
69152683Smarius	if (obd == NULL)
70152683Smarius		return;
71152683Smarius	if (obd->obd_compat != NULL)
72152683Smarius		free(obd->obd_compat, M_OFWPROP);
73152683Smarius	if (obd->obd_model != NULL)
74152683Smarius		free(obd->obd_model, M_OFWPROP);
75152683Smarius	if (obd->obd_name != NULL)
76152683Smarius		free(obd->obd_name, M_OFWPROP);
77152683Smarius	if (obd->obd_type != NULL)
78152683Smarius		free(obd->obd_type, M_OFWPROP);
79266128Sian	if (obd->obd_status != NULL)
80266128Sian		free(obd->obd_status, M_OFWPROP);
81152683Smarius}
82152683Smarius
83194138Smariusint
84186128Snwhitehornofw_bus_gen_child_pnpinfo_str(device_t cbdev, device_t child, char *buf,
85186128Snwhitehorn    size_t buflen)
86186128Snwhitehorn{
87194138Smarius
88186128Snwhitehorn	if (ofw_bus_get_name(child) != NULL) {
89186128Snwhitehorn		strlcat(buf, "name=", buflen);
90186128Snwhitehorn		strlcat(buf, ofw_bus_get_name(child), buflen);
91186128Snwhitehorn	}
92152683Smarius
93186128Snwhitehorn	if (ofw_bus_get_compat(child) != NULL) {
94186128Snwhitehorn		strlcat(buf, " compat=", buflen);
95186128Snwhitehorn		strlcat(buf, ofw_bus_get_compat(child), buflen);
96186128Snwhitehorn	}
97186128Snwhitehorn	return (0);
98186128Snwhitehorn};
99186128Snwhitehorn
100152683Smariusconst char *
101152683Smariusofw_bus_gen_get_compat(device_t bus, device_t dev)
102152683Smarius{
103152683Smarius	const struct ofw_bus_devinfo *obd;
104194138Smarius
105194138Smarius	obd = OFW_BUS_GET_DEVINFO(bus, dev);
106152683Smarius	if (obd == NULL)
107152683Smarius		return (NULL);
108152683Smarius	return (obd->obd_compat);
109152683Smarius}
110194138Smarius
111152683Smariusconst char *
112152683Smariusofw_bus_gen_get_model(device_t bus, device_t dev)
113152683Smarius{
114152683Smarius	const struct ofw_bus_devinfo *obd;
115152683Smarius
116194138Smarius	obd = OFW_BUS_GET_DEVINFO(bus, dev);
117152683Smarius	if (obd == NULL)
118152683Smarius		return (NULL);
119152683Smarius	return (obd->obd_model);
120152683Smarius}
121152683Smarius
122152683Smariusconst char *
123152683Smariusofw_bus_gen_get_name(device_t bus, device_t dev)
124152683Smarius{
125152683Smarius	const struct ofw_bus_devinfo *obd;
126152683Smarius
127194138Smarius	obd = OFW_BUS_GET_DEVINFO(bus, dev);
128152683Smarius	if (obd == NULL)
129152683Smarius		return (NULL);
130152683Smarius	return (obd->obd_name);
131152683Smarius}
132152683Smarius
133152683Smariusphandle_t
134152683Smariusofw_bus_gen_get_node(device_t bus, device_t dev)
135152683Smarius{
136152683Smarius	const struct ofw_bus_devinfo *obd;
137152683Smarius
138194138Smarius	obd = OFW_BUS_GET_DEVINFO(bus, dev);
139152683Smarius	if (obd == NULL)
140152683Smarius		return (0);
141152683Smarius	return (obd->obd_node);
142152683Smarius}
143152683Smarius
144152683Smariusconst char *
145152683Smariusofw_bus_gen_get_type(device_t bus, device_t dev)
146152683Smarius{
147152683Smarius	const struct ofw_bus_devinfo *obd;
148152683Smarius
149194138Smarius	obd = OFW_BUS_GET_DEVINFO(bus, dev);
150152683Smarius	if (obd == NULL)
151152683Smarius		return (NULL);
152152683Smarius	return (obd->obd_type);
153152683Smarius}
154186128Snwhitehorn
155266128Sianconst char *
156266128Sianofw_bus_get_status(device_t dev)
157266128Sian{
158266128Sian	const struct ofw_bus_devinfo *obd;
159266128Sian
160266128Sian	obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev);
161266128Sian	if (obd == NULL)
162266128Sian		return (NULL);
163266128Sian
164266128Sian	return (obd->obd_status);
165266128Sian}
166266128Sian
167208614Srajint
168266128Sianofw_bus_status_okay(device_t dev)
169266128Sian{
170266128Sian	const char *status;
171266128Sian
172266128Sian	status = ofw_bus_get_status(dev);
173266128Sian	if (status == NULL || strcmp(status, "okay") == 0)
174266128Sian		return (1);
175266128Sian
176266128Sian	return (0);
177266128Sian}
178266128Sian
179266128Sianint
180208614Srajofw_bus_is_compatible(device_t dev, const char *onecompat)
181208614Sraj{
182208614Sraj	phandle_t node;
183208614Sraj	const char *compat;
184208614Sraj	int len, onelen, l;
185208614Sraj
186208614Sraj	if ((compat = ofw_bus_get_compat(dev)) == NULL)
187208614Sraj		return (0);
188208614Sraj
189233018Snwhitehorn	if ((node = ofw_bus_get_node(dev)) == -1)
190208614Sraj		return (0);
191208614Sraj
192208614Sraj	/* Get total 'compatible' prop len */
193208614Sraj	if ((len = OF_getproplen(node, "compatible")) <= 0)
194208614Sraj		return (0);
195208614Sraj
196208614Sraj	onelen = strlen(onecompat);
197208614Sraj
198208614Sraj	while (len > 0) {
199239366Shrs		if (strlen(compat) == onelen &&
200239366Shrs		    strncasecmp(compat, onecompat, onelen) == 0)
201208614Sraj			/* Found it. */
202208614Sraj			return (1);
203208614Sraj
204208614Sraj		/* Slide to the next sub-string. */
205208614Sraj		l = strlen(compat) + 1;
206208614Sraj		compat += l;
207208614Sraj		len -= l;
208208614Sraj	}
209208614Sraj	return (0);
210208614Sraj}
211208614Sraj
212208614Srajint
213208614Srajofw_bus_is_compatible_strict(device_t dev, const char *compatible)
214208614Sraj{
215208614Sraj	const char *compat;
216239366Shrs	size_t len;
217208614Sraj
218208614Sraj	if ((compat = ofw_bus_get_compat(dev)) == NULL)
219208614Sraj		return (0);
220208614Sraj
221239366Shrs	len = strlen(compatible);
222239366Shrs	if (strlen(compat) == len &&
223239366Shrs	    strncasecmp(compat, compatible, len) == 0)
224208614Sraj		return (1);
225208614Sraj
226208614Sraj	return (0);
227208614Sraj}
228208614Sraj
229259316Sianconst struct ofw_compat_data *
230259316Sianofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat)
231259316Sian{
232259316Sian
233259316Sian	if (compat == NULL)
234259316Sian		return NULL;
235259316Sian
236259316Sian	for (; compat->ocd_str != NULL; ++compat) {
237259316Sian		if (ofw_bus_is_compatible(dev, compat->ocd_str))
238259316Sian			break;
239259316Sian	}
240259316Sian
241259316Sian	return (compat);
242259316Sian}
243259316Sian
244239366Shrsint
245239366Shrsofw_bus_has_prop(device_t dev, const char *propname)
246239366Shrs{
247239366Shrs	phandle_t node;
248239366Shrs
249239366Shrs	if ((node = ofw_bus_get_node(dev)) == -1)
250239366Shrs		return (0);
251239366Shrs
252239366Shrs	return (OF_hasprop(node, propname));
253239366Shrs}
254239366Shrs
255186128Snwhitehornvoid
256186128Snwhitehornofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
257186128Snwhitehorn{
258186128Snwhitehorn	pcell_t addrc;
259186128Snwhitehorn	int msksz;
260186128Snwhitehorn
261265967Sian	if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
262186128Snwhitehorn		addrc = 2;
263186128Snwhitehorn	ii->opi_addrc = addrc * sizeof(pcell_t);
264186128Snwhitehorn
265265967Sian	ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", 1,
266186128Snwhitehorn	    (void **)&ii->opi_imap);
267186128Snwhitehorn	if (ii->opi_imapsz > 0) {
268265967Sian		msksz = OF_getencprop_alloc(node, "interrupt-map-mask", 1,
269186128Snwhitehorn		    (void **)&ii->opi_imapmsk);
270186128Snwhitehorn		/*
271194138Smarius		 * Failure to get the mask is ignored; a full mask is used
272194138Smarius		 * then.  We barf on bad mask sizes, however.
273186128Snwhitehorn		 */
274194138Smarius		if (msksz != -1 && msksz != ii->opi_addrc + intrsz)
275186128Snwhitehorn			panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
276186128Snwhitehorn			    "property!");
277186128Snwhitehorn	}
278186128Snwhitehorn}
279186128Snwhitehorn
280186128Snwhitehornint
281186128Snwhitehornofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
282186128Snwhitehorn    int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
283266020Sian    phandle_t *iparent)
284186128Snwhitehorn{
285266020Sian	uint8_t maskbuf[regsz + pintrsz];
286186128Snwhitehorn	int rv;
287186128Snwhitehorn
288186128Snwhitehorn	if (ii->opi_imapsz <= 0)
289186128Snwhitehorn		return (0);
290186128Snwhitehorn	KASSERT(regsz >= ii->opi_addrc,
291186128Snwhitehorn	    ("ofw_bus_lookup_imap: register size too small: %d < %d",
292186128Snwhitehorn		regsz, ii->opi_addrc));
293265954Sian	if (node != -1) {
294265967Sian		rv = OF_getencprop(node, "reg", reg, regsz);
295265954Sian		if (rv < regsz)
296265954Sian			panic("ofw_bus_lookup_imap: cannot get reg property");
297265954Sian	}
298186128Snwhitehorn	return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
299186128Snwhitehorn	    ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
300209298Snwhitehorn	    mintrsz, iparent));
301186128Snwhitehorn}
302186128Snwhitehorn
303186128Snwhitehorn/*
304186128Snwhitehorn * Map an interrupt using the firmware reg, interrupt-map and
305186128Snwhitehorn * interrupt-map-mask properties.
306186128Snwhitehorn * The interrupt property to be mapped must be of size intrsz, and pointed to
307194138Smarius * by intr.  The regs property of the node for which the mapping is done must
308186128Snwhitehorn * be passed as regs. This property is an array of register specifications;
309186128Snwhitehorn * the size of the address part of such a specification must be passed as
310194138Smarius * physsz.  Only the first element of the property is used.
311186128Snwhitehorn * imap and imapsz hold the interrupt mask and it's size.
312186128Snwhitehorn * imapmsk is a pointer to the interrupt-map-mask property, which must have
313186128Snwhitehorn * a size of physsz + intrsz; it may be NULL, in which case a full mask is
314186128Snwhitehorn * assumed.
315186128Snwhitehorn * maskbuf must point to a buffer of length physsz + intrsz.
316186128Snwhitehorn * The interrupt is returned in result, which must point to a buffer of length
317186128Snwhitehorn * rintrsz (which gives the expected size of the mapped interrupt).
318266020Sian * Returns number of cells in the interrupt if a mapping was found, 0 otherwise.
319186128Snwhitehorn */
320186128Snwhitehornint
321186128Snwhitehornofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
322186128Snwhitehorn    void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
323209298Snwhitehorn    int rintrsz, phandle_t *iparent)
324186128Snwhitehorn{
325186128Snwhitehorn	phandle_t parent;
326194138Smarius	uint8_t *ref = maskbuf;
327194138Smarius	uint8_t *uiintr = intr;
328194138Smarius	uint8_t *uiregs = regs;
329194138Smarius	uint8_t *uiimapmsk = imapmsk;
330194138Smarius	uint8_t *mptr;
331186128Snwhitehorn	pcell_t pintrsz;
332186128Snwhitehorn	int i, rsz, tsz;
333186128Snwhitehorn
334186128Snwhitehorn	rsz = -1;
335186128Snwhitehorn	if (imapmsk != NULL) {
336186128Snwhitehorn		for (i = 0; i < physsz; i++)
337186128Snwhitehorn			ref[i] = uiregs[i] & uiimapmsk[i];
338186128Snwhitehorn		for (i = 0; i < intrsz; i++)
339186128Snwhitehorn			ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
340186128Snwhitehorn	} else {
341186128Snwhitehorn		bcopy(regs, ref, physsz);
342186128Snwhitehorn		bcopy(intr, ref + physsz, intrsz);
343186128Snwhitehorn	}
344186128Snwhitehorn
345186128Snwhitehorn	mptr = imap;
346186128Snwhitehorn	i = imapsz;
347186128Snwhitehorn	while (i > 0) {
348186128Snwhitehorn		bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
349273652Sian		if (OF_searchencprop(OF_node_from_xref(parent),
350265967Sian		    "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1)
351186128Snwhitehorn			pintrsz = 1;	/* default */
352186128Snwhitehorn		pintrsz *= sizeof(pcell_t);
353186728Snwhitehorn
354194138Smarius		/* Compute the map stride size. */
355186728Snwhitehorn		tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz;
356186728Snwhitehorn		KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
357194138Smarius
358186128Snwhitehorn		if (bcmp(ref, mptr, physsz + intrsz) == 0) {
359186128Snwhitehorn			bcopy(mptr + physsz + intrsz + sizeof(parent),
360266020Sian			    result, MIN(rintrsz, pintrsz));
361209298Snwhitehorn
362209298Snwhitehorn			if (iparent != NULL)
363209298Snwhitehorn				*iparent = parent;
364266020Sian			return (pintrsz/sizeof(pcell_t));
365186128Snwhitehorn		}
366186128Snwhitehorn		mptr += tsz;
367186128Snwhitehorn		i -= tsz;
368186128Snwhitehorn	}
369186128Snwhitehorn	return (0);
370186128Snwhitehorn}
371265954Sian
372273675Sianint
373283334Sianofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
374283334Sian    struct resource_list *rl)
375283334Sian{
376283334Sian	uint64_t phys, size;
377283334Sian	ssize_t i, j, rid, nreg, ret;
378283334Sian	uint32_t *reg;
379283334Sian	char *name;
380283334Sian
381283334Sian	/*
382283334Sian	 * This may be just redundant when having ofw_bus_devinfo
383283334Sian	 * but makes this routine independent of it.
384283334Sian	 */
385283334Sian	ret = OF_getencprop_alloc(node, "name", sizeof(*name), (void **)&name);
386283334Sian	if (ret == -1)
387283334Sian		name = NULL;
388283334Sian
389283334Sian	ret = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
390283334Sian	nreg = (ret == -1) ? 0 : ret;
391283334Sian
392283334Sian	if (nreg % (acells + scells) != 0) {
393283334Sian		if (bootverbose)
394283334Sian			device_printf(dev, "Malformed reg property on <%s>\n",
395283334Sian			    (name == NULL) ? "unknown" : name);
396283334Sian		nreg = 0;
397283334Sian	}
398283334Sian
399283334Sian	for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) {
400283334Sian		phys = size = 0;
401283334Sian		for (j = 0; j < acells; j++) {
402283334Sian			phys <<= 32;
403283334Sian			phys |= reg[i + j];
404283334Sian		}
405283334Sian		for (j = 0; j < scells; j++) {
406283334Sian			size <<= 32;
407283334Sian			size |= reg[i + acells + j];
408283334Sian		}
409283334Sian		/* Skip the dummy reg property of glue devices like ssm(4). */
410283334Sian		if (size != 0)
411283334Sian			resource_list_add(rl, SYS_RES_MEMORY, rid,
412283334Sian			    phys, phys + size - 1, size);
413283334Sian	}
414283334Sian	free(name, M_OFWPROP);
415283334Sian	free(reg, M_OFWPROP);
416283334Sian
417283334Sian	return (0);
418283334Sian}
419283334Sian
420283334Sianint
421273675Sianofw_bus_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl)
422273675Sian{
423273675Sian	phandle_t iparent;
424273675Sian	uint32_t icells, *intr;
425273675Sian	int err, i, irqnum, nintr, rid;
426273675Sian	boolean_t extended;
427273675Sian
428273675Sian	nintr = OF_getencprop_alloc(node, "interrupts",  sizeof(*intr),
429273675Sian	    (void **)&intr);
430273675Sian	if (nintr > 0) {
431273675Sian		if (OF_searchencprop(node, "interrupt-parent", &iparent,
432273675Sian		    sizeof(iparent)) == -1) {
433273675Sian			device_printf(dev, "No interrupt-parent found, "
434273675Sian			    "assuming direct parent\n");
435273675Sian			iparent = OF_parent(node);
436273675Sian		}
437273675Sian		if (OF_searchencprop(OF_node_from_xref(iparent),
438273675Sian		    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
439273675Sian			device_printf(dev, "Missing #interrupt-cells "
440273675Sian			    "property, assuming <1>\n");
441273675Sian			icells = 1;
442273675Sian		}
443273675Sian		if (icells < 1 || icells > nintr) {
444273675Sian			device_printf(dev, "Invalid #interrupt-cells property "
445273675Sian			    "value <%d>, assuming <1>\n", icells);
446273675Sian			icells = 1;
447273675Sian		}
448273675Sian		extended = false;
449273675Sian	} else {
450273675Sian		nintr = OF_getencprop_alloc(node, "interrupts-extended",
451273675Sian		    sizeof(*intr), (void **)&intr);
452273675Sian		if (nintr <= 0)
453273675Sian			return (0);
454273675Sian		extended = true;
455273675Sian	}
456273675Sian	err = 0;
457273675Sian	rid = 0;
458273675Sian	for (i = 0; i < nintr; i += icells) {
459273675Sian		if (extended) {
460273675Sian			iparent = intr[i++];
461273675Sian			if (OF_searchencprop(OF_node_from_xref(iparent),
462273675Sian			    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
463273675Sian				device_printf(dev, "Missing #interrupt-cells "
464273675Sian				    "property\n");
465273675Sian				err = ENOENT;
466273675Sian				break;
467273675Sian			}
468273675Sian			if (icells < 1 || (i + icells) > nintr) {
469273675Sian				device_printf(dev, "Invalid #interrupt-cells "
470273675Sian				    "property value <%d>\n", icells);
471273675Sian				err = ERANGE;
472273675Sian				break;
473273675Sian			}
474273675Sian		}
475273675Sian		irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
476273675Sian		resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
477273675Sian	}
478273675Sian	free(intr, M_OFWPROP);
479273675Sian	return (err);
480273675Sian}
481