xref: /freebsd/sys/dev/ofw/ofwbus.c (revision 9768746b)
1 /*-
2  * Copyright 1998 Massachusetts Institute of Technology
3  * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.
4  * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and
8  * its documentation for any purpose and without fee is hereby
9  * granted, provided that both the above copyright notice and this
10  * permission notice appear in all copies, that both the above
11  * copyright notice and this permission notice appear in all
12  * supporting documentation, and that the name of M.I.T. not be used
13  * in advertising or publicity pertaining to distribution of the
14  * software without specific, written prior permission.  M.I.T. makes
15  * no representations about the suitability of this software for any
16  * purpose.  It is provided "as is" without express or implied
17  * warranty.
18  *
19  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
20  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
23  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * 	from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 #include <sys/pcpu.h>
45 #include <sys/rman.h>
46 #ifdef INTRNG
47 #include <sys/intr.h>
48 #endif
49 
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52 
53 #include <dev/ofw/ofw_bus.h>
54 #include <dev/ofw/ofw_bus_subr.h>
55 #include <dev/ofw/openfirm.h>
56 #include <dev/fdt/simplebus.h>
57 
58 #include <machine/bus.h>
59 #include <machine/resource.h>
60 
61 /*
62  * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that
63  * hang from the Open Firmware root node and adds them as devices to this bus
64  * (except some special nodes which are excluded) so that drivers can be
65  * attached to them.
66  */
67 
68 #ifndef __aarch64__
69 static device_identify_t ofwbus_identify;
70 #endif
71 static device_probe_t ofwbus_probe;
72 static device_attach_t ofwbus_attach;
73 static bus_alloc_resource_t ofwbus_alloc_resource;
74 static bus_release_resource_t ofwbus_release_resource;
75 
76 static device_method_t ofwbus_methods[] = {
77 	/* Device interface */
78 #ifndef __aarch64__
79 	DEVMETHOD(device_identify,	ofwbus_identify),
80 #endif
81 	DEVMETHOD(device_probe,		ofwbus_probe),
82 	DEVMETHOD(device_attach,	ofwbus_attach),
83 
84 	/* Bus interface */
85 	DEVMETHOD(bus_alloc_resource,	ofwbus_alloc_resource),
86 	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
87 	DEVMETHOD(bus_release_resource,	ofwbus_release_resource),
88 
89 	DEVMETHOD_END
90 };
91 
92 DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods,
93     sizeof(struct simplebus_softc), simplebus_driver);
94 EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, 0, 0,
95     BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
96 MODULE_VERSION(ofwbus, 1);
97 
98 #ifndef __aarch64__
99 static void
100 ofwbus_identify(driver_t *driver, device_t parent)
101 {
102 
103 	/* Check if Open Firmware has been instantiated */
104 	if (OF_peer(0) == 0)
105 		return;
106 
107 	if (device_find_child(parent, "ofwbus", -1) == NULL)
108 		BUS_ADD_CHILD(parent, 0, "ofwbus", -1);
109 }
110 #endif
111 
112 static int
113 ofwbus_probe(device_t dev)
114 {
115 
116 #ifdef __aarch64__
117 	if (OF_peer(0) == 0)
118 		return (ENXIO);
119 #endif
120 
121 	device_set_desc(dev, "Open Firmware Device Tree");
122 	return (BUS_PROBE_NOWILDCARD);
123 }
124 
125 static int
126 ofwbus_attach(device_t dev)
127 {
128 	phandle_t node;
129 	struct ofw_bus_devinfo obd;
130 
131 	node = OF_peer(0);
132 
133 	/*
134 	 * If no Open Firmware, bail early
135 	 */
136 	if (node == -1)
137 		return (ENXIO);
138 
139 	/*
140 	 * ofwbus bus starts on unamed node in FDT, so we cannot make
141 	 * ofw_bus_devinfo from it. Pass node to simplebus_init directly.
142 	 */
143 	simplebus_init(dev, node);
144 
145 	/*
146 	 * Allow devices to identify.
147 	 */
148 	bus_generic_probe(dev);
149 
150 	/*
151 	 * Now walk the OFW tree and attach top-level devices.
152 	 */
153 	for (node = OF_child(node); node > 0; node = OF_peer(node)) {
154 		if (ofw_bus_gen_setup_devinfo(&obd, node) != 0)
155 			continue;
156 		simplebus_add_device(dev, node, 0, NULL, -1, NULL);
157 	}
158 	return (bus_generic_attach(dev));
159 }
160 
161 static struct resource *
162 ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
163     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
164 {
165 	struct resource *rv;
166 	struct resource_list_entry *rle;
167 	bool isdefault, passthrough;
168 
169 	isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
170 	passthrough = (device_get_parent(child) != bus);
171 	rle = NULL;
172 	if (!passthrough && isdefault) {
173 		rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child),
174 		    type, *rid);
175 		if (rle == NULL) {
176 			if (bootverbose)
177 				device_printf(bus, "no default resources for "
178 				    "rid = %d, type = %d\n", *rid, type);
179 			return (NULL);
180 		}
181 		start = rle->start;
182 		count = ummax(count, rle->count);
183 		end = ummax(rle->end, start + count - 1);
184 	}
185 
186 	/* Let nexus handle the allocation. */
187 	rv = bus_generic_alloc_resource(bus, child, type, rid, start, end,
188 	    count, flags);
189 	if (rv == NULL)
190 		return (NULL);
191 
192 	if (!passthrough && rle != NULL) {
193 		rle->res = rv;
194 		rle->start = rman_get_start(rv);
195 		rle->end = rman_get_end(rv);
196 		rle->count = rle->end - rle->start + 1;
197 	}
198 
199 	return (rv);
200 }
201 
202 static int
203 ofwbus_release_resource(device_t bus, device_t child, int type,
204     int rid, struct resource *r)
205 {
206 	struct resource_list_entry *rle;
207 	bool passthrough;
208 
209 	passthrough = (device_get_parent(child) != bus);
210 	if (!passthrough) {
211 		/* Clean resource list entry */
212 		rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child),
213 		    type, rid);
214 		if (rle != NULL)
215 			rle->res = NULL;
216 	}
217 
218 	/* Let nexus handle the release. */
219 	return (bus_generic_release_resource(bus, child, type, rid, r));
220 }
221