diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2013-08-07 07:29:21 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2013-08-07 07:29:21 +0000 |
commit | 90995fd1f69222c92bffafb661665b88a5668b65 (patch) | |
tree | 30806dbdd563ebc9c8dd8c9eb7c1a0b24f41d9c3 /sys/arch/macppc/pci | |
parent | c894b994ad2bbf72ae4a92f82b403a148212f1ed (diff) |
Mimic what's done on sparc64 and parse the OpenFirmware device tree to
enumerate the pci devices. This allow us to not store the interrupt
vector in the interrupt line register and to not try to attach pci
devices disabled by firmware.
With inputs from and ok kettenis@
Diffstat (limited to 'sys/arch/macppc/pci')
-rw-r--r-- | sys/arch/macppc/pci/ht.c | 232 | ||||
-rw-r--r-- | sys/arch/macppc/pci/mpcpcibus.c | 380 | ||||
-rw-r--r-- | sys/arch/macppc/pci/pci_machdep.c | 340 |
3 files changed, 375 insertions, 577 deletions
diff --git a/sys/arch/macppc/pci/ht.c b/sys/arch/macppc/pci/ht.c index 1de294a49cb..38e6012e929 100644 --- a/sys/arch/macppc/pci/ht.c +++ b/sys/arch/macppc/pci/ht.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ht.c,v 1.15 2013/01/21 15:06:29 mpi Exp $ */ +/* $OpenBSD: ht.c,v 1.16 2013/08/07 07:29:19 mpi Exp $ */ /* * Copyright (c) 2005 Mark Kettenis @@ -32,29 +32,11 @@ int ht_match(struct device *, void *, void *); void ht_attach(struct device *, struct device *, void *); -void ht_attach_hook(struct device *, struct device *, - struct pcibus_attach_args *); -int ht_bus_maxdevs(void *, int); -pcitag_t ht_make_tag(void *, int, int, int); -void ht_decompose_tag(void *, pcitag_t, int *, int *, int *); -int ht_conf_size(void *, pcitag_t); pcireg_t ht_conf_read(void *, pcitag_t, int); void ht_conf_write(void *, pcitag_t, int, pcireg_t); -int ht_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *); -const char *ht_intr_string(void *, pci_intr_handle_t); -int ht_intr_line(void *, pci_intr_handle_t); -void *ht_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), - void *, const char *); -void ht_intr_disestablish(void *, void *); - -int ht_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *); int ht_print(void *, const char *); -#define BUS_SHIFT 16 -#define DEVICE_SHIFT 11 -#define FNC_SHIFT 8 - struct ht_softc { struct device sc_dev; int sc_maxdevs; @@ -76,27 +58,6 @@ struct cfdriver ht_cd = { NULL, "ht", DV_DULL, }; -#if 0 -struct powerpc_bus_dma_tag pci_bus_dma_tag = { - NULL, - _dmamap_create, - _dmamap_destroy, - _dmamap_load, - _dmamap_load_mbuf, - _dmamap_load_uio, - _dmamap_load_raw, - _dmamap_unload, - _dmamap_sync, - _dmamem_alloc, - _dmamem_free, - _dmamem_map, - _dmamem_unmap, - _dmamem_mmap -}; -#else -extern struct powerpc_bus_dma_tag pci_bus_dma_tag; -#endif - int ht_match(struct device *parent, void *cf, void *aux) { @@ -115,8 +76,7 @@ ht_attach(struct device *parent, struct device *self, void *aux) struct pcibus_attach_args pba; u_int32_t regs[6]; char compat[32]; - int node, nn; - int len; + int node, len; if (ca->ca_node == 0) { printf(": invalid node on ht config\n"); @@ -144,7 +104,7 @@ ht_attach(struct device *parent, struct device *self, void *aux) sc->sc_maxdevs++; if (bus_space_map(sc->sc_memt, regs[1], - (1 << DEVICE_SHIFT)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) { + (1 << 11)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) { printf(": can't map PCI config0 memory\n"); return; } @@ -168,22 +128,10 @@ ht_attach(struct device *parent, struct device *self, void *aux) printf(": %s", compat); sc->sc_pc.pc_conf_v = sc; - sc->sc_pc.pc_attach_hook = ht_attach_hook; - sc->sc_pc.pc_bus_maxdevs = ht_bus_maxdevs; - sc->sc_pc.pc_make_tag = ht_make_tag; - sc->sc_pc.pc_decompose_tag = ht_decompose_tag; - sc->sc_pc.pc_conf_size = ht_conf_size; + sc->sc_pc.pc_node = ca->ca_node; sc->sc_pc.pc_conf_read = ht_conf_read; sc->sc_pc.pc_conf_write = ht_conf_write; - sc->sc_pc.pc_intr_v = sc; - sc->sc_pc.pc_intr_map = ht_intr_map; - sc->sc_pc.pc_intr_string = ht_intr_string; - sc->sc_pc.pc_intr_line = ht_intr_line; - sc->sc_pc.pc_intr_establish = ht_intr_establish; - sc->sc_pc.pc_intr_disestablish = ht_intr_disestablish; - sc->sc_pc.pc_ether_hw_addr = ht_ether_hw_addr; - bzero(&pba, sizeof(pba)); pba.pba_busname = "pci"; pba.pba_iot = sc->sc_iot; @@ -195,90 +143,35 @@ ht_attach(struct device *parent, struct device *self, void *aux) printf(", %d devices\n", sc->sc_maxdevs); - extern void fix_node_irq(int, struct pcibus_attach_args *); - - for (node = OF_child(ca->ca_node); node; node = nn) { - fix_node_irq(node, &pba); - - if ((nn = OF_child(node)) != 0) - continue; - - while ((nn = OF_peer(node)) == 0) { - node = OF_parent(node); - if (node == ca->ca_node) { - nn = 0; - break; - } - } - } - config_found(self, &pba, ht_print); } -void -ht_attach_hook(struct device *parent, struct device *self, - struct pcibus_attach_args *pba) -{ -} - -int -ht_bus_maxdevs(void *cpv, int bus) -{ - struct ht_softc *sc = cpv; - - /* XXX Probing more busses doesn't work. */ - if (bus == 0) - return sc->sc_maxdevs; - return 32; -} - -pcitag_t -ht_make_tag(void *cpv, int bus, int dev, int fnc) -{ - return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); -} - -void -ht_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp) -{ - if (busp != NULL) - *busp = (tag >> BUS_SHIFT) & 0xff; - if (devp != NULL) - *devp = (tag >> DEVICE_SHIFT) & 0x1f; - if (fncp != NULL) - *fncp = (tag >> FNC_SHIFT) & 0x7; -} - -int -ht_conf_size(void *cpv, pcitag_t tag) -{ - return PCI_CONFIG_SPACE_SIZE; -} - pcireg_t ht_conf_read(void *cpv, pcitag_t tag, int offset) { struct ht_softc *sc = cpv; int bus, dev, fcn; pcireg_t reg; + uint32_t val; + val = PCITAG_OFFSET(tag); #ifdef DEBUG - printf("ht_conf_read: tag=%x, offset=%x\n", tag, offset); + printf("ht_conf_read: tag=%x, offset=%x\n", val, offset); #endif - ht_decompose_tag(NULL, tag, &bus, &dev, &fcn); + pci_decompose_tag(NULL, tag, &bus, &dev, &fcn); if (bus == 0 && dev == 0) { - tag |= (offset << 2); - reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); + val |= (offset << 2); + reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val); reg = letoh32(reg); } else if (bus == 0) { /* XXX Why can we only access function 0? */ if (fcn > 0) return ~0; - tag |= offset; - reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); + val |= offset; + reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val); } else { - tag |= offset; - reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); + val |= offset; + reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val); } #ifdef DEBUG printf("ht_conf_read: reg=%x\n", reg); @@ -291,104 +184,33 @@ ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) { struct ht_softc *sc = cpv; int bus, dev, fcn; + uint32_t val; + val = PCITAG_OFFSET(tag); #ifdef DEBUG printf("ht_conf_write: tag=%x, offset=%x, data = %x\n", - tag, offset, data); + val, offset, data); #endif - ht_decompose_tag(NULL, tag, &bus, &dev, &fcn); + pci_decompose_tag(NULL, tag, &bus, &dev, &fcn); if (bus == 0 && dev == 0) { - tag |= (offset << 2); + val |= (offset << 2); data = htole32(data); - bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, tag, data); - bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); + bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, val, data); + bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val); } else if (bus == 0) { /* XXX Why can we only access function 0? */ if (fcn > 0) return; - tag |= offset; - bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, tag, data); - bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); + val |= offset; + bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, val, data); + bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val); } else { - tag |= offset; - bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, tag, data); - bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); + val |= offset; + bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, val, data); + bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val); } } -/* XXX */ -#define PCI_INTERRUPT_NO_CONNECTION 0xff - -int -ht_intr_map(void *cpv, pcitag_t tag, int pin, int line, - pci_intr_handle_t *ihp) -{ - int error = 0; - -#ifdef DEBUG - printf("ht_intr_map: tag=%x, pin=%d, line=%d\n", tag, pin, line); -#endif - - *ihp = -1; - if (line == PCI_INTERRUPT_NO_CONNECTION) - error = 1; /* No IRQ used. */ - else if (pin > PCI_INTERRUPT_PIN_MAX) { - printf("ht_intr_map: bad interrupt pin %d\n", pin); - error = 1; - } - - if (!error) - *ihp = line; - return error; -} - -const char * -ht_intr_string(void *cpv, pci_intr_handle_t ih) -{ - static char str[16]; - - snprintf(str, sizeof str, "irq %ld", ih); - return (str); -} - -int -ht_intr_line(void *cpv, pci_intr_handle_t ih) -{ - return (ih); -} - -void * -ht_intr_establish(void *cpv, pci_intr_handle_t ih, int level, - int (*func)(void *), void *arg, const char *name) -{ - return (*intr_establish_func)(cpv, ih, IST_LEVEL, level, func, arg, - name); -} - -void -ht_intr_disestablish(void *lcv, void *cookie) -{ -} - -int -ht_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr) -{ - u_int8_t laddr[6]; - int node; - int len; - - node = OF_finddevice("enet"); - len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr)); - if (sizeof(laddr) == len) { - memcpy(oaddr, laddr, sizeof(laddr)); - return 1; - } - - oaddr[0] = oaddr[1] = oaddr[2] = 0xff; - oaddr[3] = oaddr[4] = oaddr[5] = 0xff; - return 0; -} - int ht_print(void *aux, const char *pnp) { diff --git a/sys/arch/macppc/pci/mpcpcibus.c b/sys/arch/macppc/pci/mpcpcibus.c index ab4ff0bf772..e117270c3cc 100644 --- a/sys/arch/macppc/pci/mpcpcibus.c +++ b/sys/arch/macppc/pci/mpcpcibus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpcpcibus.c,v 1.45 2013/01/21 15:06:29 mpi Exp $ */ +/* $OpenBSD: mpcpcibus.c,v 1.46 2013/08/07 07:29:19 mpi Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -26,11 +26,6 @@ * */ -/* - * Generic PCI BUS Bridge driver. - * specialized hooks for different config methods. - */ - #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> @@ -49,27 +44,10 @@ int mpcpcibrmatch(struct device *, void *, void *); void mpcpcibrattach(struct device *, struct device *, void *); -void mpc_attach_hook(struct device *, struct device *, - struct pcibus_attach_args *); -int mpc_bus_maxdevs(void *, int); -pcitag_t mpc_make_tag(void *, int, int, int); -void mpc_decompose_tag(void *, pcitag_t, int *, int *, int *); -int mpc_conf_size(void *, pcitag_t); pcireg_t mpc_conf_read(void *, pcitag_t, int); void mpc_conf_write(void *, pcitag_t, int, pcireg_t); -int mpc_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *); -const char *mpc_intr_string(void *, pci_intr_handle_t); -int mpc_intr_line(void *, pci_intr_handle_t); -void *mpc_intr_establish(void *, pci_intr_handle_t, - int, int (*func)(void *), void *, const char *); -void mpc_intr_disestablish(void *, void *); -int mpc_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *); u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset); -int of_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *); -int find_node_intr (int parent, u_int32_t *addr, u_int32_t *intr); - -void fix_node_irq(int node, struct pcibus_attach_args *pba); struct pcibr_config { bus_space_tag_t lc_memt; @@ -78,8 +56,6 @@ struct pcibr_config { bus_space_handle_t ioh_cfc; struct ppc_pci_chipset lc_pc; int config_type; - int bus; - int node; }; struct pcibr_softc { @@ -132,23 +108,6 @@ struct config_type config_offsets[] = { {NULL, 0x00000000, 0x00000000, 0 }, }; -struct powerpc_bus_dma_tag pci_bus_dma_tag = { - NULL, - _dmamap_create, - _dmamap_destroy, - _dmamap_load, - _dmamap_load_mbuf, - _dmamap_load_uio, - _dmamap_load_raw, - _dmamap_unload, - _dmamap_sync, - _dmamem_alloc, - _dmamem_free, - _dmamem_map, - _dmamem_unmap, - _dmamem_mmap -}; - int mpcpcibrmatch(struct device *parent, void *match, void *aux) { @@ -319,7 +278,6 @@ mpcpcibus_find_ranges_64(struct pcibr_softc *sc, u_int32_t *range_store, prange[i].phys_lo, prange[i].size_lo); #endif - if (base != 0) { if ((base + size) == prange[i].phys_lo) { size += prange[i].size_lo; @@ -348,7 +306,6 @@ mpcpcibrattach(struct device *parent, struct device *self, void *aux) struct confargs *ca = aux; struct pcibr_config *lcp; struct pcibus_attach_args pba; - int node; int of_node = 0; char compat[32]; u_int32_t addr_offset; @@ -444,26 +401,13 @@ mpcpcibrattach(struct device *parent, struct device *self, void *aux) of_node = ca->ca_node; - lcp->node = ca->ca_node; lcp->lc_pc.pc_conf_v = lcp; - lcp->lc_pc.pc_attach_hook = mpc_attach_hook; - lcp->lc_pc.pc_bus_maxdevs = mpc_bus_maxdevs; - lcp->lc_pc.pc_make_tag = mpc_make_tag; - lcp->lc_pc.pc_decompose_tag = mpc_decompose_tag; - lcp->lc_pc.pc_conf_size = mpc_conf_size; + lcp->lc_pc.pc_node = ca->ca_node; lcp->lc_pc.pc_conf_read = mpc_conf_read; lcp->lc_pc.pc_conf_write = mpc_conf_write; - lcp->lc_pc.pc_ether_hw_addr = of_ether_hw_addr; lcp->lc_iot = &sc->sc_iobus_space; lcp->lc_memt = &sc->sc_membus_space; - lcp->lc_pc.pc_intr_v = lcp; - lcp->lc_pc.pc_intr_map = mpc_intr_map; - lcp->lc_pc.pc_intr_string = mpc_intr_string; - lcp->lc_pc.pc_intr_line = mpc_intr_line; - lcp->lc_pc.pc_intr_establish = mpc_intr_establish; - lcp->lc_pc.pc_intr_disestablish = mpc_intr_disestablish; - printf(": %s\n", compat); bzero(&pba, sizeof(pba)); @@ -478,178 +422,7 @@ mpcpcibrattach(struct device *parent, struct device *self, void *aux) pba.pba_domain = pci_ndomains++; pba.pba_bus = 0; - /* we want to check pci irq settings */ - if (of_node != 0) { - int nn; - - for (node = OF_child(of_node); node; node = nn) { - char name[32]; - int len; - len = OF_getprop(node, "name", name, - sizeof(name)); - name[len] = 0; - fix_node_irq(node, &pba); - - /* iterate section */ - if ((nn = OF_child(node)) != 0) - continue; - - while ((nn = OF_peer(node)) == 0) { - node = OF_parent(node); - if (node == of_node) { - nn = 0; /* done */ - break; - } - } - } - } - config_found(self, &pba, mpcpcibrprint); - -} - -#define OFW_PCI_PHYS_HI_BUSMASK 0x00ff0000 -#define OFW_PCI_PHYS_HI_BUSSHIFT 16 -#define OFW_PCI_PHYS_HI_DEVICEMASK 0x0000f800 -#define OFW_PCI_PHYS_HI_DEVICESHIFT 11 -#define OFW_PCI_PHYS_HI_FUNCTIONMASK 0x00000700 -#define OFW_PCI_PHYS_HI_FUNCTIONSHIFT 8 - -#define pcibus(x) \ - (((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT) -#define pcidev(x) \ - (((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT) -#define pcifunc(x) \ - (((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT) - -/* - * Find PCI IRQ from OF. - */ -int -find_node_intr(int parent, u_int32_t *addr, u_int32_t *intr) -{ - int iparent, len, mlen, alen, ilen; - int match, i, step; - u_int32_t map[144], *mp, *mp1; - u_int32_t cpu_imask[8], maskedaddr[8]; - u_int32_t address_cells, interrupt_cells, mask_cells; - - len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); - mlen = OF_getprop(parent, "interrupt-map-mask", cpu_imask, sizeof(cpu_imask)); - alen = OF_getprop(parent, "#address-cells", - &address_cells, sizeof(address_cells)); - ilen = OF_getprop(parent, "#interrupt-cells", - &interrupt_cells, sizeof(interrupt_cells)); - - if (len == -1 || mlen == -1 || alen == -1 || ilen == -1) - goto nomap; - - mask_cells = address_cells + interrupt_cells; - if (mask_cells != (mlen / sizeof(u_int32_t))) - goto nomap; - for (i = 0; i < mask_cells; i++) - maskedaddr[i] = addr[i] & cpu_imask[i]; - - /* interrupt-map is formatted as follows - * int * #address-cells, int * #interrupt-cells, int, int, int - * eg - * address-cells = 3 - * interrupt-cells = 1 - * 00001000 00000000 00000000 00000000 ff911258 00000034 00000001 - * 00001800 00000000 00000000 00000000 ff911258 00000035 00000001 - * 00002000 00000000 00000000 00000000 ff911258 00000036 00000001 - * | address cells | | intr | |parent| | irq | |edge/level| - * | cells| | interrupt cells | - * | of parent | - * or at least something close to that. - */ - - mp = map; - while (len > mlen) { - mp1 = mp + mask_cells; - - iparent = *mp1; - alen = OF_getprop(iparent, "#address-cells", - &address_cells, sizeof(address_cells)); - if (alen == -1) - address_cells = 0; - ilen = OF_getprop(iparent, "#interrupt-cells", - &interrupt_cells, sizeof(interrupt_cells)); - if (ilen == -1) - goto nomap; - - step = mask_cells + 1 + address_cells + interrupt_cells; - - match = bcmp(maskedaddr, mp, mlen); - if (match == 0) { - if (OF_getprop(iparent, "interrupt-controller", - NULL, 0) == 0) { - *intr = mp1[1]; - return 1; - } - /* Recurse with new 'addr'. */ - return find_node_intr(iparent, &mp1[1], intr); - } - len -= step * sizeof(u_int32_t); - mp += step; - } -nomap: - return -1; -} - -void -fix_node_irq(int node, struct pcibus_attach_args *pba) -{ - struct { - u_int32_t phys_hi, phys_mid, phys_lo; - u_int32_t size_hi, size_lo; - } addr [8]; - u_int32_t map[144]; - int len; - pcitag_t tag; - u_int32_t irq; - u_int32_t intr; - int parent; - - pci_chipset_tag_t pc = pba->pba_pc; - - len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr)); - if (len == -1 || len < sizeof(addr[0])) - return; - - /* if this node has a AAPL,interrupts property, firmware - * has initialized the register correctly. - */ - len = OF_getprop(node, "AAPL,interrupts", &intr, 4); - if (len != 4) { - - parent = OF_parent(node); - - irq = -1; - - /* we want the first interrupt, set size_hi to 1 */ - addr[0].size_hi = 1; - if (find_node_intr(parent, &addr[0].phys_hi, &irq) == -1) { - len = OF_getprop(node, "interrupts", map, - sizeof(map)); - if (len != -1 && len != 4) { - irq = map[0]; - } else - return; - } - } else - irq = intr; - /* program the interrupt line register with the value - * found in openfirmware - */ - - tag = pci_make_tag(pc, pcibus(addr[0].phys_hi), - pcidev(addr[0].phys_hi), pcifunc(addr[0].phys_hi)); - - intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); - intr &= ~PCI_INTERRUPT_LINE_MASK; - intr |= irq & PCI_INTERRUPT_LINE_MASK; - pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); } static int @@ -663,92 +436,14 @@ mpcpcibrprint(void *aux, const char *pnp) return(UNCONF); } -void -mpc_attach_hook(struct device *parent, struct device *self, - struct pcibus_attach_args *pba) -{ -} - -int -of_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr) -{ - u_int8_t laddr[6]; - struct pcibr_config *lcp = lcpc->pc_conf_v; - int of_node = lcp->node; - int node, nn; - for (node = OF_child(of_node); node; node = nn) { - char name[32]; - int len; - len = OF_getprop(node, "name", name, - sizeof(name)); - name[len] = 0; - - len = OF_getprop(node, "local-mac-address", laddr, - sizeof laddr); - if (sizeof (laddr) == len) { - bcopy (laddr, oaddr, sizeof laddr); - return 1; - } - - /* iterate section */ - if ((nn = OF_child(node)) != 0) { - continue; - } - while ((nn = OF_peer(node)) == 0) { - node = OF_parent(node); - if (node == of_node) { - nn = 0; /* done */ - break; - } - } - } - oaddr[0] = oaddr[1] = oaddr[2] = 0xff; - oaddr[3] = oaddr[4] = oaddr[5] = 0xff; - return 0; -} - -int -mpc_ether_hw_addr(struct ppc_pci_chipset *p, u_int8_t *s) -{ - printf("mpc_ether_hw_addr not supported\n"); - return(0); -} - -int -mpc_bus_maxdevs(void *cpv, int busno) -{ - return(32); -} - -#define BUS_SHIFT 16 -#define DEVICE_SHIFT 11 -#define FNC_SHIFT 8 - -pcitag_t -mpc_make_tag(void *cpv, int bus, int dev, int fnc) -{ - return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); -} - -void -mpc_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp) -{ - if (busp != NULL) - *busp = (tag >> BUS_SHIFT) & 0xff; - if (devp != NULL) - *devp = (tag >> DEVICE_SHIFT) & 0x1f; - if (fncp != NULL) - *fncp = (tag >> FNC_SHIFT) & 0x7; -} - u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset) { struct pcibr_config *cp = cpv; unsigned int bus, dev, fcn; - u_int32_t reg; + u_int32_t reg, val = PCITAG_OFFSET(tag); - mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); + pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); if (cp->config_type & 1) { /* Config Mechanism #2 */ @@ -762,31 +457,24 @@ mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset) * that 11-15 is reserved. */ reg = 1 << (dev) | fcn << 8 | offset; - } else { if (dev > 15) return 0xffffffff; /* * config type 1 */ - reg = tag | offset | 1; + reg = val | offset | 1; } } else { /* config mechanism #2, type 0 * standard cf8/cfc config */ - reg = 0x80000000 | tag | offset; + reg = 0x80000000 | val | offset; } return reg; } -int -mpc_conf_size(void *cpv, pcitag_t tag) -{ - return PCI_CONFIG_SPACE_SIZE; -} - /* #define DEBUG_CONFIG */ pcireg_t mpc_conf_read(void *cpv, pcitag_t tag, int offset) @@ -837,7 +525,7 @@ mpc_conf_read(void *cpv, pcitag_t tag, int offset) #ifdef DEBUG_CONFIG if (!((offset == 0) && (data == 0xffffffff))) { unsigned int bus, dev, fcn; - mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); + pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn, offset); printf(" daddr %x reg %x",daddr, reg); @@ -868,7 +556,7 @@ mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) #ifdef DEBUG_CONFIG { unsigned int bus, dev, fcn; - mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); + pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus, dev, fcn, offset); printf(" daddr %x reg %x",daddr, reg); @@ -886,55 +574,3 @@ mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) splx(s); } - - -/*ARGSUSED*/ -int -mpc_intr_map(void *lcv, pcitag_t bustag, int buspin, int line, - pci_intr_handle_t *ihp) -{ - int error = 0; - - *ihp = -1; - if (buspin == 0) - error = 1; /* No IRQ used. */ - else if (buspin > 4) { - printf("mpc_intr_map: bad interrupt pin %d\n", buspin); - error = 1; - } - if (line == 0xff || line == 0) - error = 1; - - if (!error) - *ihp = line; - return error; -} - -const char * -mpc_intr_string(void *lcv, pci_intr_handle_t ih) -{ - static char str[16]; - - snprintf(str, sizeof str, "irq %ld", ih); - return(str); -} - -int -mpc_intr_line(void *lcv, pci_intr_handle_t ih) -{ - return (ih); -} - -void * -mpc_intr_establish(void *lcv, pci_intr_handle_t ih, int level, - int (*func)(void *), void *arg, const char *name) -{ - return (*intr_establish_func)(lcv, ih, IST_LEVEL, level, func, arg, - name); -} - -void -mpc_intr_disestablish(void *lcv, void *cookie) -{ - /* XXX We should probably do something clever here.... later */ -} diff --git a/sys/arch/macppc/pci/pci_machdep.c b/sys/arch/macppc/pci/pci_machdep.c new file mode 100644 index 00000000000..fc32e87f12e --- /dev/null +++ b/sys/arch/macppc/pci/pci_machdep.c @@ -0,0 +1,340 @@ +/* $OpenBSD: pci_machdep.c,v 1.1 2013/08/07 07:29:19 mpi Exp $ */ + +/* + * Copyright (c) 2013 Martin Pieuchot + * Copyright (c) 1997 Per Fogelstrom + * + * 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 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <machine/bus.h> +#include <machine/autoconf.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_pci.h> + + +struct powerpc_bus_dma_tag pci_bus_dma_tag = { + NULL, + _dmamap_create, + _dmamap_destroy, + _dmamap_load, + _dmamap_load_mbuf, + _dmamap_load_uio, + _dmamap_load_raw, + _dmamap_unload, + _dmamap_sync, + _dmamem_alloc, + _dmamem_free, + _dmamem_map, + _dmamem_unmap, + _dmamem_mmap +}; + +void +pci_attach_hook(struct device *parent, struct device *self, + struct pcibus_attach_args *pba) +{ +} + +int +pci_bus_maxdevs(pci_chipset_tag_t pc, int busno) +{ + return (32); +} + +pcitag_t +pci_make_tag(pci_chipset_tag_t pc, int b, int d, int f) +{ + struct ofw_pci_register reg; + pcitag_t tag; + int node, busrange[2]; + + if (pc->busnode[b]) + return PCITAG_CREATE(0, b, d, f); + + for (node = pc->pc_node; node; node = OF_peer(node)) { + /* + * Check for PCI-PCI bridges. If the device we want is + * in the bus-range for that bridge, work our way down. + */ + while ((OF_getprop(node, "bus-range", &busrange, + sizeof(busrange)) == sizeof(busrange)) && + (b >= busrange[0] && b <= busrange[1])) { + node = OF_child(node); + } + + if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg)) + continue; + + if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi)) + continue; + if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi)) + continue; + if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi)) + continue; + + tag = PCITAG_CREATE(node, b, d, f); + + return (tag); + } + + return (PCITAG_CREATE(-1, b, d, f)); +} + +void +pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *b, int *d, int *f) +{ + if (b != NULL) + *b = PCITAG_BUS(tag); + if (d != NULL) + *d = PCITAG_DEV(tag); + if (f != NULL) + *f = PCITAG_FUN(tag); +} + +int +pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag) +{ + return (PCI_CONFIG_SPACE_SIZE); +} + +pcireg_t +pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) +{ + if (PCITAG_NODE(tag) != -1) + return (*(pc)->pc_conf_read)(pc->pc_conf_v, tag, reg); + + return ((pcireg_t)~0); +} + +void +pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) +{ + if (PCITAG_NODE(tag) != -1) + (*(pc)->pc_conf_write)(pc->pc_conf_v, tag, reg, data); +} + +int +pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + struct ofw_pci_register reg; + int node = PCITAG_NODE(pa->pa_tag); + int intr[4], nintr, len; + + if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg)) + return (ENODEV); + + /* Try to get the old Apple OFW interrupt property first. */ + len = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr)); + if (len == sizeof(intr[0])) + goto found; + + len = OF_getprop(node, "interrupts", intr, sizeof(intr)); + if (len < sizeof(intr[0])) + return (ENODEV); + + /* + * If we have multiple interrupts for a device, choose the one + * that corresponds to the PCI function. + */ + nintr = len / sizeof(intr[0]); + if (PCITAG_FUN(pa->pa_tag) < nintr) + intr[0] = intr[PCITAG_FUN(pa->pa_tag)]; + + reg.size_hi = intr[0]; + if (ofw_intr_map(OF_parent(node), (uint32_t *)®, intr)) { + /* + * This can fail on some machines where the parent's + * node doesn't have any "interrupt-map" and friends. + * + * In this case just trust what we got in "interrupts". + */ + } + +found: + *ihp = intr[0]; + + return (0); +} + +int +pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + return (-1); +} + +int +pci_intr_line(pci_chipset_tag_t pc, pci_intr_handle_t ih) +{ + return (ih); +} + +const char * +pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) +{ + static char str[16]; + + snprintf(str, sizeof(str), "irq %ld", ih); + + return (str); +} + +void * +pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int lvl, + int (*func)(void *), void *arg, const char *what) +{ + return (*intr_establish_func)(pc, ih, IST_LEVEL, lvl, func, arg, what); +} + +void +pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) +{ + (*intr_disestablish_func)(pc, cookie); +} + +int +pci_ether_hw_addr(pci_chipset_tag_t pc, uint8_t *oaddr) +{ + uint8_t laddr[6]; + int node, len; + + node = OF_finddevice("enet"); + len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr)); + if (sizeof(laddr) == len) { + memcpy(oaddr, laddr, sizeof(laddr)); + return (1); + } + + oaddr[0] = oaddr[1] = oaddr[2] = 0xff; + oaddr[3] = oaddr[4] = oaddr[5] = 0xff; + + return (0); +} + +int +ofw_enumerate_pcibus(struct pci_softc *sc, + int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) +{ + pci_chipset_tag_t pc = sc->sc_pc; + struct ofw_pci_register reg; + int node, b, d, f, ret; + pcireg_t bhlcr; + pcitag_t tag; + + if (sc->sc_bridgetag) + node = PCITAG_NODE(*sc->sc_bridgetag); + else + node = pc->pc_node; + + for (node = OF_child(node); node; node = OF_peer(node)) { + if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg)) + continue; + + b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi); + d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); + f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); + + tag = PCITAG_CREATE(node, b, d, f); + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + if (PCI_HDRTYPE_TYPE(bhlcr) > 2) + continue; + + ret = pci_probe_device(sc, tag, match, pap); + if (match != NULL && ret != 0) + return (ret); + } + + return (0); +} + +int +ofw_intr_map(int node, uint32_t *addr, uint32_t *intr) +{ + uint32_t imap[144], mmask[8], *mp, *mp1; + uint32_t acells, icells, mcells; + int ilen, mlen, i, step = 0; + int parent; + + ilen = OF_getprop(node, "interrupt-map", imap, sizeof(imap)); + mlen = OF_getprop(node, "interrupt-map-mask", mmask, sizeof(mmask)); + if (ilen < 0 || mlen < 0) + return (-1); + + if ((OF_getprop(node, "#address-cells", &acells, 4) < 0) || + (OF_getprop(node, "#interrupt-cells", &icells, 4) < 0)) + return (-1); + + mcells = acells + icells; + if (mcells != (mlen / sizeof(mmask[0]))) + return (-1); + + for (i = 0; i < mcells; i++) + addr[i] &= mmask[i]; + + /* interrupt-map is formatted as follows + * int * #address-cells, int * #interrupt-cells, int, int, int + * eg + * address-cells = 3 + * interrupt-cells = 1 + * 00001000 00000000 00000000 00000000 ff911258 00000034 00000001 + * 00001800 00000000 00000000 00000000 ff911258 00000035 00000001 + * 00002000 00000000 00000000 00000000 ff911258 00000036 00000001 + * | address cells | | intr | |node| | irq | |edge/level| + * | cells| | interrupt cells | + * | of node | + * or at least something close to that. + */ + for (mp = imap; ilen > mlen; mp += step) { + mp1 = mp + mcells; + parent = *mp1; + + if (bcmp(mp, addr, mlen) == 0) { + /* + * If we have a match and the parent is not an + * interrupt controller continue recursively. + */ + if (OF_getprop(parent, "interrupt-controller", NULL, 0)) + return ofw_intr_map(parent, &mp1[1], intr); + + *intr = mp1[1]; + return (0); + } + + if (OF_getprop(parent, "#address-cells", &acells, 4) < 0) + acells = 0; + if (OF_getprop(parent, "#interrupt-cells", &icells, 4) < 0) + break; + + step = mcells + 1 + acells + icells; + ilen -= step * sizeof(imap[0]); + } + + return (-1); +} |