diff options
author | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-07-07 13:28:59 +0000 |
---|---|---|
committer | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-07-07 13:28:59 +0000 |
commit | 1ce081cf8a770c9444e16eea79a50c07a845d6d7 (patch) | |
tree | 955323bff96f9f9e8965c8d3377f6c1bde060bb3 /sys/arch | |
parent | 75e5ac6599ffd77467cf9ed596b42328c0d10a86 (diff) |
Support config type 2 as required for proper uni-north pci config cycles.
use the same code for read and write for easier maintance.
code to walk the openfirmware device tree when a bridge is configured
to copy the interrupt line information into the pci register so
that the device driver can use it. Apple Openfirmware doesn't do
this automatically.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/powerpc/pci/mpcpcibus.c | 347 |
1 files changed, 251 insertions, 96 deletions
diff --git a/sys/arch/powerpc/pci/mpcpcibus.c b/sys/arch/powerpc/pci/mpcpcibus.c index dbe86716df5..d14f0edaf75 100644 --- a/sys/arch/powerpc/pci/mpcpcibus.c +++ b/sys/arch/powerpc/pci/mpcpcibus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpcpcibus.c,v 1.16 2000/04/01 15:38:21 rahnds Exp $ */ +/* $OpenBSD: mpcpcibus.c,v 1.17 2000/07/07 13:28:58 rahnds Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -33,7 +33,8 @@ */ /* - * MPC106 PCI BUS Bridge driver. + * Generic PCI BUS Bridge driver. + * specialized hooks for different config methods. */ #include <sys/param.h> @@ -92,6 +93,15 @@ static int mpcpcibrprint __P((void *, const char *pnp)); struct pcibr_config mpc_config; +/* + * config types + * bit meanings + * 0 - standard cf8/cfc type configurations, + * sometimes the base addresses for these are different + * 1 - Config Method #2 configuration - uni-north + * + * 2 - 64 bit config bus, data for accesses &4 is at daddr+4; + */ struct { char * compat; u_int32_t addr; /* offset */ @@ -99,7 +109,7 @@ struct { int config_type; } config_offsets[] = { {"grackle", 0x00c00cf8, 0x00e00cfc, 0 }, - {"uni-north", 0x00800000, 0x00c00000, 1 }, + {"uni-north", 0x00800000, 0x00c00000, 3 }, {"legacy", 0x00000cf8, 0x00000cfc, 0 }, {"IBM,27-82660", 0x00000cf8, 0x00000cfc, 0 }, {NULL, 0x00000000, 0x00000000, 0 }, @@ -160,6 +170,8 @@ mpcpcibrmatch(parent, match, aux) return found; } +void fix_node_irq(int node, struct pcibus_attach_args *pba); + int pci_map_a = 0; void mpcpcibrattach(parent, self, aux) @@ -170,8 +182,9 @@ mpcpcibrattach(parent, self, aux) struct confargs *ca = aux; struct pcibr_config *lcp; struct pcibus_attach_args pba; - int map; + int map, node; char *bridge; + int of_node = 0; switch(system_type) { case POWER4e: @@ -328,17 +341,6 @@ mpcpcibrattach(parent, self, aux) int i; int len; -#if 0 - /* for powerstack boxes? */ - struct ranges_old { - u_int32_t flags; - u_int32_t pad1; - u_int32_t pad2; - u_int32_t base; - u_int32_t size; - }; - struct ranges_old porange = &range_store; -#endif struct ranges_new { u_int32_t flags; u_int32_t pad1; @@ -367,24 +369,6 @@ mpcpcibrattach(parent, self, aux) lcp = sc->sc_pcibr = &sc->pcibr_config; -#if 0 - /* powerstack boxes? */ - if (strcmp(compat, "IBM,27-82660") { - sc->sc_membus_space.bus_base = - MPC106_P_PCI_MEM_SPACE; - sc->sc_membus_space.bus_reverse = 1; - sc->sc_iobus_space.bus_base = - MPC106_P_PCI_IO_SPACE; - sc->sc_iobus_space.bus_reverse = 1; - if ( bus_space_map(&(sc->sc_iobus_space), 0, - NBPG, 0, &lcp->ioh_cf8) != 0 ) - { - panic("mpcpcibus: unable to" - " map self\n"); - } - lcp->ioh_cfc = lcp->ioh_cf8; - } else -#endif { int found; @@ -442,6 +426,7 @@ mpcpcibrattach(parent, self, aux) data_offset = config_offsets[i].data; lcp->config_type = config_offsets[i].config_type; + break; } } if (addr_offset == 0) { @@ -449,8 +434,13 @@ mpcpcibrattach(parent, self, aux) " compatible %s\n", compat); return; } - printf("found mem base %x io base %x config addr %x config data %x\n", - sc->sc_membus_space.bus_base, sc->sc_iobus_space.bus_base, addr_offset, data_offset); +#if 0 + printf("found mem base %x io base %x config addr %x" + " config data %x\n", + sc->sc_membus_space.bus_base, + sc->sc_iobus_space.bus_base, + addr_offset, data_offset); +#endif @@ -464,8 +454,10 @@ mpcpcibrattach(parent, self, aux) { panic("mpcpcibus: unable to map self\n"); } + of_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; @@ -483,7 +475,6 @@ mpcpcibrattach(parent, self, aux) lcp->lc_pc.pc_intr_establish = mpc_intr_establish; lcp->lc_pc.pc_intr_disestablish = mpc_intr_disestablish; - printf(": %s, Revision %x. ", bridge, mpc_cfg_read_1(lcp, MPC106_PCI_REVID)); break; @@ -494,15 +485,153 @@ mpcpcibrattach(parent, self, aux) } pba.pba_dmat = &pci_bus_dma_tag; + pba.pba_busname = "pci"; pba.pba_iot = &sc->sc_iobus_space; pba.pba_memt = &sc->sc_membus_space; pba.pba_pc = &lcp->lc_pc; 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; +#if 0 + printf("checking node %s\n", name); +#endif + } + 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(node, addr, intr) + int node; + u_int32_t *addr, *intr; +{ + int parent, iparent, len, mlen; + int match, i; + u_int32_t map[64], *mp; + u_int32_t imask[8], maskedaddr[8]; + u_int32_t icells; + char name [32]; + + len = OF_getprop(node, "AAPL,interrupts", intr, 4); + if (len == 4) + return 1; + + parent = OF_parent(node); + len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); + mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask)); + + if ((len == -1) || (mlen == -1)) + goto nomap; + for (i = 0; i < (mlen / 4); i++) { + maskedaddr[i] = addr[i] & imask[i]; + } + mp = map; + while (len > mlen) { + match = bcmp(maskedaddr, mp, mlen); + mp += mlen / 4; + len -= mlen; + iparent = *mp++; + if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4) + return -1; + + if (match == 0) { + /* multiple irqs? */ + *intr = *mp; + return 1; + } + mp += icells; + len -= icells * 4; + } + return -1; +nomap: + return -1; +} + +void +fix_node_irq(node, pba) + 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]; + int len; + pcitag_t tag; + u_int32_t irq; + u_int32_t intr; + + pci_chipset_tag_t pc = pba->pba_pc; + + len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr)); + if (len < sizeof(addr[0])) { + return; + } + tag = pci_make_tag(pc, pcibus(addr[0].phys_hi), + pcidev(addr[0].phys_hi), + pcifunc(addr[0].phys_hi)); + /* program the interrupt line register with the value + * found in openfirmware + */ + if (find_node_intr(node, &addr[0].phys_hi, &irq) == -1) + return; + + intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); +#if 0 + printf("changing interrupt from %d to %d\n", + intr & PCI_INTERRUPT_LINE_MASK, + irq & PCI_INTERRUPT_LINE_MASK); +#endif + intr &= ~PCI_INTERRUPT_LINE_MASK; + intr |= irq & PCI_INTERRUPT_LINE_MASK; + pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); +} static int mpcpcibrprint(aux, pnp) @@ -624,7 +753,57 @@ mpc_decompose_tag(cpv, tag, busp, devp, fncp) *fncp = (tag >> FNC_SHIFT) & 0x7; } +static u_int32_t +mpc_gen_config_reg(cpv, tag, offset) + void *cpv; + pcitag_t tag; + int offset; +{ + struct pcibr_config *cp = cpv; + unsigned int bus, dev, fcn; + u_int32_t reg; + /* + static int spin = 0; + while (spin > 85); + spin++; + */ + + mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); + + if (cp->config_type & 1) { + /* Config Mechanism #2 */ + if (bus == 0) { + if (dev < 11) { + return 0xffffffff; + } + /* + * Need to do config type 0 operation + * 1 << (11?+dev) | fcn << 8 | reg + * 11? is because pci spec states + * that 11-15 is reserved. + */ + reg = 1 << (dev) | fcn << 8 | offset; + + } else { + if (dev > 15) { + return 0xffffffff; + } + /* + * config type 1 + */ + reg = tag | offset | 1; + + } + } else { + /* config mechanism #2, type 0 + /* standard cf8/cfc config */ + reg = 0x80000000 | tag | offset; + } + return reg; +} + +/* #define DEBUG_CONFIG */ pcireg_t mpc_conf_read(cpv, tag, offset) void *cpv; @@ -639,47 +818,22 @@ mpc_conf_read(cpv, tag, offset) int s; int handle; int daddr = 0; - unsigned int bus, dev, fcn; if(offset & 3 || offset < 0 || offset >= 0x100) { printf ("pci_conf_read: bad reg %x\n", offset); return(~0); } - mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); - - if ((cp->config_type & 1) && (bus == 0)) { - if (dev > (30 - 11)) { - return 0xffffffff; - } -#if 0 - printf(" bus %x dev %x fcn %x offset %x", bus, dev, fcn, offset); -#endif - /* - * Need to do config type 1 operation - * 1 << (11+dev) | fcn << 8 | reg - */ - reg = 1 << (11+dev) | fcn << 8 | offset; - if ((cp->config_type & 2) && (offset & 0x4)) { - daddr += 4; - } - - } else { -#if 0 - printf(" bus %x dev %x fcn %x offset %x", bus, dev, fcn, offset); -#endif - /* Config type 0 operation - * 80000000 | tag | offset - */ - reg = 0x80000000 | tag | offset; - if (bus != 0) { - reg |= 1; - } + reg = mpc_gen_config_reg(cpv, tag, offset); + /* if invalid tag, return -1 */ + if (reg == 0xffffffff) { + return 0xffffffff; + } + if ((cp->config_type & 2) && (offset & 0x04)) { + daddr += 4; } -#if 0 - printf(" daddr %x reg %x",daddr, reg); -#endif + s = splhigh(); bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); @@ -689,8 +843,15 @@ mpc_conf_read(cpv, tag, offset) bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ splx(s); -#if 0 - printf("data %x\n", data); +#ifdef DEBUG_CONFIG + if (!((offset == 0) && (data == 0xffffffff))) { + unsigned int bus, dev, fcn; + mpc_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); + printf(" data %x\n", data); + } #endif return(data); @@ -707,39 +868,33 @@ mpc_conf_write(cpv, tag, offset, data) u_int32_t reg; int s; int handle; + int daddr = 0; -#if 0 - printf("mpc_conf_write tag %x offset %x data %x\n", tag, offset, data); -#endif - - reg = 0x80000000 | tag | offset; + reg = mpc_gen_config_reg(cpv, tag, offset); - if (cp->config_type == 1) { + /* if invalid tag, return ??? */ + if (reg == 0xffffffff) { + return; + } + if ((cp->config_type & 2) && (offset & 0x04)) { + daddr += 4; + } +#ifdef DEBUG_CONFIG + { unsigned int bus, dev, fcn; - /* - * Need to do config type 1 operation - * 80800000 | 1 << dev | fcn << 8 | reg - */ - if ( dev > 11) { -#if 0 - printf("invalid device\n", dev); -#endif - return; - } mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); - reg = 0x80800000 | 1 << dev | fcn << 8 | offset; - - } else { - /* Config type 0 operation - * 80800000 | bus << 16 | dev << 11 | - */ - reg = 0x80000000 | tag | offset; - + printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus, + dev, fcn, offset); + printf(" daddr %x reg %x",daddr, reg); + printf(" data %x\n", data); } +#endif + + s = splhigh(); bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ - bus_space_write_4(cp->lc_iot, cp->ioh_cfc, 0, data); + bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data); bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */ bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ |