1a3da9792SAttilio Rao /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3ebf5747bSPedro F. Giffuni * 4a3da9792SAttilio Rao * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 5a3da9792SAttilio Rao * 6a3da9792SAttilio Rao * Redistribution and use in source and binary forms, with or without 7a3da9792SAttilio Rao * modification, are permitted provided that the following conditions 8a3da9792SAttilio Rao * are met: 9a3da9792SAttilio Rao * 1. Redistributions of source code must retain the above copyright 10a3da9792SAttilio Rao * notice, this list of conditions and the following disclaimer. 11a3da9792SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright 12a3da9792SAttilio Rao * notice, this list of conditions and the following disclaimer in the 13a3da9792SAttilio Rao * documentation and/or other materials provided with the distribution. 14a3da9792SAttilio Rao * 15a3da9792SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16a3da9792SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17a3da9792SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18a3da9792SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19a3da9792SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20a3da9792SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21a3da9792SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22a3da9792SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23a3da9792SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24a3da9792SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25a3da9792SAttilio Rao * SUCH DAMAGE. 26a3da9792SAttilio Rao */ 27a3da9792SAttilio Rao 28a3da9792SAttilio Rao /* 29a3da9792SAttilio Rao * Host to PCI and PCI to PCI bridge drivers that use the MP Table to route 30a3da9792SAttilio Rao * interrupts from PCI devices to I/O APICs. 31a3da9792SAttilio Rao */ 32a3da9792SAttilio Rao 33a3da9792SAttilio Rao #include <sys/param.h> 34a3da9792SAttilio Rao #include <sys/systm.h> 35a3da9792SAttilio Rao #include <sys/bus.h> 36a3da9792SAttilio Rao #include <sys/kernel.h> 37a3da9792SAttilio Rao #include <sys/module.h> 3883c41143SJohn Baldwin #include <sys/rman.h> 39a3da9792SAttilio Rao 40a3da9792SAttilio Rao #include <dev/pci/pcireg.h> 41a3da9792SAttilio Rao #include <dev/pci/pcivar.h> 42a3da9792SAttilio Rao #include <dev/pci/pcib_private.h> 43fcb250f3SAttilio Rao #include <x86/mptable.h> 44435803f3SJohn Baldwin #include <x86/legacyvar.h> 45a3da9792SAttilio Rao #include <machine/pci_cfgreg.h> 46a3da9792SAttilio Rao 47a3da9792SAttilio Rao #include "pcib_if.h" 48a3da9792SAttilio Rao 49a3da9792SAttilio Rao /* Host to PCI bridge driver. */ 50a3da9792SAttilio Rao 51a3da9792SAttilio Rao static int 52a3da9792SAttilio Rao mptable_hostb_probe(device_t dev) 53a3da9792SAttilio Rao { 54a3da9792SAttilio Rao 55a3da9792SAttilio Rao if (pci_cfgregopen() == 0) 56a3da9792SAttilio Rao return (ENXIO); 57b076d8d5SJohn Baldwin if (mptable_pci_probe_table(legacy_get_pcibus(dev)) != 0) 58a3da9792SAttilio Rao return (ENXIO); 59a3da9792SAttilio Rao device_set_desc(dev, "MPTable Host-PCI bridge"); 60a3da9792SAttilio Rao return (0); 61a3da9792SAttilio Rao } 62a3da9792SAttilio Rao 63a3da9792SAttilio Rao static int 64a3da9792SAttilio Rao mptable_hostb_attach(device_t dev) 65a3da9792SAttilio Rao { 66a3da9792SAttilio Rao 6734ff71eeSJohn Baldwin #ifdef NEW_PCIB 6834ff71eeSJohn Baldwin mptable_pci_host_res_init(dev); 6934ff71eeSJohn Baldwin #endif 7018c72666SZbigniew Bodek device_add_child(dev, "pci", -1); 71a3da9792SAttilio Rao return (bus_generic_attach(dev)); 72a3da9792SAttilio Rao } 73a3da9792SAttilio Rao 7434ff71eeSJohn Baldwin #ifdef NEW_PCIB 7534ff71eeSJohn Baldwin static int 762dd1bdf1SJustin Hibbits mptable_is_isa_range(rman_res_t start, rman_res_t end) 7734ff71eeSJohn Baldwin { 7834ff71eeSJohn Baldwin 7934ff71eeSJohn Baldwin if (end >= 0x10000) 8034ff71eeSJohn Baldwin return (0); 8134ff71eeSJohn Baldwin if ((start & 0xfc00) != (end & 0xfc00)) 8234ff71eeSJohn Baldwin return (0); 8334ff71eeSJohn Baldwin start &= ~0xfc00; 8434ff71eeSJohn Baldwin end &= ~0xfc00; 8534ff71eeSJohn Baldwin return (start >= 0x100 && end <= 0x3ff); 8634ff71eeSJohn Baldwin } 8734ff71eeSJohn Baldwin 8834ff71eeSJohn Baldwin static int 892dd1bdf1SJustin Hibbits mptable_is_vga_range(rman_res_t start, rman_res_t end) 9034ff71eeSJohn Baldwin { 9134ff71eeSJohn Baldwin if (end >= 0x10000) 9234ff71eeSJohn Baldwin return (0); 9334ff71eeSJohn Baldwin if ((start & 0xfc00) != (end & 0xfc00)) 9434ff71eeSJohn Baldwin return (0); 9534ff71eeSJohn Baldwin start &= ~0xfc00; 9634ff71eeSJohn Baldwin end &= ~0xfc00; 9734ff71eeSJohn Baldwin return (pci_is_vga_ioport_range(start, end)); 9834ff71eeSJohn Baldwin } 9934ff71eeSJohn Baldwin 10034ff71eeSJohn Baldwin static struct resource * 10134ff71eeSJohn Baldwin mptable_hostb_alloc_resource(device_t dev, device_t child, int type, int *rid, 1022dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 10334ff71eeSJohn Baldwin { 10434ff71eeSJohn Baldwin struct mptable_hostb_softc *sc; 10534ff71eeSJohn Baldwin 1064edef187SJohn Baldwin #ifdef PCI_RES_BUS 1074edef187SJohn Baldwin if (type == PCI_RES_BUS) 1084edef187SJohn Baldwin return (pci_domain_alloc_bus(0, child, rid, start, end, count, 1094edef187SJohn Baldwin flags)); 1104edef187SJohn Baldwin #endif 11134ff71eeSJohn Baldwin sc = device_get_softc(dev); 11234ff71eeSJohn Baldwin if (type == SYS_RES_IOPORT && start + count - 1 == end) { 11334ff71eeSJohn Baldwin if (mptable_is_isa_range(start, end)) { 11434ff71eeSJohn Baldwin switch (sc->sc_decodes_isa_io) { 11534ff71eeSJohn Baldwin case -1: 11634ff71eeSJohn Baldwin return (NULL); 11734ff71eeSJohn Baldwin case 1: 11834ff71eeSJohn Baldwin return (bus_generic_alloc_resource(dev, child, 11934ff71eeSJohn Baldwin type, rid, start, end, count, flags)); 12034ff71eeSJohn Baldwin default: 12134ff71eeSJohn Baldwin break; 12234ff71eeSJohn Baldwin } 12334ff71eeSJohn Baldwin } 12434ff71eeSJohn Baldwin if (mptable_is_vga_range(start, end)) { 12534ff71eeSJohn Baldwin switch (sc->sc_decodes_vga_io) { 12634ff71eeSJohn Baldwin case -1: 12734ff71eeSJohn Baldwin return (NULL); 12834ff71eeSJohn Baldwin case 1: 12934ff71eeSJohn Baldwin return (bus_generic_alloc_resource(dev, child, 13034ff71eeSJohn Baldwin type, rid, start, end, count, flags)); 13134ff71eeSJohn Baldwin default: 13234ff71eeSJohn Baldwin break; 13334ff71eeSJohn Baldwin } 13434ff71eeSJohn Baldwin } 13534ff71eeSJohn Baldwin } 13634ff71eeSJohn Baldwin start = hostb_alloc_start(type, start, end, count); 13734ff71eeSJohn Baldwin return (pcib_host_res_alloc(&sc->sc_host_res, child, type, rid, start, 13834ff71eeSJohn Baldwin end, count, flags)); 13934ff71eeSJohn Baldwin } 14034ff71eeSJohn Baldwin 14134ff71eeSJohn Baldwin static int 14234ff71eeSJohn Baldwin mptable_hostb_adjust_resource(device_t dev, device_t child, int type, 1432dd1bdf1SJustin Hibbits struct resource *r, rman_res_t start, rman_res_t end) 14434ff71eeSJohn Baldwin { 14534ff71eeSJohn Baldwin struct mptable_hostb_softc *sc; 14634ff71eeSJohn Baldwin 1474edef187SJohn Baldwin #ifdef PCI_RES_BUS 1484edef187SJohn Baldwin if (type == PCI_RES_BUS) 1494edef187SJohn Baldwin return (pci_domain_adjust_bus(0, child, r, start, end)); 1504edef187SJohn Baldwin #endif 15134ff71eeSJohn Baldwin sc = device_get_softc(dev); 15234ff71eeSJohn Baldwin return (pcib_host_res_adjust(&sc->sc_host_res, child, type, r, start, 15334ff71eeSJohn Baldwin end)); 15434ff71eeSJohn Baldwin } 15534ff71eeSJohn Baldwin #endif 15634ff71eeSJohn Baldwin 157a3da9792SAttilio Rao static device_method_t mptable_hostb_methods[] = { 158a3da9792SAttilio Rao /* Device interface */ 159a3da9792SAttilio Rao DEVMETHOD(device_probe, mptable_hostb_probe), 160a3da9792SAttilio Rao DEVMETHOD(device_attach, mptable_hostb_attach), 161a3da9792SAttilio Rao DEVMETHOD(device_shutdown, bus_generic_shutdown), 162a3da9792SAttilio Rao DEVMETHOD(device_suspend, bus_generic_suspend), 163a3da9792SAttilio Rao DEVMETHOD(device_resume, bus_generic_resume), 164a3da9792SAttilio Rao 165a3da9792SAttilio Rao /* Bus interface */ 166a3da9792SAttilio Rao DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar), 167a3da9792SAttilio Rao DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar), 16834ff71eeSJohn Baldwin #ifdef NEW_PCIB 16934ff71eeSJohn Baldwin DEVMETHOD(bus_alloc_resource, mptable_hostb_alloc_resource), 17034ff71eeSJohn Baldwin DEVMETHOD(bus_adjust_resource, mptable_hostb_adjust_resource), 17134ff71eeSJohn Baldwin #else 172a3da9792SAttilio Rao DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), 173d2c9344fSJohn Baldwin DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 17434ff71eeSJohn Baldwin #endif 1754edef187SJohn Baldwin #if defined(NEW_PCIB) && defined(PCI_RES_BUS) 1764edef187SJohn Baldwin DEVMETHOD(bus_release_resource, legacy_pcib_release_resource), 17731e15e53SJohn Baldwin DEVMETHOD(bus_activate_resource, legacy_pcib_activate_resource), 17831e15e53SJohn Baldwin DEVMETHOD(bus_deactivate_resource, legacy_pcib_deactivate_resource), 1794edef187SJohn Baldwin #else 180a3da9792SAttilio Rao DEVMETHOD(bus_release_resource, bus_generic_release_resource), 181a3da9792SAttilio Rao DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 182a3da9792SAttilio Rao DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 18331e15e53SJohn Baldwin #endif 184a3da9792SAttilio Rao DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 185a3da9792SAttilio Rao DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 186a3da9792SAttilio Rao 187a3da9792SAttilio Rao /* pcib interface */ 188a3da9792SAttilio Rao DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots), 189a3da9792SAttilio Rao DEVMETHOD(pcib_read_config, legacy_pcib_read_config), 190a3da9792SAttilio Rao DEVMETHOD(pcib_write_config, legacy_pcib_write_config), 191a3da9792SAttilio Rao DEVMETHOD(pcib_route_interrupt, mptable_pci_route_interrupt), 19284ca9aadSJohn Baldwin DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), 193a3da9792SAttilio Rao DEVMETHOD(pcib_release_msi, pcib_release_msi), 19484ca9aadSJohn Baldwin DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), 195a3da9792SAttilio Rao DEVMETHOD(pcib_release_msix, pcib_release_msix), 1960d95597cSJohn Baldwin DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi), 197a3da9792SAttilio Rao 1984b7ec270SMarius Strobl DEVMETHOD_END 199a3da9792SAttilio Rao }; 200a3da9792SAttilio Rao 20134ff71eeSJohn Baldwin DEFINE_CLASS_0(pcib, mptable_hostb_driver, mptable_hostb_methods, 20234ff71eeSJohn Baldwin sizeof(struct mptable_hostb_softc)); 20380d2b3deSJohn Baldwin DRIVER_MODULE(mptable_pcib, legacy, mptable_hostb_driver, 0, 0); 204a3da9792SAttilio Rao 205a3da9792SAttilio Rao /* PCI to PCI bridge driver. */ 206a3da9792SAttilio Rao 207a3da9792SAttilio Rao static int 208a3da9792SAttilio Rao mptable_pcib_probe(device_t dev) 209a3da9792SAttilio Rao { 210a3da9792SAttilio Rao int bus; 211a3da9792SAttilio Rao 212a3da9792SAttilio Rao if ((pci_get_class(dev) != PCIC_BRIDGE) || 213a3da9792SAttilio Rao (pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) 214a3da9792SAttilio Rao return (ENXIO); 215a3da9792SAttilio Rao bus = pci_read_config(dev, PCIR_SECBUS_1, 1); 216a3da9792SAttilio Rao if (bus == 0) 217a3da9792SAttilio Rao return (ENXIO); 218a3da9792SAttilio Rao if (mptable_pci_probe_table(bus) != 0) 219a3da9792SAttilio Rao return (ENXIO); 220a3da9792SAttilio Rao device_set_desc(dev, "MPTable PCI-PCI bridge"); 221a3da9792SAttilio Rao return (-1000); 222a3da9792SAttilio Rao } 223a3da9792SAttilio Rao 224a3da9792SAttilio Rao static device_method_t mptable_pcib_pci_methods[] = { 225a3da9792SAttilio Rao /* Device interface */ 226a3da9792SAttilio Rao DEVMETHOD(device_probe, mptable_pcib_probe), 227a3da9792SAttilio Rao 228a3da9792SAttilio Rao /* pcib interface */ 229a3da9792SAttilio Rao DEVMETHOD(pcib_route_interrupt, mptable_pci_route_interrupt), 230a3da9792SAttilio Rao {0, 0} 231a3da9792SAttilio Rao }; 232a3da9792SAttilio Rao 233a3da9792SAttilio Rao DEFINE_CLASS_1(pcib, mptable_pcib_driver, mptable_pcib_pci_methods, 234a3da9792SAttilio Rao sizeof(struct pcib_softc), pcib_driver); 23580d2b3deSJohn Baldwin DRIVER_MODULE(mptable_pcib, pci, mptable_pcib_driver, 0, 0); 236