[BACK]Return to pci_bus_fixup.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / pci

Annotation of sys/arch/i386/pci/pci_bus_fixup.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pci_bus_fixup.c,v 1.9 2006/08/18 22:18:18 kettenis Exp $      */
        !             2: /*     $NetBSD: pci_bus_fixup.c,v 1.1 1999/11/17 07:32:58 thorpej Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1999, by UCHIYAMA Yasushi
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. The name of the developer may NOT be used to endorse or promote products
        !            14:  *    derived from this software without specific prior written permission.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            26:  * SUCH DAMAGE.
        !            27:  */
        !            28:
        !            29: /*
        !            30:  * PCI bus renumbering support.
        !            31:  */
        !            32:
        !            33: #include <sys/param.h>
        !            34: #include <sys/systm.h>
        !            35: #include <sys/kernel.h>
        !            36: #include <sys/device.h>
        !            37:
        !            38: #include <machine/bus.h>
        !            39:
        !            40: #include <dev/pci/pcireg.h>
        !            41: #include <dev/pci/pcivar.h>
        !            42: #include <dev/pci/pcidevs.h>
        !            43: #include <dev/pci/ppbreg.h>
        !            44:
        !            45: #include <i386/pci/pcibiosvar.h>
        !            46:
        !            47: int    pci_bus_check(pci_chipset_tag_t, int);
        !            48: int    pci_bus_assign(pci_chipset_tag_t, int);
        !            49: void   pcibus_print_devid(pci_chipset_tag_t, pcitag_t);
        !            50:
        !            51: int
        !            52: pci_bus_check(pci_chipset_tag_t pc, int bus)
        !            53: {
        !            54:        int device, maxdevs, function, nfuncs, bus_max, bus_sub;
        !            55:        const struct pci_quirkdata *qd;
        !            56:        pcireg_t reg;
        !            57:        pcitag_t tag;
        !            58:
        !            59:        bus_max = bus;
        !            60:
        !            61:        maxdevs = pci_bus_maxdevs(pc, bus);
        !            62:        for (device = 0; device < maxdevs; device++) {
        !            63:                tag = pci_make_tag(pc, bus, device, 0);
        !            64:                reg = pci_conf_read(pc, tag, PCI_ID_REG);
        !            65:
        !            66:                /* can't be that many */
        !            67:                if (bus_max == 255)
        !            68:                        break;
        !            69:
        !            70:                /* Invalid vendor ID value? */
        !            71:                if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
        !            72:                        continue;
        !            73:                /* XXX Not invalid, but we've done this ~forever. */
        !            74:                if (PCI_VENDOR(reg) == 0)
        !            75:                        continue;
        !            76:
        !            77:                qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
        !            78:
        !            79:                reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !            80:                if (PCI_HDRTYPE_MULTIFN(reg) ||
        !            81:                    (qd != NULL &&
        !            82:                     (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
        !            83:                        nfuncs = 8;
        !            84:                else
        !            85:                        nfuncs = 1;
        !            86:
        !            87:                for (function = 0; function < nfuncs; function++) {
        !            88:                        tag = pci_make_tag(pc, bus, device, function);
        !            89:                        reg = pci_conf_read(pc, tag, PCI_ID_REG);
        !            90:
        !            91:                        /* Invalid vendor ID value? */
        !            92:                        if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
        !            93:                                continue;
        !            94:                        /* XXX Not invalid, but we've done this ~forever. */
        !            95:                        if (PCI_VENDOR(reg) == 0)
        !            96:                                continue;
        !            97:
        !            98:                        reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
        !            99:                        if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
        !           100:                            (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
        !           101:                             PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
        !           102:
        !           103:                                reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
        !           104:                                if (PPB_BUSINFO_PRIMARY(reg) != bus) {
        !           105:                                        if (pcibios_flags & PCIBIOS_VERBOSE) {
        !           106:                                                pcibus_print_devid(pc, tag);
        !           107:                                                printf("Mismatched primary bus: "
        !           108:                                                    "primary %d, secondary %d, "
        !           109:                                                    "subordinate %d\n",
        !           110:                                                    PPB_BUSINFO_PRIMARY(reg),
        !           111:                                                    PPB_BUSINFO_SECONDARY(reg),
        !           112:                                                    PPB_BUSINFO_SUBORDINATE(reg));
        !           113:                                        }
        !           114:                                        return (-1);
        !           115:                                }
        !           116:                                if (PPB_BUSINFO_SECONDARY(reg) <= bus) {
        !           117:                                        if (pcibios_flags & PCIBIOS_VERBOSE) {
        !           118:                                                pcibus_print_devid(pc, tag);
        !           119:                                                printf("Incorrect secondary bus: "
        !           120:                                                    "primary %d, secondary %d, "
        !           121:                                                    "subordinate %d\n",
        !           122:                                                    PPB_BUSINFO_PRIMARY(reg),
        !           123:                                                    PPB_BUSINFO_SECONDARY(reg),
        !           124:                                                    PPB_BUSINFO_SUBORDINATE(reg));
        !           125:                                        }
        !           126:                                        return (-1);
        !           127:                                }
        !           128:
        !           129:                                /* Scan subordinate bus. */
        !           130:                                bus_sub = pci_bus_check(pc,
        !           131:                                    PPB_BUSINFO_SECONDARY(reg));
        !           132:                                if (bus_sub == -1)
        !           133:                                        return (-1);
        !           134:
        !           135:                                if (PPB_BUSINFO_SUBORDINATE(reg) < bus_sub) {
        !           136:                                        if (pcibios_flags & PCIBIOS_VERBOSE) {
        !           137:                                                pcibus_print_devid(pc, tag);
        !           138:                                                printf("Incorrect subordinate bus %d: "
        !           139:                                                    "primary %d, secondary %d, "
        !           140:                                                    "subordinate %d\n", bus_sub,
        !           141:                                                    PPB_BUSINFO_PRIMARY(reg),
        !           142:                                                    PPB_BUSINFO_SECONDARY(reg),
        !           143:                                                    PPB_BUSINFO_SUBORDINATE(reg));
        !           144:                                        }
        !           145:                                        return (-1);
        !           146:                                }
        !           147:
        !           148:                                bus_max = (bus_sub > bus_max) ?
        !           149:                                    bus_sub : bus_max;
        !           150:                        }
        !           151:                }
        !           152:        }
        !           153:
        !           154:        return (bus_max);       /* last # of subordinate bus */
        !           155: }
        !           156:
        !           157: int
        !           158: pci_bus_assign(pci_chipset_tag_t pc, int bus)
        !           159: {
        !           160:        static int bridge_cnt;
        !           161:        int bridge, device, maxdevs, function, nfuncs, bus_max, bus_sub;
        !           162:        const struct pci_quirkdata *qd;
        !           163:        pcireg_t reg;
        !           164:        pcitag_t tag;
        !           165:
        !           166:        bus_max = bus;
        !           167:
        !           168:        maxdevs = pci_bus_maxdevs(pc, bus);
        !           169:        for (device = 0; device < maxdevs; device++) {
        !           170:                tag = pci_make_tag(pc, bus, device, 0);
        !           171:                reg = pci_conf_read(pc, tag, PCI_ID_REG);
        !           172:
        !           173:                /* can't be that many */
        !           174:                if (bus_max == 255)
        !           175:                        break;
        !           176:
        !           177:                /* Invalid vendor ID value? */
        !           178:                if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
        !           179:                        continue;
        !           180:                /* XXX Not invalid, but we've done this ~forever. */
        !           181:                if (PCI_VENDOR(reg) == 0)
        !           182:                        continue;
        !           183:
        !           184:                qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
        !           185:
        !           186:                reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !           187:                if (PCI_HDRTYPE_MULTIFN(reg) ||
        !           188:                    (qd != NULL &&
        !           189:                     (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
        !           190:                        nfuncs = 8;
        !           191:                else
        !           192:                        nfuncs = 1;
        !           193:
        !           194:                for (function = 0; function < nfuncs; function++) {
        !           195:                        tag = pci_make_tag(pc, bus, device, function);
        !           196:                        reg = pci_conf_read(pc, tag, PCI_ID_REG);
        !           197:
        !           198:                        /* Invalid vendor ID value? */
        !           199:                        if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
        !           200:                                continue;
        !           201:                        /* XXX Not invalid, but we've done this ~forever. */
        !           202:                        if (PCI_VENDOR(reg) == 0)
        !           203:                                continue;
        !           204:
        !           205:                        reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
        !           206:                        if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
        !           207:                            (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
        !           208:                             PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
        !           209:                                /* Assign the bridge's secondary bus #. */
        !           210:                                bus_max++;
        !           211:
        !           212:                                reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
        !           213:                                reg &= 0xff000000;
        !           214:                                reg |= bus | (bus_max << 8) | (0xff << 16);
        !           215:                                pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
        !           216:
        !           217:                                /* Scan subordinate bus. */
        !           218:                                bus_sub = pci_bus_assign(pc, bus_max);
        !           219:
        !           220:                                /* Configure the bridge. */
        !           221:                                reg &= 0xff000000;
        !           222:                                reg |= bus | (bus_max << 8) | (bus_sub << 16);
        !           223:                                pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
        !           224:
        !           225:                                if (pcibios_flags & PCIBIOS_VERBOSE) {
        !           226:                                        /* Assign the bridge #. */
        !           227:                                        bridge = bridge_cnt++;
        !           228:
        !           229:                                        printf("PCI bridge %d: primary %d, "
        !           230:                                            "secondary %d, subordinate %d\n",
        !           231:                                            bridge, bus, bus_max, bus_sub);
        !           232:                                }
        !           233:
        !           234:                                /* Next bridge's secondary bus #. */
        !           235:                                bus_max = (bus_sub > bus_max) ?
        !           236:                                    bus_sub : bus_max;
        !           237:                        }
        !           238:                }
        !           239:        }
        !           240:
        !           241:        return (bus_max);       /* last # of subordinate bus */
        !           242: }
        !           243:
        !           244: int
        !           245: pci_bus_fixup(pci_chipset_tag_t pc, int bus)
        !           246: {
        !           247:        int bus_max;
        !           248:
        !           249:        bus_max = pci_bus_check(pc, bus);
        !           250:        if (bus_max != -1)
        !           251:                return (bus_max);
        !           252:
        !           253:        if (pcibios_flags & PCIBIOS_VERBOSE)
        !           254:                printf("PCI bus renumbering needed\n");
        !           255:        return pci_bus_assign(pc, bus);
        !           256: }
        !           257:
        !           258: void
        !           259: pcibus_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
        !           260: {
        !           261:        int bus, device, function;
        !           262:        pcireg_t id;
        !           263:
        !           264:        id = pci_conf_read(pc, tag, PCI_ID_REG);
        !           265:        pci_decompose_tag(pc, tag, &bus, &device, &function);
        !           266:        printf("%03d:%02d:%d %04x:%04x\n", bus, device, function,
        !           267:               PCI_VENDOR(id), PCI_PRODUCT(id));
        !           268: }

CVSweb