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