diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/files.sparc64 | 5 | ||||
-rw-r--r-- | sys/conf/options.sparc64 | 1 | ||||
-rw-r--r-- | sys/sparc64/ebus/ebus.c | 37 | ||||
-rw-r--r-- | sys/sparc64/include/ofw_bus.h | 27 | ||||
-rw-r--r-- | sys/sparc64/isa/isa.c | 62 | ||||
-rw-r--r-- | sys/sparc64/isa/ofw_isa.c | 33 | ||||
-rw-r--r-- | sys/sparc64/isa/ofw_isa.h | 18 | ||||
-rw-r--r-- | sys/sparc64/pci/apb.c | 182 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pci.c | 37 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pci.h | 31 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pci_if.m | 76 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pcib.c | 122 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pcib_subr.c | 134 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pcib_subr.h | 49 | ||||
-rw-r--r-- | sys/sparc64/pci/ofw_pcibus.c | 264 | ||||
-rw-r--r-- | sys/sparc64/pci/psycho.c | 228 | ||||
-rw-r--r-- | sys/sparc64/pci/psychovar.h | 7 | ||||
-rw-r--r-- | sys/sparc64/sparc64/ofw_bus.c | 126 | ||||
-rw-r--r-- | sys/sparc64/sparc64/sparcbus_if.m | 93 |
19 files changed, 1160 insertions, 372 deletions
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64 index 107312f..1f76310 100644 --- a/sys/conf/files.sparc64 +++ b/sys/conf/files.sparc64 @@ -34,6 +34,10 @@ sparc64/isa/ofw_isa.c optional ebus sparc64/isa/ofw_isa.c optional isa sparc64/pci/apb.c optional apb sparc64/pci/ofw_pci.c optional pci +sparc64/pci/ofw_pcib.c optional pci ofw_newpci +sparc64/pci/ofw_pcib_subr.c optional pci ofw_newpci +sparc64/pci/ofw_pcibus.c optional pci ofw_newpci +sparc64/pci/ofw_pci_if.m optional pci sparc64/pci/psycho.c optional pci sparc64/sbus/sbus.c optional sbus sparc64/sparc64/autoconf.c standard @@ -71,7 +75,6 @@ sparc64/sparc64/ofw_machdep.c standard sparc64/sparc64/pmap.c standard sparc64/sparc64/prof_machdep.c optional profiling-routine sparc64/sparc64/rwindow.c standard -sparc64/sparc64/sparcbus_if.m standard sparc64/sparc64/spitfire.c standard sparc64/sparc64/support.S standard sparc64/sparc64/sys_machdep.c standard diff --git a/sys/conf/options.sparc64 b/sys/conf/options.sparc64 index d0893b7..5bd885a 100644 --- a/sys/conf/options.sparc64 +++ b/sys/conf/options.sparc64 @@ -6,6 +6,7 @@ EBUS_DEBUG opt_ebus.h PSYCHO_DEBUG opt_psycho.h DEBUGGER_ON_POWERFAIL opt_psycho.h OFW_PCI_DEBUG opt_ofw_pci.h +OFW_NEWPCI opt_ofw_pci.h # Normal IOMMU debugging IOMMU_DEBUG opt_iommu.h # Debug IOMMU inserts/removes using diagnostic accesses. Very loud. diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c index 6c71e02..575ba0a 100644 --- a/sys/sparc64/ebus/ebus.c +++ b/sys/sparc64/ebus/ebus.c @@ -48,6 +48,8 @@ * there are machines with both ISA and EBus. */ +#include "opt_ofw_pci.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -101,6 +103,10 @@ struct ebus_softc { int sc_nrange; int sc_nimap; + +#ifdef OFW_NEWPCI + struct ofw_bus_iinfo sc_iinfo; +#endif }; static int ebus_probe(device_t); @@ -159,12 +165,12 @@ ebus_probe(device_t dev) phandle_t node; char *cname; - /* - * XXX: PCI specific! There should be a common cookie IVAR value for all - * buses! Does not really matter much here though... - */ +#ifdef OFW_NEWPCI + node = ofw_pci_get_node(dev); +#else node = ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); +#endif if (node == 0) return (ENXIO); @@ -192,8 +198,12 @@ ebus_probe(device_t dev) if (sc->sc_nrange == -1) panic("ebus_attach: could not get ranges property"); +#ifdef OFW_NEWPCI + ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t)); +#endif + /* - * now attach all our children + * Now attach our children. */ DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node)); for (node = OF_child(node); node > 0; node = OF_peer(node)) { @@ -368,7 +378,8 @@ ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node, { struct ebus_devinfo *edi; struct isa_regs *reg; - u_int32_t *intrs, intr; + ofw_isa_intr_t *intrs; + ofw_pci_intr_t rintr; u_int64_t start; int nreg, nintr, i; @@ -395,20 +406,26 @@ ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node, resource_list_add(&edi->edi_rl, SYS_RES_IOPORT, i, start, start + reg[i].size - 1, reg[i].size); } + free(reg, M_OFWPROP); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); for (i = 0; i < nintr; i++) { - intr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback, +#ifdef OFW_NEWPCI + rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo, intrs[i]); + if (rintr == PCI_INVALID_IRQ) { +#else + rintr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback, dev); - if (intr == ORIR_NOTFOUND) { + if (rintr == ORIR_NOTFOUND) { +#endif panic("ebus_setup_dinfo: could not map ebus " "interrupt %d", intrs[i]); } resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i, - intr, intr, 1); + rintr, rintr, 1); } - free(reg, M_OFWPROP); + free(intrs, M_OFWPROP); return (edi); } diff --git a/sys/sparc64/include/ofw_bus.h b/sys/sparc64/include/ofw_bus.h index 9f07183..f720180 100644 --- a/sys/sparc64/include/ofw_bus.h +++ b/sys/sparc64/include/ofw_bus.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. + * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,9 +31,34 @@ #define ORIP_NOINT -1 #define ORIR_NOTFOUND 0xffffffff +/* + * Other than in OpenFirmware calls, the size of a bus cell seems to be always + * the same. + */ +typedef u_int32_t pcell_t; + +#ifdef OFW_NEWPCI + +struct ofw_bus_iinfo { + u_int8_t *opi_imap; + u_int8_t *opi_imapmsk; + int opi_imapsz; + pcell_t opi_addrc; +}; + +void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int); +int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int, + void *, int, void *, int, void *); +int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, + void *, void *, int); + +#else + typedef int obr_callback_t(phandle_t, u_int8_t *, int, u_int8_t *, int, u_int8_t **, int *, void *); u_int32_t ofw_bus_route_intr(phandle_t, int, obr_callback_t *, void *); +#endif + #endif /* !_MACHINE_OFW_BUS_H_ */ diff --git a/sys/sparc64/isa/isa.c b/sys/sparc64/isa/isa.c index 2df0257d..4916b1e 100644 --- a/sys/sparc64/isa/isa.c +++ b/sys/sparc64/isa/isa.c @@ -29,6 +29,8 @@ * $FreeBSD$ */ +#include "opt_ofw_pci.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -57,8 +59,6 @@ #include <sparc64/pci/ofw_pci.h> #include <sparc64/isa/ofw_isa.h> -#include "sparcbus_if.h" - /* There can be only one ISA bus, so it is safe to use globals. */ bus_space_tag_t isa_io_bt = NULL; bus_space_handle_t isa_io_hdl; @@ -73,7 +73,11 @@ u_int64_t isa_mem_limit; device_t isa_bus_device; static phandle_t isab_node; -static u_int32_t isa_ino[8]; +static ofw_pci_intr_t isa_ino[8]; + +#ifdef OFW_NEWPCI +struct ofw_bus_iinfo isa_iinfo; +#endif /* * XXX: This is really partly partly PCI-specific, but unfortunately is @@ -98,9 +102,9 @@ isa_irq_pending(void) /* XXX: Is this correct? */ for (i = 7, pending = 0; i >= 0; i--) { - pending <<= 1; - if (isa_ino[i] != ORIR_NOTFOUND) { - pending |= (SPARCBUS_INTR_PENDING(isa_bus_device, + pending <<= 1; + if (isa_ino[i] != PCI_INVALID_IRQ) { + pending |= (OFW_PCI_INTR_PENDING(isa_bus_device, isa_ino[i]) == 0) ? 0 : 1; } } @@ -112,29 +116,47 @@ isa_init(device_t dev) { device_t bridge; phandle_t node; - u_int32_t ino; + ofw_isa_intr_t ino; +#ifndef OFW_NEWPCI + ofw_pci_intr_t rino; +#endif struct isa_ranges *br; int nbr, i; /* The parent of the bus must be a PCI-ISA bridge. */ bridge = device_get_parent(dev); +#ifdef OFW_NEWPCI + isab_node = ofw_pci_get_node(bridge); +#else isab_node = ofw_pci_node(bridge); +#endif nbr = OF_getprop_alloc(isab_node, "ranges", sizeof(*br), (void **)&br); if (nbr <= 0) panic("isa_init: cannot get bridge range property"); + +#ifdef OFW_NEWPCI + ofw_bus_setup_iinfo(isab_node, &isa_iinfo, sizeof(ofw_isa_intr_t)); +#endif + /* - * This is really a bad kluge; however, it is needed to provide - * isa_irq_pending(). + * This is really a bad kludge; however, it is needed to provide + * isa_irq_pending(), which is unfortunately still used by some + * drivers. */ for (i = 0; i < 8; i++) - isa_ino[i] = ORIR_NOTFOUND; + isa_ino[i] = PCI_INVALID_IRQ; for (node = OF_child(isab_node); node != 0; node = OF_peer(node)) { if (OF_getprop(node, "interrupts", &ino, sizeof(ino)) == -1) continue; if (ino > 7) panic("isa_init: XXX: ino too large"); - isa_ino[ino] = ofw_bus_route_intr(node, ino, - ofw_pci_orb_callback, dev); +#ifdef OFW_NEWPCI + isa_ino[ino] = ofw_isa_route_intr(bridge, node, &isa_iinfo, + ino); +#else + rino = ofw_bus_route_intr(node, ino, ofw_pci_orb_callback, dev); + isa_ino[ino] = rino == ORIR_NOTFOUND ? PCI_INVALID_IRQ : rino; +#endif } for (nbr -= 1; nbr >= 0; nbr--) { @@ -143,15 +165,15 @@ isa_init(device_t dev) /* This is probably always 0. */ isa_io_base = ISAB_RANGE_PHYS(&br[nbr]); isa_io_limit = br[nbr].size; - isa_io_hdl = SPARCBUS_GET_BUS_HANDLE(bridge, SBBT_IO, - isa_io_base, &isa_io_bt); + isa_io_hdl = OFW_PCI_GET_BUS_HANDLE(bridge, + SYS_RES_IOPORT, isa_io_base, &isa_io_bt); break; case ISAR_SPACE_MEM: /* This is probably always 0. */ isa_mem_base = ISAB_RANGE_PHYS(&br[nbr]); isa_mem_limit = br[nbr].size; - isa_mem_hdl = SPARCBUS_GET_BUS_HANDLE(bridge, SBBT_MEM, - isa_mem_base, &isa_mem_bt); + isa_mem_hdl = OFW_PCI_GET_BUS_HANDLE(bridge, + SYS_RES_MEMORY, isa_mem_base, &isa_mem_bt); break; } } @@ -170,7 +192,7 @@ isa_route_intr_res(device_t bus, u_long start, u_long end) if (start > 7) panic("isa_route_intr_res: start out of isa range"); res = isa_ino[start]; - if (res == ORIR_NOTFOUND) + if (res == PCI_INVALID_IRQ) device_printf(bus, "could not map interrupt %d\n", res); return (res); } @@ -244,7 +266,7 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, "irq allocation"); if (!isdefault) { start = end = isa_route_intr_res(bus, start, end); - if (start == 255) + if (start == PCI_INVALID_IRQ) return (NULL); } break; @@ -255,7 +277,7 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, start = ulmin(start + base, limit); end = ulmin(end + base, limit); } - + /* * This inlines a modified resource_list_alloc(); this is needed * because the resources need to have offsets added to them, which @@ -289,7 +311,7 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, break; case SYS_RES_IRQ: start = end = isa_route_intr_res(bus, start, end); - if (start == 255) + if (start == PCI_INVALID_IRQ) return (NULL); break; } diff --git a/sys/sparc64/isa/ofw_isa.c b/sys/sparc64/isa/ofw_isa.c index a87665e..986220d 100644 --- a/sys/sparc64/isa/ofw_isa.c +++ b/sys/sparc64/isa/ofw_isa.c @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2000 Matthew R. Green - * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org> + * Copyright (c) 2001, 2003 Thomas Moestl <tmm@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,6 +35,8 @@ * Helper functions which can be used in both ISA and EBus code. */ +#include "opt_ofw_pci.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -42,11 +44,14 @@ #include <ofw/openfirm.h> #include <ofw/ofw_pci.h> +#include <machine/bus.h> #include <machine/resource.h> #include <machine/ofw_bus.h> -#include <sparc64/isa/ofw_isa.h> #include <sparc64/pci/ofw_pci.h> +#include <sparc64/isa/ofw_isa.h> + +#include "pcib_if.h" /* XXX: this only supports PCI as parent bus right now. */ int @@ -86,3 +91,27 @@ ofw_isa_map_iorange(struct isa_ranges *range, int nrange, u_long *start, panic("ofw_isa_map_iorange: could not map range %#lx - %#lx", *start, *end); } + +#ifdef OFW_NEWPCI +ofw_pci_intr_t +ofw_isa_route_intr(device_t bridge, phandle_t node, struct ofw_bus_iinfo *ii, + ofw_isa_intr_t intr) +{ + struct isa_regs reg; + u_int8_t maskbuf[sizeof(reg) + sizeof(intr)]; + device_t pbridge; + ofw_isa_intr_t mintr; + + pbridge = device_get_parent(device_get_parent(bridge)); + /* + * If we get a match from using the map, the resulting INO is + * fully specified, so we may not continue to map. + */ + if (!ofw_bus_lookup_imap(node, ii, ®, sizeof(reg), + &intr, sizeof(intr), &mintr, sizeof(mintr), maskbuf)) { + /* Try routing at the parent bridge. */ + mintr = PCIB_ROUTE_INTERRUPT(pbridge, bridge, intr); + } + return (mintr); +} +#endif /* OFW_NEWPCI */ diff --git a/sys/sparc64/isa/ofw_isa.h b/sys/sparc64/isa/ofw_isa.h index 9402657..dd534ad 100644 --- a/sys/sparc64/isa/ofw_isa.h +++ b/sys/sparc64/isa/ofw_isa.h @@ -60,24 +60,28 @@ struct isa_ranges { ((((u_int64_t)((r)->child_hi)) << 32) | ((u_int64_t)(r)->child_lo)) #define ISA_RANGE_PS(r) (((r)->phys_hi >> 24) & 0x03) +typedef u_int32_t ofw_isa_intr_t; + struct isa_imap { u_int32_t phys_hi; /* high phys addr mask */ u_int32_t phys_lo; /* low phys addr mask */ - u_int32_t intr; /* interrupt mask */ - int32_t cnode; /* child node */ - u_int32_t cintr; /* child interrupt */ + ofw_isa_intr_t intr; /* interrupt mask */ + phandle_t cnode; /* child node */ + ofw_pci_intr_t cintr; /* child interrupt */ }; struct isa_imap_msk { u_int32_t phys_hi; /* high phys addr */ u_int32_t phys_lo; /* low phys addr */ - u_int32_t intr; /* interrupt */ + ofw_isa_intr_t intr; /* interrupt */ }; -/* Map an interrupt property to an INO */ -int ofw_isa_map_intr(struct isa_imap *, int, struct isa_imap_msk *, int, - struct isa_regs *, int); /* Map an IO range. Returns the resource type of the range. */ int ofw_isa_map_iorange(struct isa_ranges *, int, u_long *, u_long *); +#ifdef OFW_NEWPCI +ofw_pci_intr_t ofw_isa_route_intr(device_t, phandle_t, struct ofw_bus_iinfo *, + ofw_isa_intr_t); +#endif + #endif /* !_SPARC64_ISA_OFW_ISA_H_ */ diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c index 4e8b746..49324b2 100644 --- a/sys/sparc64/pci/apb.c +++ b/sys/sparc64/pci/apb.c @@ -2,7 +2,7 @@ * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> * Copyright (c) 2000 BSDi - * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org> + * Copyright (c) 2001, 2003 Thomas Moestl <tmm@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,8 @@ * We can use some pf the pcib methods anyway. */ +#include "opt_ofw_pci.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -49,40 +51,34 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_pci.h> +#include <machine/bus.h> +#include <machine/ofw_bus.h> #include <machine/resource.h> -#include <sparc64/pci/ofw_pci.h> - -#include <pci/pcivar.h> #include <pci/pcireg.h> +#include <pci/pcivar.h> +#include <pci/pcib_private.h> #include "pcib_if.h" +#include <sparc64/pci/ofw_pci.h> +#include <sparc64/pci/ofw_pcib_subr.h> + /* * Bridge-specific data. */ struct apb_softc { - device_t dev; - u_int8_t secbus; /* secondary bus number */ - u_int8_t subbus; /* subordinate bus number */ - u_int8_t iomap; - u_int8_t memmap; + struct ofw_pcib_gen_softc sc_bsc; + u_int8_t sc_iomap; + u_int8_t sc_memmap; }; -static int apb_probe(device_t dev); -static int apb_attach(device_t dev); -static struct resource *apb_alloc_resource(device_t dev, device_t child, - int type, int *rid, u_long start, u_long end, u_long count, u_int flags); -static int apb_read_ivar(device_t dev, device_t child, int which, - uintptr_t *result); -static int apb_write_ivar(device_t dev, device_t child, int which, - uintptr_t value); -static int apb_maxslots(device_t dev); -static u_int32_t apb_read_config(device_t dev, int b, int s, int f, int reg, - int width); -static void apb_write_config(device_t dev, int b, int s, int f, int reg, - u_int32_t val, int width); -static int apb_route_interrupt(device_t pcib, device_t dev, int pin); +static device_probe_t apb_probe; +static device_attach_t apb_attach; +static bus_alloc_resource_t apb_alloc_resource; +#ifndef OFW_NEWPCI +static pcib_route_interrupt_t apb_route_interrupt; +#endif static device_method_t apb_methods[] = { /* Device interface */ @@ -94,8 +90,8 @@ static device_method_t apb_methods[] = { /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, apb_read_ivar), - DEVMETHOD(bus_write_ivar, apb_write_ivar), + DEVMETHOD(bus_read_ivar, pcib_read_ivar), + DEVMETHOD(bus_write_ivar, pcib_write_ivar), DEVMETHOD(bus_alloc_resource, apb_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), @@ -104,10 +100,20 @@ static device_method_t apb_methods[] = { DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ - DEVMETHOD(pcib_maxslots, apb_maxslots), - DEVMETHOD(pcib_read_config, apb_read_config), - DEVMETHOD(pcib_write_config, apb_write_config), + DEVMETHOD(pcib_maxslots, pcib_maxslots), + DEVMETHOD(pcib_read_config, pcib_read_config), + DEVMETHOD(pcib_write_config, pcib_write_config), +#ifdef OFW_NEWPCI + DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt), +#else DEVMETHOD(pcib_route_interrupt, apb_route_interrupt), +#endif + + /* ofw_pci interface */ +#ifdef OFW_NEWPCI + DEVMETHOD(ofw_pci_get_node, ofw_pcib_gen_get_node), + DEVMETHOD(ofw_pci_adjust_busrange, ofw_pcib_gen_adjust_busrange), +#endif { 0, 0 } }; @@ -118,9 +124,7 @@ static driver_t apb_driver = { sizeof(struct apb_softc), }; -static devclass_t apb_devclass; - -DRIVER_MODULE(apb, pci, apb_driver, apb_devclass, 0, 0); +DRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0); /* APB specific registers */ #define APBR_IOMAP 0xde @@ -178,42 +182,42 @@ static int apb_attach(device_t dev) { struct apb_softc *sc; - device_t child; sc = device_get_softc(dev); - sc->dev = dev; /* * Get current bridge configuration. */ - sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); - sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); - sc->iomap = pci_read_config(dev, APBR_IOMAP, 1); - sc->memmap = pci_read_config(dev, APBR_MEMMAP, 1); + sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1); + sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1); +#ifdef OFW_NEWPCI + ofw_pcib_gen_setup(dev); +#else + sc->sc_bsc.ops_pcib_sc.dev = dev; + sc->sc_bsc.ops_pcib_sc.secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); + sc->sc_bsc.ops_pcib_sc.subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); +#endif if (bootverbose) { - device_printf(dev, " secondary bus %d\n", sc->secbus); - device_printf(dev, " subordinate bus %d\n", sc->subbus); + device_printf(dev, " secondary bus %d\n", + sc->sc_bsc.ops_pcib_sc.secbus); + device_printf(dev, " subordinate bus %d\n", + sc->sc_bsc.ops_pcib_sc.subbus); device_printf(dev, " I/O decode "); - apb_map_print(sc->iomap, APB_IO_SCALE); + apb_map_print(sc->sc_iomap, APB_IO_SCALE); printf("\n"); device_printf(dev, " memory decode "); - apb_map_print(sc->memmap, APB_MEM_SCALE); + apb_map_print(sc->sc_memmap, APB_MEM_SCALE); printf("\n"); } - /* - * If we don't hardwire the bus down, pciconf gets confused. - */ - if (sc->secbus != 0) { - child = device_add_child(dev, "pci", sc->secbus); - if (child != NULL) - return (bus_generic_attach(dev)); - } else +#ifndef OFW_NEWPCI + if (sc->sc_bsc.ops_pcib_sc.secbus == 0) panic("apb_attach: APB with uninitialized secbus"); +#endif - /* no secondary bus; we should have fixed this */ - return (0); + device_add_child(dev, "pci", sc->sc_bsc.ops_pcib_sc.secbus); + return (bus_generic_attach(dev)); } /* @@ -244,8 +248,8 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid, */ switch (type) { case SYS_RES_IOPORT: - if (!apb_map_checkrange(sc->iomap, APB_IO_SCALE, start, - end)) { + if (!apb_map_checkrange(sc->sc_iomap, APB_IO_SCALE, + start, end)) { device_printf(dev, "device %s%d requested " "unsupported I/O range 0x%lx-0x%lx\n", device_get_name(child), @@ -253,14 +257,14 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid, return (NULL); } if (bootverbose) - device_printf(sc->dev, "device %s%d requested " - "decoded I/O range 0x%lx-0x%lx\n", - device_get_name(child), + device_printf(sc->sc_bsc.ops_pcib_sc.dev, + "device %s%d requested decoded I/O range " + "0x%lx-0x%lx\n", device_get_name(child), device_get_unit(child), start, end); break; case SYS_RES_MEMORY: - if (!apb_map_checkrange(sc->memmap, APB_MEM_SCALE, + if (!apb_map_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, end)) { device_printf(dev, "device %s%d requested " "unsupported memory range 0x%lx-0x%lx\n", @@ -269,8 +273,9 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid, return (NULL); } if (bootverbose) - device_printf(sc->dev, "device %s%d requested " - "decoded memory range 0x%lx-0x%lx\n", + device_printf(sc->sc_bsc.ops_pcib_sc.dev, + "device %s%d requested decoded memory " + "range 0x%lx-0x%lx\n", device_get_name(child), device_get_unit(child), start, end); break; @@ -287,63 +292,7 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid, count, flags)); } -static int -apb_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct apb_softc *sc = device_get_softc(dev); - - switch (which) { - case PCIB_IVAR_BUS: - *result = sc->secbus; - return (0); - } - return (ENOENT); -} - -static int -apb_write_ivar(device_t dev, device_t child, int which, uintptr_t value) -{ - struct apb_softc *sc = device_get_softc(dev); - - switch (which) { - case PCIB_IVAR_BUS: - sc->secbus = value; - break; - } - return (ENOENT); -} - -/* - * PCIB interface. - */ -static int -apb_maxslots(device_t dev) -{ - - return (PCI_SLOTMAX); -} - -/* - * Since we are a child of a PCI bus, its parent must support the pcib - * interface. - */ -static u_int32_t -apb_read_config(device_t dev, int b, int s, int f, int reg, int width) -{ - - return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, - s, f, reg, width)); -} - -static void -apb_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, - int width) -{ - - PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, - val, width); -} - +#ifndef OFW_NEWPCI /* * Route an interrupt across a PCI bridge - we need to rely on the firmware * here. @@ -369,3 +318,4 @@ apb_route_interrupt(device_t pcib, device_t dev, int pin) */ return (0); } +#endif /* !OFW_NEWPCI */ diff --git a/sys/sparc64/pci/ofw_pci.c b/sys/sparc64/pci/ofw_pci.c index ca54bf1..7da9cbb 100644 --- a/sys/sparc64/pci/ofw_pci.c +++ b/sys/sparc64/pci/ofw_pci.c @@ -1,7 +1,7 @@ /* * Copyright (c) 1999, 2000 Matthew R. Green + * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org> * All rights reserved. - * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,27 +38,29 @@ #include <sys/systm.h> #include <sys/bus.h> -#include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> #include <dev/ofw/ofw_pci.h> #include <dev/ofw/openfirm.h> -#include <sparc64/pci/ofw_pci.h> - #include <machine/bus.h> #include <machine/cache.h> #include <machine/iommureg.h> #include <machine/ofw_bus.h> #include <machine/ver.h> +#include <sparc64/pci/ofw_pci.h> + #include "pcib_if.h" -#include "sparcbus_if.h" u_int8_t pci_bus_cnt; phandle_t *pci_bus_map; int pci_bus_map_sz; +#define PCI_BUS_MAP_INC 10 + +#ifndef OFW_NEWPCI /* Do not swizzle on a PCI bus node with no interrupt-map propery. */ #define OPQ_NO_SWIZZLE 1 /* @@ -85,7 +87,6 @@ static int pci_quirks; #define OFW_PCI_PCIBUS "pci" #define OFW_PCI_EBUS "ebus" -#define PCI_BUS_MAP_INC 10 int ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, @@ -94,7 +95,7 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, { device_t dev = cookie; struct ofw_pci_register preg; - u_int32_t pintr, intr; + ofw_pci_intr_t pintr, intr; u_int slot; char type[32]; int found = 0; @@ -105,7 +106,7 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, *terminate = 1; return (-1); } - if (pintsz != sizeof(u_int32_t) || pregsz < sizeof(preg)) + if (pintsz != sizeof(pintr) || pregsz < sizeof(preg)) return (-1); bcopy(pintptr, &pintr, sizeof(pintr)); bcopy(pregptr, &preg, sizeof(preg)); @@ -119,13 +120,13 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, * values for external PCI devices seem to always be below 255 * and describe the interrupt pin to be used on the slot, while * we have to figure out the base INO by looking at the slot - * number (which we do using a sparcbus method). + * number (which we do using an ofw_pci method). * * Of course, there is an exception to that nice rule: * in the ebus case, the interrupt property has the correct * INO (but without IGN). This is dealt with above. */ - intr = SPARCBUS_GUESS_INO(dev, node, slot, pintr); + intr = OFW_PCI_GUESS_INO(dev, node, slot, pintr); found = intr != 255; *terminate = found; } @@ -150,14 +151,14 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, return (-1); } -static u_int32_t -ofw_pci_route_intr(device_t dev, phandle_t node, u_int32_t ign) +static ofw_pci_intr_t +ofw_pci_route_intr(device_t dev, phandle_t node, ofw_pci_intr_t ign) { u_int32_t rv; rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback, dev); if (rv == ORIR_NOTFOUND) - return (255); + return (PCI_INVALID_IRQ); /* * Some machines (notably the SPARCengine Ultra AX and the e450) have * no mappings at all, but use complete interrupt vector number @@ -167,6 +168,7 @@ ofw_pci_route_intr(device_t dev, phandle_t node, u_int32_t ign) rv -= ign; return (rv); } +#endif /* !OFW_NEWCPI */ u_int8_t ofw_pci_alloc_busno(phandle_t node) @@ -192,6 +194,7 @@ ofw_pci_alloc_busno(phandle_t node) return (n); } +#ifndef OFW_NEWPCI /* * Initialize bridge bus numbers for bridges that implement the primary, * secondary and subordinate bus number registers. @@ -220,7 +223,7 @@ ofw_pci_binit(device_t busdev, struct ofw_pci_bdesc *obd) * as well as the the bus numbers and ranges of the bridges. */ void -ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, +ofw_pci_init(device_t dev, phandle_t bushdl, ofw_pci_intr_t ign, struct ofw_pci_bdesc *obd) { struct ofw_pci_register pcir; @@ -321,7 +324,8 @@ ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, } /* Initialize the intline registers. */ - if ((intr = ofw_pci_route_intr(dev, node, ign)) != 255) { + if ((intr = ofw_pci_route_intr(dev, node, ign)) != + PCI_INVALID_IRQ) { #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: mapping intr for " "%d/%d/%d to %d (preset was %d)\n", @@ -344,7 +348,7 @@ ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, * 255. */ PCIB_WRITE_CONFIG(dev, busno, slot, func, - PCIR_INTLINE, 255, 1); + PCIR_INTLINE, PCI_INVALID_IRQ, 1); } } } while ((node = OF_peer(node)) != 0); @@ -384,3 +388,4 @@ ofw_pci_node(device_t dev) return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev))); } +#endif /* OFW_NEWPCI */ diff --git a/sys/sparc64/pci/ofw_pci.h b/sys/sparc64/pci/ofw_pci.h index 1c2122b..af26526 100644 --- a/sys/sparc64/pci/ofw_pci.h +++ b/sys/sparc64/pci/ofw_pci.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1999, 2000 Matthew R. Green + * Copyright (c) 2001, 2003 by Thomas Moestl <tmm@FreeBSD.org> * All rights reserved. - * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,6 +36,10 @@ #include <machine/ofw_bus.h> +typedef u_int32_t ofw_pci_intr_t; + +#include "ofw_pci_if.h" + /* PCI range child spaces. XXX: are these MI? */ #define PCI_CS_CONFIG 0x00 #define PCI_CS_IO 0x01 @@ -46,18 +50,31 @@ struct ofw_pci_imap { u_int32_t phys_hi; u_int32_t phys_mid; u_int32_t phys_lo; - u_int32_t intr; - int32_t child_node; - u_int32_t child_intr; + ofw_pci_intr_t intr; + phandle_t child_node; + phandle_t child_intr; }; struct ofw_pci_imap_msk { u_int32_t phys_hi; u_int32_t phys_mid; u_int32_t phys_lo; - u_int32_t intr; + ofw_pci_intr_t intr; }; +u_int8_t ofw_pci_alloc_busno(phandle_t); + +#ifdef OFW_NEWPCI + +static __inline phandle_t +ofw_pci_get_node(device_t dev) +{ + + return (OFW_PCI_GET_NODE(device_get_parent(dev), dev)); +} + +#else + struct ofw_pci_bdesc; typedef void ofw_pci_binit_t(device_t, struct ofw_pci_bdesc *); @@ -72,10 +89,10 @@ struct ofw_pci_bdesc { }; obr_callback_t ofw_pci_orb_callback; -u_int8_t ofw_pci_alloc_busno(phandle_t); ofw_pci_binit_t ofw_pci_binit; -void ofw_pci_init(device_t, phandle_t, u_int32_t, struct ofw_pci_bdesc *); +void ofw_pci_init(device_t, phandle_t, ofw_pci_intr_t, struct ofw_pci_bdesc *); phandle_t ofw_pci_find_node(int, int, int); phandle_t ofw_pci_node(device_t); +#endif #endif /* ! _SPARC64_PCI_OFW_PCI_H_ */ diff --git a/sys/sparc64/pci/ofw_pci_if.m b/sys/sparc64/pci/ofw_pci_if.m index fe7826e..508e842 100644 --- a/sys/sparc64/pci/ofw_pci_if.m +++ b/sys/sparc64/pci/ofw_pci_if.m @@ -1,4 +1,4 @@ -# Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. +# Copyright (c) 2001, 2003 by Thomas Moestl <tmm@FreeBSD.org> # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -28,66 +28,98 @@ #include <dev/ofw/openfirm.h> -INTERFACE sparcbus; +#include <sparc64/pci/ofw_pci.h> -HEADER { - /* Bus tag types for the get_bustag method */ - enum sbbt_id { - SBBT_IO, - SBBT_MEM, - }; -}; +INTERFACE ofw_pci; CODE { + static ofw_pci_intr_pending_t ofw_pci_default_intr_pending; + static ofw_pci_guess_ino_t ofw_pci_default_guess_ino; + static ofw_pci_get_bus_handle_t ofw_pci_default_get_bus_handle; + static ofw_pci_get_node_t ofw_pci_default_get_node; + static ofw_pci_adjust_busrange_t ofw_pci_default_adjust_busrange; + static int - sparcbus_default_intr_pending(device_t dev, int intr) + ofw_pci_default_intr_pending(device_t dev, ofw_pci_intr_t intr) { - return (SPARCBUS_INTR_PENDING(device_get_parent(dev), intr)); + return (OFW_PCI_INTR_PENDING(device_get_parent(dev), intr)); } - static u_int32_t - sparcbus_default_guess_ino(device_t dev, phandle_t node, u_int slot, + static ofw_pci_intr_t + ofw_pci_default_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin) { - return (SPARCBUS_GUESS_INO(device_get_parent(dev), node, slot, + return (OFW_PCI_GUESS_INO(device_get_parent(dev), node, slot, pin)); } static bus_space_handle_t - sparcbus_default_get_bus_handle(device_t dev, enum sbbt_id id, + ofw_pci_default_get_bus_handle(device_t dev, int type, bus_space_handle_t childhdl, bus_space_tag_t *tag) { - return (SPARCBUS_GET_BUS_HANDLE(device_get_parent(dev), id, + return (OFW_PCI_GET_BUS_HANDLE(device_get_parent(dev), type, childhdl, tag)); } + + static phandle_t + ofw_pci_default_get_node(device_t bus, device_t dev) + { + + return (0); + } + + static void + ofw_pci_default_adjust_busrange(device_t dev, u_int busno) + { + + return (OFW_PCI_ADJUST_BUSRANGE(device_get_parent(dev), busno)); + } }; # Return whether an interrupt request is pending for the INO intr. METHOD int intr_pending { device_t dev; - int intr; -} DEFAULT sparcbus_default_intr_pending; + ofw_pci_intr_t intr; +} DEFAULT ofw_pci_default_intr_pending; # Let the bus driver guess the INO of the device at the given slot and intpin # on the bus described by the node if it could not be determined from the # firmware properties. Returns 255 if no INO could be found (mapping will # continue at the parent), or the desired INO. -METHOD u_int32_t guess_ino { +# This method is only used in the !OFW_NEWPCI case, and will go away soon. +METHOD ofw_pci_intr_t guess_ino { device_t dev; phandle_t node; u_int slot; u_int pin; -} DEFAULT sparcbus_default_guess_ino; +} DEFAULT ofw_pci_default_guess_ino; # Get the bustag for the root bus. This is needed for ISA old-stlye # in[bwl]()/out[bwl]() support, where no tag retrieved from a resource is # passed. The returned tag is used to construct a tag for the whole ISA bus. METHOD bus_space_handle_t get_bus_handle { device_t dev; - enum sbbt_id id; + int type; bus_space_handle_t childhdl; bus_space_tag_t *tag; -} DEFAULT sparcbus_default_get_bus_handle; +} DEFAULT ofw_pci_default_get_bus_handle; + +# Get the firmware node for the device dev on the bus bus. The default mthod +# will return 0, which signals that there is no such node. +# This could be an ivar, but isn't to avoid numbering conflicts with standard +# pci/pcib ones. +METHOD phandle_t get_node { + device_t bus; + device_t dev; +} DEFAULT ofw_pci_default_get_node; + +# Make sure that all PCI bridges up in the hierarchy contain this bus in their +# subordinate bus range. This is required because we reenumerate all PCI +# buses. +METHOD void adjust_busrange { + device_t dev; + u_int subbus; +} DEFAULT ofw_pci_default_adjust_busrange; diff --git a/sys/sparc64/pci/ofw_pcib.c b/sys/sparc64/pci/ofw_pcib.c new file mode 100644 index 0000000..c70286a --- /dev/null +++ b/sys/sparc64/pci/ofw_pcib.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier + * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> + * Copyright (c) 2000 BSDi + * Copyright (c) 2001 - 2003 Thomas Moestl <tmm@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.3 2000/12/13 + * + * $FreeBSD$ + */ + +#include "opt_ofw_pci.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/pciio.h> + +#include <dev/ofw/openfirm.h> + +#include <machine/bus.h> +#include <machine/ofw_bus.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> + +#include "pcib_if.h" + +#include <sparc64/pci/ofw_pci.h> +#include <sparc64/pci/ofw_pcib_subr.h> + +static device_probe_t ofw_pcib_probe; +static device_attach_t ofw_pcib_attach; + +static device_method_t ofw_pcib_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ofw_pcib_probe), + DEVMETHOD(device_attach, ofw_pcib_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, pcib_read_ivar), + DEVMETHOD(bus_write_ivar, pcib_write_ivar), + DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + /* pcib interface */ + DEVMETHOD(pcib_maxslots, pcib_maxslots), + DEVMETHOD(pcib_read_config, pcib_read_config), + DEVMETHOD(pcib_write_config, pcib_write_config), + DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt), + + /* ofw_pci interface */ + DEVMETHOD(ofw_pci_get_node, ofw_pcib_gen_get_node), + DEVMETHOD(ofw_pci_adjust_busrange, ofw_pcib_gen_adjust_busrange), + + { 0, 0 } +}; + +static driver_t ofw_pcib_driver = { + "pcib", + ofw_pcib_methods, + sizeof(struct ofw_pcib_gen_softc), +}; + +DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_driver, pcib_devclass, 0, 0); + +static int +ofw_pcib_probe(device_t dev) +{ + if ((pci_get_class(dev) == PCIC_BRIDGE) && + (pci_get_subclass(dev) == PCIS_BRIDGE_PCI) && + ofw_pci_get_node(dev) != 0) { + device_set_desc(dev, "OFW PCI-PCI bridge"); + return (0); + } + return (ENXIO); +} + +static int +ofw_pcib_attach(device_t dev) +{ + struct ofw_pcib_gen_softc *sc = device_get_softc(dev); + + ofw_pcib_gen_setup(dev); + pcib_attach_common(dev); + device_add_child(dev, "pci", sc->ops_pcib_sc.secbus); + return (bus_generic_attach(dev)); +} diff --git a/sys/sparc64/pci/ofw_pcib_subr.c b/sys/sparc64/pci/ofw_pcib_subr.c new file mode 100644 index 0000000..0c72c48 --- /dev/null +++ b/sys/sparc64/pci/ofw_pcib_subr.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2003 by Thomas Moestl <tmm@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_ofw_pci.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_pci.h> + +#include <machine/bus.h> +#include <machine/ofw_bus.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> + +#include "pcib_if.h" + +#include <sparc64/pci/ofw_pci.h> +#include <sparc64/pci/ofw_pcib_subr.h> + +void +ofw_pcib_gen_setup(device_t bridge) +{ + struct ofw_pcib_gen_softc *sc = device_get_softc(bridge); + u_int secbus; + + sc->ops_pcib_sc.dev = bridge; + sc->ops_node = ofw_pci_get_node(bridge); + KASSERT(sc->ops_node != 0, + ("ofw_pcib_gen_setup: no ofw pci parent bus!")); + + /* + * Setup the secondary bus number register, by allocating a new unique + * bus number for it; the firmware preset does not always seem to be + * correct. + */ + secbus = ofw_pci_alloc_busno(sc->ops_node); + pci_write_config(bridge, PCIR_PRIBUS_1, pci_get_bus(bridge), 1); + pci_write_config(bridge, PCIR_SECBUS_1, secbus, 1); + pci_write_config(bridge, PCIR_SUBBUS_1, secbus, 1); + sc->ops_pcib_sc.subbus = sc->ops_pcib_sc.secbus = secbus; + /* Notify parent bridges. */ + OFW_PCI_ADJUST_BUSRANGE(device_get_parent(bridge), secbus); + + ofw_bus_setup_iinfo(sc->ops_node, &sc->ops_iinfo, + sizeof(ofw_pci_intr_t)); +} + +int +ofw_pcib_gen_route_interrupt(device_t bridge, device_t dev, int intpin) +{ + struct ofw_pcib_gen_softc *sc = device_get_softc(bridge); + struct ofw_bus_iinfo *ii = &sc->ops_iinfo; + struct ofw_pci_register reg; + device_t pbridge = device_get_parent(device_get_parent(bridge)); + phandle_t node = ofw_pci_get_node(dev); + ofw_pci_intr_t pintr, mintr; + u_int8_t maskbuf[sizeof(reg) + sizeof(pintr)]; + + if (ii->opi_imapsz > 0) { + pintr = intpin; + if (ofw_bus_lookup_imap(node, ii, ®, sizeof(reg), &pintr, + sizeof(pintr), &mintr, sizeof(mintr), maskbuf)) { + /* + * If we've found a mapping, return it and don't map + * it again on higher levels - that causes problems + * in some cases, and never seems to be required. + */ + return (mintr); + } + } else if (intpin >= 1 && intpin <= 4) { + /* + * When an interrupt map is missing, we need to do the + * standard PCI swizzle and continue mapping at the parent. + */ + return (pcib_route_interrupt(bridge, dev, intpin)); + } + /* Try at the parent. */ + return (PCIB_ROUTE_INTERRUPT(pbridge, bridge, intpin)); +} + +phandle_t +ofw_pcib_gen_get_node(device_t bridge, device_t dev) +{ + struct ofw_pcib_gen_softc *sc = device_get_softc(bridge); + + return (sc->ops_node); +} + +void +ofw_pcib_gen_adjust_busrange(device_t bridge, u_int subbus) +{ + struct ofw_pcib_gen_softc *sc = device_get_softc(bridge); + + if (subbus > sc->ops_pcib_sc.subbus) { +#ifdef OFW_PCI_DEBUG + device_printf(bridge, + "adjusting secondary bus number from %d to %d\n", + sc->ops_pcib_sc.subbus, subbus); +#endif + pci_write_config(bridge, PCIR_SUBBUS_1, subbus, 1); + sc->ops_pcib_sc.subbus = subbus; + /* Notify parent bridges. */ + OFW_PCI_ADJUST_BUSRANGE(device_get_parent(bridge), subbus); + } +} + diff --git a/sys/sparc64/pci/ofw_pcib_subr.h b/sys/sparc64/pci/ofw_pcib_subr.h new file mode 100644 index 0000000..8e03532 --- /dev/null +++ b/sys/sparc64/pci/ofw_pcib_subr.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2003 by Thomas Moestl <tmm@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SPARC64_PCI_OFW_PCI_SUBR_H +#define _SPARC64_PCI_OFW_PCI_SUBR_H + +struct ofw_pcib_gen_softc { + /* + * This is here so that we can use pci bridge methods, too - the + * generic routines only need the dev, secbus and subbus members + * filled. + */ + struct pcib_softc ops_pcib_sc; +#ifdef OFW_NEWPCI + phandle_t ops_node; + struct ofw_bus_iinfo ops_iinfo; +#endif +}; + +void ofw_pcib_gen_setup(device_t); +pcib_route_interrupt_t ofw_pcib_gen_route_interrupt; +ofw_pci_get_node_t ofw_pcib_gen_get_node; +ofw_pci_adjust_busrange_t ofw_pcib_gen_adjust_busrange; + +#endif /* !_SPARC64_PCI_OFW_PCI_SUBR_H */ diff --git a/sys/sparc64/pci/ofw_pcibus.c b/sys/sparc64/pci/ofw_pcibus.c new file mode 100644 index 0000000..597b656 --- /dev/null +++ b/sys/sparc64/pci/ofw_pcibus.c @@ -0,0 +1,264 @@ +/*- + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> + * Copyright (c) 2000, BSDi + * Copyright (c) 2003, Thomas Moestl <tmm@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_ofw_pci.h" +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/module.h> +#include <sys/pciio.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_pci.h> + +#include <machine/bus.h> +#include <machine/bus_common.h> +#include <machine/cache.h> +#include <machine/iommureg.h> +#include <machine/resource.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pci_private.h> + +#include <sparc64/pci/ofw_pci.h> + +#include "pcib_if.h" +#include "pci_if.h" + +/* Helper functions. */ +static void ofw_pcibus_setup_device(device_t, u_int, u_int, u_int); + +/* Methods. */ +static device_probe_t ofw_pcibus_probe; +static device_attach_t ofw_pcibus_attach; +static pci_assign_interrupt_t ofw_pcibus_assign_interrupt; +static ofw_pci_get_node_t ofw_pcibus_get_node; + +static device_method_t ofw_pcibus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ofw_pcibus_probe), + DEVMETHOD(device_attach, ofw_pcibus_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, pci_print_child), + DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), + DEVMETHOD(bus_read_ivar, pci_read_ivar), + DEVMETHOD(bus_write_ivar, pci_write_ivar), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + DEVMETHOD(bus_get_resource_list, pci_get_resource_list), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_delete_resource, pci_delete_resource), + DEVMETHOD(bus_alloc_resource, pci_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), + DEVMETHOD(bus_child_location_str, pci_child_location_str_method), + + /* PCI interface */ + DEVMETHOD(pci_read_config, pci_read_config_method), + DEVMETHOD(pci_write_config, pci_write_config_method), + DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), + DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), + DEVMETHOD(pci_enable_io, pci_enable_io_method), + DEVMETHOD(pci_disable_io, pci_disable_io_method), + DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), + DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), + DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt), + + /* OFW PCI interface */ + DEVMETHOD(ofw_pci_get_node, ofw_pcibus_get_node), + + { 0, 0 } +}; + +struct ofw_pcibus_devinfo { + struct pci_devinfo opd_dinfo; + phandle_t opd_node; +}; + +struct ofw_pcibus_softc { + phandle_t ops_node; +}; + +static driver_t ofw_pcibus_driver = { + "pci", + ofw_pcibus_methods, + sizeof(struct ofw_pcibus_softc), +}; + +DRIVER_MODULE(ofw_pcibus, pcib, ofw_pcibus_driver, pci_devclass, 0, 0); +MODULE_VERSION(ofw_pcibus, 1); +MODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1); + +static int +ofw_pcibus_probe(device_t dev) +{ + + if (ofw_pci_get_node(dev) == 0) + return (ENXIO); + device_set_desc(dev, "OFW PCI bus"); + + return (0); +} + +/* + * Perform miscellaneous setups the firmware usually does not do for us. + */ +static void +ofw_pcibus_setup_device(device_t bridge, u_int busno, u_int slot, u_int func) +{ + u_int lat, clnsz; + + /* + * Initialize the latency timer register for busmaster devices to work + * properly. This is another task which the firmware does not always + * perform. The Min_Gnt register can be used to compute it's recommended + * value: it contains the desired latency in units of 1/4 us. To + * calculate the correct latency timer value, a bus clock of 33MHz and + * no wait states should be assumed. + */ + lat = PCIB_READ_CONFIG(bridge, busno, slot, func, PCIR_MINGNT, 1) * + 33 / 4; + if (lat != 0) { +#ifdef OFW_PCI_DEBUG + device_printf(bridge, "device %d/%d/%d: latency timer %d -> " + "%d\n", busno, slot, func, + PCIB_READ_CONFIG(bridge, busno, slot, func, + PCIR_LATTIMER, 1), lat); +#endif /* OFW_PCI_DEBUG */ + PCIB_WRITE_CONFIG(bridge, busno, slot, func, + PCIR_LATTIMER, imin(lat, 255), 1); + } + + /* + * Compute a value to write into the cache line size register. + * The role of the streaming cache is unclear in write invalidate + * transfers, so it is made sure that it's line size is always reached. + */ + clnsz = imax(cache.ec_linesize, STRBUF_LINESZ); + KASSERT((clnsz / STRBUF_LINESZ) * STRBUF_LINESZ == clnsz && + (clnsz / cache.ec_linesize) * cache.ec_linesize == clnsz && + (clnsz / 4) * 4 == clnsz, ("bogus cache line size %d", clnsz)); + PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_CACHELNSZ, + clnsz / 4, 1); + + /* + * The preset in the intline register is usually wrong. Reset it to 255, + * so that the PCI code will reroute the interrupt if needed. + */ + PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_INTLINE, + PCI_INVALID_IRQ, 1); +} + +static int +ofw_pcibus_attach(device_t dev) +{ + device_t pcib = device_get_parent(dev); + struct ofw_pci_register pcir; + struct ofw_pcibus_devinfo *dinfo; + phandle_t node, child; + u_int slot, busno, func; + + /* + * Ask the bridge for the bus number - in some cases, we need to + * renumber buses, so the firmware information cannot be trusted. + */ + busno = pcib_get_bus(dev); + if (bootverbose) + device_printf(dev, "physical bus=%d\n", busno); + + node = ofw_pci_get_node(dev); + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) + panic("ofw_pci_attach: OF_getprop failed"); + slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); + func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); + ofw_pcibus_setup_device(pcib, busno, slot, func); + dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, + busno, slot, func, sizeof(*dinfo)); + if (dinfo != NULL) { + dinfo->opd_node = child; + pci_add_child(dev, (struct pci_devinfo *)dinfo); + } + } + + return (bus_generic_attach(dev)); +} + +static int +ofw_pcibus_assign_interrupt(device_t dev, device_t child) +{ + struct ofw_pcibus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->opd_dinfo.cfg; + phandle_t node = ofw_pci_get_node(child); + ofw_pci_intr_t intr; + int isz; + + isz = OF_getprop(node, "interrupts", &intr, sizeof(intr)); + if (isz != sizeof(intr)) { + /* No property; our best guess is the intpin. */ + intr = cfg->intpin; + } else if (intr >= 255) { + /* + * A fully specified interrupt (including IGN), as present on + * SPARCengine Ultra AX and e450. Extract the INO and return it. + */ + return (INTINO(intr)); + } + /* + * If we got intr from a property, it may or may not be an intpin. + * For on-board devices, it frequently is not, and is completely out + * of the valid intpin range. For PCI slots, it hopefully is, otherwise + * we will have trouble interfacing with non-OFW buses such as cardbus. + * Since we cannot tell which it is without violating layering, we + * will always use the route_interrupt method, and treat exceptions on + * the level they become apparent. + */ + return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); +} + +static phandle_t +ofw_pcibus_get_node(device_t bus, device_t dev) +{ + struct ofw_pcibus_devinfo *dinfo = device_get_ivars(dev); + + return (dinfo->opd_node); +} diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index 4d5a3a3..a1d7fee 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -1,7 +1,7 @@ /* * Copyright (c) 1999, 2000 Matthew R. Green + * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org> * All rights reserved. - * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,6 +36,7 @@ * UltraSPARC IIi and IIe `sabre' PCI controllers. */ +#include "opt_ofw_pci.h" #include "opt_psycho.h" #include <sys/param.h> @@ -55,6 +56,7 @@ #include <machine/frame.h> #include <machine/intr_machdep.h> #include <machine/nexusvar.h> +#include <machine/ofw_bus.h> #include <machine/ofw_upa.h> #include <machine/resource.h> #include <machine/cpu.h> @@ -71,7 +73,6 @@ #include <sparc64/pci/psychovar.h> #include "pcib_if.h" -#include "sparcbus_if.h" static void psycho_get_ranges(phandle_t, struct upa_ranges **, int *); static void psycho_set_intr(struct psycho_softc *, int, device_t, bus_addr_t, @@ -80,7 +81,9 @@ static int psycho_find_intrmap(struct psycho_softc *, int, bus_addr_t *, bus_addr_t *, u_long *); static void psycho_intr_stub(void *); static bus_space_tag_t psycho_alloc_bus_tag(struct psycho_softc *, int); - +#ifndef OFW_NEWPCI +static ofw_pci_binit_t psycho_binit; +#endif /* Interrupt handlers */ static void psycho_ue(void *); @@ -94,34 +97,32 @@ static void psycho_wakeup(void *); /* IOMMU support */ static void psycho_iommu_init(struct psycho_softc *, int); -static ofw_pci_binit_t psycho_binit; /* - * autoconfiguration + * Methods. */ -static int psycho_probe(device_t); -static int psycho_attach(device_t); -static int psycho_read_ivar(device_t, device_t, int, u_long *); -static int psycho_setup_intr(device_t, device_t, struct resource *, int, - driver_intr_t *, void *, void **); -static int psycho_teardown_intr(device_t, device_t, struct resource *, void *); -static struct resource *psycho_alloc_resource(device_t, device_t, int, int *, - u_long, u_long, u_long, u_int); -static int psycho_activate_resource(device_t, device_t, int, int, - struct resource *); -static int psycho_deactivate_resource(device_t, device_t, int, int, - struct resource *); -static int psycho_release_resource(device_t, device_t, int, int, - struct resource *); -static int psycho_maxslots(device_t); -static u_int32_t psycho_read_config(device_t, u_int, u_int, u_int, u_int, int); -static void psycho_write_config(device_t, u_int, u_int, u_int, u_int, u_int32_t, - int); -static int psycho_route_interrupt(device_t, device_t, int); -static int psycho_intr_pending(device_t, int); -static u_int32_t psycho_guess_ino(device_t, phandle_t, u_int, u_int); -static bus_space_handle_t psycho_get_bus_handle(device_t dev, enum sbbt_id id, - bus_space_handle_t childhdl, bus_space_tag_t *tag); +static device_probe_t psycho_probe; +static device_attach_t psycho_attach; +static bus_read_ivar_t psycho_read_ivar; +static bus_setup_intr_t psycho_setup_intr; +static bus_teardown_intr_t psycho_teardown_intr; +static bus_alloc_resource_t psycho_alloc_resource; +static bus_activate_resource_t psycho_activate_resource; +static bus_deactivate_resource_t psycho_deactivate_resource; +static bus_release_resource_t psycho_release_resource; +static pcib_maxslots_t psycho_maxslots; +static pcib_read_config_t psycho_read_config; +static pcib_write_config_t psycho_write_config; +static pcib_route_interrupt_t psycho_route_interrupt; +static ofw_pci_intr_pending_t psycho_intr_pending; +#ifndef OFW_NEWPCI +static ofw_pci_guess_ino_t psycho_guess_ino; +#endif +static ofw_pci_get_bus_handle_t psycho_get_bus_handle; +#ifdef OFW_NEWPCI +static ofw_pci_get_node_t psycho_get_node; +static ofw_pci_adjust_busrange_t psycho_adjust_busrange; +#endif static device_method_t psycho_methods[] = { /* Device interface */ @@ -144,10 +145,16 @@ static device_method_t psycho_methods[] = { DEVMETHOD(pcib_write_config, psycho_write_config), DEVMETHOD(pcib_route_interrupt, psycho_route_interrupt), - /* sparcbus interface */ - DEVMETHOD(sparcbus_intr_pending, psycho_intr_pending), - DEVMETHOD(sparcbus_guess_ino, psycho_guess_ino), - DEVMETHOD(sparcbus_get_bus_handle, psycho_get_bus_handle), + /* ofw_pci interface */ + DEVMETHOD(ofw_pci_intr_pending, psycho_intr_pending), +#ifndef OFW_NEWPCI + DEVMETHOD(ofw_pci_guess_ino, psycho_guess_ino), +#endif + DEVMETHOD(ofw_pci_get_bus_handle, psycho_get_bus_handle), +#ifdef OFW_NEWPCI + DEVMETHOD(ofw_pci_get_node, psycho_get_node), + DEVMETHOD(ofw_pci_adjust_busrange, psycho_adjust_busrange), +#endif { 0, 0 } }; @@ -314,7 +321,9 @@ psycho_attach(device_t dev) struct psycho_softc *osc = NULL; struct psycho_softc *asc; struct upa_regs *reg; +#ifndef OFW_NEWPCI struct ofw_pci_bdesc obd; +#endif struct psycho_desc *desc; phandle_t node; u_int64_t csr; @@ -587,17 +596,30 @@ psycho_attach(device_t dev) if (n != sizeof(psycho_br)) panic("broken psycho bus-range (%d)", n); - sc->sc_busno = ofw_pci_alloc_busno(sc->sc_node); - obd.obd_bus = psycho_br[0]; - obd.obd_secbus = obd.obd_subbus = sc->sc_busno; + sc->sc_secbus = sc->sc_subbus = ofw_pci_alloc_busno(sc->sc_node); + /* + * Program the bus range registers. + * NOTE: the psycho, the second write changes the bus number the + * psycho itself uses for it's configuration space, so these + * writes must be kept in this order! + * The sabre always uses bus 0, but there only can be one sabre per + * machine. + */ + PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SUBBUS, + sc->sc_subbus, 1); + PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SECBUS, + sc->sc_secbus, 1); + +#ifdef OFW_NEWPCI + ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_pci_intr_t)); +#else + obd.obd_bus = obd.obd_secbus = sc->sc_secbus; + obd.obd_subbus = sc->sc_subbus; obd.obd_slot = PCS_DEVICE; obd.obd_func = PCS_FUNC; obd.obd_init = psycho_binit; obd.obd_super = NULL; - /* Initial setup. */ - psycho_binit(dev, &obd); - /* Update the bus number to what was just programmed. */ - obd.obd_bus = obd.obd_secbus; + /* * Initialize the interrupt registers of all devices hanging from * the host bridge directly or indirectly via PCI-PCI bridges. @@ -608,8 +630,9 @@ psycho_attach(device_t dev) * Additionally, set up the bus numbers and ranges. */ ofw_pci_init(dev, sc->sc_node, sc->sc_ign, &obd); +#endif /* OFW_NEWPCI */ - device_add_child(dev, "pci", device_get_unit(dev)); + device_add_child(dev, "pci", sc->sc_secbus); return (bus_generic_attach(dev)); } @@ -726,8 +749,8 @@ psycho_ce(void *arg) afar = PSYCHO_READ8(sc, PSR_CE_AFA); afsr = PSYCHO_READ8(sc, PSR_CE_AFS); /* It's correctable. Dump the regs and continue. */ - printf("%s: correctable DMA error AFAR %#lx AFSR %#lx\n", - device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr); + device_printf(sc->sc_dev, "correctable DMA error AFAR %#lx " + "AFSR %#lx\n", (u_long)afar, (u_long)afsr); } static void @@ -780,7 +803,7 @@ psycho_wakeup(void *arg) PSYCHO_WRITE8(sc, PSR_PWRMGT_INT_CLR, 0); /* Gee, we don't really have a framework to deal with this properly. */ - printf("%s: power management wakeup\n", device_get_name(sc->sc_dev)); + device_printf(sc->sc_dev, "power management wakeup\n"); } #endif /* PSYCHO_MAP_WAKEUP */ @@ -810,6 +833,7 @@ psycho_iommu_init(struct psycho_softc *sc, int tsbsize) iommu_init(name, is, tsbsize, sc->sc_dvmabase, 0); } +#ifndef OFW_NEWPCI static void psycho_binit(device_t busdev, struct ofw_pci_bdesc *obd) { @@ -819,28 +843,20 @@ psycho_binit(device_t busdev, struct ofw_pci_bdesc *obd) obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus, obd->obd_secbus, obd->obd_subbus); #endif /* PSYCHO_DEBUG */ - /* - * NOTE: this must be kept in this order, since the last write will - * change the config space address of the psycho. - */ PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, PCSR_SUBBUS, obd->obd_subbus, 1); - PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, - PCSR_SECBUS, obd->obd_secbus, 1); } +#endif static int psycho_maxslots(device_t dev) { - /* - * XXX: is this correct? At any rate, a number that is too high - * shouldn't do any harm, if only because of the way things are - * handled in psycho_read_config. - */ - return (31); + /* XXX: is this correct? */ + return (PCI_SLOTMAX); } +#ifndef OFW_NEWPCI /* * Keep a table of quirky PCI devices that need fixups before the MI PCI code * creates the resource lists. This needs to be moved around once other bus @@ -862,6 +878,7 @@ static struct psycho_dquirk dquirks[] = { { 0x1102108e, DQT_BAD_INTPIN }, /* Sun FireWire ctl. (PCIO2 func. 2) */ { 0x1103108e, DQT_BAD_INTPIN }, /* Sun USB ctl. (PCIO2 func. 3) */ }; +#endif /* !OFW_NEWPCI */ #define NDQUIRKS (sizeof(dquirks) / sizeof(dquirks[0])) @@ -872,10 +889,13 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, struct psycho_softc *sc; bus_space_handle_t bh; u_long offset = 0; - u_int32_t r, devid; +#ifndef OFW_NEWPCI + u_int32_t devid; +#endif u_int8_t byte; u_int16_t shrt; u_int32_t wrd; + u_int32_t r; int i; sc = (struct psycho_softc *)device_get_softc(dev); @@ -906,6 +926,7 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, r = -1; } +#ifndef OFW_NEWPCI if (reg == PCIR_INTPIN && r == 0) { /* Check for DQT_BAD_INTPIN quirk. */ devid = psycho_read_config(dev, bus, slot, func, @@ -927,6 +948,7 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, } } } +#endif /* !OFW_NEWPCI */ return (r); } @@ -957,9 +979,44 @@ psycho_write_config(device_t dev, u_int bus, u_int slot, u_int func, } static int -psycho_route_interrupt(device_t bus, device_t dev, int pin) +psycho_route_interrupt(device_t bridge, device_t dev, int pin) { - +#ifdef OFW_NEWPCI + struct psycho_softc *sc = device_get_softc(bridge); + struct ofw_pci_register reg; + bus_addr_t intrmap; + phandle_t node = ofw_pci_get_node(dev); + ofw_pci_intr_t pintr, mintr; + u_int8_t maskbuf[sizeof(reg) + sizeof(pintr)]; + + pintr = pin; + if (ofw_bus_lookup_imap(node, &sc->sc_iinfo, ®, sizeof(reg), + &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf)) + return (mintr); + /* + * If this is outside of the range for an intpin, it's likely a full + * INO, and no mapping is required at all; this happens on the u30, + * where there's no interrupt map at the psycho node. Fortunately, + * there seem to be no INOs in the intpin range on this boxen, so + * this easy heuristics will do. + */ + if (pin > 4) + return (pin); + /* + * Guess the INO; we always assume that this is a non-OBIO + * device, and that pin is a "real" intpin number. Determine + * the mapping register to be used by the slot number. + * We only need to do this on e450s, it seems; here, the slot numbers + * for bus A are one-based, while those for bus B seemingly have an + * offset of 2 (hence the factor of 3 below). + */ + intrmap = PSR_PCIA0_INT_MAP + + 8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half); + mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1; + device_printf(bridge, "guessing interrupt %d for device %d/%d pin %d\n", + (int)mintr, pci_get_slot(dev), pci_get_function(dev), pin); + return (mintr); +#else /* * XXX: ugly loathsome hack: * We can't use ofw_pci_route_intr() here; the device passed may be @@ -976,6 +1033,7 @@ psycho_route_interrupt(device_t bus, device_t dev, int pin) * which case we are lost. */ return (0); +#endif /* OFW_NEWPCI */ } static int @@ -986,7 +1044,7 @@ psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) sc = (struct psycho_softc *)device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: - *result = sc->sc_busno; + *result = sc->sc_secbus; return (0); } return (ENOENT); @@ -1032,7 +1090,7 @@ psycho_setup_intr(device_t dev, device_t child, ino = INTINO(vec); if (!psycho_find_intrmap(sc, ino, &intrmapptr, &intrclrptr, NULL)) { - printf("Cannot find interrupt vector %lx\n", vec); + device_printf(dev, "Cannot find interrupt vector %lx\n", vec); free(pc, M_DEVBUF); return (NULL); } @@ -1204,20 +1262,22 @@ psycho_release_resource(device_t bus, device_t child, int type, int rid, } static int -psycho_intr_pending(device_t dev, int intr) +psycho_intr_pending(device_t dev, ofw_pci_intr_t intr) { struct psycho_softc *sc; u_long diag; sc = (struct psycho_softc *)device_get_softc(dev); if (!psycho_find_intrmap(sc, intr, NULL, NULL, &diag)) { - printf("psycho_intr_pending: mapping not found for %d\n", intr); + device_printf(dev, "psycho_intr_pending: mapping not found for" + " %d\n", intr); return (0); } return (diag != 0); } -static u_int32_t +#ifndef OFW_NEWPCI +static ofw_pci_intr_t psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin) { struct psycho_softc *sc = (struct psycho_softc *)device_get_softc(dev); @@ -1230,7 +1290,7 @@ psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin) * the INO. */ if (node != sc->sc_node) - return (255); + return (PCI_INVALID_IRQ); /* * Actually guess the INO. We always assume that this is a non-OBIO * device, and use from the slot number to determine it. @@ -1241,19 +1301,20 @@ psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin) intrmap = PSR_PCIA0_INT_MAP + 8 * (slot - 1 + 3 * sc->sc_half); return (INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1); } +#endif /* !OFW_NEWPCI */ static bus_space_handle_t -psycho_get_bus_handle(device_t dev, enum sbbt_id id, - bus_space_handle_t childhdl, bus_space_tag_t *tag) +psycho_get_bus_handle(device_t dev, int type, bus_space_handle_t childhdl, + bus_space_tag_t *tag) { struct psycho_softc *sc; sc = (struct psycho_softc *)device_get_softc(dev); - switch(id) { - case SBBT_IO: + switch (type) { + case SYS_RES_IOPORT: *tag = sc->sc_iot; return (sc->sc_bh[PCI_CS_IO] + childhdl); - case SBBT_MEM: + case SYS_RES_MEMORY: *tag = sc->sc_memt; return (sc->sc_bh[PCI_CS_MEM32] + childhdl); default: @@ -1261,6 +1322,35 @@ psycho_get_bus_handle(device_t dev, enum sbbt_id id, } } +#ifdef OFW_NEWPCI +static phandle_t +psycho_get_node(device_t bus, device_t dev) +{ + struct psycho_softc *sc = device_get_softc(bus); + + /* We only have one child, the PCI bus, which needs our own node. */ + return (sc->sc_node); +} + +static void +psycho_adjust_busrange(device_t dev, u_int subbus) +{ + struct psycho_softc *sc = device_get_softc(dev); + + /* If necessary, adjust the subordinate bus number register. */ + if (subbus > sc->sc_subbus) { +#ifdef PSYCHO_DEBUG + device_printf(dev, + "adjusting secondary bus number from %d to %d\n", + sc->sc_subbus, subbus); +#endif + sc->sc_subbus = subbus; + PCIB_WRITE_CONFIG(dev, sc->sc_secbus, PCS_DEVICE, PCS_FUNC, + PCSR_SUBBUS, subbus, 1); + } +} +#endif + /* * below here is bus space and bus dma support */ diff --git a/sys/sparc64/pci/psychovar.h b/sys/sparc64/pci/psychovar.h index 2a77b15..584d8a4 100644 --- a/sys/sparc64/pci/psychovar.h +++ b/sys/sparc64/pci/psychovar.h @@ -71,6 +71,10 @@ struct psycho_softc { struct resource *sc_irq_res[6]; void *sc_ihand[6]; +#ifdef OFW_NEWPCI + struct ofw_bus_iinfo sc_iinfo; +#endif + /* * note that the sabre really only has one ranges property, * used for both simba a and simba b (but the ranges for @@ -87,7 +91,8 @@ struct psycho_softc { bus_space_handle_t sc_bh[4]; - int sc_busno; + u_int sc_secbus; + u_int sc_subbus; struct rman sc_mem_rman; struct rman sc_io_rman; diff --git a/sys/sparc64/sparc64/ofw_bus.c b/sys/sparc64/sparc64/ofw_bus.c index 6d8e242..359da41 100644 --- a/sys/sparc64/sparc64/ofw_bus.c +++ b/sys/sparc64/sparc64/ofw_bus.c @@ -29,7 +29,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- - * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. + * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,6 +64,8 @@ * bits left. */ +#include "opt_ofw_pci.h" + #include <sys/param.h> #include <sys/malloc.h> #include <sys/systm.h> @@ -72,12 +74,6 @@ #include <machine/ofw_bus.h> -/* - * Other than in OpenFirmware calls, the size of a bus cell seems to be always - * the same. - */ -typedef u_int32_t pcell_t; - static int ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen) { @@ -90,7 +86,122 @@ ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen) return (-1); } +#ifdef OFW_NEWPCI + +void +ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) +{ + pcell_t addrc; + int msksz; + + if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1) + addrc = 2; + ii->opi_addrc = addrc * sizeof(pcell_t); + + ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1, + (void **)&ii->opi_imap); + if (ii->opi_imapsz > 0) { + msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1, + (void **)&ii->opi_imapmsk); + /* + * Failure to get the mask is ignored; a full mask is used then. + * Barf on bad mask sizes, however. + */ + if (msksz != -1 && msksz != ii->opi_addrc + intrsz) { + panic("ofw_bus_setup_iinfo: bad interrupt-map-mask " + "property!"); + } + } + +} + +int +ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, + int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, + void *maskbuf) +{ + int rv; + + if (ii->opi_imapsz <= 0) + return (0); + KASSERT(regsz >= ii->opi_addrc, + ("ofw_bus_lookup_imap: register size too small: %d < %d", + regsz, ii->opi_addrc)); + rv = OF_getprop(node, "reg", reg, regsz); + if (rv < regsz) + panic("ofw_bus_lookup_imap: could not get reg property"); + return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc, + ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr, + mintrsz)); +} + +/* + * Map an interrupt using the firmware reg, interrupt-map and + * interrupt-map-mask properties. + * The interrupt property to be mapped must be of size intrsz, and pointed to + * by intr. The regs property of the node for which the mapping is done must + * be passed as regs. This property is an array of register specifications; + * the size of the address part of such a specification must be passed as + * physsz. Only the first element of the property is used. + * imap and imapsz hold the interrupt mask and it's size. + * imapmsk is a pointer to the interrupt-map-mask property, which must have + * a size of physsz + intrsz; it may be NULL, in which case a full mask is + * assumed. + * maskbuf must point to a buffer of length physsz + intrsz. + * The interrupt is returned in result, which must point to a buffer of length + * rintrsz (which gives the expected size of the mapped interrupt). + * Returns 1 if a mapping was found, 0 otherwise. + */ +int +ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, + void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, + int rintrsz) +{ + phandle_t parent; + u_int8_t *ref = maskbuf; + u_int8_t *uiintr = intr; + u_int8_t *uiregs = regs; + u_int8_t *uiimapmsk = imapmsk; + u_int8_t *mptr; + pcell_t pintrsz; + int i, rsz, tsz; + + rsz = -1; + if (imapmsk != NULL) { + for (i = 0; i < physsz; i++) + ref[i] = uiregs[i] & uiimapmsk[i]; + for (i = 0; i < intrsz; i++) + ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i]; + } else { + bcopy(regs, ref, physsz); + bcopy(intr, ref + physsz, intrsz); + } + + mptr = imap; + i = imapsz; + tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz; + while (i > 0) { + KASSERT(i >= tsz, ("ofw_bus_find_intr: truncated map")); + bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); + if (ofw_bus_searchprop(parent, "#interrupt-cells", + &pintrsz, sizeof(pintrsz)) == -1) + pintrsz = 1; /* default */ + pintrsz *= sizeof(pcell_t); + if (pintrsz != rintrsz) + panic("ofw_bus_search_intrmap: expected interrupt cell " + "size incorrect: %d != %d", rintrsz, pintrsz); + if (bcmp(ref, mptr, physsz + intrsz) == 0) { + bcopy(mptr + physsz + intrsz + sizeof(parent), + result, rintrsz); + return (1); + } + mptr += tsz; + i -= tsz; + } + return (0); +} +#else /* * Map an interrupt using the firmware reg, interrupt-map and * interrupt-map-mask properties. @@ -253,3 +364,4 @@ ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb, void *cookie) free(intr, M_OFWPROP); return (rv); } +#endif /* OFW_NEWPCI */ diff --git a/sys/sparc64/sparc64/sparcbus_if.m b/sys/sparc64/sparc64/sparcbus_if.m deleted file mode 100644 index fe7826e..0000000 --- a/sys/sparc64/sparc64/sparcbus_if.m +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# $FreeBSD$ - -#include <sys/bus.h> -#include <machine/bus.h> - -#include <dev/ofw/openfirm.h> - -INTERFACE sparcbus; - -HEADER { - /* Bus tag types for the get_bustag method */ - enum sbbt_id { - SBBT_IO, - SBBT_MEM, - }; -}; - -CODE { - static int - sparcbus_default_intr_pending(device_t dev, int intr) - { - - return (SPARCBUS_INTR_PENDING(device_get_parent(dev), intr)); - } - - static u_int32_t - sparcbus_default_guess_ino(device_t dev, phandle_t node, u_int slot, - u_int pin) - { - - return (SPARCBUS_GUESS_INO(device_get_parent(dev), node, slot, - pin)); - } - - static bus_space_handle_t - sparcbus_default_get_bus_handle(device_t dev, enum sbbt_id id, - bus_space_handle_t childhdl, bus_space_tag_t *tag) - { - - return (SPARCBUS_GET_BUS_HANDLE(device_get_parent(dev), id, - childhdl, tag)); - } -}; - -# Return whether an interrupt request is pending for the INO intr. -METHOD int intr_pending { - device_t dev; - int intr; -} DEFAULT sparcbus_default_intr_pending; - -# Let the bus driver guess the INO of the device at the given slot and intpin -# on the bus described by the node if it could not be determined from the -# firmware properties. Returns 255 if no INO could be found (mapping will -# continue at the parent), or the desired INO. -METHOD u_int32_t guess_ino { - device_t dev; - phandle_t node; - u_int slot; - u_int pin; -} DEFAULT sparcbus_default_guess_ino; - -# Get the bustag for the root bus. This is needed for ISA old-stlye -# in[bwl]()/out[bwl]() support, where no tag retrieved from a resource is -# passed. The returned tag is used to construct a tag for the whole ISA bus. -METHOD bus_space_handle_t get_bus_handle { - device_t dev; - enum sbbt_id id; - bus_space_handle_t childhdl; - bus_space_tag_t *tag; -} DEFAULT sparcbus_default_get_bus_handle; |