diff options
Diffstat (limited to 'sys/arch/macppc')
-rw-r--r-- | sys/arch/macppc/conf/GENERIC | 14 | ||||
-rw-r--r-- | sys/arch/macppc/conf/files.macppc | 6 | ||||
-rw-r--r-- | sys/arch/macppc/include/rbus_machdep.h | 61 | ||||
-rw-r--r-- | sys/arch/macppc/macppc/machdep.c | 27 | ||||
-rw-r--r-- | sys/arch/macppc/macppc/rbus_machdep.c | 146 | ||||
-rw-r--r-- | sys/arch/macppc/pci/mpcpcibus.c | 31 | ||||
-rw-r--r-- | sys/arch/macppc/pci/pci_addr_fixup.c | 498 | ||||
-rw-r--r-- | sys/arch/macppc/pci/pcibrvar.h | 9 |
8 files changed, 750 insertions, 42 deletions
diff --git a/sys/arch/macppc/conf/GENERIC b/sys/arch/macppc/conf/GENERIC index 4651f252fa5..a396620abcc 100644 --- a/sys/arch/macppc/conf/GENERIC +++ b/sys/arch/macppc/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.28 2002/06/25 17:11:49 itojun Exp $g +# $OpenBSD: GENERIC,v 1.29 2002/07/23 17:53:24 drahn Exp $g # # PPC GENERIC config file # @@ -168,6 +168,18 @@ aue* at uhub? port ? # USB EtherNet uplcom* at uhub? port ? # I/O DATA USB-RSAQ2 serial adapter ucom* at uplcom? portno ? +# CardBus bus support +cardbus* at cardslot? +pcmcia* at cardslot? +cbb* at pci? dev ? function ? +cardslot* at cbb? +wi* at pcmcia? function ? # WaveLAN IEEE 802.11DS +#dc* at cardbus? dev ? function ? # 21143, "tulip" clone ethernet +#fxp* at cardbus? dev ? function ? # Intel PRO/100 ethernet +#xl* at cardbus? dev ? function ? # 3C575/3C656 ethernet +#rl* at cardbus? dev ? function ? # RealTek 81[23]9 ethernet +#wdc* at pcmcia? function ? + wsdisplay* at vgafb? wskbd* at ukbd? console ? mux 1 diff --git a/sys/arch/macppc/conf/files.macppc b/sys/arch/macppc/conf/files.macppc index 3f7b71b8655..6149a487c3c 100644 --- a/sys/arch/macppc/conf/files.macppc +++ b/sys/arch/macppc/conf/files.macppc @@ -1,4 +1,4 @@ -# $OpenBSD: files.macppc,v 1.12 2002/06/25 17:11:49 itojun Exp $ +# $OpenBSD: files.macppc,v 1.13 2002/07/23 17:53:24 drahn Exp $ # # macppc-specific configuration info @@ -71,7 +71,7 @@ file arch/macppc/pci/pciide_machdep.c pciide device mpcpcibr {} : pcibus attach mpcpcibr at mainbus file arch/macppc/pci/mpcpcibus.c mpcpcibr -#file arch/macppc/pci/pci_addr_fixup.c mpcpcibr +file arch/macppc/pci/pci_addr_fixup.c mpcpcibr # # "workstation console" routines @@ -204,7 +204,7 @@ file arch/macppc/pci/vgafb_pci.c vgafb_pci needs-flag # CARDBUS # include "dev/cardbus/files.cardbus" -#file arch/macppc/macppc/rbus_machdep.c cardbus +file arch/macppc/macppc/rbus_machdep.c cardbus # # Machine-independent PCMCIA drivers diff --git a/sys/arch/macppc/include/rbus_machdep.h b/sys/arch/macppc/include/rbus_machdep.h new file mode 100644 index 00000000000..42bb0cc022b --- /dev/null +++ b/sys/arch/macppc/include/rbus_machdep.h @@ -0,0 +1,61 @@ +/* $OpenBSD: rbus_machdep.h,v 1.1 2002/07/23 17:53:24 drahn Exp $ */ +/* $NetBSD: rbus_machdep.h,v 1.2 1999/10/15 06:43:05 haya Exp $ */ + +/* + * Copyright (c) 1999 + * HAYAKAWA Koichi. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by HAYAKAWA Koichi. + * 4. 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 ``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. + */ + + +#if !defined _ARCH_MACPPC_MACPPC_RBUS_MACHDEP_H_ +#define _ARCH_MACPPC_MACPPC_RBUS_MACHDEP_H_ + +struct pci_attach_args; /* XXX */ + +void _bus_space_unmap(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_addr_t *); + +#define md_space_map(bt, physaddr, size, flags, bshp) \ + bus_space_map((bt), (physaddr), (size), (flags), (bshp)) + +/* XXX */ +bus_addr_t bus_space_unmap_p(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + + +#define md_space_unmap(bt, bsh, size, adrp) \ + do { \ + *adrp = bus_space_unmap_p((bt), (bsh), (size)); \ + } while (0) + +rbus_tag_t rbus_pccbb_parent_io(struct device *self, + struct pci_attach_args *pa); +rbus_tag_t rbus_pccbb_parent_mem(struct device *self, + struct pci_attach_args *pa); + +#endif /* _ARCH_MACPPC_MACPPC_RBUS_MACHDEP_H_ */ diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c index f50cb9699ae..e76cf0d1fa4 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.36 2002/07/20 19:24:56 art Exp $ */ +/* $OpenBSD: machdep.c,v 1.37 2002/07/23 17:53:24 drahn Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -1168,30 +1168,31 @@ bus_space_unmap(t, bsh, size) { bus_addr_t sva; bus_size_t off, len; + bus_addr_t bpa; /* should this verify that the proper size is freed? */ sva = trunc_page(bsh); off = bsh - sva; len = size+off; + if (pmap_extract(pmap_kernel(), sva, &bpa) == TRUE) { + if (extent_free(devio_ex, bpa, size, EX_NOWAIT | + (ppc_malloc_ok ? EX_MALLOCOK : 0))) + { + printf("bus_space_map: pa 0x%x, size 0x%x\n", + bpa, size); + printf("bus_space_map: can't free region\n"); + } + } /* do not free memory which was stolen from the vm system */ if (ppc_malloc_ok && ((sva >= VM_MIN_KERNEL_ADDRESS) && (sva < VM_MAX_KERNEL_ADDRESS)) ) { uvm_km_free(phys_map, sva, len); + } else { + pmap_remove(vm_map_pmap(phys_map), sva, sva+len); + pmap_update(pmap_kernel()); } -#if 0 - pmap_extract(pmap_kernel(), sva, &bpa); - if (extent_free(devio_ex, bpa, size, EX_NOWAIT | - (ppc_malloc_ok ? EX_MALLOCOK : 0))) - { - printf("bus_space_map: pa 0x%x, size 0x%x\n", - bpa, size); - printf("bus_space_map: can't free region\n"); - } -#endif - pmap_remove(vm_map_pmap(phys_map), sva, sva+len); - pmap_update(pmap_kernel()); } vm_offset_t ppc_kvm_stolen = VM_KERN_ADDRESS_SIZE; diff --git a/sys/arch/macppc/macppc/rbus_machdep.c b/sys/arch/macppc/macppc/rbus_machdep.c new file mode 100644 index 00000000000..b801620c47f --- /dev/null +++ b/sys/arch/macppc/macppc/rbus_machdep.c @@ -0,0 +1,146 @@ +/* $OpenBSD: rbus_machdep.c,v 1.1 2002/07/23 17:53:24 drahn Exp $ */ +/* $NetBSD: rbus_machdep.c,v 1.2 1999/10/15 06:43:06 haya Exp $ */ + +/* + * Copyright (c) 1999 + * HAYAKAWA Koichi. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by HAYAKAWA Koichi. + * 4. 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 ``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 <sys/extent.h> + +#include <uvm/uvm_extern.h> + +#include <sys/sysctl.h> + +#include <sys/device.h> + +#include <machine/bus.h> +#include <dev/cardbus/rbus.h> + +#include <dev/pci/pcivar.h> +#include <arch/macppc/pci/pcibrvar.h> + +void macppc_cardbus_init(pci_chipset_tag_t pc, pcitag_t tag); + +/********************************************************************** + * rbus_tag_t rbus_fakeparent_mem(struct pci_attach_args *pa) + * + * This function makes an rbus tag for memory space. This rbus tag + * shares the all memory region of ex_iomem. + **********************************************************************/ +#define RBUS_MEM_SIZE 0x10000000 + +rbus_tag_t +rbus_pccbb_parent_mem(self, pa) + struct device *self; + struct pci_attach_args *pa; +{ + bus_addr_t start; + bus_size_t size; + struct extent *ex; + + macppc_cardbus_init(pa->pa_pc, pa->pa_tag); + + size = RBUS_MEM_SIZE; + if ((ex = pciaddr_search(PCIADDR_SEARCH_MEM, self, &start, size)) == NULL) + { + /* XXX */ + printf("failed\n"); + } + + return rbus_new_root_share(pa->pa_memt, ex, start, size, 0); +} + + +/********************************************************************** + * rbus_tag_t rbus_pccbb_parent_io(struct pci_attach_args *pa) + **********************************************************************/ +#define RBUS_IO_SIZE 0x1000 + +rbus_tag_t +rbus_pccbb_parent_io(self, pa) + struct device *self; + struct pci_attach_args *pa; +{ + struct extent *ex; + bus_addr_t start; + bus_size_t size; + + + size = RBUS_IO_SIZE; + if ((ex = pciaddr_search(PCIADDR_SEARCH_IO, self, &start, size)) == NULL) + { + /* XXX */ + printf("failed\n"); + } + + return rbus_new_root_share(pa->pa_iot, ex, start, size, 0); +} + + +/* + * Big ugly hack to enable bridge/fix interrupts + */ +void +macppc_cardbus_init(pc, tag) + pci_chipset_tag_t pc; + pcitag_t tag; +{ + u_int x; + static int initted = 0; + + if (initted) + return; + initted = 1; + + /* XXX What about other bridges? */ + + x = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(x) == PCI_VENDOR_TI && + PCI_PRODUCT(x) == PCI_PRODUCT_TI_PCI1211) { + /* For CardBus card. */ + pci_conf_write(pc, tag, 0x18, 0x10010100); + + /* Route INTA to MFUNC0 */ + x = pci_conf_read(pc, tag, 0x8c); + x |= 0x02; + pci_conf_write(pc, tag, 0x8c, x); + + tag = pci_make_tag(pc, 0, 0, 0); + x = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(x) == PCI_VENDOR_MOT && + PCI_PRODUCT(x) == PCI_PRODUCT_MOT_MPC106) { + /* Set subordinate bus number to 1. */ + x = pci_conf_read(pc, tag, 0x40); + x |= 1 << 8; + pci_conf_write(pc, tag, 0x40, x); + } + } +} diff --git a/sys/arch/macppc/pci/mpcpcibus.c b/sys/arch/macppc/pci/mpcpcibus.c index 6d7d4d0483a..ac7a104ed31 100644 --- a/sys/arch/macppc/pci/mpcpcibus.c +++ b/sys/arch/macppc/pci/mpcpcibus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpcpcibus.c,v 1.10 2002/04/22 21:39:58 miod Exp $ */ +/* $OpenBSD: mpcpcibus.c,v 1.11 2002/07/23 17:53:25 drahn Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -445,7 +445,7 @@ mpcpcibrattach(parent, self, aux) " compatible %s\n", compat); return; } -#ifdef PCI_DEBUG +#ifdef DEBUG_FIXUP printf(" mem base %x sz %x io base %x sz %x\n config addr %x" " config data %x\n", sc->sc_membus_space.bus_base, @@ -492,9 +492,7 @@ mpcpcibrattach(parent, self, aux) printf(": %s, Revision 0x%x\n", compat, mpc_cfg_read_1(lcp, MPC106_PCI_REVID)); -#if 0 - pci_addr_fixup(sc, &lcp->lc_pc, 32, &null_reserve); -#endif + pci_addr_fixup(sc, &lcp->lc_pc, 32); } break; @@ -523,9 +521,6 @@ mpcpcibrattach(parent, self, aux) len = OF_getprop(node, "name", name, sizeof(name)); name[len] = 0; -#ifdef DEBUG_FIXUP - printf("checking node %s", name); -#endif fix_node_irq(node, &pba); /* iterate section */ @@ -574,9 +569,6 @@ find_node_intr(int parent, u_int32_t *addr, u_int32_t *intr) len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask)); -#ifdef DEBUG_FIXUP - printf("parent %x len %x mlen %x\n", parent, len, mlen); -#endif if ((len == -1) || (mlen == -1)) goto nomap; n_mlen = mlen/sizeof(u_int32_t); @@ -601,11 +593,6 @@ find_node_intr(int parent, u_int32_t *addr, u_int32_t *intr) } while (len > mlen) { -#ifdef DEBUG_FIXUP - printf ("[%x %x %x %x] [%x %x %x %x] %x\n", - maskedaddr[0], maskedaddr[1], maskedaddr[2], maskedaddr[3], - mp[0], mp[1], mp[2], mp[3], step); -#endif match = bcmp(maskedaddr, mp, mlen); mp1 = mp + n_mlen; @@ -672,11 +659,6 @@ fix_node_irq(node, pba) pcifunc(addr[0].phys_hi)); intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); -#ifdef DEBUG_FIXUP - printf("changing interrupt from %x to %x\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); @@ -1126,3 +1108,10 @@ mpc_cfg_read_4(cp, reg) splx(s); return(_v_); } + +int +pci_intr_line(ih) + pci_intr_handle_t ih; +{ + return (ih); +} diff --git a/sys/arch/macppc/pci/pci_addr_fixup.c b/sys/arch/macppc/pci/pci_addr_fixup.c new file mode 100644 index 00000000000..2055be6a380 --- /dev/null +++ b/sys/arch/macppc/pci/pci_addr_fixup.c @@ -0,0 +1,498 @@ +/* $OpenBSD: pci_addr_fixup.c,v 1.1 2002/07/23 17:53:25 drahn Exp $ */ +/* $NetBSD: pci_addr_fixup.c,v 1.7 2000/08/03 20:10:45 nathanw Exp $ */ + +/*- + * Copyright (c) 2000 UCHIYAMA Yasushi. 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 ``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 <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/extent.h> + +#include <uvm/uvm_param.h> +#include <machine/bus.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <macppc/pci/pcibrvar.h> + +typedef int (*pciaddr_resource_manage_func_t)(struct pcibr_softc *, + pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *, + bus_size_t); +void pciaddr_resource_manage(struct pcibr_softc *, + pci_chipset_tag_t, pcitag_t, pciaddr_resource_manage_func_t); +void pciaddr_resource_reserve(struct pcibr_softc *, + pci_chipset_tag_t, pcitag_t); +int pciaddr_do_resource_reserve(struct pcibr_softc *, + pci_chipset_tag_t, pcitag_t, int, struct extent *, int, + bus_addr_t *, bus_size_t); +void pciaddr_resource_allocate(struct pcibr_softc *, + pci_chipset_tag_t, pcitag_t); +int pciaddr_do_resource_allocate(struct pcibr_softc *, + pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *, + bus_size_t); +bus_addr_t pciaddr_ioaddr(u_int32_t); +void pciaddr_print_devid(pci_chipset_tag_t, pcitag_t); + +int pciaddr_device_is_agp(pci_chipset_tag_t, pcitag_t); + +void pci_device_foreach(struct pcibr_softc *sc, pci_chipset_tag_t pc, + int maxbus, + void (*func)(struct pcibr_softc *, pci_chipset_tag_t, pcitag_t)); + +#define PCIADDR_MEM_START 0x0 +#define PCIADDR_MEM_END 0xffffffff +#define PCIADDR_PORT_START 0x0 +#define PCIADDR_PORT_END 0xffff + +int pcibr_flags = 0; +#define PCIBR_VERBOSE 1 +#define PCIBR_ADDR_FIXUP 2 + +#define PCIBIOS_PRINTV(x) if (pcibr_flags & PCIBR_VERBOSE) \ + printf x + +void +pci_addr_fixup(sc, pc, maxbus) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + int maxbus; +{ + const char *verbose_header = + "[%s]-----------------------\n" + " device vendor product\n" + " register space address size\n" + "--------------------------------------------\n"; + const char *verbose_footer = + "--------------------------[%3d devices bogus]\n"; + + sc->extent_mem = extent_create("PCI I/O memory space", + sc->sc_membus_space.bus_base, + sc->sc_membus_space.bus_base + sc->sc_membus_space.bus_size, + M_DEVBUF, 0, 0, EX_NOWAIT); + KASSERT(sc->extent_mem); + sc->extent_port = extent_create("PCI I/O port space", +#if 1 + sc->sc_iobus_space.bus_base, + sc->sc_iobus_space.bus_base + sc->sc_iobus_space.bus_size, +#else + PCIADDR_PORT_START, PCIADDR_PORT_END, +#endif + M_DEVBUF, 0, 0, EX_NOWAIT); + KASSERT(sc->extent_port); + + /* + * 1. check & reserve system BIOS setting. + */ + PCIBIOS_PRINTV((verbose_header, "System BIOS Setting")); + pci_device_foreach(sc, pc, maxbus, pciaddr_resource_reserve); + PCIBIOS_PRINTV((verbose_footer, sc->nbogus)); + + { + struct extent_region *rp; + struct extent *ex = sc->extent_mem; + for (rp = LIST_FIRST(&ex->ex_regions); + rp; rp = LIST_NEXT(rp, er_link)) { + } + } + { + struct extent_region *rp; + struct extent *ex = sc->extent_port; + for (rp = LIST_FIRST(&ex->ex_regions); + rp; rp = LIST_NEXT(rp, er_link)) { + } + } + + if (sc->nbogus == 0) + return; /* no need to fixup */ + + /* + * 4. do fixup + */ + PCIBIOS_PRINTV((verbose_header, "PCIBIOS fixup stage")); + sc->nbogus = 0; + pci_device_foreach(sc, pc, maxbus, pciaddr_resource_allocate); + PCIBIOS_PRINTV((verbose_footer, sc->nbogus)); + +} + +void +pciaddr_resource_reserve(sc, pc, tag) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + pcitag_t tag; +{ + if (pcibr_flags & PCIBR_VERBOSE) + pciaddr_print_devid(pc, tag); + pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_reserve); +} + +void +pciaddr_resource_allocate(sc, pc, tag) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + pcitag_t tag; +{ + if (pcibr_flags & PCIBR_VERBOSE) + pciaddr_print_devid(pc, tag); + pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_allocate); +} + +void +pciaddr_resource_manage(sc, pc, tag, func) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + pcitag_t tag; + pciaddr_resource_manage_func_t func; +{ + struct extent *ex; + pcireg_t val, mask; + bus_addr_t addr; + bus_size_t size; + int error, mapreg, type, reg_start, reg_end, width; + + val = pci_conf_read(pc, tag, PCI_BHLC_REG); + switch (PCI_HDRTYPE_TYPE(val)) { + default: + printf("WARNING: unknown PCI device header.\n"); + sc->nbogus++; + return; + case 0: + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_END; + break; + case 1: /* PCI-PCI bridge */ + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_PPB_END; + break; + case 2: /* PCI-CardBus bridge */ + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_PCB_END; + break; + } + error = 0; + + for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { + /* inquire PCI device bus space requirement */ + val = pci_conf_read(pc, tag, mapreg); + pci_conf_write(pc, tag, mapreg, ~0); + + mask = pci_conf_read(pc, tag, mapreg); + pci_conf_write(pc, tag, mapreg, val); + + type = PCI_MAPREG_TYPE(val); + width = 4; + if (type == PCI_MAPREG_TYPE_MEM) { + if (PCI_MAPREG_MEM_TYPE(val) == + PCI_MAPREG_MEM_TYPE_64BIT) { + /* XXX We could examine the upper 32 bits + * XXX of the BAR here, but we are totally + * XXX unprepared to handle a non-zero value, + * XXX either here or anywhere else in + * XXX i386-land. + * XXX So just arrange to not look at the + * XXX upper 32 bits, lest we misinterpret + * XXX it as a 32-bit BAR set to zero. + */ + width = 8; + } + addr = PCI_MAPREG_MEM_ADDR(val); + size = PCI_MAPREG_MEM_SIZE(mask); + ex = sc->extent_mem; + } else { + /* XXX some devices give 32bit value */ + addr = (PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END) | + sc->sc_iobus_space.bus_base, + + size = PCI_MAPREG_IO_SIZE(mask); + ex = sc->extent_port; + } + + if (!size) /* unused register */ + continue; + + /* reservation/allocation phase */ + error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size); + + PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n", + mapreg, type ? "port" : "mem ", + (unsigned int)addr, (unsigned int)size)); + } + + /* enable/disable PCI device */ + val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); + if (error == 0) + val |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | + PCI_COMMAND_MASTER_ENABLE); + else + val &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | + PCI_COMMAND_MASTER_ENABLE); + pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); + + if (error) + sc->nbogus++; + + PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK")); +} + +int +pciaddr_do_resource_allocate(sc, pc, tag, mapreg, ex, type, addr, size) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + pcitag_t tag; + struct extent *ex; + int mapreg, type; + bus_addr_t *addr; + bus_size_t size; +{ + bus_addr_t start; + int error; + + if (*addr) /* no need to allocate */ + return (0); + + /* XXX Don't allocate if device is AGP device to avoid conflict. */ + if (pciaddr_device_is_agp(pc, tag)) + return (0); + + start = (type == PCI_MAPREG_TYPE_MEM ? sc->sc_membus_space.bus_base + : sc->sc_iobus_space.bus_base); + if (start < ex->ex_start || start + size - 1 >= ex->ex_end) { + PCIBIOS_PRINTV(("No available resources. fixup failed\n")); + return (1); + } + error = extent_alloc_subregion(ex, start, ex->ex_end, size, size, 0, 0, + EX_FAST|EX_NOWAIT|EX_MALLOCOK, addr); + if (error) { + PCIBIOS_PRINTV(("No available resources. fixup failed\n")); + return (1); + } + + /* write new address to PCI device configuration header */ + pci_conf_write(pc, tag, mapreg, *addr); + /* check */ + if (!pcibr_flags & PCIBR_VERBOSE) + { + printf("pci_addr_fixup: "); + pciaddr_print_devid(pc, tag); + } + + if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) { + pci_conf_write(pc, tag, mapreg, 0); /* clear */ + printf("fixup failed. (new address=%#x)\n", *addr); + return (1); + } + if (!pcibr_flags & PCIBR_VERBOSE) + printf("new address 0x%08x\n", *addr); + + return (0); +} + +int +pciaddr_do_resource_reserve(sc, pc, tag, mapreg, ex, type, addr, size) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + pcitag_t tag; + struct extent *ex; + int type, mapreg; + bus_addr_t *addr; + bus_size_t size; +{ + int error; + + if (*addr == 0) + return (1); + + error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK); + if (error) { + PCIBIOS_PRINTV(("Resource conflict.\n")); + pci_conf_write(pc, tag, mapreg, 0); /* clear */ + return (1); + } + + return (0); +} + +bus_addr_t +pciaddr_ioaddr(val) + u_int32_t val; +{ + return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) + ? PCI_MAPREG_MEM_ADDR(val) + : (PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END)); +} + +void +pciaddr_print_devid(pc, tag) + pci_chipset_tag_t pc; + pcitag_t tag; +{ + int bus, device, function; + pcireg_t id; + + id = pci_conf_read(pc, tag, PCI_ID_REG); + pci_decompose_tag(pc, tag, &bus, &device, &function); + printf("%03d:%02d:%d %04x:%04x\n", bus, device, function, + PCI_VENDOR(id), PCI_PRODUCT(id)); +} + +int +pciaddr_device_is_agp(pc, tag) + pci_chipset_tag_t pc; + pcitag_t tag; +{ + pcireg_t class, status, rval; + int off; + + /* Check AGP device. */ + class = pci_conf_read(pc, tag, PCI_CLASS_REG); + if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) { + status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); + if (status & PCI_STATUS_CAPLIST_SUPPORT) { + rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG); + for (off = PCI_CAPLIST_PTR(rval); + off != 0; + off = PCI_CAPLIST_NEXT(rval) ) { + rval = pci_conf_read(pc, tag, off); + if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP) + return (1); + } + } + } + return (0); +} + + +struct extent * +pciaddr_search(mem_port, parent, startp, size) + int mem_port; + struct device *parent; + bus_addr_t *startp; + bus_size_t size; +{ + struct pcibr_softc *sc; + + /* find the bridge, 'mpcpcibr' */ + + sc = NULL; + while (parent != NULL) { + if (strncmp("mpcpcibr", parent->dv_xname, 8) == 0) { + sc = (void *)parent; + break; + } + parent = parent->dv_parent; + } + + if (sc && !(pcibr_flags & PCIBR_ADDR_FIXUP)) { + struct extent_region *rp; + struct extent *ex = mem_port? sc->extent_mem : sc->extent_port; + + /* Search the PCI I/O memory space extent for free + * space that will accomodate size. Remember that the + * extent stores allocated space and we're searching + * for the gaps. + * + * If we're at the end or the gap between this region + * and the next region big enough, then we're done + */ + *startp = ex->ex_start; + rp = LIST_FIRST(&ex->ex_regions); + + for (rp = LIST_FIRST(&ex->ex_regions); + rp && *startp + size > rp->er_start; + rp = LIST_NEXT(rp, er_link)) { + bus_addr_t new_start; + + new_start = (rp->er_end - 1 + size) & ~(size - 1); + if (new_start > *startp) + *startp = new_start; + } + + return (ex); + } + + return (NULL); +} + + +void +pci_device_foreach(sc, pc, maxbus, func) + struct pcibr_softc *sc; + pci_chipset_tag_t pc; + int maxbus; + void (*func)(struct pcibr_softc *, pci_chipset_tag_t, pcitag_t); +{ + const struct pci_quirkdata *qd; + int bus, device, function, maxdevs, nfuncs; + pcireg_t id, bhlcr; + pcitag_t tag; + + for (bus = 0; bus <= maxbus; bus++) { + maxdevs = pci_bus_maxdevs(pc, bus); + for (device = 0; device < maxdevs; device++) { + tag = pci_make_tag(pc, bus, device, 0); + id = pci_conf_read(pc, tag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) + continue; + /* XXX Not invalid, but we've done this ~forever. */ + if (PCI_VENDOR(id) == 0) + continue; + + qd = pci_lookup_quirkdata(PCI_VENDOR(id), + PCI_PRODUCT(id)); + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + if (PCI_HDRTYPE_MULTIFN(bhlcr) || + (qd != NULL && + (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) + nfuncs = 8; + else + nfuncs = 1; + + for (function = 0; function < nfuncs; function++) { + tag = pci_make_tag(pc, bus, device, function); + id = pci_conf_read(pc, tag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) + continue; + /* + * XXX Not invalid, but we've done this + * ~forever. + */ + if (PCI_VENDOR(id) == 0) + continue; + (*func)(sc, pc, tag); + } + } + } +} diff --git a/sys/arch/macppc/pci/pcibrvar.h b/sys/arch/macppc/pci/pcibrvar.h index 6efdbc8af38..39dba16855c 100644 --- a/sys/arch/macppc/pci/pcibrvar.h +++ b/sys/arch/macppc/pci/pcibrvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcibrvar.h,v 1.2 2002/03/14 01:26:37 millert Exp $ */ +/* $OpenBSD: pcibrvar.h,v 1.3 2002/07/23 17:53:25 drahn Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -68,10 +68,11 @@ struct pci_reserve_mem { char *name; }; -void pci_addr_fixup(struct pcibr_softc *, pci_chipset_tag_t, int, - struct pci_reserve_mem *); +void pci_addr_fixup(struct pcibr_softc *, pci_chipset_tag_t, int); #define PCIADDR_SEARCH_IO 0 #define PCIADDR_SEARCH_MEM 1 -struct extent *pciaddr_search(struct device *, int, bus_addr_t *, bus_size_t); + +struct extent * pciaddr_search(int mem_port, struct device *, + bus_addr_t *startp, bus_size_t size); |