1 /* $OpenBSD: ebus_mainbus.c,v 1.13 2024/03/29 21:29:33 miod 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 const 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
ebus_mainbus_match(struct device * parent,void * match,void * aux)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
ebus_mainbus_attach(struct device * parent,struct device * self,void * aux)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, j;
91
92 printf("\n");
93
94 sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
95 sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
96 sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag);
97
98 sc->sc_node = node = ma->ma_node;
99
100 /*
101 * fill in our softc with information from the prom
102 */
103 sc->sc_intmap = NULL;
104 sc->sc_range = NULL;
105 error = getprop(node, "interrupt-map",
106 sizeof(struct ebus_interrupt_map),
107 &sc->sc_nintmap, (void **)&sc->sc_intmap);
108 switch (error) {
109 case 0:
110 immp = &sc->sc_intmapmask;
111 error = getprop(node, "interrupt-map-mask",
112 sizeof(struct ebus_interrupt_map_mask), &nmapmask,
113 (void **)&immp);
114 if (error)
115 panic("could not get ebus interrupt-map-mask");
116 if (nmapmask != 1)
117 panic("ebus interrupt-map-mask is broken");
118 break;
119 case ENOENT:
120 break;
121 default:
122 panic("ebus interrupt-map: error %d", error);
123 break;
124 }
125
126 /*
127 * Ebus interrupts may be connected to any of the PCI Express
128 * leafs. Here we add the appropriate IGN to the interrupt
129 * mappings such that we can use it to distinguish between
130 * interrupts connected to PCIE-A and PCIE-B.
131 */
132 for (i = 0; i < sc->sc_nintmap; i++) {
133 for (j = 0; j < pyro_cd.cd_ndevs; j++) {
134 psc = pyro_cd.cd_devs[j];
135 if (psc && psc->sc_node == sc->sc_intmap[i].cnode) {
136 sc->sc_intmap[i].cintr |= psc->sc_ign;
137 break;
138 }
139 }
140 }
141
142 error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
143 &sc->sc_nrange, (void **)&sc->sc_range);
144 if (error)
145 panic("ebus ranges: error %d", error);
146
147 /*
148 * now attach all our children
149 */
150 DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
151 for (node = firstchild(node); node; node = nextsibling(node)) {
152 if (ebus_setup_attach_args(sc, node, &eba) != 0) {
153 DPRINTF(EDB_CHILD,
154 ("ebus_mainbus_attach: %s: incomplete\n",
155 getpropstring(node, "name")));
156 continue;
157 } else {
158 DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
159 eba.ea_name));
160 (void)config_found(self, &eba, ebus_print);
161 }
162 ebus_destroy_attach_args(&eba);
163 }
164 }
165
166 bus_space_tag_t
ebus_alloc_bus_tag(struct ebus_softc * sc,bus_space_tag_t parent)167 ebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent)
168 {
169 struct sparc_bus_space_tag *bt;
170
171 bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
172 if (bt == NULL)
173 panic("could not allocate ebus bus tag");
174
175 strlcpy(bt->name, sc->sc_dev.dv_xname, sizeof(bt->name));
176 bt->cookie = sc;
177 bt->parent = parent;
178 bt->asi = parent->asi;
179 bt->sasi = parent->sasi;
180 bt->sparc_bus_map = ebus_mainbus_bus_map;
181 bt->sparc_intr_establish = ebus_mainbus_intr_establish;
182
183 return (bt);
184 }
185
186 int
ebus_mainbus_bus_map(bus_space_tag_t t,bus_space_tag_t t0,bus_addr_t offset,bus_size_t size,int flags,bus_space_handle_t * hp)187 ebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
188 bus_size_t size, int flags, bus_space_handle_t *hp)
189 {
190 struct ebus_softc *sc = t->cookie;
191 struct ebus_mainbus_ranges *range;
192 bus_addr_t hi, lo;
193 int i;
194
195 DPRINTF(EDB_BUSMAP,
196 ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
197 (unsigned long long)offset, (int)size, (int)flags));
198
199 if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
200 printf("\n_ebus_mainbus_bus_map: invalid parent");
201 return (EINVAL);
202 }
203
204 t = t->parent;
205
206 if (flags & BUS_SPACE_MAP_PROMADDRESS) {
207 return ((*t->sparc_bus_map)
208 (t, t0, offset, size, flags, hp));
209 }
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 addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
226 range[i].phys_lo;
227 addr += lo;
228 DPRINTF(EDB_BUSMAP,
229 ("\n_ebus_mainbus_bus_map: paddr offset %llx addr %llx\n",
230 (unsigned long long)offset, (unsigned long long)addr));
231 return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp));
232 }
233 DPRINTF(EDB_BUSMAP, (": FAILED\n"));
234 return (EINVAL);
235 }
236
237 void *
ebus_mainbus_intr_establish(bus_space_tag_t t,bus_space_tag_t t0,int ihandle,int level,int flags,int (* handler)(void *),void * arg,const char * what)238 ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
239 int level, int flags, int (*handler)(void *), void *arg, const char *what)
240 {
241 struct ebus_softc *sc = t->cookie;
242 struct intrhand *ih = NULL;
243 volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
244 int ino;
245
246 #ifdef SUN4V
247 if (CPU_ISSUN4V) {
248 struct upa_reg reg;
249 u_int64_t devhandle, devino = INTINO(ihandle);
250 u_int64_t sysino;
251 int node = -1;
252 int i, err;
253
254 for (i = 0; i < sc->sc_nintmap; i++) {
255 if (sc->sc_intmap[i].cintr == ihandle) {
256 node = sc->sc_intmap[i].cnode;
257 break;
258 }
259 }
260 if (node == -1)
261 return (NULL);
262
263 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg))
264 return (NULL);
265 devhandle = (reg.ur_paddr >> 32) & 0x0fffffff;
266
267 err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
268 if (err != H_EOK)
269 return (NULL);
270
271 KASSERT(sysino == INTVEC(sysino));
272 ih = bus_intr_allocate(t0, handler, arg, sysino, level,
273 NULL, NULL, what);
274 if (ih == NULL)
275 return (NULL);
276
277 intr_establish(ih);
278 ih->ih_ack = ebus_mainbus_intr_ack;
279
280 err = hv_intr_settarget(sysino, ih->ih_cpu->ci_upaid);
281 if (err != H_EOK)
282 return (NULL);
283
284 /* Clear pending interrupts. */
285 err = hv_intr_setstate(sysino, INTR_IDLE);
286 if (err != H_EOK)
287 return (NULL);
288
289 err = hv_intr_setenabled(sysino, INTR_ENABLED);
290 if (err != H_EOK)
291 return (NULL);
292
293 return (ih);
294 }
295 #endif
296
297 ino = INTINO(ihandle);
298
299 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
300 struct pyro_softc *psc = NULL;
301 u_int64_t *imap, *iclr;
302 int i;
303
304 for (i = 0; i < pyro_cd.cd_ndevs; i++) {
305 psc = pyro_cd.cd_devs[i];
306 if (psc && psc->sc_ign == INTIGN(ihandle)) {
307 break;
308 }
309 }
310 if (psc == NULL)
311 return (NULL);
312
313 imap = bus_space_vaddr(psc->sc_bust, psc->sc_csrh) + 0x1000;
314 iclr = bus_space_vaddr(psc->sc_bust, psc->sc_csrh) + 0x1400;
315 intrmapptr = &imap[ino];
316 intrclrptr = &iclr[ino];
317 ino |= INTVEC(ihandle);
318 }
319
320 ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
321 intrclrptr, what);
322 if (ih == NULL)
323 return (NULL);
324
325 intr_establish(ih);
326
327 if (intrmapptr != NULL) {
328 u_int64_t intrmap;
329
330 intrmap = *intrmapptr;
331 intrmap |= (1LL << 6);
332 intrmap |= INTMAP_V;
333 *intrmapptr = intrmap;
334 intrmap = *intrmapptr;
335 ih->ih_number |= intrmap & INTMAP_INR;
336 }
337
338 return (ih);
339 }
340
341 #ifdef SUN4V
342
343 void
ebus_mainbus_intr_ack(struct intrhand * ih)344 ebus_mainbus_intr_ack(struct intrhand *ih)
345 {
346 hv_intr_setstate(ih->ih_number, INTR_IDLE);
347 }
348
349 #endif
350