pci_subr.c revision 131398
1284990Scy/*- 2284990Scy * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 3284990Scy * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 4284990Scy * Copyright (c) 2000 BSDi 5284990Scy * All rights reserved. 6284990Scy * 7284990Scy * Redistribution and use in source and binary forms, with or without 8284990Scy * modification, are permitted provided that the following conditions 9290000Sglebius * are met: 10284990Scy * 1. Redistributions of source code must retain the above copyright 11284990Scy * notice, this list of conditions and the following disclaimer. 12290000Sglebius * 2. Redistributions in binary form must reproduce the above copyright 13293894Sglebius * notice, this list of conditions and the following disclaimer in the 14293894Sglebius * documentation and/or other materials provided with the distribution. 15284990Scy * 3. The name of the author may not be used to endorse or promote products 16284990Scy * derived from this software without specific prior written permission. 17284990Scy * 18290000Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19293894Sglebius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20293894Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21284990Scy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22284990Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23284990Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24284990Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25284990Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26284990Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27284990Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28290000Sglebius * SUCH DAMAGE. 29284990Scy */ 30284990Scy 31284990Scy#include <sys/cdefs.h> 32284990Scy__FBSDID("$FreeBSD: head/sys/dev/pci/pci_pci.c 131398 2004-07-01 07:46:29Z jhb $"); 33284990Scy 34284990Scy/* 35290000Sglebius * PCI:PCI bridge support. 36293894Sglebius */ 37290000Sglebius 38290000Sglebius#include <sys/param.h> 39290000Sglebius#include <sys/systm.h> 40290000Sglebius#include <sys/kernel.h> 41290000Sglebius#include <sys/module.h> 42290000Sglebius#include <sys/bus.h> 43290000Sglebius#include <machine/bus.h> 44290000Sglebius#include <sys/rman.h> 45290000Sglebius#include <sys/sysctl.h> 46290000Sglebius 47290000Sglebius#include <machine/resource.h> 48290000Sglebius 49290000Sglebius#include <dev/pci/pcivar.h> 50290000Sglebius#include <dev/pci/pcireg.h> 51290000Sglebius#include <dev/pci/pcib_private.h> 52290000Sglebius 53290000Sglebius#include "pcib_if.h" 54290000Sglebius 55290000Sglebiusstatic int pcib_probe(device_t dev); 56290000Sglebius 57290000Sglebiusstatic device_method_t pcib_methods[] = { 58290000Sglebius /* Device interface */ 59290000Sglebius DEVMETHOD(device_probe, pcib_probe), 60290000Sglebius DEVMETHOD(device_attach, pcib_attach), 61290000Sglebius DEVMETHOD(device_shutdown, bus_generic_shutdown), 62290000Sglebius DEVMETHOD(device_suspend, bus_generic_suspend), 63290000Sglebius DEVMETHOD(device_resume, bus_generic_resume), 64290000Sglebius 65290000Sglebius /* Bus interface */ 66293894Sglebius DEVMETHOD(bus_print_child, bus_generic_print_child), 67290000Sglebius DEVMETHOD(bus_read_ivar, pcib_read_ivar), 68293894Sglebius DEVMETHOD(bus_write_ivar, pcib_write_ivar), 69293894Sglebius DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 70293894Sglebius DEVMETHOD(bus_release_resource, bus_generic_release_resource), 71293894Sglebius DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 72293894Sglebius DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 73290000Sglebius DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 74290000Sglebius DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 75293894Sglebius 76284990Scy /* pcib interface */ 77284990Scy DEVMETHOD(pcib_maxslots, pcib_maxslots), 78293894Sglebius DEVMETHOD(pcib_read_config, pcib_read_config), 79293894Sglebius DEVMETHOD(pcib_write_config, pcib_write_config), 80293894Sglebius DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 81293894Sglebius 82284990Scy { 0, 0 } 83293894Sglebius}; 84293894Sglebius 85293894Sglebiusstatic driver_t pcib_driver = { 86293894Sglebius "pcib", 87290000Sglebius pcib_methods, 88293894Sglebius sizeof(struct pcib_softc), 89293894Sglebius}; 90293894Sglebius 91290000Sglebiusdevclass_t pcib_devclass; 92290000Sglebius 93290000SglebiusDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); 94290000Sglebius 95290000Sglebius/* 96293894Sglebius * Generic device interface 97293894Sglebius */ 98293894Sglebiusstatic int 99293894Sglebiuspcib_probe(device_t dev) 100284990Scy{ 101284990Scy if ((pci_get_class(dev) == PCIC_BRIDGE) && 102293894Sglebius (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 103284990Scy device_set_desc(dev, "PCI-PCI bridge"); 104284990Scy return(-10000); 105284990Scy } 106290000Sglebius return(ENXIO); 107290000Sglebius} 108293894Sglebius 109293894Sglebiusvoid 110284990Scypcib_attach_common(device_t dev) 111293894Sglebius{ 112284990Scy struct pcib_softc *sc; 113284990Scy uint8_t iolow; 114284990Scy 115284990Scy sc = device_get_softc(dev); 116284990Scy sc->dev = dev; 117284990Scy 118290000Sglebius /* 119290000Sglebius * Get current bridge configuration. 120293894Sglebius */ 121293894Sglebius sc->command = pci_read_config(dev, PCIR_COMMAND, 1); 122284990Scy sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 123284990Scy sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 124284990Scy sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 125284990Scy sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 126284990Scy sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 127284990Scy 128284990Scy /* 129284990Scy * Determine current I/O decode. 130284990Scy */ 131293894Sglebius if (sc->command & PCIM_CMD_PORTEN) { 132284990Scy iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 133284990Scy if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 134284990Scy sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), 135290000Sglebius pci_read_config(dev, PCIR_IOBASEL_1, 1)); 136284990Scy } else { 137284990Scy sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); 138284990Scy } 139284990Scy 140284990Scy iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 141290000Sglebius if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 142293894Sglebius sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), 143293894Sglebius pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 144293894Sglebius } else { 145284990Scy sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 146284990Scy } 147284990Scy } 148284990Scy 149284990Scy /* 150284990Scy * Determine current memory decode. 151284990Scy */ 152290000Sglebius if (sc->command & PCIM_CMD_MEMEN) { 153284990Scy sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); 154284990Scy sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 155284990Scy sc->pmembase = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4), 156284990Scy pci_read_config(dev, PCIR_PMBASEL_1, 2)); 157284990Scy sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4), 158284990Scy pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 159284990Scy } 160284990Scy 161284990Scy /* 162284990Scy * Quirk handling. 163284990Scy */ 164284990Scy switch (pci_get_devid(dev)) { 165284990Scy case 0x12258086: /* Intel 82454KX/GX (Orion) */ 166284990Scy { 167284990Scy uint8_t supbus; 168284990Scy 169284990Scy supbus = pci_read_config(dev, 0x41, 1); 170284990Scy if (supbus != 0xff) { 171284990Scy sc->secbus = supbus + 1; 172284990Scy sc->subbus = supbus + 1; 173284990Scy } 174284990Scy break; 175284990Scy } 176284990Scy 177290000Sglebius /* 178293894Sglebius * The i82380FB mobile docking controller is a PCI-PCI bridge, 179293894Sglebius * and it is a subtractive bridge. However, the ProgIf is wrong 180284990Scy * so the normal setting of PCIB_SUBTRACTIVE bit doesn't 181284990Scy * happen. There's also a Toshiba bridge that behaves this 182284990Scy * way. 183284990Scy */ 184293894Sglebius case 0x124b8086: /* Intel 82380FB Mobile */ 185284990Scy case 0x060513d7: /* Toshiba ???? */ 186284990Scy sc->flags |= PCIB_SUBTRACTIVE; 187284990Scy break; 188284990Scy } 189284990Scy 190284990Scy /* 191284990Scy * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, 192284990Scy * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, 193284990Scy * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. 194290000Sglebius * This means they act as if they were subtractively decoding 195290000Sglebius * bridges and pass all transactions. Mark them and real ProgIf 1 196293894Sglebius * parts as subtractive. 197293894Sglebius */ 198293894Sglebius if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || 199284990Scy pci_read_config(dev, PCIR_PROGIF, 1) == 1) 200284990Scy sc->flags |= PCIB_SUBTRACTIVE; 201284990Scy 202284990Scy if (bootverbose) { 203284990Scy device_printf(dev, " secondary bus %d\n", sc->secbus); 204284990Scy device_printf(dev, " subordinate bus %d\n", sc->subbus); 205284990Scy device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); 206284990Scy device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit); 207284990Scy device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit); 208284990Scy if (sc->flags & PCIB_SUBTRACTIVE) 209284990Scy device_printf(dev, " Subtractively decoded bridge.\n"); 210284990Scy } 211284990Scy 212284990Scy /* 213284990Scy * XXX If the secondary bus number is zero, we should assign a bus number 214290000Sglebius * since the BIOS hasn't, then initialise the bridge. 215293894Sglebius */ 216293894Sglebius 217284990Scy /* 218284990Scy * XXX If the subordinate bus number is less than the secondary bus number, 219284990Scy * we should pick a better value. One sensible alternative would be to 220284990Scy * pick 255; the only tradeoff here is that configuration transactions 221284990Scy * would be more widely routed than absolutely necessary. 222284990Scy */ 223284990Scy} 224284990Scy 225284990Scyint 226284990Scypcib_attach(device_t dev) 227284990Scy{ 228284990Scy struct pcib_softc *sc; 229293894Sglebius device_t child; 230293894Sglebius 231284990Scy pcib_attach_common(dev); 232284990Scy sc = device_get_softc(dev); 233284990Scy if (sc->secbus != 0) { 234284990Scy child = device_add_child(dev, "pci", sc->secbus); 235284990Scy if (child != NULL) 236284990Scy return(bus_generic_attach(dev)); 237284990Scy } 238290000Sglebius 239293894Sglebius /* no secondary bus; we should have fixed this */ 240293894Sglebius return(0); 241284990Scy} 242293894Sglebius 243284990Scyint 244284990Scypcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 245284990Scy{ 246284990Scy struct pcib_softc *sc = device_get_softc(dev); 247284990Scy 248284990Scy switch (which) { 249293894Sglebius case PCIB_IVAR_BUS: 250293894Sglebius *result = sc->secbus; 251284990Scy return(0); 252284990Scy } 253284990Scy return(ENOENT); 254284990Scy} 255284990Scy 256284990Scyint 257290000Sglebiuspcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 258293894Sglebius{ 259293894Sglebius struct pcib_softc *sc = device_get_softc(dev); 260284990Scy 261284990Scy switch (which) { 262293894Sglebius case PCIB_IVAR_BUS: 263284990Scy sc->secbus = value; 264284990Scy break; 265284990Scy } 266284990Scy return(ENOENT); 267284990Scy} 268284990Scy 269284990Scy/* 270293894Sglebius * Is the prefetch window open (eg, can we allocate memory in it?) 271293894Sglebius */ 272284990Scystatic int 273284990Scypcib_is_prefetch_open(struct pcib_softc *sc) 274290000Sglebius{ 275290000Sglebius return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); 276293894Sglebius} 277293894Sglebius 278284990Scy/* 279284990Scy * Is the nonprefetch window open (eg, can we allocate memory in it?) 280293894Sglebius */ 281284990Scystatic int 282284990Scypcib_is_nonprefetch_open(struct pcib_softc *sc) 283284990Scy{ 284284990Scy return (sc->membase > 0 && sc->membase < sc->memlimit); 285293894Sglebius} 286284990Scy 287284990Scy/* 288293894Sglebius * Is the io window open (eg, can we allocate ports in it?) 289293894Sglebius */ 290284990Scystatic int 291284990Scypcib_is_io_open(struct pcib_softc *sc) 292284990Scy{ 293284990Scy return (sc->iobase > 0 && sc->iobase < sc->iolimit); 294284990Scy} 295290000Sglebius 296293894Sglebius/* 297293894Sglebius * We have to trap resource allocation requests and ensure that the bridge 298284990Scy * is set up to, or capable of handling them. 299290000Sglebius */ 300284990Scystruct resource * 301284990Scypcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 302284990Scy u_long start, u_long end, u_long count, u_int flags) 303284990Scy{ 304284990Scy struct pcib_softc *sc = device_get_softc(dev); 305284990Scy int ok; 306293894Sglebius 307284990Scy /* 308284990Scy * Fail the allocation for this range if it's not supported. 309293894Sglebius */ 310293894Sglebius switch (type) { 311284990Scy case SYS_RES_IOPORT: 312284990Scy ok = 0; 313290000Sglebius if (!pcib_is_io_open(sc)) 314290000Sglebius break; 315293894Sglebius ok = (start >= sc->iobase && end <= sc->iolimit); 316293894Sglebius if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 317284990Scy if (!ok) { 318290000Sglebius if (start < sc->iobase) 319293894Sglebius start = sc->iobase; 320284990Scy if (end > sc->iolimit) 321284990Scy end = sc->iolimit; 322284990Scy } 323284990Scy } else { 324284990Scy ok = 1; 325284990Scy#if 1 326293894Sglebius if (start < sc->iobase && end > sc->iolimit) { 327284990Scy start = sc->iobase; 328284990Scy end = sc->iolimit; 329293894Sglebius } 330293894Sglebius#endif 331284990Scy } 332284990Scy if (end < start) { 333290000Sglebius device_printf(dev, "ioport: end (%lx) < start (%lx)\n", end, start); 334290000Sglebius start = 0; 335293894Sglebius end = 0; 336293894Sglebius ok = 0; 337284990Scy } 338290000Sglebius if (!ok) { 339293894Sglebius device_printf(dev, "device %s requested unsupported I/O " 340284990Scy "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", 341284990Scy device_get_nameunit(child), start, end, 342284990Scy sc->iobase, sc->iolimit); 343284990Scy return (NULL); 344284990Scy } 345284990Scy if (bootverbose) 346293894Sglebius device_printf(dev, "device %s requested decoded I/O range 0x%lx-0x%lx\n", 347284990Scy device_get_nameunit(child), start, end); 348284990Scy break; 349293894Sglebius 350293894Sglebius case SYS_RES_MEMORY: 351284990Scy ok = 0; 352284990Scy if (pcib_is_nonprefetch_open(sc)) 353284990Scy ok = ok || (start >= sc->membase && end <= sc->memlimit); 354284990Scy if (pcib_is_prefetch_open(sc)) 355284990Scy ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 356284990Scy if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 357290000Sglebius if (!ok) { 358293894Sglebius ok = 1; 359293894Sglebius if (flags & RF_PREFETCHABLE) { 360290000Sglebius if (pcib_is_prefetch_open(sc)) { 361293894Sglebius if (start < sc->pmembase) 362284990Scy start = sc->pmembase; 363284990Scy if (end > sc->pmemlimit) 364284990Scy end = sc->pmemlimit; 365284990Scy } else { 366284990Scy ok = 0; 367284990Scy } 368284990Scy } else { /* non-prefetchable */ 369284990Scy if (pcib_is_nonprefetch_open(sc)) { 370284990Scy if (start < sc->membase) 371284990Scy start = sc->membase; 372293894Sglebius if (end > sc->memlimit) 373293894Sglebius end = sc->memlimit; 374284990Scy } else { 375284990Scy ok = 0; 376290000Sglebius } 377290000Sglebius } 378293894Sglebius } 379293894Sglebius } else if (!ok) { 380290000Sglebius ok = 1; /* subtractive bridge: always ok */ 381293894Sglebius#if 1 382284990Scy if (pcib_is_nonprefetch_open(sc)) { 383284990Scy if (start < sc->membase && end > sc->memlimit) { 384284990Scy start = sc->membase; 385284990Scy end = sc->memlimit; 386284990Scy } 387284990Scy } 388284990Scy if (pcib_is_prefetch_open(sc)) { 389284990Scy if (start < sc->pmembase && end > sc->pmemlimit) { 390284990Scy start = sc->pmembase; 391284990Scy end = sc->pmemlimit; 392293894Sglebius } 393293894Sglebius } 394284990Scy#endif 395284990Scy } 396290000Sglebius if (end < start) { 397290000Sglebius device_printf(dev, "memory: end (%lx) < start (%lx)\n", end, start); 398290000Sglebius start = 0; 399284990Scy end = 0; 400293894Sglebius ok = 0; 401284990Scy } 402284990Scy if (!ok && bootverbose) 403284990Scy device_printf(dev, 404284990Scy "device %s requested unsupported memory range " 405284990Scy "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", 406284990Scy device_get_nameunit(child), start, end, 407284990Scy sc->membase, sc->memlimit, sc->pmembase, 408284990Scy sc->pmemlimit); 409293894Sglebius if (!ok) 410293894Sglebius return (NULL); 411284990Scy if (bootverbose) 412284990Scy device_printf(dev,"device %s requested decoded memory range 0x%lx-0x%lx\n", 413290000Sglebius device_get_nameunit(child), start, end); 414290000Sglebius break; 415293894Sglebius 416293894Sglebius default: 417284990Scy break; 418293894Sglebius } 419284990Scy /* 420284990Scy * Bridge is OK decoding this resource, so pass it up. 421284990Scy */ 422284990Scy return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); 423284990Scy} 424284990Scy 425284990Scy/* 426284990Scy * PCIB interface. 427293894Sglebius */ 428293894Sglebiusint 429284990Scypcib_maxslots(device_t dev) 430284990Scy{ 431284990Scy return(PCI_SLOTMAX); 432284990Scy} 433284990Scy 434284990Scy/* 435290000Sglebius * Since we are a child of a PCI bus, its parent must support the pcib interface. 436293894Sglebius */ 437293894Sglebiusuint32_t 438290000Sglebiuspcib_read_config(device_t dev, int b, int s, int f, int reg, int width) 439293894Sglebius{ 440284990Scy return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 441284990Scy} 442284990Scy 443284990Scyvoid 444284990Scypcib_write_config(device_t dev, int b, int s, int f, int reg, uint32_t val, int width) 445284990Scy{ 446284990Scy PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 447284990Scy} 448284990Scy 449284990Scy/* 450293894Sglebius * Route an interrupt across a PCI bridge. 451293894Sglebius */ 452284990Scyint 453284990Scypcib_route_interrupt(device_t pcib, device_t dev, int pin) 454290000Sglebius{ 455290000Sglebius device_t bus; 456293894Sglebius int parent_intpin; 457293894Sglebius int intnum; 458290000Sglebius 459293894Sglebius /* 460284990Scy * 461284990Scy * The PCI standard defines a swizzle of the child-side device/intpin to 462290000Sglebius * the parent-side intpin as follows. 463290000Sglebius * 464290000Sglebius * device = device on child bus 465284990Scy * child_intpin = intpin on child bus slot (0-3) 466284990Scy * parent_intpin = intpin on parent bus slot (0-3) 467284990Scy * 468284990Scy * parent_intpin = (device + child_intpin) % 4 469284990Scy */ 470293894Sglebius parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 471293894Sglebius 472284990Scy /* 473284990Scy * Our parent is a PCI bus. Its parent must export the pcib interface 474290000Sglebius * which includes the ability to route interrupts. 475290000Sglebius */ 476293894Sglebius bus = device_get_parent(pcib); 477293894Sglebius intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 478284990Scy if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 479293894Sglebius device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 480284990Scy pci_get_slot(dev), 'A' + pin - 1, intnum); 481284990Scy } 482284990Scy return(intnum); 483284990Scy} 484284990Scy 485284990Scy/* 486284990Scy * Try to read the bus number of a host-PCI bridge using appropriate config 487284990Scy * registers. 488293894Sglebius */ 489293894Sglebiusint 490284990Scyhost_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, 491284990Scy uint8_t *busnum) 492290000Sglebius{ 493290000Sglebius uint32_t id; 494293894Sglebius 495293894Sglebius id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); 496284990Scy if (id == 0xffffffff) 497293894Sglebius return (0); 498284990Scy 499284990Scy switch (id) { 500284990Scy case 0x12258086: 501284990Scy /* Intel 824?? */ 502284990Scy /* XXX This is a guess */ 503284990Scy /* *busnum = read_config(bus, slot, func, 0x41, 1); */ 504284990Scy *busnum = bus; 505284990Scy break; 506293894Sglebius case 0x84c48086: 507293894Sglebius /* Intel 82454KX/GX (Orion) */ 508284990Scy *busnum = read_config(bus, slot, func, 0x4a, 1); 509284990Scy break; 510284990Scy case 0x84ca8086: 511284990Scy /* 512284990Scy * For the 450nx chipset, there is a whole bundle of 513284990Scy * things pretending to be host bridges. The MIOC will 514290000Sglebius * be seen first and isn't really a pci bridge (the 515290000Sglebius * actual busses are attached to the PXB's). We need to 516293894Sglebius * read the registers of the MIOC to figure out the 517293894Sglebius * bus numbers for the PXB channels. 518284990Scy * 519293894Sglebius * Since the MIOC doesn't have a pci bus attached, we 520284990Scy * pretend it wasn't there. 521284990Scy */ 522284990Scy return (0); 523284990Scy case 0x84cb8086: 524284990Scy switch (slot) { 525284990Scy case 0x12: 526284990Scy /* Intel 82454NX PXB#0, Bus#A */ 527284990Scy *busnum = read_config(bus, 0x10, func, 0xd0, 1); 528284990Scy break; 529293894Sglebius case 0x13: 530293894Sglebius /* Intel 82454NX PXB#0, Bus#B */ 531284990Scy *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; 532284990Scy break; 533284990Scy case 0x14: 534284990Scy /* Intel 82454NX PXB#1, Bus#A */ 535284990Scy *busnum = read_config(bus, 0x10, func, 0xd3, 1); 536284990Scy break; 537290000Sglebius case 0x15: 538293894Sglebius /* Intel 82454NX PXB#1, Bus#B */ 539293894Sglebius *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; 540284990Scy break; 541293894Sglebius } 542284990Scy break; 543284990Scy 544284990Scy /* ServerWorks -- vendor 0x1166 */ 545284990Scy case 0x00051166: 546284990Scy case 0x00061166: 547284990Scy case 0x00081166: 548284990Scy case 0x00091166: 549293894Sglebius case 0x00101166: 550293894Sglebius case 0x00111166: 551284990Scy case 0x00171166: 552284990Scy case 0x01011166: 553290000Sglebius case 0x010f1014: 554290000Sglebius case 0x02011166: 555293894Sglebius case 0x03021014: 556293894Sglebius *busnum = read_config(bus, slot, func, 0x44, 1); 557284990Scy break; 558293894Sglebius default: 559284990Scy /* Don't know how to read bus number. */ 560284990Scy return 0; 561284990Scy } 562284990Scy 563284990Scy return 1; 564284990Scy} 565284990Scy