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