]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/sparc64/sparc64/ofw_bus.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / sparc64 / sparc64 / ofw_bus.c
1 /*-
2  * Copyright (C) 1996 Wolfgang Solfrank.
3  * Copyright (C) 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*-
32  * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
45  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
48  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
49  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
50  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
51  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
53  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  *
55  *      from: $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $
56  *
57  * $FreeBSD$
58  */
59
60 /*
61  * Open Firmware bus support code that is (hopefully) independent from the
62  * used hardware.
63  * Maybe this should go into dev/ofw/; there may however be sparc specific
64  * bits left.
65  */
66
67 #include <sys/param.h>
68 #include <sys/malloc.h>
69 #include <sys/systm.h>
70
71 #include <dev/ofw/openfirm.h>
72
73 #include <machine/ofw_bus.h>
74
75 static int
76 ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen)
77 {
78         int rv;
79
80         for (; node != 0; node = OF_parent(node)) {
81                 if ((rv = OF_getprop(node, propname, buf, buflen)) != -1)
82                         return (rv);
83         }
84         return (-1);
85 }
86
87 void
88 ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
89 {
90         pcell_t addrc;
91         int msksz;
92
93         if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
94                 addrc = 2;
95         ii->opi_addrc = addrc * sizeof(pcell_t);
96
97         ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1,
98             (void **)&ii->opi_imap);
99         if (ii->opi_imapsz > 0) {
100                 msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1,
101                     (void **)&ii->opi_imapmsk);
102                 /*
103                  * Failure to get the mask is ignored; a full mask is used then.
104                  * Barf on bad mask sizes, however.
105                  */
106                 if (msksz != -1 && msksz != ii->opi_addrc + intrsz) {
107                         panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
108                             "property!");
109                 }
110         }
111
112 }
113
114 int
115 ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
116     int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
117     void *maskbuf)
118 {
119         int rv;
120
121         if (ii->opi_imapsz <= 0)
122                 return (0);
123         KASSERT(regsz >= ii->opi_addrc,
124             ("ofw_bus_lookup_imap: register size too small: %d < %d",
125                 regsz, ii->opi_addrc));
126         rv = OF_getprop(node, "reg", reg, regsz);
127         if (rv < regsz)
128                 panic("ofw_bus_lookup_imap: could not get reg property");
129         return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
130             ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
131             mintrsz));
132 }
133
134 /*
135  * Map an interrupt using the firmware reg, interrupt-map and
136  * interrupt-map-mask properties.
137  * The interrupt property to be mapped must be of size intrsz, and pointed to
138  * by intr. The regs property of the node for which the mapping is done must
139  * be passed as regs. This property is an array of register specifications;
140  * the size of the address part of such a specification must be passed as
141  * physsz. Only the first element of the property is used.
142  * imap and imapsz hold the interrupt mask and it's size.
143  * imapmsk is a pointer to the interrupt-map-mask property, which must have
144  * a size of physsz + intrsz; it may be NULL, in which case a full mask is
145  * assumed.
146  * maskbuf must point to a buffer of length physsz + intrsz.
147  * The interrupt is returned in result, which must point to a buffer of length
148  * rintrsz (which gives the expected size of the mapped interrupt).
149  * Returns 1 if a mapping was found, 0 otherwise.
150  */
151 int
152 ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
153     void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
154     int rintrsz)
155 {
156         phandle_t parent;
157         u_int8_t *ref = maskbuf;
158         u_int8_t *uiintr = intr;
159         u_int8_t *uiregs = regs;
160         u_int8_t *uiimapmsk = imapmsk;
161         u_int8_t *mptr;
162         pcell_t pintrsz;
163         int i, rsz, tsz;
164
165         rsz = -1;
166         if (imapmsk != NULL) {
167                 for (i = 0; i < physsz; i++)
168                         ref[i] = uiregs[i] & uiimapmsk[i];
169                 for (i = 0; i < intrsz; i++)
170                         ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
171         } else {
172                 bcopy(regs, ref, physsz);
173                 bcopy(intr, ref + physsz, intrsz);
174         }
175
176         mptr = imap;
177         i = imapsz;
178         tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz;
179         while (i > 0) {
180                 KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
181                 bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
182                 if (ofw_bus_searchprop(parent, "#interrupt-cells",
183                     &pintrsz, sizeof(pintrsz)) == -1)
184                         pintrsz = 1;    /* default */
185                 pintrsz *= sizeof(pcell_t);
186                 if (pintrsz != rintrsz)
187                         panic("ofw_bus_search_intrmap: expected interrupt cell "
188                             "size incorrect: %d != %d", rintrsz, pintrsz);
189                 if (bcmp(ref, mptr, physsz + intrsz) == 0) {
190                         bcopy(mptr + physsz + intrsz + sizeof(parent),
191                             result, rintrsz);
192                         return (1);
193                 }
194                 mptr += tsz;
195                 i -= tsz;
196         }
197         return (0);
198 }