| Commit | Line | Data |
|---|---|---|
| 4d28e78f SZ |
1 | /*- |
| 2 | * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier | |
| 3 | * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> | |
| 4 | * Copyright (c) 2000 BSDi | |
| 5 | * All rights reserved. | |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 10 | * 1. Redistributions of source code must retain the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer. | |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 13 | * notice, this list of conditions and the following disclaimer in the | |
| 14 | * documentation and/or other materials provided with the distribution. | |
| 15 | * 3. The name of the author may not be used to endorse or promote products | |
| 16 | * derived from this software without specific prior written permission. | |
| 17 | * | |
| 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
| 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
| 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 28 | * SUCH DAMAGE. | |
| 29 | * __FBSDID("$FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.50.2.2.4.1 2009/04/15 03:14:26 kensmith Exp $"); | |
| 30 | */ | |
| 31 | ||
| 32 | #include <sys/cdefs.h> | |
| 33 | ||
| 34 | /* | |
| 35 | * PCI:PCI bridge support. | |
| 36 | */ | |
| 37 | ||
| 38 | #include <sys/param.h> | |
| 39 | #include <sys/systm.h> | |
| 40 | #include <sys/kernel.h> | |
| 41 | #include <sys/module.h> | |
| 42 | #include <sys/bus.h> | |
| 43 | #include <sys/rman.h> | |
| 44 | #include <sys/sysctl.h> | |
| 45 | ||
| 46 | #include <bus/pci/pcivar.h> | |
| 47 | #include <bus/pci/pcireg.h> | |
| 48 | #include <bus/pci/pcib_private.h> | |
| 49 | ||
| 50 | #include "pcib_if.h" | |
| 51 | ||
| 52 | static int pcib_probe(device_t dev); | |
| 53 | ||
| 54 | static device_method_t pcib_methods[] = { | |
| 55 | /* Device interface */ | |
| 56 | DEVMETHOD(device_probe, pcib_probe), | |
| 57 | DEVMETHOD(device_attach, pcib_attach), | |
| 58 | DEVMETHOD(device_detach, bus_generic_detach), | |
| 59 | DEVMETHOD(device_shutdown, bus_generic_shutdown), | |
| 60 | DEVMETHOD(device_suspend, bus_generic_suspend), | |
| 61 | DEVMETHOD(device_resume, bus_generic_resume), | |
| 62 | ||
| 63 | /* Bus interface */ | |
| 64 | DEVMETHOD(bus_print_child, bus_generic_print_child), | |
| 65 | DEVMETHOD(bus_read_ivar, pcib_read_ivar), | |
| 66 | DEVMETHOD(bus_write_ivar, pcib_write_ivar), | |
| 67 | DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), | |
| 68 | DEVMETHOD(bus_release_resource, bus_generic_release_resource), | |
| 69 | DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), | |
| 70 | DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), | |
| 71 | DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), | |
| 72 | DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), | |
| 73 | ||
| 74 | /* pcib interface */ | |
| 75 | DEVMETHOD(pcib_maxslots, pcib_maxslots), | |
| 76 | DEVMETHOD(pcib_read_config, pcib_read_config), | |
| 77 | DEVMETHOD(pcib_write_config, pcib_write_config), | |
| 78 | DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), | |
| 79 | DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), | |
| 80 | DEVMETHOD(pcib_release_msi, pcib_release_msi), | |
| 81 | DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), | |
| 82 | DEVMETHOD(pcib_release_msix, pcib_release_msix), | |
| 83 | DEVMETHOD(pcib_map_msi, pcib_map_msi), | |
| 84 | ||
| 85 | { 0, 0 } | |
| 86 | }; | |
| 87 | ||
| 88 | static devclass_t pcib_devclass; | |
| 89 | ||
| 90 | DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); | |
| 91 | DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); | |
| 92 | ||
| 93 | /* | |
| 94 | * Is the prefetch window open (eg, can we allocate memory in it?) | |
| 95 | */ | |
| 96 | static int | |
| 97 | pcib_is_prefetch_open(struct pcib_softc *sc) | |
| 98 | { | |
| 99 | return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); | |
| 100 | } | |
| 101 | ||
| 102 | /* | |
| 103 | * Is the nonprefetch window open (eg, can we allocate memory in it?) | |
| 104 | */ | |
| 105 | static int | |
| 106 | pcib_is_nonprefetch_open(struct pcib_softc *sc) | |
| 107 | { | |
| 108 | return (sc->membase > 0 && sc->membase < sc->memlimit); | |
| 109 | } | |
| 110 | ||
| 111 | /* | |
| 112 | * Is the io window open (eg, can we allocate ports in it?) | |
| 113 | */ | |
| 114 | static int | |
| 115 | pcib_is_io_open(struct pcib_softc *sc) | |
| 116 | { | |
| 117 | return (sc->iobase > 0 && sc->iobase < sc->iolimit); | |
| 118 | } | |
| 119 | ||
| 120 | /* | |
| 121 | * Generic device interface | |
| 122 | */ | |
| 123 | static int | |
| 124 | pcib_probe(device_t dev) | |
| 125 | { | |
| 126 | if ((pci_get_class(dev) == PCIC_BRIDGE) && | |
| 127 | (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { | |
| 128 | device_set_desc(dev, "PCI-PCI bridge"); | |
| 87d0a809 SZ |
129 | #ifndef APIC_IO |
| 130 | return (-10000); | |
| 131 | #else | |
| 132 | /* PCIBIOS PCI-PCI bridge is -2000 */ | |
| 133 | return (-1000); | |
| 134 | #endif | |
| 4d28e78f SZ |
135 | } |
| 136 | return(ENXIO); | |
| 137 | } | |
| 138 | ||
| 139 | void | |
| 140 | pcib_attach_common(device_t dev) | |
| 141 | { | |
| 142 | struct pcib_softc *sc; | |
| 143 | uint8_t iolow; | |
| 144 | ||
| 145 | sc = device_get_softc(dev); | |
| 146 | sc->dev = dev; | |
| 147 | ||
| 148 | /* | |
| 149 | * Get current bridge configuration. | |
| 150 | */ | |
| 151 | sc->command = pci_read_config(dev, PCIR_COMMAND, 1); | |
| 152 | sc->domain = pci_get_domain(dev); | |
| 153 | sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); | |
| 154 | sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); | |
| 155 | sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); | |
| 156 | sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); | |
| 157 | sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); | |
| 158 | ||
| 159 | /* | |
| 160 | * Determine current I/O decode. | |
| 161 | */ | |
| 162 | if (sc->command & PCIM_CMD_PORTEN) { | |
| 163 | iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); | |
| 164 | if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { | |
| 165 | sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), | |
| 166 | pci_read_config(dev, PCIR_IOBASEL_1, 1)); | |
| 167 | } else { | |
| 168 | sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); | |
| 169 | } | |
| 170 | ||
| 171 | iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); | |
| 172 | if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { | |
| 173 | sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), | |
| 174 | pci_read_config(dev, PCIR_IOLIMITL_1, 1)); | |
| 175 | } else { | |
| 176 | sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); | |
| 177 | } | |
| 178 | } | |
| 179 | ||
| 180 | /* | |
| 181 | * Determine current memory decode. | |
| 182 | */ | |
| 183 | if (sc->command & PCIM_CMD_MEMEN) { | |
| 184 | sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); | |
| 185 | sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); | |
| 186 | iolow = pci_read_config(dev, PCIR_PMBASEL_1, 1); | |
| 187 | if ((iolow & PCIM_BRPM_MASK) == PCIM_BRPM_64) | |
| 188 | sc->pmembase = PCI_PPBMEMBASE( | |
| 189 | pci_read_config(dev, PCIR_PMBASEH_1, 4), | |
| 190 | pci_read_config(dev, PCIR_PMBASEL_1, 2)); | |
| 191 | else | |
| 192 | sc->pmembase = PCI_PPBMEMBASE(0, | |
| 193 | pci_read_config(dev, PCIR_PMBASEL_1, 2)); | |
| 194 | iolow = pci_read_config(dev, PCIR_PMLIMITL_1, 1); | |
| 195 | if ((iolow & PCIM_BRPM_MASK) == PCIM_BRPM_64) | |
| 196 | sc->pmemlimit = PCI_PPBMEMLIMIT( | |
| 197 | pci_read_config(dev, PCIR_PMLIMITH_1, 4), | |
| 198 | pci_read_config(dev, PCIR_PMLIMITL_1, 2)); | |
| 199 | else | |
| 200 | sc->pmemlimit = PCI_PPBMEMLIMIT(0, | |
| 201 | pci_read_config(dev, PCIR_PMLIMITL_1, 2)); | |
| 202 | } | |
| 203 | ||
| 204 | /* | |
| 205 | * Quirk handling. | |
| 206 | */ | |
| 207 | switch (pci_get_devid(dev)) { | |
| 208 | case 0x12258086: /* Intel 82454KX/GX (Orion) */ | |
| 209 | { | |
| 210 | uint8_t supbus; | |
| 211 | ||
| 212 | supbus = pci_read_config(dev, 0x41, 1); | |
| 213 | if (supbus != 0xff) { | |
| 214 | sc->secbus = supbus + 1; | |
| 215 | sc->subbus = supbus + 1; | |
| 216 | } | |
| 217 | break; | |
| 218 | } | |
| 219 | ||
| 220 | /* | |
| 221 | * The i82380FB mobile docking controller is a PCI-PCI bridge, | |
| 222 | * and it is a subtractive bridge. However, the ProgIf is wrong | |
| 223 | * so the normal setting of PCIB_SUBTRACTIVE bit doesn't | |
| 224 | * happen. There's also a Toshiba bridge that behaves this | |
| 225 | * way. | |
| 226 | */ | |
| 227 | case 0x124b8086: /* Intel 82380FB Mobile */ | |
| 228 | case 0x060513d7: /* Toshiba ???? */ | |
| 229 | sc->flags |= PCIB_SUBTRACTIVE; | |
| 230 | break; | |
| 231 | ||
| 232 | /* Compaq R3000 BIOS sets wrong subordinate bus number. */ | |
| 233 | case 0x00dd10de: | |
| 234 | { | |
| 235 | char *cp; | |
| 236 | ||
| 237 | if ((cp = kgetenv("smbios.planar.maker")) == NULL) | |
| 238 | break; | |
| 239 | if (strncmp(cp, "Compal", 6) != 0) { | |
| 240 | kfreeenv(cp); | |
| 241 | break; | |
| 242 | } | |
| 243 | kfreeenv(cp); | |
| 244 | if ((cp = kgetenv("smbios.planar.product")) == NULL) | |
| 245 | break; | |
| 246 | if (strncmp(cp, "08A0", 4) != 0) { | |
| 247 | kfreeenv(cp); | |
| 248 | break; | |
| 249 | } | |
| 250 | kfreeenv(cp); | |
| 251 | if (sc->subbus < 0xa) { | |
| 252 | pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); | |
| 253 | sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); | |
| 254 | } | |
| 255 | break; | |
| 256 | } | |
| 257 | } | |
| 258 | ||
| 259 | if (pci_msi_device_blacklisted(dev)) | |
| 260 | sc->flags |= PCIB_DISABLE_MSI; | |
| 261 | ||
| 262 | /* | |
| 263 | * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, | |
| 264 | * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, | |
| 265 | * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. | |
| 266 | * This means they act as if they were subtractively decoding | |
| 267 | * bridges and pass all transactions. Mark them and real ProgIf 1 | |
| 268 | * parts as subtractive. | |
| 269 | */ | |
| 270 | if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || | |
| 271 | pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) | |
| 272 | sc->flags |= PCIB_SUBTRACTIVE; | |
| 273 | ||
| 274 | if (bootverbose) { | |
| 275 | device_printf(dev, " domain %d\n", sc->domain); | |
| 276 | device_printf(dev, " secondary bus %d\n", sc->secbus); | |
| 277 | device_printf(dev, " subordinate bus %d\n", sc->subbus); | |
| 278 | device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); | |
| 279 | if (pcib_is_nonprefetch_open(sc)) | |
| 280 | device_printf(dev, " memory decode 0x%jx-0x%jx\n", | |
| 281 | (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); | |
| 282 | if (pcib_is_prefetch_open(sc)) | |
| 283 | device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", | |
| 284 | (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); | |
| 285 | else | |
| 286 | device_printf(dev, " no prefetched decode\n"); | |
| 287 | if (sc->flags & PCIB_SUBTRACTIVE) | |
| 288 | device_printf(dev, " Subtractively decoded bridge.\n"); | |
| 289 | } | |
| 290 | ||
| d85e7311 SZ |
291 | if (pci_is_pcie(dev) && pcie_slot_implemented(dev)) { |
| 292 | uint16_t slot_ctrl; | |
| 293 | uint8_t ptr; | |
| 294 | ||
| 295 | /* | |
| 296 | * XXX | |
| 297 | * Before proper PCI Express hot-plug support is in place, | |
| 298 | * disable all hot-plug interrupts on the PCI Express root | |
| 299 | * port or down stream port for now. | |
| 300 | */ | |
| 301 | #define HPINTRS (PCIEM_SLTCTL_HPINTR_MASK | PCIEM_SLTCTL_HPINTR_EN) | |
| 302 | ||
| 303 | ptr = pci_get_pciecap_ptr(dev); | |
| 304 | slot_ctrl = pci_read_config(dev, ptr + PCIER_SLOTCTRL, 2); | |
| 305 | if (slot_ctrl & HPINTRS) { | |
| 306 | device_printf(dev, "Disable PCI Express hot-plug " | |
| 307 | "interrupts(0x%04x)\n", slot_ctrl & HPINTRS); | |
| 308 | slot_ctrl &= ~HPINTRS; | |
| 309 | pci_write_config(dev, ptr + PCIER_SLOTCTRL, slot_ctrl, 2); | |
| 310 | } | |
| 311 | ||
| 312 | #undef HPINTRS | |
| 313 | } | |
| 314 | ||
| 4d28e78f SZ |
315 | /* |
| 316 | * XXX If the secondary bus number is zero, we should assign a bus number | |
| 317 | * since the BIOS hasn't, then initialise the bridge. | |
| 318 | */ | |
| 319 | ||
| 320 | /* | |
| 321 | * XXX If the subordinate bus number is less than the secondary bus number, | |
| 322 | * we should pick a better value. One sensible alternative would be to | |
| 323 | * pick 255; the only tradeoff here is that configuration transactions | |
| 324 | * would be more widely routed than absolutely necessary. | |
| 325 | */ | |
| 326 | } | |
| 327 | ||
| 328 | int | |
| 329 | pcib_attach(device_t dev) | |
| 330 | { | |
| 331 | struct pcib_softc *sc; | |
| 332 | device_t child; | |
| 333 | ||
| 334 | pcib_attach_common(dev); | |
| 335 | sc = device_get_softc(dev); | |
| 336 | if (sc->secbus != 0) { | |
| 337 | child = device_add_child(dev, "pci", sc->secbus); | |
| 338 | if (child != NULL) | |
| 339 | return(bus_generic_attach(dev)); | |
| 340 | } | |
| 341 | ||
| 342 | /* no secondary bus; we should have fixed this */ | |
| 343 | return(0); | |
| 344 | } | |
| 345 | ||
| 346 | int | |
| 347 | pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) | |
| 348 | { | |
| 349 | struct pcib_softc *sc = device_get_softc(dev); | |
| 350 | ||
| 351 | switch (which) { | |
| 352 | case PCIB_IVAR_DOMAIN: | |
| 353 | *result = sc->domain; | |
| 354 | return(0); | |
| 355 | case PCIB_IVAR_BUS: | |
| 356 | *result = sc->secbus; | |
| 357 | return(0); | |
| 358 | } | |
| 359 | return(ENOENT); | |
| 360 | } | |
| 361 | ||
| 362 | int | |
| 363 | pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) | |
| 364 | { | |
| 365 | struct pcib_softc *sc = device_get_softc(dev); | |
| 366 | ||
| 367 | switch (which) { | |
| 368 | case PCIB_IVAR_DOMAIN: | |
| 369 | return(EINVAL); | |
| 370 | case PCIB_IVAR_BUS: | |
| 371 | sc->secbus = value; | |
| 372 | return(0); | |
| 373 | } | |
| 374 | return(ENOENT); | |
| 375 | } | |
| 376 | ||
| 377 | /* | |
| 378 | * We have to trap resource allocation requests and ensure that the bridge | |
| 379 | * is set up to, or capable of handling them. | |
| 380 | */ | |
| 381 | struct resource * | |
| 382 | pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, | |
| 383 | u_long start, u_long end, u_long count, u_int flags) | |
| 384 | { | |
| 385 | struct pcib_softc *sc = device_get_softc(dev); | |
| 386 | const char *name, *suffix; | |
| 387 | int ok; | |
| 388 | ||
| 389 | /* | |
| 390 | * Fail the allocation for this range if it's not supported. | |
| 391 | */ | |
| 392 | name = device_get_nameunit(child); | |
| 393 | if (name == NULL) { | |
| 394 | name = ""; | |
| 395 | suffix = ""; | |
| 396 | } else | |
| 397 | suffix = " "; | |
| 398 | switch (type) { | |
| 399 | case SYS_RES_IOPORT: | |
| 400 | ok = 0; | |
| 401 | if (!pcib_is_io_open(sc)) | |
| 402 | break; | |
| 403 | ok = (start >= sc->iobase && end <= sc->iolimit); | |
| 404 | ||
| 405 | /* | |
| 406 | * Make sure we allow access to VGA I/O addresses when the | |
| 407 | * bridge has the "VGA Enable" bit set. | |
| 408 | */ | |
| 409 | if (!ok && pci_is_vga_ioport_range(start, end)) | |
| 410 | ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; | |
| 411 | ||
| 412 | if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { | |
| 413 | if (!ok) { | |
| 414 | if (start < sc->iobase) | |
| 415 | start = sc->iobase; | |
| 416 | if (end > sc->iolimit) | |
| 417 | end = sc->iolimit; | |
| 418 | if (start < end) | |
| 419 | ok = 1; | |
| 420 | } | |
| 421 | } else { | |
| 422 | ok = 1; | |
| 423 | #if 1 | |
| 424 | if (start < sc->iobase && end > sc->iolimit) { | |
| 425 | start = sc->iobase; | |
| 426 | end = sc->iolimit; | |
| 427 | } | |
| 428 | #endif | |
| 429 | } | |
| 430 | if (end < start) { | |
| 431 | device_printf(dev, "ioport: end (%lx) < start (%lx)\n", | |
| 432 | end, start); | |
| 433 | start = 0; | |
| 434 | end = 0; | |
| 435 | ok = 0; | |
| 436 | } | |
| 437 | if (!ok) { | |
| 438 | device_printf(dev, "%s%srequested unsupported I/O " | |
| 439 | "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", | |
| 440 | name, suffix, start, end, sc->iobase, sc->iolimit); | |
| 441 | return (NULL); | |
| 442 | } | |
| 443 | if (bootverbose) | |
| 444 | device_printf(dev, | |
| 445 | "%s%srequested I/O range 0x%lx-0x%lx: in range\n", | |
| 446 | name, suffix, start, end); | |
| 447 | break; | |
| 448 | ||
| 449 | case SYS_RES_MEMORY: | |
| 450 | ok = 0; | |
| 451 | if (pcib_is_nonprefetch_open(sc)) | |
| 452 | ok = ok || (start >= sc->membase && end <= sc->memlimit); | |
| 453 | if (pcib_is_prefetch_open(sc)) | |
| 454 | ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); | |
| 455 | ||
| 456 | /* | |
| 457 | * Make sure we allow access to VGA memory addresses when the | |
| 458 | * bridge has the "VGA Enable" bit set. | |
| 459 | */ | |
| 460 | if (!ok && pci_is_vga_memory_range(start, end)) | |
| 461 | ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; | |
| 462 | ||
| 463 | if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { | |
| 464 | if (!ok) { | |
| 465 | ok = 1; | |
| 466 | if (flags & RF_PREFETCHABLE) { | |
| 467 | if (pcib_is_prefetch_open(sc)) { | |
| 468 | if (start < sc->pmembase) | |
| 469 | start = sc->pmembase; | |
| 470 | if (end > sc->pmemlimit) | |
| 471 | end = sc->pmemlimit; | |
| 472 | } else { | |
| 473 | ok = 0; | |
| 474 | } | |
| 475 | } else { /* non-prefetchable */ | |
| 476 | if (pcib_is_nonprefetch_open(sc)) { | |
| 477 | if (start < sc->membase) | |
| 478 | start = sc->membase; | |
| 479 | if (end > sc->memlimit) | |
| 480 | end = sc->memlimit; | |
| 481 | } else { | |
| 482 | ok = 0; | |
| 483 | } | |
| 484 | } | |
| 485 | } | |
| 486 | } else if (!ok) { | |
| 487 | ok = 1; /* subtractive bridge: always ok */ | |
| 488 | #if 1 | |
| 489 | if (pcib_is_nonprefetch_open(sc)) { | |
| 490 | if (start < sc->membase && end > sc->memlimit) { | |
| 491 | start = sc->membase; | |
| 492 | end = sc->memlimit; | |
| 493 | } | |
| 494 | } | |
| 495 | if (pcib_is_prefetch_open(sc)) { | |
| 496 | if (start < sc->pmembase && end > sc->pmemlimit) { | |
| 497 | start = sc->pmembase; | |
| 498 | end = sc->pmemlimit; | |
| 499 | } | |
| 500 | } | |
| 501 | #endif | |
| 502 | } | |
| 503 | if (end < start) { | |
| 504 | device_printf(dev, "memory: end (%lx) < start (%lx)\n", | |
| 505 | end, start); | |
| 506 | start = 0; | |
| 507 | end = 0; | |
| 508 | ok = 0; | |
| 509 | } | |
| 510 | if (!ok && bootverbose) | |
| 511 | device_printf(dev, | |
| 512 | "%s%srequested unsupported memory range %#lx-%#lx " | |
| 513 | "(decoding %#jx-%#jx, %#jx-%#jx)\n", | |
| 514 | name, suffix, start, end, | |
| 515 | (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, | |
| 516 | (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); | |
| 517 | if (!ok) | |
| 518 | return (NULL); | |
| 519 | if (bootverbose) | |
| 520 | device_printf(dev,"%s%srequested memory range " | |
| 521 | "0x%lx-0x%lx: good\n", | |
| 522 | name, suffix, start, end); | |
| 523 | break; | |
| 524 | ||
| 525 | default: | |
| 526 | break; | |
| 527 | } | |
| 528 | /* | |
| 529 | * Bridge is OK decoding this resource, so pass it up. | |
| 530 | */ | |
| 531 | return (bus_generic_alloc_resource(dev, child, type, rid, start, end, | |
| 532 | count, flags)); | |
| 533 | } | |
| 534 | ||
| 535 | /* | |
| 536 | * PCIB interface. | |
| 537 | */ | |
| 538 | int | |
| 539 | pcib_maxslots(device_t dev) | |
| 540 | { | |
| 541 | return(PCI_SLOTMAX); | |
| 542 | } | |
| 543 | ||
| 544 | /* | |
| 545 | * Since we are a child of a PCI bus, its parent must support the pcib interface. | |
| 546 | */ | |
| 547 | uint32_t | |
| 548 | pcib_read_config(device_t dev, int b, int s, int f, int reg, int width) | |
| 549 | { | |
| 550 | return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); | |
| 551 | } | |
| 552 | ||
| 553 | void | |
| 554 | pcib_write_config(device_t dev, int b, int s, int f, int reg, uint32_t val, int width) | |
| 555 | { | |
| 556 | PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); | |
| 557 | } | |
| 558 | ||
| 559 | /* | |
| 560 | * Route an interrupt across a PCI bridge. | |
| 561 | */ | |
| 562 | int | |
| 563 | pcib_route_interrupt(device_t pcib, device_t dev, int pin) | |
| 564 | { | |
| 565 | device_t bus; | |
| 566 | int parent_intpin; | |
| 567 | int intnum; | |
| 568 | ||
| 569 | /* | |
| 570 | * | |
| 571 | * The PCI standard defines a swizzle of the child-side device/intpin to | |
| 572 | * the parent-side intpin as follows. | |
| 573 | * | |
| 574 | * device = device on child bus | |
| 575 | * child_intpin = intpin on child bus slot (0-3) | |
| 576 | * parent_intpin = intpin on parent bus slot (0-3) | |
| 577 | * | |
| 578 | * parent_intpin = (device + child_intpin) % 4 | |
| 579 | */ | |
| 580 | parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; | |
| 581 | ||
| 582 | /* | |
| 583 | * Our parent is a PCI bus. Its parent must export the pcib interface | |
| 584 | * which includes the ability to route interrupts. | |
| 585 | */ | |
| 586 | bus = device_get_parent(pcib); | |
| 587 | intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); | |
| 588 | if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { | |
| 589 | device_printf(pcib, "slot %d INT%c is routed to irq %d\n", | |
| 590 | pci_get_slot(dev), 'A' + pin - 1, intnum); | |
| 591 | } | |
| 592 | return(intnum); | |
| 593 | } | |
| 594 | ||
| 595 | /* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ | |
| 596 | int | |
| 597 | pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) | |
| 598 | { | |
| 599 | struct pcib_softc *sc = device_get_softc(pcib); | |
| 600 | device_t bus; | |
| 601 | ||
| 602 | if (sc->flags & PCIB_DISABLE_MSI) | |
| 603 | return (ENXIO); | |
| 604 | bus = device_get_parent(pcib); | |
| 605 | return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, | |
| 606 | irqs)); | |
| 607 | } | |
| 608 | ||
| 609 | /* Pass request to release MSI/MSI-X messages up to the parent bridge. */ | |
| 610 | int | |
| 611 | pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) | |
| 612 | { | |
| 613 | device_t bus; | |
| 614 | ||
| 615 | bus = device_get_parent(pcib); | |
| 616 | return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); | |
| 617 | } | |
| 618 | ||
| 619 | /* Pass request to alloc an MSI-X message up to the parent bridge. */ | |
| 620 | int | |
| 621 | pcib_alloc_msix(device_t pcib, device_t dev, int *irq) | |
| 622 | { | |
| 623 | struct pcib_softc *sc = device_get_softc(pcib); | |
| 624 | device_t bus; | |
| 625 | ||
| 626 | if (sc->flags & PCIB_DISABLE_MSI) | |
| 627 | return (ENXIO); | |
| 628 | bus = device_get_parent(pcib); | |
| 629 | return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); | |
| 630 | } | |
| 631 | ||
| 632 | /* Pass request to release an MSI-X message up to the parent bridge. */ | |
| 633 | int | |
| 634 | pcib_release_msix(device_t pcib, device_t dev, int irq) | |
| 635 | { | |
| 636 | device_t bus; | |
| 637 | ||
| 638 | bus = device_get_parent(pcib); | |
| 639 | return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); | |
| 640 | } | |
| 641 | ||
| 642 | /* Pass request to map MSI/MSI-X message up to parent bridge. */ | |
| 643 | int | |
| 644 | pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, | |
| 645 | uint32_t *data) | |
| 646 | { | |
| 647 | device_t bus; | |
| 648 | int error; | |
| 649 | ||
| 650 | bus = device_get_parent(pcib); | |
| 651 | error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); | |
| 652 | if (error) | |
| 653 | return (error); | |
| 654 | ||
| 655 | pci_ht_map_msi(pcib, *addr); | |
| 656 | return (0); | |
| 657 | } | |
| 658 | ||
| 659 | /* | |
| 660 | * Try to read the bus number of a host-PCI bridge using appropriate config | |
| 661 | * registers. | |
| 662 | */ | |
| 663 | int | |
| 664 | host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, | |
| 665 | uint8_t *busnum) | |
| 666 | { | |
| 667 | uint32_t id; | |
| 668 | ||
| 669 | id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); | |
| 670 | if (id == 0xffffffff) | |
| 671 | return (0); | |
| 672 | ||
| 673 | switch (id) { | |
| 674 | case 0x12258086: | |
| 675 | /* Intel 824?? */ | |
| 676 | /* XXX This is a guess */ | |
| 677 | /* *busnum = read_config(bus, slot, func, 0x41, 1); */ | |
| 678 | *busnum = bus; | |
| 679 | break; | |
| 680 | case 0x84c48086: | |
| 681 | /* Intel 82454KX/GX (Orion) */ | |
| 682 | *busnum = read_config(bus, slot, func, 0x4a, 1); | |
| 683 | break; | |
| 684 | case 0x84ca8086: | |
| 685 | /* | |
| 686 | * For the 450nx chipset, there is a whole bundle of | |
| 687 | * things pretending to be host bridges. The MIOC will | |
| 688 | * be seen first and isn't really a pci bridge (the | |
| 689 | * actual busses are attached to the PXB's). We need to | |
| 690 | * read the registers of the MIOC to figure out the | |
| 691 | * bus numbers for the PXB channels. | |
| 692 | * | |
| 693 | * Since the MIOC doesn't have a pci bus attached, we | |
| 694 | * pretend it wasn't there. | |
| 695 | */ | |
| 696 | return (0); | |
| 697 | case 0x84cb8086: | |
| 698 | switch (slot) { | |
| 699 | case 0x12: | |
| 700 | /* Intel 82454NX PXB#0, Bus#A */ | |
| 701 | *busnum = read_config(bus, 0x10, func, 0xd0, 1); | |
| 702 | break; | |
| 703 | case 0x13: | |
| 704 | /* Intel 82454NX PXB#0, Bus#B */ | |
| 705 | *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; | |
| 706 | break; | |
| 707 | case 0x14: | |
| 708 | /* Intel 82454NX PXB#1, Bus#A */ | |
| 709 | *busnum = read_config(bus, 0x10, func, 0xd3, 1); | |
| 710 | break; | |
| 711 | case 0x15: | |
| 712 | /* Intel 82454NX PXB#1, Bus#B */ | |
| 713 | *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; | |
| 714 | break; | |
| 715 | } | |
| 716 | break; | |
| 717 | ||
| 718 | /* ServerWorks -- vendor 0x1166 */ | |
| 719 | case 0x00051166: | |
| 720 | case 0x00061166: | |
| 721 | case 0x00081166: | |
| 722 | case 0x00091166: | |
| 723 | case 0x00101166: | |
| 724 | case 0x00111166: | |
| 725 | case 0x00171166: | |
| 726 | case 0x01011166: | |
| 727 | case 0x010f1014: | |
| 728 | case 0x02011166: | |
| 729 | case 0x03021014: | |
| 730 | *busnum = read_config(bus, slot, func, 0x44, 1); | |
| 731 | break; | |
| 732 | ||
| 733 | /* Compaq/HP -- vendor 0x0e11 */ | |
| 734 | case 0x60100e11: | |
| 735 | *busnum = read_config(bus, slot, func, 0xc8, 1); | |
| 736 | break; | |
| 737 | default: | |
| 738 | /* Don't know how to read bus number. */ | |
| 739 | return 0; | |
| 740 | } | |
| 741 | ||
| 742 | return 1; | |
| 743 | } |