xref: /openbsd-src/sys/arch/sparc64/dev/ebus_mainbus.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: ebus_mainbus.c,v 1.6 2008/04/03 19:41:20 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #ifdef DEBUG
20 #define	EDB_PROM	0x01
21 #define EDB_CHILD	0x02
22 #define	EDB_INTRMAP	0x04
23 #define EDB_BUSMAP	0x08
24 #define EDB_BUSDMA	0x10
25 #define EDB_INTR	0x20
26 extern int ebus_debug;
27 #define DPRINTF(l, s)   do { if (ebus_debug & l) printf s; } while (0)
28 #else
29 #define DPRINTF(l, s)
30 #endif
31 
32 #include <sys/param.h>
33 #include <sys/conf.h>
34 #include <sys/device.h>
35 #include <sys/errno.h>
36 #include <sys/extent.h>
37 #include <sys/malloc.h>
38 #include <sys/systm.h>
39 #include <sys/time.h>
40 
41 #define _SPARC_BUS_DMA_PRIVATE
42 #include <machine/bus.h>
43 #include <machine/autoconf.h>
44 #include <machine/hypervisor.h>
45 #include <machine/openfirm.h>
46 
47 #include <dev/pci/pcivar.h>
48 
49 #include <sparc64/dev/iommureg.h>
50 #include <sparc64/dev/ebusreg.h>
51 #include <sparc64/dev/ebusvar.h>
52 #include <sparc64/dev/pyrovar.h>
53 
54 extern struct cfdriver pyro_cd;
55 
56 int	ebus_mainbus_match(struct device *, void *, void *);
57 void	ebus_mainbus_attach(struct device *, struct device *, void *);
58 
59 struct cfattach ebus_mainbus_ca = {
60 	sizeof(struct ebus_softc), ebus_mainbus_match, ebus_mainbus_attach
61 };
62 
63 
64 int ebus_mainbus_bus_map(bus_space_tag_t, bus_space_tag_t,
65     bus_addr_t, bus_size_t, int, bus_space_handle_t *);
66 void *ebus_mainbus_intr_establish(bus_space_tag_t, bus_space_tag_t,
67     int, int, int, int (*)(void *), void *, const char *);
68 bus_space_tag_t ebus_alloc_bus_tag(struct ebus_softc *, bus_space_tag_t);
69 void ebus_mainbus_intr_ack(struct intrhand *);
70 
71 int
72 ebus_mainbus_match(struct device *parent, void *match, void *aux)
73 {
74 	struct mainbus_attach_args *ma = aux;
75 
76 	if (strcmp(ma->ma_name, "ebus") == 0)
77 		return (1);
78 	return (0);
79 }
80 
81 void
82 ebus_mainbus_attach(struct device *parent, struct device *self, void *aux)
83 {
84 	struct ebus_softc *sc = (struct ebus_softc *)self;
85 	struct mainbus_attach_args *ma = aux;
86 	struct ebus_attach_args eba;
87 	struct ebus_interrupt_map_mask *immp;
88 	int node, nmapmask, error;
89 	struct pyro_softc *psc;
90 	int i;
91 
92 	sc->sc_node = node = ma->ma_node;
93 	sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
94 
95 	if (CPU_ISSUN4U) {
96 		printf(": ign %x", sc->sc_ign);
97 
98 		for (i = 0; i < pyro_cd.cd_ndevs; i++) {
99 			psc = pyro_cd.cd_devs[i];
100 			if (psc && psc->sc_ign == sc->sc_ign) {
101 				sc->sc_bust = psc->sc_bust;
102 				sc->sc_csr = psc->sc_csr;
103 				sc->sc_csrh = psc->sc_csrh;
104 				break;
105 			}
106 		}
107 
108 		if (sc->sc_csr == 0) {
109 			printf(": can't find matching host bridge leaf\n");
110 			return;
111 		}
112 	}
113 
114 	printf("\n");
115 
116 	sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
117 	sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
118 	sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag);
119 
120 	/*
121 	 * fill in our softc with information from the prom
122 	 */
123 	sc->sc_intmap = NULL;
124 	sc->sc_range = NULL;
125 	error = getprop(node, "interrupt-map",
126 			sizeof(struct ebus_interrupt_map),
127 			&sc->sc_nintmap, (void **)&sc->sc_intmap);
128 	switch (error) {
129 	case 0:
130 		immp = &sc->sc_intmapmask;
131 		error = getprop(node, "interrupt-map-mask",
132 			    sizeof(struct ebus_interrupt_map_mask), &nmapmask,
133 			    (void **)&immp);
134 		if (error)
135 			panic("could not get ebus interrupt-map-mask");
136 		if (nmapmask != 1)
137 			panic("ebus interrupt-map-mask is broken");
138 		break;
139 	case ENOENT:
140 		break;
141 	default:
142 		panic("ebus interrupt-map: error %d", error);
143 		break;
144 	}
145 
146 	error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
147 	    &sc->sc_nrange, (void **)&sc->sc_range);
148 	if (error)
149 		panic("ebus ranges: error %d", error);
150 
151 	/*
152 	 * now attach all our children
153 	 */
154 	DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
155 	for (node = firstchild(node); node; node = nextsibling(node)) {
156 		if (ebus_setup_attach_args(sc, node, &eba) != 0) {
157 			DPRINTF(EDB_CHILD,
158 			    ("ebus_mainbus_attach: %s: incomplete\n",
159 			    getpropstring(node, "name")));
160 			continue;
161 		} else {
162 			DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
163 			    eba.ea_name));
164 			(void)config_found(self, &eba, ebus_print);
165 		}
166 		ebus_destroy_attach_args(&eba);
167 	}
168 }
169 
170 bus_space_tag_t
171 ebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent)
172 {
173 	struct sparc_bus_space_tag *bt;
174 
175 	bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
176 	if (bt == NULL)
177 		panic("could not allocate ebus bus tag");
178 
179 	snprintf(bt->name, sizeof(bt->name), "%s", sc->sc_dev.dv_xname);
180 	bt->cookie = sc;
181 	bt->parent = parent;
182 	bt->asi = parent->asi;
183 	bt->sasi = parent->sasi;
184 	bt->sparc_bus_map = ebus_mainbus_bus_map;
185 	bt->sparc_intr_establish = ebus_mainbus_intr_establish;
186 
187 	return (bt);
188 }
189 
190 int
191 ebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
192     bus_size_t size, int flags, bus_space_handle_t *hp)
193 {
194 	struct ebus_softc *sc = t->cookie;
195 	struct ebus_mainbus_ranges *range;
196 	bus_addr_t hi, lo;
197 	int i;
198 
199 	DPRINTF(EDB_BUSMAP,
200 	    ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
201 	    (unsigned long long)offset, (int)size, (int)flags));
202 
203 	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
204 		printf("\n_ebus_mainbus_bus_map: invalid parent");
205 		return (EINVAL);
206 	}
207 
208 	t = t->parent;
209 
210 	if (flags & BUS_SPACE_MAP_PROMADDRESS) {
211 		return ((*t->sparc_bus_map)
212 		    (t, t0, offset, size, flags, hp));
213 	}
214 
215 	hi = offset >> 32UL;
216 	lo = offset & 0xffffffff;
217 	range = (struct ebus_mainbus_ranges *)sc->sc_range;
218 
219 	DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
220 	for (i = 0; i < sc->sc_nrange; i++) {
221 		bus_addr_t addr;
222 
223 		if (hi != range[i].child_hi)
224 			continue;
225 		if (lo < range[i].child_lo ||
226 		    (lo + size) > (range[i].child_lo + range[i].size))
227 			continue;
228 
229 		addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
230 				    range[i].phys_lo;
231 		addr += lo;
232 		DPRINTF(EDB_BUSMAP,
233 		    ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n",
234 		    (unsigned long long)offset, (unsigned long long)addr));
235                 return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp));
236 	}
237 	DPRINTF(EDB_BUSMAP, (": FAILED\n"));
238 	return (EINVAL);
239 }
240 
241 void *
242 ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
243     int level, int flags, int (*handler)(void *), void *arg, const char *what)
244 {
245 	struct ebus_softc *sc = t->cookie;
246 	struct intrhand *ih = NULL;
247 	volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
248 	int ino;
249 
250 #ifdef SUN4V
251 	if (CPU_ISSUN4V) {
252 		struct upa_reg reg;
253 		u_int64_t devhandle, devino = INTINO(ihandle);
254 		u_int64_t sysino;
255 		int node = -1;
256 		int i, err;
257 
258 		for (i = 0; i < sc->sc_nintmap; i++) {
259 			if (sc->sc_intmap[i].cintr == ihandle) {
260 				node = sc->sc_intmap[i].cnode;
261 				break;
262 			}
263 		}
264 		if (node == -1)
265 			return (NULL);
266 
267 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
268 			return (NULL);
269 		devhandle = (reg.ur_paddr >> 32) & 0x0fffffff;
270 
271 		err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
272 		if (err != H_EOK)
273 			return (NULL);
274 
275 		KASSERT(sysino == INTVEC(sysino));
276 		ih = bus_intr_allocate(t0, handler, arg, sysino, level,
277 		    NULL, NULL, what);
278 		if (ih == NULL)
279 			return (NULL);
280 
281 		intr_establish(ih->ih_pil, ih);
282 		ih->ih_ack = ebus_mainbus_intr_ack;
283 
284 		err = hv_intr_settarget(sysino, cpus->ci_upaid);
285 		if (err != H_EOK)
286 			return (NULL);
287 
288 		/* Clear pending interrupts. */
289 		err = hv_intr_setstate(sysino, INTR_IDLE);
290 		if (err != H_EOK)
291 			return (NULL);
292 
293 		err = hv_intr_setenabled(sysino, INTR_ENABLED);
294 		if (err != H_EOK)
295 			return (NULL);
296 
297 		return (ih);
298 	}
299 #endif
300 
301 	ihandle |= sc->sc_ign;
302 	ino = INTINO(ihandle);
303 
304 	if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
305 		u_int64_t *imap, *iclr;
306 
307 		/* XXX */
308 		imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
309 		iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
310 		intrmapptr = &imap[ino];
311 		intrclrptr = &iclr[ino];
312 		ino |= INTVEC(ihandle);
313 	}
314 
315 	ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
316 	    intrclrptr, what);
317 	if (ih == NULL)
318 		return (NULL);
319 
320 	intr_establish(ih->ih_pil, ih);
321 
322 	if (intrmapptr != NULL) {
323 		u_int64_t intrmap;
324 
325 		intrmap = *intrmapptr;
326 		intrmap |= (1LL << 6);
327 		intrmap |= INTMAP_V;
328 		*intrmapptr = intrmap;
329 		intrmap = *intrmapptr;
330 		ih->ih_number |= intrmap & INTMAP_INR;
331 	}
332 
333 	return (ih);
334 }
335 
336 #ifdef SUN4V
337 
338 void
339 ebus_mainbus_intr_ack(struct intrhand *ih)
340 {
341 	hv_intr_setstate(ih->ih_number, INTR_IDLE);
342 }
343 
344 #endif
345