1 /* $NetBSD: ebus.c,v 1.52 2008/05/29 14:51:26 mrg Exp $ */
4 * Copyright (c) 1999, 2000, 2001 Matthew R. Green
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ebus.c,v 1.52 2008/05/29 14:51:26 mrg Exp $");
35 * UltraSPARC 5 and beyond ebus support.
37 * note that this driver is not complete:
38 * - interrupt establish is written and appears to work
39 * - bus map code is written and appears to work
40 * - ebus2 DMA code is completely unwritten, we just punt to
46 #define EDB_CHILD 0x02
47 #define EDB_INTRMAP 0x04
48 #define EDB_BUSMAP 0x08
50 #define DPRINTF(l, s) do { if (ebus_debug & l) printf s; } while (0)
55 #include <sys/param.h>
57 #include <sys/device.h>
58 #include <sys/errno.h>
59 #include <sys/extent.h>
60 #include <sys/malloc.h>
61 #include <sys/systm.h>
64 #define _SPARC_BUS_DMA_PRIVATE
65 #include <machine/bus.h>
66 #include <machine/autoconf.h>
67 #include <machine/openfirm.h>
69 #include <dev/pci/pcivar.h>
70 #include <dev/pci/pcireg.h>
71 #include <dev/pci/pcidevs.h>
73 #include <sparc64/dev/iommureg.h>
74 #include <sparc64/dev/iommuvar.h>
75 #include <sparc64/dev/psychoreg.h>
76 #include <sparc64/dev/psychovar.h>
77 #include <dev/ebus/ebusreg.h>
78 #include <dev/ebus/ebusvar.h>
85 bus_space_tag_t sc_memtag
; /* from pci */
86 bus_space_tag_t sc_iotag
; /* from pci */
87 bus_space_tag_t sc_childbustag
; /* pass to children */
88 bus_dma_tag_t sc_dmatag
;
90 struct ebus_ranges
*sc_range
;
91 struct ebus_interrupt_map
*sc_intmap
;
92 struct ebus_interrupt_map_mask sc_intmapmask
;
94 int sc_nrange
; /* counters */
98 int ebus_match(struct device
*, struct cfdata
*, void *);
99 void ebus_attach(struct device
*, struct device
*, void *);
101 CFATTACH_DECL(ebus
, sizeof(struct ebus_softc
),
102 ebus_match
, ebus_attach
, NULL
, NULL
);
104 bus_space_tag_t
ebus_alloc_bus_tag(struct ebus_softc
*, int);
106 int ebus_setup_attach_args(struct ebus_softc
*, int,
107 struct ebus_attach_args
*);
108 void ebus_destroy_attach_args(struct ebus_attach_args
*);
109 int ebus_print(void *, const char *);
110 void ebus_find_ino(struct ebus_softc
*, struct ebus_attach_args
*);
113 * here are our bus space and bus DMA routines.
115 static paddr_t
ebus_bus_mmap(bus_space_tag_t
, bus_addr_t
, off_t
, int, int);
116 static int _ebus_bus_map(bus_space_tag_t
, bus_addr_t
, bus_size_t
, int, vaddr_t
,
117 bus_space_handle_t
*);
118 static void *ebus_intr_establish(bus_space_tag_t
, int, int, int (*)(void *),
119 void *, void(*)(void));
122 ebus_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
124 struct pci_attach_args
*pa
= aux
;
128 /* Only attach if there's a PROM node. */
129 node
= PCITAG_NODE(pa
->pa_tag
);
133 if (PCI_CLASS(pa
->pa_class
) != PCI_CLASS_BRIDGE
)
136 /* Match a real ebus */
137 name
= prom_getpropstring(node
, "name");
138 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SUN
&&
139 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_SUN_EBUS
&&
140 strcmp(name
, "ebus") == 0)
143 /* Or a real ebus III */
144 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SUN
&&
145 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_SUN_EBUSIII
&&
146 strcmp(name
, "ebus") == 0)
149 /* Or a PCI-ISA bridge XXX I hope this is on-board. */
150 if (PCI_SUBCLASS(pa
->pa_class
) == PCI_SUBCLASS_BRIDGE_ISA
) {
158 * attach an ebus and all it's children. this code is modeled
159 * after the sbus code which does similar things.
162 ebus_attach(struct device
*parent
, struct device
*self
, void *aux
)
164 struct ebus_softc
*sc
= (struct ebus_softc
*)self
;
165 struct pci_attach_args
*pa
= aux
;
166 struct ebus_attach_args eba
;
167 struct ebus_interrupt_map_mask
*immp
;
168 int node
, nmapmask
, error
;
173 pci_devinfo(pa
->pa_id
, pa
->pa_class
, 0, devinfo
, sizeof(devinfo
));
174 printf("%s: %s, revision 0x%02x\n", device_xname(self
), devinfo
,
175 PCI_REVISION(pa
->pa_class
));
177 sc
->sc_memtag
= pa
->pa_memt
;
178 sc
->sc_iotag
= pa
->pa_iot
;
179 sc
->sc_childbustag
= ebus_alloc_bus_tag(sc
, PCI_MEMORY_BUS_SPACE
);
180 sc
->sc_dmatag
= pa
->pa_dmat
;
182 node
= PCITAG_NODE(pa
->pa_tag
);
184 panic("could not find ebus node");
189 * fill in our softc with information from the prom
191 sc
->sc_intmap
= NULL
;
194 error
= prom_getprop(node
, "interrupt-map",
195 sizeof(struct ebus_interrupt_map
),
196 &sc
->sc_nintmap
, &sc
->sc_intmap
);
199 immp
= &sc
->sc_intmapmask
;
200 nmapmask
= sizeof(*immp
);
201 error
= prom_getprop(node
, "interrupt-map-mask",
202 sizeof(struct ebus_interrupt_map_mask
), &nmapmask
,
205 panic("could not get ebus interrupt-map-mask, error %d",
208 panic("ebus interrupt-map-mask is broken");
213 panic("ebus interrupt-map: error %d", error
);
217 error
= prom_getprop(node
, "ranges", sizeof(struct ebus_ranges
),
218 &sc
->sc_nrange
, &sc
->sc_range
);
220 panic("ebus ranges: error %d", error
);
223 * now attach all our children
225 DPRINTF(EDB_CHILD
, ("ebus node %08x, searching children...\n", node
));
226 for (node
= firstchild(node
); node
; node
= nextsibling(node
)) {
227 char *name
= prom_getpropstring(node
, "name");
229 if (ebus_setup_attach_args(sc
, node
, &eba
) != 0) {
230 printf("ebus_attach: %s: incomplete\n", name
);
233 DPRINTF(EDB_CHILD
, ("- found child `%s', attaching\n",
235 (void)config_found(self
, &eba
, ebus_print
);
237 ebus_destroy_attach_args(&eba
);
241 int ebus_setup_attach_args(struct ebus_softc
*, int,
242 struct ebus_attach_args
*);
244 ebus_setup_attach_args(struct ebus_softc
*sc
, int node
,
245 struct ebus_attach_args
*ea
)
249 memset(ea
, 0, sizeof(struct ebus_attach_args
));
251 rv
= prom_getprop(node
, "name", 1, &n
, &ea
->ea_name
);
254 ea
->ea_name
[n
] = '\0';
257 ea
->ea_bustag
= sc
->sc_childbustag
;
258 ea
->ea_dmatag
= sc
->sc_dmatag
;
260 rv
= prom_getprop(node
, "reg", sizeof(struct ebus_regs
), &ea
->ea_nreg
,
265 rv
= prom_getprop(node
, "address", sizeof(uint32_t), &ea
->ea_nvaddr
,
271 if (ea
->ea_nreg
!= ea
->ea_nvaddr
)
272 printf("ebus loses: device %s: %d regs and %d addrs\n",
273 ea
->ea_name
, ea
->ea_nreg
, ea
->ea_nvaddr
);
277 if (prom_getprop(node
, "interrupts", sizeof(uint32_t), &ea
->ea_nintr
,
281 ebus_find_ino(sc
, ea
);
287 ebus_destroy_attach_args(struct ebus_attach_args
*ea
)
291 free((void *)ea
->ea_name
, M_DEVBUF
);
293 free((void *)ea
->ea_reg
, M_DEVBUF
);
295 free((void *)ea
->ea_intr
, M_DEVBUF
);
297 free((void *)ea
->ea_vaddr
, M_DEVBUF
);
301 ebus_print(void *aux
, const char *p
)
303 struct ebus_attach_args
*ea
= aux
;
307 aprint_normal("%s at %s", ea
->ea_name
, p
);
308 for (i
= 0; i
< ea
->ea_nreg
; i
++)
309 aprint_normal("%s %x-%x", i
== 0 ? " addr" : ",",
311 ea
->ea_reg
[i
].lo
+ ea
->ea_reg
[i
].size
- 1);
312 for (i
= 0; i
< ea
->ea_nintr
; i
++)
313 aprint_normal(" ipl %d", ea
->ea_intr
[i
]);
319 * find the INO values for each interrupt and fill them in.
321 * for each "reg" property of this device, mask it's hi and lo
322 * values with the "interrupt-map-mask"'s hi/lo values, and also
323 * mask the interrupt number with the interrupt mask. search the
324 * "interrupt-map" list for matching values of hi, lo and interrupt
325 * to give the INO for this interrupt.
328 ebus_find_ino(struct ebus_softc
*sc
, struct ebus_attach_args
*ea
)
330 uint32_t hi
, lo
, intr
;
333 if (sc
->sc_nintmap
== 0) {
334 for (i
= 0; i
< ea
->ea_nintr
; i
++) {
335 OF_mapintr(ea
->ea_node
, &ea
->ea_intr
[i
],
336 sizeof(ea
->ea_intr
[0]),
337 sizeof(ea
->ea_intr
[0]));
343 ("ebus_find_ino: searching %d interrupts", ea
->ea_nintr
));
345 for (j
= 0; j
< ea
->ea_nintr
; j
++) {
347 intr
= ea
->ea_intr
[j
] & sc
->sc_intmapmask
.intr
;
350 ("; intr %x masked to %x", ea
->ea_intr
[j
], intr
));
351 for (i
= 0; i
< ea
->ea_nreg
; i
++) {
352 hi
= ea
->ea_reg
[i
].hi
& sc
->sc_intmapmask
.hi
;
353 lo
= ea
->ea_reg
[i
].lo
& sc
->sc_intmapmask
.lo
;
356 ("; reg hi.lo %08x.%08x masked to %08x.%08x",
357 ea
->ea_reg
[i
].hi
, ea
->ea_reg
[i
].lo
, hi
, lo
));
358 for (k
= 0; k
< sc
->sc_nintmap
; k
++) {
360 ("; checking hi.lo %08x.%08x intr %x",
361 sc
->sc_intmap
[k
].hi
, sc
->sc_intmap
[k
].lo
,
362 sc
->sc_intmap
[k
].intr
));
363 if (hi
== sc
->sc_intmap
[k
].hi
&&
364 lo
== sc
->sc_intmap
[k
].lo
&&
365 intr
== sc
->sc_intmap
[k
].intr
) {
367 sc
->sc_intmap
[k
].cintr
;
369 ("; FOUND IT! changing to %d\n",
370 sc
->sc_intmap
[k
].cintr
));
380 * bus space support. <sparc64/dev/psychoreg.h> has a discussion
381 * about PCI physical addresses, which also applies to ebus.
384 ebus_alloc_bus_tag(struct ebus_softc
*sc
, int type
)
388 bt
= (bus_space_tag_t
)
389 malloc(sizeof(struct sparc_bus_space_tag
), M_DEVBUF
, M_NOWAIT
);
391 panic("could not allocate ebus bus tag");
393 memset(bt
, 0, sizeof *bt
);
395 bt
->parent
= sc
->sc_memtag
;
397 bt
->sparc_bus_map
= _ebus_bus_map
;
398 bt
->sparc_bus_mmap
= ebus_bus_mmap
;
399 bt
->sparc_intr_establish
= ebus_intr_establish
;
404 _ebus_bus_map(bus_space_tag_t t
, bus_addr_t ba
, bus_size_t size
, int flags
,
405 vaddr_t va
, bus_space_handle_t
*hp
)
407 struct ebus_softc
*sc
= t
->cookie
;
412 bar
= BUS_ADDR_IOSPACE(ba
);
413 offset
= BUS_ADDR_PADDR(ba
);
416 ("\n_ebus_bus_map: bar %d offset %08x sz %x flags %x va %p\n",
417 (int)bar
, (uint32_t)offset
, (uint32_t)size
,
420 for (i
= 0; i
< sc
->sc_nrange
; i
++) {
423 if (bar
!= sc
->sc_range
[i
].child_hi
)
425 if (offset
< sc
->sc_range
[i
].child_lo
||
427 (sc
->sc_range
[i
].child_lo
+ sc
->sc_range
[i
].size
))
430 /* Isolate address space and find the right tag */
431 ss
= (sc
->sc_range
[i
].phys_hi
>>24)&3;
433 case 1: /* I/O space */
436 case 2: /* Memory space */
439 case 0: /* Config space */
440 case 3: /* 64-bit Memory space */
442 /* We don't handle these */
443 panic("_ebus_bus_map: illegal space %x", ss
);
446 pciaddr
= ((bus_addr_t
)sc
->sc_range
[i
].phys_mid
<< 32UL) |
447 sc
->sc_range
[i
].phys_lo
;
451 ("_ebus_bus_map: mapping to PCI addr %x\n",
454 /* pass it onto the psycho */
455 return (bus_space_map(t
, pciaddr
, size
, flags
, hp
));
457 DPRINTF(EDB_BUSMAP
, (": FAILED\n"));
462 ebus_bus_mmap(bus_space_tag_t t
, bus_addr_t paddr
, off_t off
, int prot
,
465 bus_addr_t offset
= paddr
;
466 struct ebus_softc
*sc
= t
->cookie
;
469 for (i
= 0; i
< sc
->sc_nrange
; i
++) {
471 ((bus_addr_t
)sc
->sc_range
[i
].child_hi
<< 32) |
472 sc
->sc_range
[i
].child_lo
;
474 if (offset
!= paddr1
)
477 DPRINTF(EDB_BUSMAP
, ("\n_ebus_bus_mmap: mapping paddr %qx\n",
478 (unsigned long long)paddr1
));
479 return (bus_space_mmap(sc
->sc_memtag
, paddr1
, off
,
487 * install an interrupt handler for a ebus device
490 ebus_intr_establish(bus_space_tag_t t
, int pri
, int level
,
491 int (*handler
)(void *), void *arg
, void (*fastvec
)(void) /* ignored */)
494 return (bus_intr_establish(t
->parent
, pri
, level
, handler
, arg
));