1 /* $NetBSD: ebus_mainbus.c,v 1.23 2022/05/24 20:50:19 andvar 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.23 2022/05/24 20:50:19 andvar 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/kmem.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 #include "ioconf.h"
60
61 int ebus_mainbus_match(device_t, cfdata_t, void *);
62 void ebus_mainbus_attach(device_t, device_t, void *);
63
64 CFATTACH_DECL_NEW(ebus_mainbus, sizeof(struct ebus_softc),
65 ebus_mainbus_match, ebus_mainbus_attach, NULL, NULL);
66
67 static int ebus_mainbus_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
68 vaddr_t, bus_space_handle_t *);
69 static void *ebus_mainbus_intr_establish(bus_space_tag_t, int, int,
70 int (*)(void *), void *, void (*)(void));
71 static bus_space_tag_t ebus_mainbus_alloc_bus_tag(struct ebus_softc *,
72 bus_space_tag_t, int);
73 #ifdef SUN4V
74 #if 0
75 XXX
76 static void ebus_mainbus_intr_ack(struct intrhand *);
77 #endif
78 #endif
79 int
ebus_mainbus_match(device_t parent,cfdata_t cf,void * aux)80 ebus_mainbus_match(device_t parent, cfdata_t cf, void *aux)
81 {
82 struct mainbus_attach_args *ma = aux;
83
84 if (strcmp(ma->ma_name, "ebus") == 0)
85 return (1);
86 return (0);
87 }
88
89 void
ebus_mainbus_attach(device_t parent,device_t self,void * aux)90 ebus_mainbus_attach(device_t parent, device_t self, void *aux)
91 {
92 struct ebus_softc *sc = device_private(self);
93 struct mainbus_attach_args *ma = aux;
94 struct ebus_attach_args eba;
95 struct ebus_interrupt_map_mask *immp;
96 int node, nmapmask, error;
97 struct pyro_softc *psc;
98 int i, j;
99
100 sc->sc_dev = self;
101
102 printf("\n");
103
104 sc->sc_memtag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag,
105 PCI_MEMORY_BUS_SPACE);
106 sc->sc_iotag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag,
107 PCI_IO_BUS_SPACE);
108 sc->sc_childbustag = sc->sc_memtag;
109 sc->sc_dmatag = ma->ma_dmatag;
110
111 sc->sc_node = node = ma->ma_node;
112
113 /*
114 * fill in our softc with information from the prom
115 */
116 sc->sc_intmap = NULL;
117 sc->sc_range = NULL;
118 error = prom_getprop(node, "interrupt-map",
119 sizeof(struct ebus_interrupt_map),
120 &sc->sc_nintmap, (void **)&sc->sc_intmap);
121 switch (error) {
122 case 0:
123 immp = &sc->sc_intmapmask;
124 nmapmask = 1;
125 error = prom_getprop(node, "interrupt-map-mask",
126 sizeof(struct ebus_interrupt_map_mask), &nmapmask,
127 (void **)&immp);
128 if (error)
129 panic("could not get ebus interrupt-map-mask: error %d",
130 error);
131 if (nmapmask != 1)
132 panic("ebus interrupt-map-mask is broken");
133 break;
134 case ENOENT:
135 break;
136 default:
137 panic("ebus interrupt-map: error %d", error);
138 break;
139 }
140
141 /*
142 * Ebus interrupts may be connected to any of the PCI Express
143 * leafs. Here we add the appropriate IGN to the interrupt
144 * mappings such that we can use it to distinguish between
145 * interrupts connected to PCIE-A and PCIE-B.
146 */
147 for (i = 0; i < sc->sc_nintmap; i++) {
148 for (j = 0; j < pyro_cd.cd_ndevs; j++) {
149 device_t dt = device_lookup(&pyro_cd, j);
150 psc = device_private(dt);
151 if (psc && psc->sc_node == sc->sc_intmap[i].cnode) {
152 sc->sc_intmap[i].cintr |= psc->sc_ign;
153 break;
154 }
155 }
156 }
157
158 error = prom_getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
159 &sc->sc_nrange, (void **)&sc->sc_range);
160 if (error)
161 panic("ebus ranges: error %d", error);
162
163 /*
164 * now attach all our children
165 */
166 DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
167 devhandle_t selfh = device_handle(self);
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 CFARGS(.devhandle = prom_node_to_devhandle(selfh,
179 node)));
180 }
181 ebus_destroy_attach_args(&eba);
182 }
183 }
184
185 static bus_space_tag_t
ebus_mainbus_alloc_bus_tag(struct ebus_softc * sc,bus_space_tag_t parent,int type)186 ebus_mainbus_alloc_bus_tag(struct ebus_softc *sc,
187 bus_space_tag_t parent,
188 int type)
189 {
190 struct sparc_bus_space_tag *bt;
191
192 bt = kmem_zalloc(sizeof(*bt), KM_SLEEP);
193 bt->cookie = sc;
194 bt->parent = parent;
195 bt->type = type;
196 bt->sparc_bus_map = ebus_mainbus_bus_map;
197 bt->sparc_bus_mmap = ebus_bus_mmap;
198 bt->sparc_intr_establish = ebus_mainbus_intr_establish;
199
200 return (bt);
201 }
202
203 int
ebus_mainbus_bus_map(bus_space_tag_t t,bus_addr_t offset,bus_size_t size,int flags,vaddr_t va,bus_space_handle_t * hp)204 ebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size,
205 int flags, vaddr_t va, bus_space_handle_t *hp)
206 {
207 struct ebus_softc *sc = t->cookie;
208 struct ebus_mainbus_ranges *range;
209 bus_addr_t hi, lo;
210 int i;
211 #if 0
212 int ss;
213 #endif
214
215 DPRINTF(EDB_BUSMAP,
216 ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
217 (unsigned long long)offset, (int)size, (int)flags));
218
219 if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
220 printf("\n_ebus_mainbus_bus_map: invalid parent");
221 return (EINVAL);
222 }
223
224 t = t->parent;
225
226 hi = offset >> 32UL;
227 lo = offset & 0xffffffff;
228 range = (struct ebus_mainbus_ranges *)sc->sc_range;
229
230 DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
231 for (i = 0; i < sc->sc_nrange; i++) {
232 bus_addr_t addr;
233
234 if (hi != range[i].child_hi)
235 continue;
236 if (lo < range[i].child_lo ||
237 (lo + size) > (range[i].child_lo + range[i].size))
238 continue;
239
240 #if 0
241 /* Isolate address space and find the right tag */
242 ss = (range[i].phys_hi>>24)&3;
243 switch (ss) {
244 case 1: /* I/O space */
245 t = sc->sc_iotag;
246 break;
247 case 2: /* Memory space */
248 t = sc->sc_memtag;
249 break;
250 case 0: /* Config space */
251 case 3: /* 64-bit Memory space */
252 default: /* WTF? */
253 /* We don't handle these */
254 panic("ebus_mainbus_bus_map: illegal space %x", ss);
255 break;
256 }
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 *
ebus_mainbus_intr_establish(bus_space_tag_t t,int ihandle,int level,int (* handler)(void *),void * arg,void (* fastvec)(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 intrhand *ih = NULL;
276 volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
277 u_int64_t *imap, *iclr;
278 int ino;
279
280 #if 0
281 XXX
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", ®, 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 ino = INTINO(ihandle);
333
334 struct pyro_softc *psc = NULL;
335 int i;
336
337 for (i = 0; i < pyro_cd.cd_ndevs; i++) {
338 device_t dt = device_lookup(&pyro_cd, i);
339 psc = device_private(dt);
340 if (psc && psc->sc_ign == INTIGN(ihandle)) {
341 break;
342 }
343 }
344 if (psc == NULL)
345 return (NULL);
346
347 imap = (uint64_t *)((uintptr_t)bus_space_vaddr(psc->sc_bustag, psc->sc_csrh) + 0x1000);
348 iclr = (uint64_t *)((uintptr_t)bus_space_vaddr(psc->sc_bustag, psc->sc_csrh) + 0x1400);
349 intrmapptr = &imap[ino];
350 intrclrptr = &iclr[ino];
351 ino |= INTVEC(ihandle);
352
353 ih = intrhand_alloc();
354
355 /* Register the map and clear intr registers */
356 ih->ih_map = intrmapptr;
357 ih->ih_clr = intrclrptr;
358
359 ih->ih_ivec = ihandle;
360 ih->ih_fun = handler;
361 ih->ih_arg = arg;
362 ih->ih_pil = level;
363 ih->ih_number = ino;
364 ih->ih_pending = 0;
365
366 intr_establish(ih->ih_pil, level != IPL_VM, ih);
367
368 if (intrmapptr != NULL) {
369 u_int64_t imapval;
370
371 imapval = *intrmapptr;
372 imapval |= (1LL << 6);
373 imapval |= INTMAP_V;
374 *intrmapptr = imapval;
375 imapval = *intrmapptr;
376 ih->ih_number |= imapval & INTMAP_INR;
377 }
378
379 return (ih);
380 }
381
382 #ifdef SUN4V
383 #if 0
384 XXX
385 static void
386 ebus_mainbus_intr_ack(struct intrhand *ih)
387 {
388 hv_intr_setstate(ih->ih_number, INTR_IDLE);
389 }
390 #endif
391 #endif
392